目前共有28篇帖子。 字體大小:較小 - 100% (默認)▼  內容轉換:港澳繁體▼
 
點擊 回復
1622 27
【原創C++程序】用C++創建顯示文章事件指令的剪切板內容(可粘貼到RMXP事件編輯器中)
一派掌門 二十級
1樓 發表于:2016-1-26 22:44
【核心代碼】
// RXData.cpp : 定義控制台應用程式的入口點。
//

#include "stdafx.h"
#include "RubyMarshal.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream; // 這是一個字符串的緩衝區
    RubyMarshal rms(&stream);
    rms.WriteHeader(); // 寫入Marshal的版本號4.8

    rms.BeginArray(1); // 整個剪切板的內容是一個單元素數組
    // ---- 從下面開始都是這個大數組的第一個元素的值 ------
    rms.BeginObject("RPG::EventCommand", 3); // 這個數組的唯一元素是一個RPG::EventCommand對象的實例,該對象有3個成員變量
        rms.BeginMember("code"); // 第一個成員變量code指定了事件指令編號
        rms.WriteFixnum(101); // 「顯示文章」的編號為101
        rms.BeginMember("indent"); // 第二個成員變量indent指定了事件指令在事件編輯器中的縮進程度
        rms.WriteFixnum(0); // 縮進為0
   
        rms.BeginMember("parameters"); // 第三個成員變量是事件指令的參數
        rms.BeginArray(1); // 該成員變量的值是一個單元素數組
        rms.WriteString("This is a string."); // 數組的唯一元素是一個字符串,指定了顯示文章的內容
        // 注意,文章內容的編碼必須是UTF8編碼格式(準確的說是Unicode編碼的UTF8存儲方式)
        // 在C++中,char字符數組可以存儲任何編碼的字符串,默認的編碼是ANSI編碼,而wchar_t字符數組存儲的字符串編碼一般為Unicode編碼的UTF16存儲方式。因此,使用wchar_t或wstring來存儲字符串時,可以先將UTF16存儲方式用WideCharToMultiByte函數轉換為UTF8存儲方式,最後再傳入WriteString方法裏
    // --------------------------------------------------

    rms.Copy(CF_RPGXPEVENTCOMMAND); // 複製到剪切板中,括號中是剪切板的格式編號

    return 0;
}

【運行程序後生成的剪切板內容】

一派掌門 二十級
2樓 發表于:2016-1-26 22:46
【基礎類庫】
// 目前我只完成了寫的部分,還沒完成讀的部分
【頭文件RubyMarshal.h】
#pragma once

#define MARSHAL_MAJOR 4
#define MARSHAL_MINOR 8

#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
#define TYPE_EXTENDED 'e'
#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_DATA 'd'
#define TYPE_USERDEF 'u'
#define TYPE_USRMARSHAL 'U'
#define TYPE_FLOAT 'f'
#define TYPE_BIGNUM 'l'
#define TYPE_STRING '"'
#define TYPE_REGEXP '/'
#define TYPE_ARRAY '['
#define TYPE_HASH '{'
#define TYPE_HASH_DEF '}'
#define TYPE_STRUCT 'S'
#define TYPE_MODULE_OLD 'M'
#define TYPE_CLASS 'c'
#define TYPE_MODULE 'm'
#define TYPE_SYMBOL ':'
#define TYPE_SYMLINK ';'
#define TYPE_IVAR 'I'
#define TYPE_LINK '@'

#define ONIG_OPTION_IGNORECASE 0x01
#define ONIG_OPTION_EXTEND 0x02
#define ONIG_OPTION_MULTILINE 0x04

#define CF_RPGXPEVENTCOMMAND 50306

class RubyMarshal
{
private:
    std::ostream *filestream;

    int WriteString(char type, char *pStr);
public:
    RubyMarshal(std::ostream *stream);
    ~RubyMarshal(void);

