目前共有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許可協議進行許可。