目前共有28篇帖子。 內容轉換:不轉換▼
 
點擊 回復
702 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)
 

本帖信息

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