    int BeginArray(long length);
    int BeginExtended(char *modulename);
    int BeginHash(long length, bool hasDefValue = false);
    int BeginMember(char *memname);
    int BeginObject(char *clsname, long memlen);
    void Copy(UINT format);
    int WriteBignum(long long num);
    int WriteBool(bool value);
    int WriteClass(char *clsname);
    int WriteFixnum(long num);
    int WriteFloat(double num);
    int WriteHeader(void);
    int WriteLong(long num);
    int WriteModule(char *name);
    int WriteNil(void);
    int WriteRegexp(char *pStr);
    int WriteString(char *pStr);
    int WriteSymbol(char *pStr);
    int WriteSymLink(long link);
};
 
一派掌門 二十級
3樓 發表于:2016-1-26 22:46
【源文件RubyMarshal.cpp】
#include "StdAfx.h"
#include "RubyMarshal.h"

using namespace std;

RubyMarshal::RubyMarshal(ostream *stream) : filestream(stream)
{
}


RubyMarshal::~RubyMarshal(void)
{
}

int RubyMarshal::BeginArray(long length)
{
    filestream->put(TYPE_ARRAY);
    return WriteLong(length) + 1;
}

int RubyMarshal::BeginExtended(char *modulename)
{
    filestream->put(TYPE_EXTENDED);
    return WriteSymbol(modulename) + 1;
}

int RubyMarshal::BeginHash(long length, bool hasDefValue)
{
    if (hasDefValue)
        filestream->put(TYPE_HASH_DEF);
    else
        filestream->put(TYPE_HASH);
    return WriteLong(length) + 1;
}

int RubyMarshal::BeginMember(char *memname)
{
    int len = strlen(memname);
    int count = len + 2;
    filestream->put(TYPE_SYMBOL);
    count += WriteLong(len + 1);
    filestream->put(TYPE_LINK);
    filestream->write(memname, len);
    return count;
}

int RubyMarshal::BeginObject(char *clsname, long memlen)
{
    int count = 1;
    filestream->put(TYPE_OBJECT);
    count += WriteSymbol(clsname);
    count += WriteLong(memlen);
    return count;
}

void RubyMarshal::Copy(UINT format)
{
    ostringstream *stream = reinterpret_cast<ostringstream *>(filestream);
    string &str = stream->str();
    int len = str.length();
    OpenClipboard(NULL);
    EmptyClipboard();
    HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, len + 4);
    char *data = (char *)GlobalLock(hMem);
    data[0] = len & 0xff;
    data[1] = len >> 8 & 0xff;
    data[2] = len >> 16 & 0xff;
    data[3] = len >> 24 & 0xff;
    memcpy(data + 4, str.data(), len);

    GlobalUnlock(hMem);
    SetClipboardData(format, hMem);
    CloseClipboard();
}

int RubyMarshal::WriteBignum(long long num)
{
    char data[sizeof(long long)] = {0};
    int count = 2;
    int i;
    filestream->put(TYPE_BIGNUM);
    if (num >= 0)
        filestream->put('+');
    else
    {
        filestream->put('-');
        num = -num;
    }
    for (i = 0; i < sizeof(long long); i++)
    {
        data[i] = num & 0xff;
        num >>= 8;
        if (num == 0)
            break;
    }
    i = i / 2 + 1;
    count += WriteLong(i);
    i *= 2;
    filestream->write(data, i);
    count += i;
    return count;
}

int RubyMarshal::WriteBool(bool value)
{
    if (value)
        filestream->put(TYPE_TRUE);
    else
        filestream->put(TYPE_FALSE);
    return 1;
}

int RubyMarshal::WriteClass(char *clsname)
{
    return WriteString(TYPE_CLASS, clsname);
}

int RubyMarshal::WriteFixnum(long num)
{
    filestream->put(TYPE_FIXNUM);
    return WriteLong(num) + 1;
}


int RubyMarshal::WriteFloat(double num)
{
    ostringstream strstream;
    strstream << setiosflags(ios::fixed) << setprecision(16) << num;
    string str = strstream.str();
    int len = str.length();
   
    int count = len + 1;
    filestream->put(TYPE_FLOAT);
    count += WriteLong(len);
    filestream->write(str.c_str(), len);
    return count;
}

