目前共有28篇帖子。
【原創C++程序】用C++創建顯示文章事件指令的剪切板內容(可粘貼到RMXP事件編輯器中)
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數據中不能出現兩個完全相同符號對象。如果同一符號對象第二次出現,就必須改成符號連結(用分號表示)。

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。