int RubyMarshal::WriteHeader(void)
{
    char header[] = {MARSHAL_MAJOR, MARSHAL_MINOR};
    filestream->write(header, sizeof(header));
    return sizeof(header);
}

int RubyMarshal::WriteLong(long num)
{
    char data[sizeof(long) + 1];
    int count = 1;
    int i;
    if (num == 0)
        data[0] = 0;
    else if (num > 0 && num < 123)
        data[0] = (char)(num + 5);
    else if (num > -124 && num < 0)
        data[0] = (char)((num - 5) & 0xff);
    else
    {
        for (i = 1; i < sizeof(long) + 1; i++)
        {
            data[i] = (char)(num & 0xff);
            num >>= 8;
            if (num == 0)
            {
                data[0] = i;
                break;
            }
            else if (num == -1)
            {
                data[0] = -i;
                break;
            }
        }
        count += i;
    }
    filestream->write(data, count);
    return count;
}

int RubyMarshal::WriteModule(char *name)
{
    return WriteString(TYPE_MODULE, name);
}

int RubyMarshal::WriteNil(void)
{
    filestream->put(TYPE_NIL);
    return 1;
}

int RubyMarshal::WriteRegexp(char *pStr)
{
    int start = 0, end;
    int len = strlen(pStr);
    int count = 2;
    if (pStr[0] == '/')
        start = 1;
    for (end = len - 1; pStr[end] != '/' && end >= 0; end--);
    if (end <= start)
        end = len;
    int regLen = end - start;
    filestream->put(TYPE_REGEXP);
    count += WriteLong(regLen);
    filestream->write(pStr + start, regLen);
    count += regLen;
   
    char flag = 0;
    for (pStr += end + 1; *pStr != '\0'; pStr++)
    {
        switch (*pStr)
        {
        case 'i':
            flag |= ONIG_OPTION_IGNORECASE;
            break;
        case 'm':
            flag |= ONIG_OPTION_MULTILINE;
            break;
        case 'x':
            flag |= ONIG_OPTION_EXTEND;
            break;
        }
    }
    filestream->put(flag);
    return count;
}

int RubyMarshal::WriteString(char *pStr)
{
    return WriteString(TYPE_STRING, pStr);
}

int RubyMarshal::WriteString(char type, char *pStr)
{
    int len = strlen(pStr);
    filestream->put(type);
    int count = WriteLong(len);
    filestream->write(pStr, len);
    count += len + 1;
    return count;
}

int RubyMarshal::WriteSymbol(char *pStr)
{
    return WriteString(TYPE_SYMBOL, pStr);
}

int RubyMarshal::WriteSymLink(long link)
{
    filestream->put(TYPE_SYMLINK);
    return WriteLong(link) + 1;
}
 
一派掌門 二十級
4樓 發表于:2016-1-26 22:47
【預編譯頭文件】
// stdafx.h : 標準系統包含文件的包含文件,
// 或是經常使用但不常更改的
// 特定於項目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>

#include <Windows.h>

// TODO: 在此處引用程序需要的其他頭文件

 
一派掌門 二十級
5樓 發表于:2016-1-26 22:49
整個剪切板就是一個RXData片段,裏面的內容和rxdata文件的格式完全一樣。
RubyMarshal類就是用來寫rxdata文件的(目前讀的部分還沒做)
 
一派掌門 二十級
6樓 發表于:2016-1-26 22:59
示例程序及原始碼下載地址:
http://zlk1214.ys168.com/
文件夾:C++
文件名:Cpp生成RMXP顯示文章事件指令的示例代碼.7z
文件大小:664KB
 
一派掌門 二十級
7樓 發表于:2016-1-27 10:11
【補充】
由於每次開機後rmxp向系統註冊的剪切板格式編號不一樣,但名字是相同的,所以應該把代碼中的rms.Copy那句話改成:
UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT_COMMAND"));
rms.Copy(format);
並且去掉原先define的那個宏。
今天,我電腦上的編號已經變成50204了,不再是昨天晚上的50306了。
在Windows API中不能向剪切板中放置未註冊格式的內容。
 
一派掌門 二十級
8樓 發表于:2016-1-27 10:15
【示例:複製等待300幀的事件指令】
int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream;
    RubyMarshal rms(&stream);
    rms.WriteHeader();

    rms.BeginArray(1);
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
   
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(300);

    UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT_COMMAND"));
    rms.Copy(format);

    return 0;
}
 
一派掌門 二十級
9樓 發表于:2016-1-27 10:25
【示例:複製兩個事件指令。一個是等待300幀,另一個是等待20幀】
    rms.WriteHeader();
    rms.BeginArray(2);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(300);

    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(106);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(1);
    rms.WriteFixnum(20);
 
一派掌門 二十級
10樓 發表于:2016-1-27 10:29
【示例:複製中斷事件處理,這個事件指令無參數】
    rms.WriteHeader();
    rms.BeginArray(1);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(115);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(0); // 無參數
 
一派掌門 二十級
11樓 發表于:2016-1-27 10:32
所有的RMXP事件指令的編號都可以在腳本「Interpreter 2」中查出來。
至於參數列表,可以在Interpreter 3~7裏面查出來(通過查看@parameters在各def command_***里的用法)
 
一派掌門 二十級
12樓 發表于:2016-1-27 10:35
【示例:開關操作,開關1=ON】
rms.WriteHeader();
    rms.BeginArray(1);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(121);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(3);
    rms.WriteFixnum(1);
    rms.WriteFixnum(1); // 這裏如果是5的話,那麼就是開關1~5都設置為ON了
    rms.WriteFixnum(0);
 
一派掌門 二十級
13樓 發表于:2016-1-27 10:39
【示例:獨立開關操作E為OFF】
rms.WriteHeader();
    rms.BeginArray(1);
   
    rms.BeginObject("RPG::EventCommand", 3);
    rms.BeginMember("code");
    rms.WriteFixnum(123);
    rms.BeginMember("indent");
    rms.WriteFixnum(0);
    rms.BeginMember("parameters");
    rms.BeginArray(2);
    rms.WriteString("E");
    rms.WriteFixnum(1); // 1為OFF,0為ON

一粘貼,還真把獨立開關E給粘上去了。。。牛逼

 
一派掌門 二十級
14樓 發表于:2016-1-27 10:41
    rms.BeginArray(2);
    rms.WriteString("I'm a pig.");
    rms.WriteFixnum(1);
還能產生更怪的獨立開關名字:
 
一派掌門 二十級
15樓 發表于:2016-1-27 10:45
複製一個不存在的623指令試試看:
rms.BeginMember("code");
rms.WriteFixnum(623);


這更牛逼了。
 
一派掌門 二十級
16樓 發表于:2016-1-27 11:26
在剪切板中,RPG::EventCommand對象的三個參數code, indent, parameters一個都不能省略,但順序可以任意調換。其中indent參數雖然沒有用,但也必須寫出來,不能省略。
 
一派掌門 二十級
17樓 發表于:2016-1-27 12:28
【擴展】
// 下面為了簡化程序,定義三個AddMember方法:
int RubyMarshal::AddMember(char *memname, bool memvalue)
{
    int count = BeginMember(memname);
    count += WriteBool(memvalue);
    return count;
}

int RubyMarshal::AddMember(char *memname, char *memvalue)
{
    int count = BeginMember(memname);
    count += WriteString(memvalue);
    return count;
}

int RubyMarshal::AddMember(char *memname, long memvalue)
{
    int count = BeginMember(memname);
    count += WriteFixnum(memvalue);
    return count;
}
// 這三個方法都是BeginMember和WriteXXXX方法的簡寫
 
一派掌門 二十級
18樓 發表于:2016-1-27 12:29
【示例:複製一個事件】
// RXData.cpp : 定義控制台應用程式的入口點。
//

#include "stdafx.h"
#include "RubyMarshal.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream;
    RubyMarshal rms(&stream);

    rms.WriteHeader();
    rms.BeginObject("RPG::Event", 2);
    rms.AddMember("name", "Event Example"); // 事件名
    // 本來RMXP幫助手冊里寫着RPG::Event有5個成員,但在剪切板中,成員id, x, y都可以省略不寫

    /* 事件頁 */
    rms.BeginMember("pages");
    rms.BeginArray(1); // 事件頁的數量
    /* 第一頁 */
    rms.BeginObject("RPG::Event::Page", 13);
        rms.AddMember("move_type", 0L); // 移動類型
        rms.AddMember("move_speed", 3L); // 移動速度
        rms.AddMember("move_frequency", 3L); // 移動頻度
        rms.AddMember("walk_anime", false); // 移動時動畫
        rms.AddMember("step_anime", true); // 停止時動畫
        rms.AddMember("direction_fix", true); // 固定朝向
        rms.AddMember("through", false); // 允許穿透
        rms.AddMember("always_on_top", false); // 在最前面顯示
        rms.AddMember("trigger", 1L); // 事件開始條件: 與主角接觸

        /* 事件頁出現條件 */
        rms.BeginMember("condition");
            rms.BeginObject("RPG::Event::Page::Condition", 9);
            rms.AddMember("switch1_valid", false);
            rms.AddMember("switch2_valid", false);
            rms.AddMember("variable_valid", false);
            rms.AddMember("self_switch_valid", false);
            rms.AddMember("switch1_id", 1L);
            rms.AddMember("switch2_id", 1L);
            rms.AddMember("variable_id", 1L);
            rms.AddMember("variable_value", 0L);
            rms.AddMember("self_switch_ch", "A");

        /* 事件圖像 */
        rms.BeginMember("graphic");
            rms.BeginObject("RPG::Event::Page::Graphic", 7);
            rms.AddMember("tile_id", 0L); // 圖塊id
            rms.AddMember("character_name", ""); // 文件名為空表示沒有圖像
            rms.AddMember("character_hue", 0L); // 色相
            rms.AddMember("direction", 2L); // 方向
            rms.AddMember("pattern", 0L); // 角色腳的狀態
            rms.AddMember("opacity", 0xffL); // 不透明度為255
            rms.AddMember("blend_type", 0L); // 合成方式為普通

        /* 移動路線 */
        rms.BeginMember("move_route");
            rms.BeginObject("RPG::MoveRoute", 3);
            rms.AddMember("repeat", true);
            rms.AddMember("skippable", false);
            rms.BeginMember("list");
            rms.BeginArray(0);

        /* 執行內容 */
        rms.BeginMember("list");
            rms.BeginArray(1); // 執行內容只有一條指令
            rms.BeginObject("RPG::EventCommand", 2);
            // 這裏應該是RMXP檢查不嚴,所以indent(縮進的深度)參數也可以省略了
            // 不過事件指令中有條件分歧的話最好還是把indent寫上
            rms.AddMember("code", 106L); // 指令為: 等待
            rms.BeginMember("parameters");
            rms.BeginArray(1);
            rms.WriteFixnum(300); // 等待300幀

    UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT"));
    rms.Copy(format);

    return 0;
}
 
一派掌門 二十級
19樓 發表于:2016-1-27 12:33
注意,上面的程序最後的剪切板格式變成了RPGXP EVENT。
粘貼後的事件:



 
一派掌門 二十級
20樓 發表于:2016-1-27 13:24
【擴展】
接下來,為了解決中文亂碼的問題,定義下列兩個方法:
int RubyMarshal::AddMember(char *memname, wchar_t *memvalue)
{
    int count = BeginMember(memname);
    count += WriteString(memvalue);
    return count;
}
int RubyMarshal::WriteString(wchar_t *pStr)
{
    int size = WideCharToMultiByte(CP_UTF8, NULL, pStr, -1, NULL, 0, NULL, NULL);
    char *buffer = new char[size];
    WideCharToMultiByte(CP_UTF8, NULL, pStr, -1, buffer, size, NULL, NULL);
    filestream->put(RBT_STRING);
    int count = WriteLong(size - 1) + size;
    filestream->write(buffer, size - 1);
    delete[] buffer;
    return count;
}

然後在執行時給成員變量的值加上L就行了。
例如:
rms.AddMember("name", L"老人"); // 事件名
效果:

 
一派掌門 二十級
21樓 發表于:2016-1-27 13:43
上面的RBT_STRING就是TYPE_STRING,我只是修改了一下宏的名字。
RBT就是RubyType的意思。

下面,我們來創建一個完整的商人事件。
請看代碼:
// RXData.cpp : 定義控制台應用程式的入口點。
//

#include "stdafx.h"
#include "RubyMarshal.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream;
    RubyMarshal rms(&stream);

    rms.WriteHeader();
    rms.BeginObject("RPG::Event", 2);
    rms.AddMember("name", L"商人"); // 事件名
    // 本來RMXP幫助手冊里寫着RPG::Event有5個成員,但在剪切板中,成員id, x, y都可以省略不寫

    /* 事件頁 */
    rms.BeginMember("pages");
    rms.BeginArray(1); // 事件頁的數量
    /* 第一頁 */
    rms.BeginObject("RPG::Event::Page", 13);
        rms.AddMember("move_type", 0L); // 移動類型
        rms.AddMember("move_speed", 3L); // 移動速度
        rms.AddMember("move_frequency", 3L); // 移動頻度
        rms.AddMember("walk_anime", false); // 移動時動畫
        rms.AddMember("step_anime", true); // 停止時動畫
        rms.AddMember("direction_fix", true); // 固定朝向
        rms.AddMember("through", false); // 允許穿透
        rms.AddMember("always_on_top", false); // 在最前面顯示
        rms.AddMember("trigger", 1L); // 事件開始條件: 與主角接觸

        /* 事件頁出現條件 */
        rms.BeginMember("condition");
            rms.BeginObject("RPG::Event::Page::Condition", 9);
            rms.AddMember("switch1_valid", false);
            rms.AddMember("switch2_valid", false);
            rms.AddMember("variable_valid", false);
            rms.AddMember("self_switch_valid", false);
            rms.AddMember("switch1_id", 1L);
            rms.AddMember("switch2_id", 1L);
            rms.AddMember("variable_id", 1L);
            rms.AddMember("variable_value", 0L);
            rms.AddMember("self_switch_ch", "A");

        /* 事件圖像 */
        rms.BeginMember("graphic");
            rms.BeginObject("RPG::Event::Page::Graphic", 7);
            rms.AddMember("tile_id", 0L); // 圖塊id
            rms.AddMember("character_name", "001-npc01"); // 注意: 文件名不要帶上擴展名
            rms.AddMember("character_hue", 0L); // 色相
            rms.AddMember("direction", 4L); // 方向 (2, 4, 6, 8)
            rms.AddMember("pattern", 0L); // 角色腳的狀態
            rms.AddMember("opacity", 0xffL); // 不透明度為255
            rms.AddMember("blend_type", 0L); // 合成方式為普通

        /* 移動路線 */
        rms.BeginMember("move_route");
            rms.BeginObject("RPG::MoveRoute", 3);
            rms.AddMember("repeat", true);
            rms.AddMember("skippable", false);
            rms.BeginMember("list");
            rms.BeginArray(0);

        /* 執行內容 */
        rms.BeginMember("list");
        rms.BeginArray(4);
            rms.BeginObject("RPG::EventCommand", 2);
            rms.AddMember("code", 106L); // 等待: 10幀
            rms.BeginMember("parameters");
            rms.BeginArray(1);
            rms.WriteFixnum(10);

            rms.BeginObject("RPG::EventCommand", 2);
            rms.AddMember("code", 101L); // 顯示文章的第一行
            rms.BeginMember("parameters");
            rms.BeginArray(1);
            rms.WriteString(L"我是商人");
            rms.BeginObject("RPG::EventCommand", 2);
            rms.AddMember("code", 401L); // 第二行及以上要用401指令!
            rms.BeginMember("parameters");
            rms.BeginArray(1);
            rms.WriteString(L"我聽說,這座塔有50層");

            // 最後一個空指令確保了用戶能夠在事件編輯器中執行內容的最後插入新指令
            rms.BeginObject("RPG::EventCommand", 2);
            rms.AddMember("code", 0L);
            rms.BeginMember("parameters");
            rms.BeginArray(0);

    UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT"));
    rms.Copy(format);

    return 0;
}

粘貼後:

 
一派掌門 二十級
22樓 發表于:2016-1-27 13:44

最後的那個空指令很重要,沒有了它,我們就無法在RMXP事件編輯器中的最後添加新指令了。。。
 
一派掌門 二十級
23樓 發表于:2016-1-27 13:49
注意,兩行及其以上的顯示文章要每行佔一個指令。第一行的指令編號是101,其他行都是401。不能只寫成一個指令,然後文章內容用\n換行,不然粘貼後就是下面這個樣子:

錯誤的代碼:
rms.BeginObject("RPG::EventCommand", 2);
rms.AddMember("code", 101L);
rms.BeginMember("parameters");
rms.BeginArray(1);
rms.WriteString(L"我是商人\n我聽說,這座塔有50層");

這同時也證明了,RMXP事件編輯器中的ListBox控件用的是自繪的方式實現的,也就是所謂的Owner-drawn ListBox。具體可以去看看微軟的MSDN。
 
一派掌門 二十級
24樓 發表于:2016-1-27 13:51
在事件指令的最後沒有插入空指令的後果:


同時,末尾也無法加入新指令:

 
一派掌門 二十級
25樓 發表于:2016-1-27 13:55
【示例:插入中文名稱的獨立開關】
rms.BeginObject("RPG::EventCommand", 2);
rms.AddMember("code", 123L);
rms.BeginMember("parameters");
rms.BeginArray(2);
rms.WriteString(L"我是豬");
rms.WriteFixnum(0);
【運行效果】

 
一派掌門 二十級
26樓 發表于:2016-1-27 14:07
事實上,RMXP對剪切板中複製的事件幾乎不做檢查。
僅僅下面幾行代碼就能創建一個空白但不完整的事件:
#include "stdafx.h"
#include "RubyMarshal.h"

using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    ostringstream stream;
    RubyMarshal rms(&stream);

    rms.WriteHeader();
    rms.BeginObject("RPG::Event", 1);
    rms.BeginMember("pages");
    rms.BeginArray(1);
    rms.BeginObject("RPG::Event::Page", 0);

    UINT format = RegisterClipboardFormat(TEXT("RPGXP EVENT"));
    rms.Copy(format);
    return 0;
}
 
一派掌門 二十級
27樓 發表于:2016-1-28 14:01
RMXP的剪切板內容的首4個字節表示全部後續內容的大小。比如後續內容有8個字節,那麼前四個字節的內容就是:08 00 00 00,然後緊接着就是這8個字節的內容。
在RMXP剪切板中,除了開頭4個字節外,其餘內容和rxdata文件中的格式完全一樣。因此,上述的C++ RubyMarshal類完全可以用來寫(或者說是生成)rxdata文件。程序一開始只需創建一個ofstream對象,並以ios::binary方式打開一個rxdata文件,傳入RubyMarshal類的構造函數中就可以了,只不過不能再用Copy方法了。
 
一派掌門 二十級
28樓 發表于:2016-2-17 23:28
其實這段程序裏面還有一個問題。就是沒要考慮同一段rxdata數據中不能出現兩個完全相同符號對象。如果同一符號對象第二次出現,就必須改成符號連結(用分號表示)。
 

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:1622 回複數:27
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2016-2-17 23:28
 
©2010-2025 Purasbar Ver2.0
除非另有聲明,本站採用共享創意姓名標示-相同方式分享 3.0 Unported許可協議進行許可。