diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ca1782 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ + +dyndemo/ +htmlhelp/ +docs/ + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1d4ade1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,36 @@ +Copyright (C) 2006-2021, David "Cherry" Trapp +All rights reserved. + +1. Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the conditions laid out in the + following paragraphs are met. +2. Redistributions of source code (if available) must retain the above + copyright notice, this list of conditions and the following disclaimer. +3. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3.1. In case this software is redistributed in binary form inside of a + executable or library file belonging to Third Parties and/or + including modifications done by Third Parties (or done by the Author + in Third Parties' names), any license restrictions imposed by the + Third Parties which disallow modification and/or redistribution remain + valid and have to be adhered, overriding the rights described in + paragraph 1 of this license. This does not give the Third Parties + the right to claim ownership of those parts of the software which + were developed by the Author, nor does it affect the remaining + parts of this license. +4. All advertising materials by Third Parties mentioning features or use + of this software must display the following acknowledgement (unless + agreed otherwise through written notice): + This product includes software developed by David "Cherry" Trapp. + +DISCLAIMER: +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b74bdb5 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# DynRPG - The RPG Maker 2003 Plugin SDK + +**by David “Cherry” Trapp** - http://cherrytree.at/dynrpg - dynrpg@cherrytree.at + +For an explanation of what this is and how to use it, or to **download a release**, check [its **website**](http://cherrytree.at/dynrpg). + +This repository houses the full source code of DynRPG. If you are an end-user, get the release linked above instead. + +## Directory structure + +* `patch`: Contains the source code of the RPG_RT patch (written in assembly). +* `sdk`: Contains the header files and documentation of the DynRPG SDK (written in C++). +* `library`: Contains the source code of the DynRPG library (written in C++). +* `loader`: Contains the source code of the loader DLL (written in FreeBasic). +* `patcher`: Contains the source code of the patcher tool (written in FreeBasic). +* `dyndemo`: Will contain an RM2k3 project as test environment for the patch and loader, will contain the patched RPG_RT and the loader binary. +* `htmlhelp`: Will contain the HTML Help Compiler. +* `docs`: Will contain HTML docs. + +## Build instructions + +### Patch + +#### Prerequisites + +* Create an RPG Maker 2003 v1.08 project in a new folder `dyndemo`. You will test the patch and its functions here. The base version of the RPG_RT.exe can be found [here](https://cherryshare.at/f/maVT0s/RPG_RT.exe). +* Install [OllyDbg v1.10](http://ollydbg.de/odbg110.zip) and the [MUltimate Assembler](https://rammichael.com/multimate-assembler) plugin. Also check out [this answer](https://stackoverflow.com/a/13673957/1871033) in case you run into a problem with “Single-step event at ntdll” events. Add `0EEDFADE` to the allowed exceptions list to avoid breaking unnecessarily (for example when pressing F12). + +#### Build + +1. Load `dyndemo\RPG_RT.exe` into OllyDbg. You can specify command line arguments `TestPlay ShowTitle Window` for easier testing. If you have already loaded it and worked on it before, make sure to rewind it using Ctrl+F2 before saving changes (because further changes may have been made at runtime which you don’t want to include in the patch). +2. Press Ctrl+M to open MUltimate Assembler. +3. If you do this for the first time, right-click the tab bar and use the “Load from file…” option to load `patch\patch.asm`. +4. Click “Assemble” to apply the patch. +5. Make sure you are in the code segment - if not, press Ctrl+G and enter `401000`. +6. Right-click assembly code in the CPU window and select “Copy to executable” => “All modifications”. +7. Right-click the file window contents and select “Save file”. +8. Save to `RPG_RT2.exe`. + +This will create a patched RPG_RT binary `dyndemo\RPG_RT2.exe`. + +### Loader + +#### Prerequisites + +* Install [FreeBasic](https://www.freebasic.net/). Known working version is 1.03.0 but newer versions may work as well. +* Install [FBEdit](https://github.com/CherryDT/FbEditMOD/) to open the `.fbp` project files. +* Test project in `dyndemo` must exist (see patch building prerequisites above). + +#### Build + +1. Open `loader\dynloader.fbp` in FBEdit. +2. Select target `Windows dll` and hit F5 to compile. + +This will create a loader DLL`dyndemo\dynloader.dll`. + +### Library + +#### Prerequisites + +* Install MinGW with [GCC 5.3.0](https://sourceforge.net/projects/mingw/files/MinGW/Base/gcc/Version5/gcc-5.3.0-3/). Using a different version may require tweaks to compiler flags and/or modifications of `__asm` statements to work properly! +* Install [CodeBlocks](https://www.codeblocks.org/downloads/) (10.05 is known to work) and make sure it is configured to use the correct GCC version. + +#### Build + +1. Open `library\DynRPG.cbp` in CodeBlocks. +2. Select target `Release` and Ctrl+F9 to compile. + +This will create a static library `sdk\lib\libDynRPG.a`. + +**Note:** To build plugins using the DynRPG development environment, all you need to do is adding `(DynRPG repo path)\sdk\include` to your include search paths and `(DynRPG repo path)\sdk\lib` to your library search paths in the plugin project. If you then set the build output as `(DynRPG repo path)\dyndemo\DynPlugins\your_plugin.dll`, you can immediately test the plugin together with the dev version of DynRPG. + +### Patcher + +#### Prerequisites + +* Install [FreeBasic](https://www.freebasic.net/). Known working version is 1.03.0 but newer versions may work as well. +* Install [FBEdit](https://github.com/CherryDT/FbEditMOD/) to open the `.fbp` project files. +* Unpatched file `dyndemo\RPG_RT.exe`, patched file `dyndemo\RPG_RT2.exe` and loader `dyndemo\dynloader.dll` must exist (see instructions to build the patch and the loader above). + +#### Build + +1. Open a command prompt and go to directory `patcher`. +2. Run `hpdpa dynrpg.txt` to create `dynrpg.hpd`. +3. Open `patcher\dynrpg_patcher.fbp` in FBEdit. +4. Select target `Windows GUI` and hit F5 to compile. + +This will create a patcher binary `patcher\dynrpg_patcher.exe`. + +### Documentation + +#### Prerequisites + +* Install [Doxygen](https://www.doxygen.nl/download.html), but get [version 1.7.6.1](https://sourceforge.net/projects/doxygen/files/rel-1.7.6.1/) - there is no guarantee newer versions are compatible. +* Install [HTML Help Compiler](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/htmlhelp/microsoft-html-help-downloads?redirectedfrom=MSDN) into a new directory `htmlhelp`. + +#### Build + +* Open a command prompt and go to directory `sdk\include\DynRPG`. +* Run `doxygen doxygen.cfg`. + +This will create HTML docs in `docs\html` and a CHM file in `sdk\dynrpg.chm`. + diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..6e5a0be --- /dev/null +++ b/library/.gitignore @@ -0,0 +1,8 @@ +obj/ +libDynRPG.a +*.dll.a +*.o + +*.depends +*.layout + diff --git a/library/Actor.cpp b/library/Actor.cpp new file mode 100644 index 0000000..bd1e0b8 --- /dev/null +++ b/library/Actor.cpp @@ -0,0 +1,50 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + std::string Actor::getDegree() { + if(degree.s_str() == "\x01") return dbActors[id]->degree; + return degree; + } + + std::string Actor::getCharsetFilename() { + if(charsetFilename.s_str() == "") return dbActors[id]->charsetFilename; + return charsetFilename; + } + + int Actor::getCharsetId() { + if(charsetFilename.s_str() == "") return dbActors[id]->charsetId; + return charsetId; + } + + int Actor::getCharsetTransparency() { + if(charsetFilename.s_str() == "") return dbActors[id]->charsetTransparent ? 3 : 0; + return charsetTransparency; + } + + std::string Actor::getFacesetFilename() { + if(facesetFilename.s_str() == "") return dbActors[id]->facesetFilename; + return facesetFilename; + } + + int Actor::getFacesetId() { + if(facesetFilename.s_str() == "") return dbActors[id]->facesetId; + return facesetId; + } + + int Actor::getBattleGraphicId() { + if(battleGraphicId == 0) return dbActors[id]->battleGraphicId; + return battleGraphicId; + } + + int Actor::getBattleCommand(int index) { + if(!customBattleCommands) return dbActors[id]->battleCommands[index]; + return battleCommands[index]; + } + + Actor *Actor::partyMember(int index) { + Actor *ret = NULL; + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x4A6014), "a" (**(void ***)0x4CDB74), "d" (index) : "ecx", "cc", "memory"); // GetPartyMember + return ret; + } +} diff --git a/library/Battler.cpp b/library/Battler.cpp new file mode 100644 index 0000000..e5de3d4 --- /dev/null +++ b/library/Battler.cpp @@ -0,0 +1,84 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + std::string Battler::getName() { + DStringPtr s; + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (vTable[9]), "a" (this), "d" (&s) : "ecx", "cc", "memory"); // GetMaxHP + return s; + } + + int Battler::getMaxHp() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (vTable[10]), "a" (this) : "edx", "ecx", "cc", "memory"); // GetMaxHP + return ret; + } + + int Battler::getMaxMp() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (vTable[11]), "a" (this) : "edx", "ecx", "cc", "memory"); // GetMaxMP + return ret; + } + + int Battler::getAttack() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4BFB28), "a" (this) : "edx", "ecx", "cc", "memory"); // GetATK + return ret; + } + + int Battler::getDefense() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4BFBF4), "a" (this) : "edx", "ecx", "cc", "memory"); // GetDEF + return ret; + } + + int Battler::getIntelligence() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4BFCC0), "a" (this) : "edx", "ecx", "cc", "memory"); // GetINT + return ret; + } + + int Battler::getAgility() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4BFD5C), "a" (this) : "edx", "ecx", "cc", "memory"); // GetAGI + return ret; + } + + void Battler::setRow(Row newRow) { + rowAlt = newRow; + row = newRow; + } + + void Battler::damagePopup(int number, int color) { + damagePopupTimer = DPT_START; + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4BF5E4), "a" (this), "d" (number), "c" (color) : "cc", "memory"); // ShowDamage + } + + void Battler::damagePopup(std::string text) { + damagePopupTimer = DPT_START; + DStringPtr s(text); + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x4BF550), "a" (this), "d" (s.str) : "ecx", "cc", "memory"); + } + + bool Battler::isMonster() { + return vTable == reinterpret_cast(0x4BD35C); + } + + void Battler::flash(int r, int g, int b, int intensity, int duration) { + flashR = r; + flashG = g; + flashB = b; + flashIntensity = (double)intensity; + flashTimer = duration; + } + + bool Battler::executeAction(bool skipPluginHandlers) { + bool ret; + if(skipPluginHandlers) { + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x49A04C), "a" (**sceneObjects[SCENE_BATTLE]), "d" (this) : "ecx", "cc", "memory"); // ExecuteBattlerAction + } else { + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x45CDF4), "a" (**sceneObjects[SCENE_BATTLE]), "d" (this) : "ecx", "cc", "memory"); // ExecuteBattlerAction (DynRPG) + } + return ret; + } +} diff --git a/library/Canvas.cpp b/library/Canvas.cpp new file mode 100644 index 0000000..79c87b1 --- /dev/null +++ b/library/Canvas.cpp @@ -0,0 +1,81 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + unsigned short &Canvas::pixel(int x, int y) { + return getScanline(y)[x]; + } + + unsigned short *Canvas::getScanline(int y) { + unsigned short *ret; + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x4683B8), "a" (this), "d" (y) : "ecx", "cc", "memory"); // GetAuroraBoardPixelLineAddress + return ret; + } + + int Canvas::width() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4680CC), "a" (this) : "edx", "ecx", "cc", "memory"); // GetBoardBitmapWidth + return ret; + } + + int Canvas::height() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4680D8), "a" (this) : "edx", "ecx", "cc", "memory"); // GetBoardBitmapHeight + return ret; + } + + void Canvas::draw(int x, int y, Image *image, int srcX, int srcY, int srcWidth, int srcHeight) { + if(srcWidth == -1) srcWidth = image->width; + if(srcHeight == -1) srcHeight = image->height; + RECT rc; + rc.left = srcX; + rc.top = srcY; + rc.right = srcX + srcWidth; + rc.bottom = srcY + srcHeight; + asm volatile( + "pushl %7;" + "pushl %8;" + "call *%%esi;" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4684C0), "a" (this), "d" (x), "c" (y), "m" (image), "D" (&rc) : "cc", "memory" + ); + // Changed constraints to "m" for image and "D" for &rc because the new GCC would assign &rc to ESP even though I had put "g"... + // I think it's a bug, and it messes up everything because it generates a "push esp"! + } + + void Canvas::drawStretched(int x, int y, int width, int height, Image *image, int srcX, int srcY, int srcWidth, int srcHeight) { + if(srcWidth == -1) srcWidth = image->width; + if(srcHeight == -1) srcHeight = image->height; + if(width == srcWidth && height == srcHeight) { + draw(x, y, image, srcX, srcY, srcWidth, srcHeight); + return; + } + RECT rc1; + RECT rc2; + rc1.left = srcX; + rc1.top = srcY; + rc1.right = srcX + srcWidth; + rc1.bottom = srcY + srcHeight; + rc2.left = x; + rc2.top = y; + rc2.right = x + width; + rc2.bottom = y + height; + asm volatile( + "pushl %7;" + "call *%%esi;" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4688B0), "a" (this), "d" (&rc2), "c" (image), "D" (&rc1) : "cc", "memory" + ); + // See comment above about "D" + } + + void Canvas::drawCenteredZoomed(int x, int y, double zoomX, double zoomY, Image *image, int srcX, int srcY, int srcWidth, int srcHeight) { + if(srcWidth == -1) srcWidth = image->width; + if(srcHeight == -1) srcHeight = image->height; + if(zoomX == 1.0 && zoomY == 1.0) { + draw(x - (srcWidth + 1) / 2, y - (srcHeight + 1) / 2, image, srcX, srcY, srcWidth, srcHeight); + return; + } + int newWidth = (int)((double)srcWidth * zoomX + 0.5); + int newHeight = (int)((double)srcHeight * zoomY + 0.5); + drawStretched(x - (newWidth + 1) / 2, y - (newHeight + 1) / 2, newWidth, newHeight, image, srcX, srcY, srcWidth, srcHeight); + } +} diff --git a/library/Character.cpp b/library/Character.cpp new file mode 100644 index 0000000..69071b6 --- /dev/null +++ b/library/Character.cpp @@ -0,0 +1,108 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + int Character::getScreenX() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4C46E8), "a" (this) : "edx", "ecx", "cc", "memory"); + return ret; + } + + int Character::getScreenY() { + int ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x4C47C4), "a" (this) : "edx", "ecx", "cc", "memory"); + return ret; + } + + void Character::setFixedStep(int newStep) { + stepFrameCounter = -1; + step = newStep; + } + + void Character::setNormalStep() { + stepFrameCounter = 0; + step = 3; + } + + void Character::setAnimationType(AnimationType type) { + animationType = type; + fixedDirection = type == ANI_FIXED_DIR_NORMAL || type == ANI_FIXED_DIR_STEPPING || type == ANI_FIXED_GRAPHIC; + } + + bool Character::isMovePossible(int fromX, int fromY, int toX, int toY) { + bool ret; + asm volatile( + "pushl %7;" + "pushl %8;" + "call *%%esi" + : "=a" (ret), "=d" (_edx), "=c" (_ecx) : "S" (vTable[11]), "a" (this), "d" (fromX), "c" (fromY), "m" (toX), "m" (toY) : "cc", "memory" + ); + return ret; + } + + std::string Character::getName() { + if(vTable == reinterpret_cast(0x4AAC8C)) { + return reinterpret_cast(this)->eventData->name; + } else if(this == hero) { + Actor *firstHero = Actor::partyMember(0); + if(firstHero) return firstHero->getName(); else return ""; + } else { + return ""; + } + } + + void Character::move(const char* data, int length, bool repeatPattern, bool ignoreImpossible, int frequency) { + asm volatile( + "pushl %7;" + "pushl %8;" + "pushl %9;" + "call *%%esi" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4C43EC), "a" (this), "d" (data), "c" (length), "m" (frequency), "m" (repeatPattern), "m" (ignoreImpossible) : "cc", "memory" + ); + // Constraints for repeatPattern and ignoreImpossible are "m" and not "g" because they are bool and trying to push an 8-bit register won't work + // Also, frequency is now "m" too because of possible "g" bugs + } + + void Character::stop() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4C445C), "a" (this) : "edx", "ecx", "cc", "memory"); + } + + void Character::doStep(Direction direction) { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (vTable[12]), "a" (this), "d" (direction) : "ecx", "cc", "memory"); + } + + bool Event::doesEventPageExist(int id) { + void **script; + asm volatile("call *%%esi" : "=a" (script), "=d" (_edx) : "S" (0x47A0D0), "a" ((**reinterpret_cast(0x4CDD14))[15]), "d" (this->id) : "ecx", "cc", "memory"); + NamedCatalogPtr pages; + pages.ptr = reinterpret_cast *>(script[5]); + return pages[id] != NULL; + } + + HeroControlMode Hero::getControlMode() { + unsigned char &a1 = *(unsigned char*)0x4A9B87; + unsigned char &a2 = *(unsigned char*)0x4A9A04; + if(a2 == 0xC3) return CONTROL_NOTHING; + if(a1 == 0x7F) return CONTROL_EVERYTHING_EXCEPT_MOVEMENT; + return CONTROL_EVERYTHING; + } + + void Hero::setControlMode(HeroControlMode controlMode) { + unsigned char &a1 = *(unsigned char*)0x4A9B87; + unsigned char &a2 = *(unsigned char*)0x4A9A04; + switch(controlMode) { + case CONTROL_EVERYTHING: + a1 = 0x02; + a2 = 0x53; + break; + case CONTROL_EVERYTHING_EXCEPT_MOVEMENT: + a1 = 0x7F; + a2 = 0x53; + break; + case CONTROL_NOTHING: + a1 = 0x7F; + a2 = 0xC3; + break; + } + } +} diff --git a/library/DString.cpp b/library/DString.cpp new file mode 100644 index 0000000..719a441 --- /dev/null +++ b/library/DString.cpp @@ -0,0 +1,96 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + DString::operator std::string () const { + std::string s = ""; + if(this) s = std::string(reinterpret_cast(this), reinterpret_cast(this)[-1]); + return s; + } + + DString::operator char *() const { + return (char *)reinterpret_cast(this); + } + + int DString::length() { + if(this) return reinterpret_cast(this)[-1]; + return 0; + } + + DStringPtr::DStringPtr() { + str = NULL; + } + + DStringPtr::DStringPtr(DStringPtr &s) { + std::string tmp = s; + assign((char *)tmp.c_str(), tmp.length()); + } + + DStringPtr::DStringPtr(std::string s) { + str = NULL; + assign((char *)s.c_str(), s.length()); + } + + DStringPtr::~DStringPtr() { + clear(); + } + + DStringPtr::operator std::string () { + return s_str(); + } + + DStringPtr::operator char *() { + return reinterpret_cast(str); + } + + const DStringPtr &DStringPtr::operator=(std::string rhs) { + assign((char *)rhs.c_str(), rhs.length()); + return *this; + } + + const DStringPtr &DStringPtr::operator=(char *rhs) { + assign(rhs, strlen(rhs)); + return *this; + } + + const DStringPtr &DStringPtr::operator=(const char *rhs) { + assign((char *)rhs, strlen(rhs)); + return *this; + } + + const DStringPtr &DStringPtr::operator=(DString *rhs) { + clear(); + if(rhs) asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x404540), "a" (&str), "d" (rhs) : "ecx", "cc", "memory"); // LStrAsg + return *this; + } + + bool DStringPtr::operator==(std::string rhs) { + return s_str() == rhs; + } + + bool DStringPtr::operator==(const char *rhs) { + return s_str() == std::string(rhs); + } + + bool DStringPtr::operator==(DStringPtr &rhs) { + return s_str() == rhs.s_str(); + } + + void DStringPtr::clear() { + if(str) asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4044EC), "a" (&str) : "edx", "ecx", "cc", "memory"); // LStrClr + } + + void DStringPtr::assign(char *s, int len) { + clear(); + if(s && len) asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4045DC), "a" (&str), "d" (s), "c" (len) : "cc", "memory"); // LStrFromPCharLen + } + + std::string DStringPtr::s_str() { + std::string s = *str; + return s; + } + + int DStringPtr::length() { + return str->length(); + } +} diff --git a/library/DynRPG.cbp b/library/DynRPG.cbp new file mode 100644 index 0000000..c1fe48d --- /dev/null +++ b/library/DynRPG.cbp @@ -0,0 +1,94 @@ + + + + + + diff --git a/library/DynRPG.cpp b/library/DynRPG.cpp new file mode 100644 index 0000000..a84d250 --- /dev/null +++ b/library/DynRPG.cpp @@ -0,0 +1,124 @@ +/* + DynRPG v0.10 + RM2k3 Plugin SDK + by David "Cherry" Trapp + http://cherrytree.at +*/ + +#include +#define DYNRPG_STATIC +#include "DynRPG.h" +#include +#include + +namespace RPG { + void showError(std::string message, int eventId, int pageId, int lineId) { + std::stringstream s; + s << "An error has occured:\r\n" << message << "\r\n"; + if(eventId > 0) { + s << "...at map event " << eventId << ", page " << pageId << ", line " << lineId + 1 << "."; + } else if(eventId < 0) { + s << "...at common event " << 0 - eventId << ", line " << lineId + 1 << "."; + } else { + s << "...at an unknown or battle event, line " << lineId + 1 << "."; + } + s << "\r\nContinue game?"; + HWND hWnd = NULL; + if(RPG::screen) { + try { + hWnd = RPG::screen->getCanvasHWND(); + if(GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) hWnd = GetAncestor(hWnd, GA_ROOT); + } catch(...) { + + } + if(MessageBox(hWnd, s.str().c_str(), "DynRPG", MB_YESNO | MB_ICONWARNING) != IDYES && IsWindow(hWnd)) { + PostMessage(hWnd, WM_CLOSE, 0, 0); + } + } + } + + void updateBattle() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x497244), "a" (**sceneObjects[SCENE_BATTLE]) : "edx", "ecx", "cc", "memory"); + } + + void updateBattleEvents(BattleEventUpdateMode mode, Battler *battler) { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x499800), "a" (**sceneObjects[SCENE_BATTLE]), "d" (battler), "c" (mode) : "cc", "memory"); + } + + int getSelectedMonsterIndex() { + int *window = ((int **)**sceneObjects[SCENE_BATTLE])[15]; + if(!window[20]) return -1; + return window[window[17] + 30]; + } + + std::string getSkillName(int id) { + DStringPtr *p = (**reinterpret_cast **>(0x4CDBC4))[id]; + if(!p) return ""; + return p[2]; + } + + std::string getSkillDescription(int id) { + DStringPtr *p = (**reinterpret_cast **>(0x4CDBC4))[id]; + if(!p) return ""; + return p[3]; + } + + std::string getItemName(int id) { + DStringPtr *p = (**reinterpret_cast **>(0x4CDB14))[id]; + if(!p) return ""; + return p[2]; + } + + std::string getItemDescription(int id) { + DStringPtr *p = (**reinterpret_cast **>(0x4CDB14))[id]; + if(!p) return ""; + return p[3]; + } + + std::string getConditionName(int id) { + DStringPtr *p = (**reinterpret_cast **>(0x4CDE84))[id]; + if(!p) return ""; + return p[2]; + } + + std::map loadConfiguration(char *sectionName, char *filename) { + char *buffer = new char[32768]; + char *pKey = buffer; + std::map data; + + std::string sFilename(".\\"); + if(filename) { + sFilename += filename; + } else { + sFilename += "DynRPG.ini"; + } + GetPrivateProfileSection(sectionName, buffer, 32767, sFilename.c_str()); + + while(*pKey) { + std::string strKey = pKey; + std::string::size_type nPos = strKey.find('=', 0); + data[strKey.substr(0, nPos)] = strKey.substr(nPos + 1); + pKey += strlen(pKey) + 1; + } + + delete[] buffer; + return data; + } + + std::string encode(int value) { + std::string ret; + for(int i = 0; value != 0; i++) { + ret.insert(0, 1, (value & 0x7F) | (i ? 0x80 : 0)); + value >>= 7; + } + return ret; + } + + std::string encode(std::string value) { + std::string ret = encode(value.length()); + for(std::string::iterator it = value.begin(); it < value.end(); it++) { + ret += encode(*it); + } + return ret; + } +} diff --git a/library/EventScriptData.cpp b/library/EventScriptData.cpp new file mode 100644 index 0000000..8228e69 --- /dev/null +++ b/library/EventScriptData.cpp @@ -0,0 +1,9 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + EventScriptLine *EventScriptData::line(int index) { + if(lines && lines->list) return lines->list->get(index); + return NULL; + } +} diff --git a/library/EventScriptLine.cpp b/library/EventScriptLine.cpp new file mode 100644 index 0000000..03e17cf --- /dev/null +++ b/library/EventScriptLine.cpp @@ -0,0 +1,9 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + int EventScriptLine::parameter(int index) { + if(index < 0 || index >= parameters.size) return 0; + return parameters[index]; + } +} diff --git a/library/Image.cpp b/library/Image.cpp new file mode 100644 index 0000000..463425f --- /dev/null +++ b/library/Image.cpp @@ -0,0 +1,119 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + void Image::applyPalette() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x467384), "a" (this) : "edx", "ecx", "cc", "memory"); // FlushPalette + } + + unsigned char &Image::pixel(int x, int y) { + return pixels[x + y * width]; + } + + void Image::free() { + if(!pixels) return; + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x466E70), "a" (this) : "edx", "ecx", "cc", "memory"); // FreeImage + } + + void Image::init(int newWidth, int newHeight) { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x466DEC), "a" (this), "d" (newWidth), "c" (newHeight) : "cc", "memory"); // CreateImage + } + + void Image::setPalette(int* newPalette) { + memcpy(palette, newPalette, sizeof(palette)); + applyPalette(); + } + + void Image::copy(Image *image) { + if(!image->pixels) { + free(); + } else { + init(image->width, image->height); + memcpy(pixels, image->pixels, image->width * image->height); + } + setPalette(image->palette); + useMaskColor = image->useMaskColor; + alpha = image->alpha; + autoResize = image->autoResize; + colorControl1->red = image->colorControl1->red; + colorControl1->green = image->colorControl1->green; + colorControl1->blue = image->colorControl1->blue; + colorControl1->chroma = image->colorControl1->chroma; + colorControl2->red = image->colorControl2->red; + colorControl2->green = image->colorControl2->green; + colorControl2->blue = image->colorControl2->blue; + colorControl2->chroma = image->colorControl2->chroma; + } + + void Image::loadFromFile(std::string filename, bool throwErrors, bool autoResize) { + this->autoResize = autoResize; + DStringPtr s(filename); + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x467ABC), "a" (this), "d" (s.str), "c" (throwErrors) : "cc", "memory"); + } + + void Image::draw(int x, int y, unsigned char *newPixels, int srcWidth, int srcHeight, int srcLineWidth, int maskColor) { + if(maskColor != TRANS_NONE) { + for(int cy = 0; cy < srcHeight; cy++) { + unsigned char *dst = pixels + x + (y + cy) * width; + unsigned char *src = newPixels + cy * srcLineWidth; + for(int cx = 0; cx < srcWidth; cx++) { + if(src[cx] != maskColor) dst[cx] = src[cx]; + } + } + } else { + for(int cy = 0; cy < srcHeight; cy++) { + unsigned char *dst = pixels + x + (y + cy) * width; + unsigned char *src = newPixels + cy * srcLineWidth; + memcpy(dst, src, srcWidth); + } + } + } + + void Image::draw(int x, int y, Image *image, int srcX, int srcY, int srcWidth, int srcHeight, int maskColor) { + if(srcWidth == -1) srcWidth = image->width; + if(srcHeight == -1) srcHeight = image->height; + draw(x, y, &image->pixel(srcX, srcY), srcWidth, srcHeight, image->width, maskColor); + } + + void Image::clear() { + memset(pixels, 0, width * height); + } + + void Image::setSystemPalette() { + setPalette(system->systemGraphic->systemImage->palette); + } + + void Image::drawText(int x, int y, std::string text, int color) { + DStringPtr s(text); + asm volatile( + "pushl %7;" + "pushl %8;" + "pushl %9;" + "call *%%esi;" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x4892AC), "a" (system->systemGraphic), "d" (this), "c" (x), "m" (y), "m" (s.str), "m" (color) : "cc", "memory" // DrawText + ); + } + + Image *Image::create() { + Image *ret; + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x466D3C), "a" (*(void **)0x46679C), "d" (1) : "ecx", "cc", "memory"); // TAuroraSheet_Constructor + return ret; + } + + Image *Image::create(int newWidth, int newHeight) { + Image *image = create(); + image->init(newWidth, newHeight); + return image; + } + + Image *Image::create(Image *templateImage) { + Image *image = create(); + image->copy(templateImage); + return image; + } + + void Image::destroy(Image *&image) { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x466DB4), "a" (image), "d" (1) : "ecx", "cc", "memory"); // TAuroraSheet_Destructor + image = NULL; + } +} diff --git a/library/Input.cpp b/library/Input.cpp new file mode 100644 index 0000000..7c0e102 --- /dev/null +++ b/library/Input.cpp @@ -0,0 +1,24 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + int *Input::key(Key keyId) { + if(keyId >= KEY_0) { + return keys2k3 + (keyId - KEY_0) * 8; + } else { + return keys + keyId * 8; + } + } + + bool Input::pressed(Key keyId) { + int *k = key(keyId); + for(int i = 0; i < 8; i++) { + if(GetAsyncKeyState(k[i]) & 0x8000) return true; + } + return false; + } + + void Input::update() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4974F4), "a" (this) : "edx", "ecx", "cc", "memory"); + } +} diff --git a/library/Map.cpp b/library/Map.cpp new file mode 100644 index 0000000..4be76d3 --- /dev/null +++ b/library/Map.cpp @@ -0,0 +1,41 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + int Map::getCameraX() { + return cameraSubX / 16; + } + + int Map::getCameraY() { + return cameraSubY / 16; + } + + void Map::setCamera(int x, int y) { + x *= 16; + y *= 16; + int *p = (**(int ***)(0x4CDE54)); + p[43] += x - cameraSubX; + p[44] += y - cameraSubY; + p[45] += x - cameraSubX; + p[46] += y - cameraSubY; + } + + void Map::moveCamera(int offsetX, int offsetY, int speed) { + int *p = (**(int ***)(0x4CDE54)); + p[45] += offsetX * 16; + p[46] += offsetY * 16; + p[47] = speed; + } + + int Map::getWidth() { + return (**(int ***)(0x4CDD14))[5]; + } + + int Map::getHeight() { + return (**(int ***)(0x4CDD14))[6]; + } + + void Map::updateEvents() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4AB8B4), "a" (events.ptr) : "edx", "ecx", "cc", "memory"); + } +} diff --git a/library/Music.cpp b/library/Music.cpp new file mode 100644 index 0000000..f81ef33 --- /dev/null +++ b/library/Music.cpp @@ -0,0 +1,57 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + Music::Music() { + init(); + filename = "(OFF)"; + fadeInTime = 0; + volume = 100; + speed = 100; + pan = 50; + } + + Music::Music(Music &ref) { + init(); + set(ref); + } + + Music::Music(std::string filename, int fadeInTime, int volume, int speed, int pan) { + init(); + this->filename = filename; + this->fadeInTime = fadeInTime; + this->volume = volume; + this->speed = speed; + this->pan = pan; + } + + Music::~Music() { + filename = ""; + } + + void Music::set(Music &ref) { + filename = ref.filename.str; + fadeInTime = ref.fadeInTime; + volume = ref.volume; + speed = ref.speed; + pan = ref.pan; + } + + void Music::play() { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : "S" (0x48B408), "a" (system), "d" (this), "c" (0) : "cc", "memory"); // CallHarmonyPlayMusic + if(system->currentBGM) system->currentBGM->set(*this); + if(system->scene == SCENE_MAP && system->mapBGM) system->mapBGM->set(*this); + } + + void Music::stop() { + Music().play(); + } + + void Music::fadeOut(int time) { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x48B4E0), "a" (system), "d" (time) : "ecx", "cc", "memory"); // CallHarmonyFadeOutMusic + } + + void Music::init() { + vTable = (void **)0x475E98; + } +} diff --git a/library/Picture.cpp b/library/Picture.cpp new file mode 100644 index 0000000..f1393a9 --- /dev/null +++ b/library/Picture.cpp @@ -0,0 +1,80 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + void Picture::merge() { + if(image->pixels && image2->pixels) { + image->draw(0, 0, image2, 0, 0, image->width, image->height, 0); + image2->clear(); + } + } + + void Picture::show( + std::string filename, int x, int y, bool moveWithMap, + int magnification, int transparency, int transparency2, + bool useMaskColor, int red, int green, int blue, int chroma, + PictureEffect effect, int effectStrength + ) { + DStringPtr s(filename); + asm volatile( + "pushl %7;" + "pushl %8;" + "pushl %9;" + "pushl %10;" + "pushl %11;" + "pushl %12;" + "pushl %13;" + "pushl %14;" + "pushl %15;" + "pushl %16;" + "pushl %17;" + "pushl %18;" + "call *%%esi" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : + "S" (0x4C1964), "a" (this), "d" (s.str), "c" (x), "m" (y), "m" (moveWithMap), + "m" (magnification), "m" (transparency), "m" (transparency2), + "m" (useMaskColor), "m" (red), "m" (green), "m" (blue), "m" (chroma), + "m" (effect), "m" (effectStrength) : "cc", "memory" + ); + } + + void Picture::move( + int x, int y, int magnification, int transparency, int transparency2, + int red, int green, int blue, int chroma, PictureEffect effect, int effectStrength, + int duration + ) { + volatile DStringPtr s("DUMMY"); // This is needed so that the function gets a stack frame, otherwise "m" will produce [esp+x] (sigh!) instead of [ebp+x], interfering with the push! [Added 2020-01-08] + asm volatile( + "pushl %7;" + "pushl %8;" + "pushl %9;" + "pushl %10;" + "pushl %11;" + "pushl %12;" + "pushl %13;" + "pushl %14;" + "pushl %15;" + "pushl %16;" + "call *%%esi" + : "=a" (_eax), "=d" (_edx), "=c" (_ecx) : + "S" (0x4C1AD8), "a" (this), "d" (x), "c" (y), "m" (magnification), + "m" (transparency), "m" (transparency2), + "m" (red), "m" (green), "m" (blue), "m" (chroma), + "m" (effect), "m" (effectStrength), "m" (duration) : "cc", "memory" + ); + } + + void Picture::erase() { + filename = ""; + image->init(0, 0); + image2->init(0, 0); + } + + void Picture::update() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4C1C20), "a" (this) : "edx", "ecx", "cc", "memory"); + } + + void Picture::draw() { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x4C1E6C), "a" (this) : "edx", "ecx", "cc", "memory"); + } +} diff --git a/library/Screen.cpp b/library/Screen.cpp new file mode 100644 index 0000000..9bb6224 --- /dev/null +++ b/library/Screen.cpp @@ -0,0 +1,21 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + HWND Screen::getCanvasHWND() { + try { + return (**reinterpret_cast(0x4CE048))[25][96]; + } catch(...) { + return NULL; + } + } + + void Screen::setFPS(int fps) { + millisecondsPerFrame = 1000.0 / (double)fps; + maxFPS = fps; + } + + void Screen::update(Scene scene) { + asm volatile("call *%%esi" : "=a" (_eax) : "S" (0x48CD40), "a" (**sceneObjects[scene]) : "edx", "ecx", "cc", "memory"); + } +} diff --git a/library/Sound.cpp b/library/Sound.cpp new file mode 100644 index 0000000..7f9d1fb --- /dev/null +++ b/library/Sound.cpp @@ -0,0 +1,52 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + Sound::Sound() { + init(); + filename = "(OFF)"; + volume = 100; + speed = 100; + pan = 50; + } + + Sound::Sound(Sound &ref) { + init(); + set(ref); + } + + Sound::Sound(std::string filename, int volume, int speed, int pan) { + init(); + this->filename = filename; + this->volume = volume; + this->speed = speed; + this->pan = pan; + } + + Sound::~Sound() { + filename = ""; + } + + void Sound::set(Sound &ref) { + filename = ref.filename.str; + volume = ref.volume; + speed = ref.speed; + pan = ref.pan; + } + + void Sound::play() { + if(filename == "(OFF)") { + asm volatile("call *%%esi" : : "S" (0x471FBC) : "eax", "edx", "ecx", "cc", "memory"); // CallHarmonyStopSound + } else { + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x48B538), "a" (system), "d" (this) : "ecx", "cc", "memory"); // CallHarmonyPlaySound + } + } + + void Sound::stop() { + Sound().play(); + } + + void Sound::init() { + vTable = (void **)0x475E14; + } +} diff --git a/library/System.cpp b/library/System.cpp new file mode 100644 index 0000000..1e0e2f8 --- /dev/null +++ b/library/System.cpp @@ -0,0 +1,63 @@ +#define DYNRPG_STATIC +#include "DynRPG.h" + +namespace RPG { + +#define defaultAccessorBGM(_member_, _function_) \ + Music *System::_function_() { \ + if(_member_->filename.s_str() == "") return dbSystem->_member_; \ + return _member_; \ + } + +#define defaultAccessorSE(_member_, _function_) \ + Sound *System::_function_() { \ + if(_member_->filename.s_str() == "") return dbSystem->_member_; \ + return _member_; \ + } + +#define defaultAccessorTrans(_member_, _function_) \ + Transition System::_function_() { \ + if(_member_ == TRANS_DEFAULT) return (Transition)dbSystem->_member_; \ + return (Transition)_member_; \ + } + + defaultAccessorBGM(titleBGM, getTitleBGM); + defaultAccessorBGM(battleBGM, getBattleBGM); + defaultAccessorBGM(victoryBGM, getVictoryBGM); + defaultAccessorBGM(innBGM,getInnBGM); + defaultAccessorBGM(skiffBGM, getSkiffBGM); + defaultAccessorBGM(shipBGM, getShipBGM); + defaultAccessorBGM(airshipBGM, getAirshipBGM); + defaultAccessorBGM(gameOverBGM, getGameOverBGM); + + defaultAccessorSE(cursorSE, getCursorSE); + defaultAccessorSE(decisionSE, getDecisionSE); + defaultAccessorSE(cancelSE, getCancelSE); + defaultAccessorSE(buzzerSE, getBuzzerSE); + defaultAccessorSE(battleStartSE, getBattleStartSE); + defaultAccessorSE(fleeSE, getFleeSE); + defaultAccessorSE(enemyAttackSE, getEnemyAttackSE); + defaultAccessorSE(enemyDamageSE, getEnemyDamageSE); + defaultAccessorSE(heroDamageSE, getHeroDamageSE); + defaultAccessorSE(evasionSE, getEvasionSE); + defaultAccessorSE(enemyDeathSE, getEnemyDeathSE); + defaultAccessorSE(itemSE, getItemSE); + + defaultAccessorTrans(teleportEraseTrans, getTeleportEraseTrans); + defaultAccessorTrans(teleportShowTrans, getTeleportShowTrans); + defaultAccessorTrans(battleStartEraseTrans, getBattleStartEraseTrans); + defaultAccessorTrans(battleStartShowTrans, getBattleStartShowTrans); + defaultAccessorTrans(battleEndEraseTrans, getBattleEndEraseTrans); + defaultAccessorTrans(battleEndShowTrans, getBattleEndShowTrans); + +#undef defaultAccessorBGM +#undef defaultAccessorSE +#undef defaultAccessorTrans + + void SystemGraphic::loadFont(std::string fontName) { + void **rCanvas; + DStringPtr s(fontName); + asm volatile("call *%%esi" : "=a" (rCanvas) : "S" (0x4683AC), "a" (font) : "edx", "ecx", "cc", "memory"); // GetCanvas + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x4228CC), "a" (rCanvas[3]), "d" (s.str) : "ecx", "cc", "memory"); // TFont::SetName + } +} diff --git a/library/TextMain.cpp b/library/TextMain.cpp new file mode 100644 index 0000000..244495f --- /dev/null +++ b/library/TextMain.cpp @@ -0,0 +1,314 @@ +#define AUTO_DLLMAIN +#include +#include +#include +#include +#include + +struct textObj +{ + int x; + int y; + int color; + bool fixed; + std::string txt; + RPG::Image* img; +}; + +std::string parseText(std::string in); +typedef std::map TextMap; + +int picID; +TextMap drawList; + +bool onDrawPicture(RPG::Picture* picture) +{ + if(picture->id == picID) + { + TextMap::iterator itr = drawList.begin(); + while(itr != drawList.end()) + { + int x = itr->second.x; + int y = itr->second.y; + if(itr->second.fixed) + { + x -= RPG::map->getCameraX(); + y -= RPG::map->getCameraY(); + } + itr->second.img->alpha = 255 - picture->transparency/100.0 * 255; + RPG::screen->canvas->draw(x, y, itr->second.img); + itr++; + } + } + return true; +} + +void onInitTitleScreen() +{ + TextMap::iterator itr = drawList.begin(); + while(itr != drawList.end()) + { + TextMap::iterator tmp = itr; + RPG::Image::destroy(itr->second.img); + itr++; + drawList.erase(tmp); + } +} + +bool onStartup(char *pluginName) +{ + std::map configuration = RPG::loadConfiguration(pluginName); + std::map::iterator itr = configuration.find("PictureID"); + if(itr != configuration.end()) + { + picID = atoi(itr->second.c_str()); + } + else + picID = 1; + return true; +} + +void onSaveGame(int id, void __cdecl(*savePluginData)(char*data,int length)) +{ + std::string s; + TextMap::iterator itr = drawList.begin(); + while(itr != drawList.end()) + { + std::stringstream ss; + ss << itr->second.x << "," << itr->second.y << ","; + ss << itr->second.txt << "," << itr->second.color << ","; + ss << itr->second.fixed << "," << itr->first << ","; + s += ss.str(); + itr++; + } + savePluginData((char *)s.c_str(), s.size()); +} + +void onLoadGame(int id, char* data, int length) +{ + char* buffer; + if(data == NULL) return; + buffer = strtok(data, ","); + while(buffer != NULL) + { + textObj obj; + obj.x = atoi(buffer); + buffer = strtok(NULL, ","); + obj.y = atoi(buffer); + buffer = strtok(NULL, ","); + obj.txt = buffer; + buffer = strtok(NULL, ","); + obj.color = atoi(buffer); + buffer = strtok(NULL, ","); + obj.fixed = atoi(buffer); + buffer = strtok(NULL, ","); + obj.img = RPG::Image::create(obj.txt.size()*6 + 8, 16); + obj.img->setSystemPalette(); + obj.img->useMaskColor = true; + obj.img->drawText(0, 0, obj.txt, obj.color); + drawList.insert(std::make_pair(buffer, obj)); + buffer = strtok(NULL, ","); + } +} + +std::string formatText(std::string s) +{ + int size = 2; + while(size < s.size() && s[size]!=']')size++; + size -= 2; + switch (s[0]) + { + case 'x': + { + TextMap::iterator itr = drawList.find(s.substr(2, size)); + if(itr != drawList.end()) + return itr->second.txt; + return s; + } + case 'n': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + return RPG::actors[n]->getName(); + } + case 'v': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + std::stringstream ss; + ss << RPG::variables[n]; + return ss.str(); + } + case 'i': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + return RPG::getItemName(n); + } + case 'I': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + return RPG::getItemDescription(n); + } + case 't': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + return RPG::getSkillName(n); + } + case 'T': + { + int n = atoi(parseText(s.substr(2, size)).c_str()); + return RPG::getSkillDescription(n); + } + default: + return s; + } +} + +std::string parseText(std::string in) +{ + std::string out; + for(unsigned int i = 0; i < in.size(); i++) + { + if(in[i] == '\\') + { + out += formatText(in.substr(i + 1, in.size())); + while(i < in.size() && in[i]!=']')i++; + while(i + 1 < in.size() && in[i+1]==']')i++; + } + else + out += in[i]; + } + return out; +} + +bool onComment( const char* text, + const RPG::ParsedCommentData* parsedData, + RPG::EventScriptLine* nextScriptLine, + RPG::EventScriptData* scriptData, + int eventId, + int pageId, + int lineId, + int* nextLineId ) +{ + std::string s = parsedData->command; + + if(s.compare("write_text") == 0) + { + TextMap::iterator itr = drawList.find(parsedData->parameters[0].text); + if(itr == drawList.end()) + { + textObj obj; + obj.x = parsedData->parameters[1].number; + obj.y = parsedData->parameters[2].number; + obj.color = (parsedData->parameters[5].type == RPG::PARAM_NUMBER && parsedData->parametersCount >= 6)?parsedData->parameters[5].number:0; + if(parsedData->parameters[4].type == RPG::PARAM_STRING) + { + std::string tmp = parsedData->parameters[4].text; + obj.fixed = (!tmp.compare("fixed"))?true:false; + } + else + obj.fixed = false; + if(parsedData->parameters[3].type == RPG::PARAM_NUMBER) + { + std::stringstream ss; + ss << parsedData->parameters[3].number; + obj.txt = ss.str(); + } + else + obj.txt = parseText(parsedData->parameters[3].text); + obj.img = RPG::Image::create(obj.txt.size()*6 + 8, 16); + obj.img->setSystemPalette(); + obj.img->useMaskColor = true; + obj.img->drawText(0, 0, obj.txt, obj.color); + drawList.insert(std::make_pair(parseText(parsedData->parameters[0].text), obj)); + } + return false; + } + + if(s.compare("append_text") == 0) + { + TextMap::iterator itr = drawList.find(parseText(parsedData->parameters[0].text)); + if(itr != drawList.end()) + { + if(parsedData->parameters[1].type == RPG::PARAM_NUMBER) + { + std::stringstream ss; + ss << parsedData->parameters[1].number; + itr->second.txt += ss.str(); + } + else + itr->second.txt += parseText(parsedData->parameters[1].text); + itr->second.img->free(); + itr->second.img->init(itr->second.txt.size()*6 + 8, 16); + itr->second.img->drawText(0, 0, itr->second.txt, itr->second.color); + } + return false; + } + + if(s.compare("change_text") == 0) + { + TextMap::iterator itr = drawList.find(parseText(parsedData->parameters[0].text)); + if(itr != drawList.end()) + { + if(parsedData->parameters[1].type == RPG::PARAM_NUMBER) + { + std::stringstream ss; + ss << parsedData->parameters[1].number; + itr->second.txt = ss.str(); + } + else + itr->second.txt = parseText(parsedData->parameters[1].text); + itr->second.color = (parsedData->parameters[2].type == RPG::PARAM_NUMBER)?parsedData->parameters[2].number:0; + itr->second.img->free(); + itr->second.img->init(itr->second.txt.size()*6 + 8, 16); + itr->second.img->drawText(0, 0, itr->second.txt, itr->second.color); + } + return false; + } + + if(s.compare("change_position") == 0) + { + TextMap::iterator itr = drawList.find(parseText(parsedData->parameters[0].text)); + if(itr != drawList.end()) + { + itr->second.x = parsedData->parameters[1].number; + itr->second.y = parsedData->parameters[2].number; + } + return false; + } + + + if(s.compare("remove_text") == 0) + { + TextMap::iterator itr = drawList.find(parseText(parsedData->parameters[0].text)); + if(itr != drawList.end()) + { + RPG::Image::destroy(itr->second.img); + drawList.erase(itr); + } + return false; + } + + if(s.compare("remove_all") == 0) + { + TextMap::iterator itr = drawList.begin(); + while(itr != drawList.end()) + { + RPG::Image::destroy(itr->second.img); + drawList.erase(itr); + itr++; + } + return false; + } + + if(s.compare("debug") == 0) + { + TextMap::iterator itr = drawList.begin(); + while(itr != drawList.end()) + { + MessageBox(NULL, itr->first.c_str(), "textPlugin", MB_ICONINFORMATION); + itr++; + } + return false; + } + + return true; +} diff --git a/loader/.gitignore b/loader/.gitignore new file mode 100644 index 0000000..63589c9 --- /dev/null +++ b/loader/.gitignore @@ -0,0 +1,7 @@ +Bak/ + +*.asm +*.obj +*.dll.a +*.undo + diff --git a/loader/dynloader.bas b/loader/dynloader.bas new file mode 100644 index 0000000..24a36fa --- /dev/null +++ b/loader/dynloader.bas @@ -0,0 +1,1293 @@ +#Define LINK_VERSION 3 +#Include "dynloader.bi" + +Function StrToImg(s As String) As FB.IMAGE Ptr + Var img = ImageCreate(Len(s) * 8, 14, &hFF00FF) + Draw String img, (0, 0), s + Return img +End Function + +Function GetIcon() As FB.IMAGE Ptr + Var img = ImageCreate(10, 10, &hFF00FF) + For y As Integer = 0 To 8 + For x As Integer = 0 To 8 + Dim p As Integer + Read p + If p Then PSet img, (x, y), &h0000FF + Next + Next + Return img +End Function + +Sub MultiPut(Byval lpTarget As Any Ptr= 0, _ + Byval xMidPos As Integer= 0, _ + Byval yMidPos As Integer= 0, _ + Byval lpSource As Any Ptr , _ + Byval xScale As Single = 1, _ + Byval yScale As Single = 1, _ + Byval Rotate As Single = 0, _ + Byval Trans As Integer= 0) + + If (screenptr=0) Or (lpSource=0) Then Exit Sub + + If xScale < 0.001 Then xScale=0.001 + If yScale < 0.001 Then yScale=0.001 + + Dim As Integer MustLock,MustRotate + + If lpTarget= 0 Then MustLock =1 + If Rotate <>0 Then MustRotate=1 + + Dim as Integer TargetWidth,TargetHeight,TargetBytes,TargetPitch + If MustLock Then + ScreenInfo _ + TargetWidth , _ + TargetHeight, _ + TargetBytes ,,_ + TargetPitch + TargetBytes shr=3 + + lpTarget=ScreenPtr + Else + TargetBytes = cptr(uinteger Ptr,lpTarget)[1] + TargetWidth = cptr(uinteger Ptr,lpTarget)[2] + TargetHeight = cptr(uinteger Ptr,lpTarget)[3] + TargetPitch = cptr(uinteger Ptr,lpTarget)[4] + lpTarget += 32 + End If + If (TargetWidth<4) Or (TargetHeight<4) Then Exit Sub + + Dim As Integer SourceWidth,SourceHeight,SourceBytes,SourcePitch + if cptr(integer Ptr,lpSource)[0] = 7 then + SourceBytes = cptr(uinteger Ptr,lpSource)[1] + SourceWidth = cptr(uinteger Ptr,lpSource)[2] + SourceHeight = cptr(uinteger Ptr,lpSource)[3] + SourcePitch = cptr(uinteger Ptr,lpSource)[4] + lpSource += 32 + else + SourceBytes = 1 + SourceWidth = cptr(ushort Ptr,lpSource)[0] shr 3 + SourceHeight = cptr(ushort Ptr,lpSource)[1] + SourcePitch = SourceWidth + lpSource += 4 + end if +#if 0 + ? TargetWidth & "x" & TargetHeight & "x" & TargetBytes,TargetPitch + ? SourceWidth & "x" & SourceHeight & "x" & SourceBytes,SourcePitch + ? MustLock,Trans + sleep:end +#endif + + If (SourceWidth<2) Or (SourceHeight<2) Then Exit Sub + If (TargetBytes<>SourceBytes) Then Exit Sub + +#define xs 0 'screen +#define ys 1 +#define xt 2 'texture +#define yt 3 + Dim As Single Points(3,3) + points(0,xs)=-SourceWidth/2 * xScale + points(1,xs)= SourceWidth/2 * xScale + points(2,xs)= points(1,xs) + points(3,xs)= points(0,xs) + + points(0,ys)=-SourceHeight/2 * yScale + points(1,ys)= points(0,ys) + points(2,ys)= SourceHeight/2 * yScale + points(3,ys)= points(2,ys) + + points(1,xt)= SourceWidth-1 + points(2,xt)= points(1,xt) + points(2,yt)= SourceHeight-1 + points(3,yt)= points(2,yt) + + Dim As Uinteger i + Dim As Single x,y + If MustRotate Then + #ifndef UseRad + Rotate*=0.017453292 'degre 2 rad + #endif + While Rotate< 0 :rotate+=6.2831853:Wend + While Rotate>=6.2831853:rotate-=6.2831853:Wend + For i=0 To 3 + x=points(i,xs)*Cos(Rotate) - points(i,ys)*Sin(Rotate) + y=points(i,xs)*Sin(Rotate) + points(i,ys)*Cos(Rotate) + points(i,xs)=x:points(i,ys)=y + Next + End If + + Dim As Integer yStart,yEnd,xStart,xEnd + yStart=100000:yEnd=-yStart:xStart=yStart:xEnd=yEnd + +#define LI 0 'LeftIndex +#define RI 1 'RightIndex +#define IND 0 'Index +#define NIND 1 'NextIndex + Dim As Integer CNS(1,1) 'Counters + + For i=0 To 3 + points(i,xs)=Int(points(i,xs)+xMidPos) + points(i,ys)=Int(points(i,ys)+yMidPos) + If points(i,ys)yEnd Then yEnd =points(i,ys) + If points(i,xs)xEnd Then xEnd =points(i,xs) + Next + If yStart =yEnd Then Exit Sub + If yStart>=TargetHeight Then Exit Sub + If yEnd <0 Then Exit Sub + If xStart = xEnd Then Exit Sub + If xStart>=TargetWidth Then Exit Sub + If xEnd <0 Then Exit Sub + + Dim As uByte Ptr t1,s1 + Dim As uShort Ptr t2,s2 + Dim As uInteger Ptr t4,s4 + + +#define ADD 0 +#define CMP 1 +#define SET 2 + Dim As Integer ACS(1,2) 'add compare and set + ACS(LI,ADD)=-1:ACS(LI,CMP)=-1:ACS(LI,SET)=3 + ACS(RI,ADD)= 1:ACS(RI,CMP)= 4:ACS(RI,SET)=0 + +#define EX 0 +#define EU 1 +#define EV 2 +#define EXS 3 +#define EUS 4 +#define EVS 5 + Dim As Single E(2,6),S(6),Length,uSlope,vSlope + Dim As Integer U,UV,UA,UN,V,VV,VA,VN + + ' share the same highest point + CNS(RI,IND)=CNS(LI,IND) + If MustLock Then ScreenLock + ' loop from Top to Bottom + While yStart 0.0 Then + E(i,EXS) = points(CNS(i, NIND),xs)-E(i,EX):E(i,EXS)/=Length + E(i,EUS) = points(CNS(i, NIND),xt)-E(i,EU):E(i,EUS)/=Length + E(i,EVS) = points(CNS(i, NIND),yt)-E(i,EV):E(i,EVS)/=Length + End If + CNS(i,IND)=CNS(i,NIND) + End If + Next + + If (yStart<0) Then Goto SkipScanLine + xStart=E(LI,EX)+0.5:If xStart>=TargetWidth Then Goto SkipScanLine + xEnd =E(RI,EX)-0.5:If xEnd < 0 Then Goto SkipScanLine + If (xStart=xEnd) Then Goto SkipScanLine + 'if xEnd =TargetWidth Then xEnd=TargetWidth-1 + UV=Int(uSlope):UA=(uSlope-UV)*100000:UN=0 + VV=Int(vSlope):VA=(vSlope-VV)*100000:VN=0 + xEnd-=xStart + Select Case TargetBytes + Case 1 + t1=cptr(ubyte ptr,lpTarget) + t1+=yStart*TargetPitch+xStart:xStart=0 + If Trans=0 Then + While xStart=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t1+=1 + Wend + Else + While xStart=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t1+=1 + Wend + End If + Case 2 + t2=cptr(Short Ptr,lpTarget) + t2+=yStart*(TargetPitch shr 1)+xStart:xStart=0 + If Trans=0 Then + While xStart=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t2+=1 + Wend + Else + While xStart&HF81F Then *t2=*s2 + U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t2+=1 + Wend + End If + Case 4 + t4=cptr(Integer Ptr,lpTarget)+yStart*(TargetPitch shr 2)+xStart:xStart=0 + If Trans=0 Then + While xStart=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t4+=1 + Wend + Else + While xStart&HFFFF00FF Then *t4=*s4 + U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000 + V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000 + If u<0 Then u=0 + If v<0 Then v=0 + xStart+=1:t4+=1 + Wend + End If + End Select + +SkipScanLine: + E(LI,EX)+=E(LI,EXS):E(LI,EU)+=E(LI,EUS):E(LI,EV)+=E(LI,EVS) + E(RI,EX)+=E(RI,EXS):E(RI,EU)+=E(RI,EUS):E(RI,EV)+=E(RI,EVS) + yStart+=1:If yStart=TargetHeight Then yStart=yEnd 'exit loop + Wend +If MustLock Then ScreenUnlock +End Sub + +Sub ForceToForeground(hWnd As HWND) + Var fgWnd = GetForegroundWindow() + AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(hWnd, NULL), TRUE) + AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(fgWnd, NULL), TRUE) + BringWindowToTop(hWnd) + SetForegroundWindow(hWnd) + AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(fgWnd, NULL), FALSE) + AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(hWnd, NULL), FALSE) +End Sub + +Function EnumWindowsProc(hWnd As HWND, lParam As HWND Ptr) As BOOL + Dim cn As ZString * 1000 + GetClassName(hWnd, @cn, 1000) + Dim pid As Integer + GetWindowThreadProcessId(hWnd, @pid) + If pid = GetCurrentProcessId() AndAlso GetWindowLong(hWnd, GWL_STYLE) And (WS_BORDER Or WS_VISIBLE) AndAlso InStr(cn, "IME") = 0 AndAlso cn <> "TApplication" Then + If GetProp(hWnd, "wcheckedfg") <> TRUE Then + SetProp(hWnd, "wcheckedfg", TRUE) + Sleep(100, 1) + ForceToForeground(hWnd) + EndIf + If cn = "TFormLcfGameMain" Then + *lParam = hWnd + Return FALSE + EndIf + EndIf + Return TRUE +End Function + +Sub WindowChecker() + Do + Dim hWnd As HWND = NULL + EnumWindows(@EnumWindowsProc, @hWnd) + If hWnd Then + hWndMain = hWnd + Exit Do + EndIf + + Sleep(100, 1) + Loop +End Sub + +' VA/File mapping (VA range = 400000 - 4CF000): +' 400000 - 400400 = 00000 - 00400 HEADER +' 401000 - 4C9E00 = 00400 - C9200 CODE +' 4CA000 - 4CE200 = C9200 - CD400 DATA + +Sub ApplyQuickPatches() + Var INIFile = ExePathCached & "\DynRPG.ini" + GetPrivateProfileString("QuickPatches", NULL, !"\0", @KeyNamesBuffer, SizeOf(KeyNamesBuffer), INIFile) + Dim KeyName As ZString Ptr = @KeyNamesBuffer + Do While KeyName[0] + ZeroMemory(@ValueBuffer, SizeOf(ValueBuffer)) ' For easier handling of malformed code + GetPrivateProfileString("QuickPatches", KeyName, !"\0", @ValueBuffer, SizeOf(ValueBuffer), INIFile) + Dim p As Integer = 0 + Do While ValueBuffer[p] + Dim AddrString As String + Do While ValueBuffer[p] AndAlso ValueBuffer[p] <> Asc(",") + AddrString += Chr(ValueBuffer[p]) + p += 1 + Loop + If ValueBuffer[p] = Asc(",") Then p += 1 + Dim Address As UByte Ptr = ValUInt("&h" & AddrString) + If Address = 0 Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & """: Malformed address """ & AddrString & """!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do + EndIf + If ValueBuffer[p] = 0 OrElse ValueBuffer[p] = Asc(",") Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & """: Empty byte string for address """ & AddrString & """!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + EndIf + If ValueBuffer[p] = Asc("%") OrElse ValueBuffer[p] = Asc("#") Then + Var UseInt32 = IIf(ValueBuffer[p] = Asc("#"), TRUE, FALSE) + p += 1 + Dim ValueString As String + Do While ValueBuffer[p] AndAlso ValueBuffer[p] <> Asc(",") + If ValueBuffer[p] = Asc(" ") Then + p += 1 + Continue Do + EndIf + ValueString += Chr(ValueBuffer[p]) + p += 1 + Loop + Var Value = ValUInt(ValueString) + If Address = &h45CE00 OrElse (UseInt32 AndAlso ((CUInt(Address) + 3) And (Not 3) = &h45CE00)) Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & !""": Trying to write to protected address ""45CE00""!\r\nA possible cause would be the comparison of a DynRPG-patched RPG_RT.exe against a non-patched one at the time the IPS file was created.", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do + EndIf + If Address < &h400000 OrElse Address >= &h4CF000 - 3 Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & """: Address """ & Hex(Address) & !""" is outside of limits!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do + EndIf + + If UseInt32 Then + *CPtr(UInteger Ptr, Address) = Value + Else + *Address = Value + EndIf + Else + Do While ValueBuffer[p] AndAlso ValueBuffer[p] <> Asc(",") + If ValueBuffer[p] = Asc(" ") Then + p += 1 + Continue Do + EndIf + Var ByteStr = Chr(ValueBuffer[p]) + Chr(ValueBuffer[p + 1]) + Var ByteVal = CUByte("&h" & ByteStr) + If ByteStr[1] = 0 OrElse ByteStr[1] = Asc(",") OrElse (ByteVal = 0 AndAlso ByteStr <> "00") OrElse (ByteStr[0] <> Asc("0") AndAlso ByteVal < 10) Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & """: Malformed byte value """ & ByteStr & """!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do, Do + EndIf + + If Address = &h45CE00 Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & !""": Trying to write to protected address ""45CE00""!\r\nA possible cause would be the comparison of a DynRPG-patched RPG_RT.exe against a non-patched one at the time the IPS file was created.", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do, Do + EndIf + If Address < &h400000 OrElse Address >= &h4CF000 Then + MessageBox(NULL, "Error in quick patch """ & *KeyName & """: Address """ & Hex(Address) & !""" is outside of limits!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Exit Do, Do + EndIf + *Address = ByteVal ' Write changed data to memory + + p += 2 + Address += 1 + Loop + EndIf + If ValueBuffer[p] = Asc(",") Then p += 1 + Loop + KeyName += Len(*KeyName) + 1 + Loop +End Sub + +Function OffsetToVA(offs As UInteger) As UByte Ptr + Select Case offs + Case &h00000 To &h003FF + Return offs + &h400000 + Case &h00400 To &hC9200 + Return offs + &h400C00 + Case &hC9200 To &hCD400 + Return offs + &h400E00 + Case Else + Return NULL + End Select +End Function + +Sub ApplyIPSPatch(filename As String) + Var file = FileObj.File(ExePathCached & "\DynPatches\" & filename, FileObj.MODE_BINARY) + If file.ReadString(5) <> "PATCH" Then + MessageBox(NULL, "Error in patch file """ & filename & """: Invalid file header! Not an IPS file?", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Return + EndIf + Do Until file.EndReached() + Dim OffsetInt As UInteger = 0 + For i As Integer = 0 To 2 + OffsetInt Shl= 8 + OffsetInt Or= file.ReadByte() + Next + If OffsetInt = &h454F46 Then Exit Do ' EOF + Dim Length As UShort = 0 + For i As Integer = 0 To 1 + Length Shl= 8 + Length Or= file.ReadByte() + Next + Dim Bytes As String + If Length = 0 Then + For i As Integer = 0 To 1 + Length Shl= 8 + Length Or= file.ReadByte() + Next + Bytes = String(Length, file.ReadString(1)) + Else + Bytes = file.ReadString(Length) + EndIf + For i As Integer = 0 To Length - 1 + Dim Address As UByte Ptr = OffsetToVA(OffsetInt + i) + If Address = &h45CE00 Then + MessageBox(NULL, "Error in patch file """ & filename & !""": Trying to write to protected address ""45CE00""!\r\nA possible cause would be the comparison of a DynRPG-patched RPG_RT.exe against a non-patched one at the time the IPS file was created.", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Return + EndIf + If Address = NULL Then + MessageBox(NULL, "Error in patch file """ & filename & """: Offset """ & Hex(OffsetInt + i) & !""" is outside of limits!", "DynRPG Loader", MB_OK Or MB_ICONWARNING) + Return + EndIf + + *Address = Bytes[i] ' Write changed data to memory + Next + Loop +End Sub + +Sub OnStartup() + WindowTitle("DynRPG Loader") + ' Trick to reduce the "black window" moment + ScreenRes 1, 1, 32, 1, FB.GFX_SHAPED_WINDOW Or FB.GFX_NO_FRAME Or FB.GFX_NO_SWITCH Or FB.GFX_ALWAYS_ON_TOP + ScreenRes 320, 240, 32, 1, FB.GFX_SHAPED_WINDOW Or FB.GFX_NO_FRAME Or FB.GFX_NO_SWITCH Or FB.GFX_ALWAYS_ON_TOP + Color &hFFFFFF, &hFF00FF + Cls() + + Color &hFF8000 + Dim st As String = Space(10) + st[0] = Asc("P") - 55 + st[1] = Asc("o") - 55 + st[2] = Asc("w") - 55 + st[3] = Asc("e") - 55 + st[4] = Asc("r") - 55 + st[5] = Asc("e") - 55 + st[6] = Asc("d") - 55 + st[7] = Asc(" ") - 55 + st[8] = Asc("b") - 55 + st[9] = Asc("y") - 55 + For i As Integer = 0 To 9 + st[i] += 55 + Next + Var text0 = StrToImg(st) 'StrToImg("Powered by") + Color &hFF0000 + st = Space(6) + st[0] = Asc("D") - 66 + st[1] = Asc("y") - 66 + st[2] = Asc("n") - 66 + st[3] = Asc("R") - 66 + st[4] = Asc("P") - 66 + st[5] = Asc("G") - 66 + For i As Integer = 0 To 5 + st[i] += 66 + Next + Var text1 = StrToImg(st) 'StrToImg("DynRPG") + Color &h00FE00 + st = Space(9) + st[0] = Asc("B") - 77 + st[1] = Asc("y") - 77 + st[2] = Asc(" ") - 77 + st[3] = Asc("C") - 77 + st[4] = Asc("h") - 77 + st[5] = Asc("e") - 77 + st[6] = Asc("r") - 77 + st[7] = Asc("r") - 77 + st[8] = Asc("y") - 77 + For i As Integer = 0 To 8 + st[i] += 77 + Next + Var text2 = StrToImg(st) 'StrToImg("By Cherry") + Var icon = GetIcon() + + Var IsTestPlay = InStr(*GetCommandLine(), "TestPlay") > 0 + + For i As Integer = 0 To 200 + If IsTestPlay AndAlso i <> 50 Then Continue For + ScreenLock() + Color &hFFFFFF, &hFF00FF + Cls() + MultiPut(0, 60 + i * 2, 9, text0, 1, 1, i * 8 - 400, 1) + MultiPut(0, 110 + i, i * 2 - 50, text1, 3 + i / 50, 3 + i / 50, 200 - i * 4, 1) + MultiPut(0, 210 - i, 360 - i * 3, text2, 3 - i / 50, 3 - i / 50, i * 6 - 300, 1) + MultiPut(0, 160, 125, icon, IIf(i < 50, i / 5, 10 - (i - 50) / 15), IIf(i < 50, i / 5, 10 - (i - 50) / 15), 50 * 12 - i * 12, 1) + ScreenUnLock() + If i Mod 5 = 0 Then Sleep(20, 1) + + If i = 50 AndAlso IsTestPlay = FALSE Then + For i As Integer = -1 To 4 + If i > -1 Then + ScreenLock() + For y As Integer = 0 To 239 + For x As Integer = 0 To 319 + Var c = Point(x, y) + If c <> &hFF00FF Then + PSet (x, y), c Xor -1 + EndIf + Next + Next + ScreenUnLock() + EndIf + Sleep(300, 1) + Next + EndIf + Next + + If IsTestPlay Then Sleep(1000, 1) + + Screen 0 + Sleep(100, 1) + + ThreadCall WindowChecker() + + ' Apply patches + Var IPSFileName = Dir(ExePathCached & "\DynPatches\*.ips") + Do While IPSFileName <> "" + ApplyIPSPatch(IPSFileName) + IPSFileName = Dir() + Loop + ApplyQuickPatches() + + + Dim FnNames(...) As String = { _ + "onStartup", _ + "onInitFinished", _ + "onInitTitleScreen", _ + "onNewGame", _ + "onLoadGame", _ + "onSaveGame", _ + "onExit", _ + "onFrame", _ + "onSetVariable", _ + "onGetVariable", _ + "onSetSwitch", _ + "onGetSwitch", _ + "onEventCommand", _ + "onComment", _ + "onDrawScreen", _ + "onDrawPicture", _ + "onPictureDrawn", _ + "onCheckEventVisibility", _ + "onDrawEvent", _ + "onEventDrawn", _ + "onDrawBattler", _ + "onBattlerDrawn", _ + "onDrawBattleActionWindow", _ + "onBattleStatusWindowDrawn", _ + "onDrawBattleActionWindow", _ + "onDoBattlerAction", _ + "onBattlerActionDone", _ + "onSystemBackgroundDrawn" _ + } + + Var p = ExePathCached & "\DynPlugins" + Var s = Dir(p & "\*.dll") + For Each(Plugin In Plugins) + If s = "" Then Exit For + Plugin = LoadLibrary(p & "\" & s) + If Plugin = NULL Then + Plugin = NULL + MessageBox(NULL, "Loading plugin """ & s & """ failed! (" & GetLastError() & ")", "DynRPG Loader", MB_OK Or MB_ICONERROR) + Else + Dim P_LinkVersion As Integer Ptr = GetProcAddress(Plugin, "linkVersion") + If P_LinkVersion = NULL Then + If InStr(s, ".plugin.") Then + MessageBox(NULL, "Plugin """ & s & """ is invalid!", "DynRPG Loader", MB_OK Or MB_ICONERROR) + EndIf + FreeLibrary(Plugin) + Plugin = NULL + ElseIf *P_LinkVersion > LINK_VERSION Then + MessageBox(NULL, "Plugin """ & s & !""" is not compatible with this version of DynRPG!\r\nPlugin link version: " & *P_LinkVersion & !"\r\nLoader link version: " & LINK_VERSION, "DynRPG Loader", MB_OK Or MB_ICONERROR) + FreeLibrary(Plugin) + Plugin = NULL + Else + PluginNames(__index) = Left(s, Len(s) - 4) + PluginLinkVersions(__index) = *P_LinkVersion + For i As Integer = 0 To UBound(FnNames) + PluginFn(__index, i) = GetProcAddress(Plugin, FnNames(i)) + Next + Dim P_OnStartup As Function Cdecl (As ZString Ptr) As Boolean = PluginFn(__index, 0) + If P_OnStartup Then + ChDir(ExePathCached) + If P_OnStartup(StrPtr(PluginNames(__index))) = FALSE Then + OnExit() + End(29) + EndIf + EndIf + EndIf + EndIf + s = Dir() + Next +End Sub + +Sub OnInitFinished() + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnInitFinished As Sub Cdecl () = PluginFn(__index, 1) + If P_OnInitFinished Then + ChDir2(ExePathCached) + P_OnInitFinished() + EndIf + EndIf + Next +End Sub + +Sub OnInitTitleScreen() + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnInitTitleScreen As Sub Cdecl () = PluginFn(__index, 2) + If P_OnInitTitleScreen Then + ChDir2(ExePathCached) + P_OnInitTitleScreen() + EndIf + EndIf + Next +End Sub + +Sub OnNewGame() + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnNewGame As Sub Cdecl () = PluginFn(__index, 3) + If P_OnNewGame Then + ChDir2(ExePathCached) + P_OnNewGame() + EndIf + EndIf + Next +End Sub + +Sub OnLoadGame(id As Integer) + If StopCallbacks Then Return + ChDir(ExePathCached) + Var file = FileObj.File("Save" & Format(id, "00") & ".dyn", FileObj.MODE_BINARY) + Dim fileok As Boolean + If file.ReadString(8) = "DYNSAVE1" AndAlso file.length() > 8 Then fileok = TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim plugindata As String = "" + If fileok Then + file.position = 9 + Do Until file.EndReached() + Var pname = file.ReadStringAuto() + Var pdata = file.ReadStringAuto() + If pname = PluginNames(__index) Then + plugindata = pdata + Exit Do + EndIf + 'If file.EndReached() Then + ' file.position = 9 + 'EndIf + Loop + EndIf + Dim P_OnLoadGame As Sub Cdecl (As Integer, As UByte Ptr, As Integer) = PluginFn(__index, 4) + If P_OnLoadGame Then + ChDir2(ExePathCached) + P_OnLoadGame(id, StrPtr(plugindata), Len(plugindata)) + EndIf + EndIf + Next + file.CloseF() +End Sub + +Sub SavePluginData Cdecl (pdata As ZString Ptr, length As Integer) + PluginData = String(length, 0) + CopyMemory(StrPtr(PluginData), pdata, length) +End Sub + +Sub OnSaveGame(id As Integer) + If StopCallbacks Then Return + ChDir(ExePathCached) + Var file = FileObj.File("Save" & Format(id, "00") & ".dyn", FileObj.MODE_BINARY) + file.WriteString("DYNSAVE1") + For Each(Plugin In Plugins) + If Plugin Then + PluginData = "" + Dim P_OnSaveGame As Sub Cdecl (As Integer, As Any Ptr) = PluginFn(__index, 5) + If P_OnSaveGame Then + ChDir2(ExePathCached) + P_OnSaveGame(id, @SavePluginData) + EndIf + file.WriteStringAuto(PluginNames(__index)) + file.WriteStringAuto(PluginData) + EndIf + Next +End Sub + +Sub OnExit() + If StopCallbacks Then Return + StopCallbacks = TRUE + + ShowWindow(hWndMain, SW_HIDE) + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnExit As Sub Cdecl () = PluginFn(__index, 6) + If P_OnExit Then + ChDir2(ExePathCached) + P_OnExit() + EndIf + EndIf + Next + + Sleep(300, TRUE) + + For Each(Plugin In Plugins) + If Plugin Then + FreeLibrary(Plugin) + Plugin = NULL + EndIf + Next +End Sub + +Sub OnFrame(scene As Integer) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnFrame As Sub Cdecl (As Integer) = PluginFn(__index, 7) + If P_OnFrame Then + ChDir2(ExePathCached) + P_OnFrame(scene) + EndIf + EndIf + Next +End Sub + +Function OnSetVariable(id As Integer, value As Integer) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnSetVariable As Function Cdecl (As Integer, As Integer) As Boolean = PluginFn(__index, 8) + If P_OnSetVariable Then + ChDir2(ExePathCached) + If P_OnSetVariable(id, value) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnGetVariable(id As Integer) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnGetVariable As Function Cdecl (As Integer) As Boolean = PluginFn(__index, 9) + If P_OnGetVariable Then + ChDir2(ExePathCached) + If P_OnGetVariable(id) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnSetSwitch(id As Integer, value As Boolean) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnSetSwitch As Function Cdecl (As Integer, As Boolean) As Boolean = PluginFn(__index, 10) + If P_OnSetSwitch Then + ChDir2(ExePathCached) + If P_OnSetSwitch(id, value) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnGetSwitch(id As Integer) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnGetSwitch As Function Cdecl (As Integer) As Boolean = PluginFn(__index, 11) + If P_OnGetSwitch Then + ChDir2(ExePathCached) + If P_OnGetSwitch(id) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnEventCommand(scriptLine As Any Ptr, scriptData As Any Ptr, eventId As Integer, pageId As Integer, lineId As Integer, nextLineId As Integer Ptr) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnEventCommand As Function Cdecl (As Any Ptr, As Any Ptr, As Integer, As Integer, As Integer, As Integer Ptr) As Boolean = PluginFn(__index, 12) + If P_OnEventCommand Then + ChDir2(ExePathCached) + If P_OnEventCommand(scriptLine, scriptData, eventId, pageId, lineId, nextLineId) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub ParseComment(text As ZString Ptr) + With CommentData + .command[0] = 0 + .parametersCount = 0 + If text = NULL Then Return + If text[0] <> Asc("@") Then Return + Dim p As Integer = 0 + Dim strend As Boolean = FALSE + .command[SizeOf(.command) - 1] = 0 + Do + p += 1 + Select Case (*text)[p] + Case 0 + strend = TRUE + Exit Do + Case Asc(" ") + Exit Do + Case Asc("A") To Asc("Z") + If p < SizeOf(.command) - 1 Then + .command[p - 1] = (*text)[p] + 32 + EndIf + Case Else + If p < SizeOf(.command) - 1 Then + .command[p - 1] = (*text)[p] + EndIf + End Select + Loop + If p < SizeOf(.command) - 1 Then + .command[p - 1] = 0 + EndIf + If strend = FALSE Then + Dim v_deref As Integer = 0 + Dim n_deref As Boolean = FALSE + Do Until strend + If .parametersCount >= UBound(.parameters) Then + strend = TRUE + Exit Do + EndIf + p += 1 + Select Case (*text)[p] + Case 0 + strend = TRUE + Exit Do + Case Asc(" "), 13, 10 + Continue Do + Case Asc("0") To Asc("9"), Asc("."), Asc("-") + ' Number + Static n As String * 20 = "" + n = "" + p -= 1 + Do + p += 1 + Select Case (*text)[p] + Case Asc(" "), 13, 10 + Continue Do + Case 0 + strend = TRUE + Exit Do + Case Asc(",") + Exit Do + Case Else + n += Chr((*text)[p]) + End Select + Loop + Var d = Val(n) + Do Until v_deref = 0 + d = GetVar(d) + v_deref -= 1 + Loop + If n_deref Then + n_deref = FALSE + With .parameters(.parametersCount) + .ptype = PARAM_STRING + .text = GetHeroName(d) + End With + Else + With .parameters(.parametersCount) + .ptype = PARAM_NUMBER + .number = d + End With + EndIf + .parametersCount += 1 + Case Asc("""") + ' String + With .parameters(.parametersCount) + .ptype = PARAM_STRING + Dim sp As Integer = 0 + Dim paramend As Boolean = FALSE + Do Until paramend OrElse strend ' ADDED: OrElse strend + p += 1 + Select Case (*text)[p] + Case 0 + strend = TRUE + Exit Do + Case 13, 10 + Continue Do + Case Asc("""") + If text[p + 1] = Asc("""") Then + If sp < SizeOf(.text) - 1 Then + .text[sp] = Asc("""") + sp += 1 + EndIf + p += 1 + Continue Do + Else + Do + p += 1 + Select Case (*text)[p] + Case 0 + strend = TRUE + Exit Do + Case Asc(",") + paramend = TRUE + Exit Do + End Select + Loop + EndIf + Case Else + If sp < SizeOf(.text) - 1 Then + .text[sp] = (*text)[p] + sp += 1 + EndIf + End Select + Loop + .text[sp] = 0 + End With + .parametersCount += 1 + v_deref = 0 + n_deref = FALSE + Case Asc("v"), Asc("V") + ' Variable + v_deref += 1 + Continue Do + Case Asc("n"), Asc("N") + ' Hero name + If v_deref = 0 AndAlso n_deref = FALSE Then + n_deref = TRUE + Continue Do + Else + GoTo IsToken + EndIf + Case Else + ' Token +IsToken: + With .parameters(.parametersCount) + .ptype = PARAM_TOKEN + Dim sp As Integer = v_deref + If n_deref Then + sp += 1 + .text = "n" + String(v_deref, Asc("v")) + Else + .text = String(v_deref, Asc("v")) + EndIf + p -= 1 + Do + p += 1 + Select Case (*text)[p] + Case 0 + strend = TRUE + Exit Do + Case Asc(" "), 13, 10 + Continue Do + Case Asc(",") + Exit Do + Case Asc("A") To Asc("Z") + If sp < SizeOf(.text) - 1 Then + .text[sp] = (*text)[p] + 32 + sp += 1 + EndIf + Case Else + If sp < SizeOf(.text) - 1 Then + .text[sp] = (*text)[p] + sp += 1 + EndIf + End Select + Loop + If sp < SizeOf(.text) Then ' ADDED! + .text[sp] = 0 + EndIf + End With + .parametersCount += 1 + v_deref = 0 + n_deref = FALSE + End Select + Loop + EndIf + End With +End Sub + +Sub OnComment(text As ZString Ptr, nextScriptLine As Any Ptr, scriptData As Any Ptr, eventId As Integer, pageId As Integer, lineId As Integer, nextLineId As Integer Ptr) + If StopCallbacks Then Return + ParseComment(text) + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnComment As Function Cdecl (As ZString Ptr, As TCommentData Ptr, As Any Ptr, As Any Ptr, As Integer, As Integer, As Integer, As Integer Ptr) As Boolean = PluginFn(__index, 13) + If P_OnComment Then + ChDir2(ExePathCached) + If P_OnComment(text, @CommentData, nextScriptLine, scriptData, eventId, pageId, lineId, nextLineId) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Sub OnDrawScreen() + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawScreen As Sub Cdecl () = PluginFn(__index, 14) + If P_OnDrawScreen Then + ChDir2(ExePathCached) + P_OnDrawScreen() + EndIf + EndIf + Next +End Sub + +Function OnDrawPicture(picture As Any Ptr) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawPicture As Function Cdecl (As Any Ptr) As Boolean = PluginFn(__index, 15) + If P_OnDrawPicture Then + ChDir2(ExePathCached) + If P_OnDrawPicture(picture) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnPictureDrawn(picture As Any Ptr) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnPictureDrawn As Function Cdecl (As Any Ptr) As Boolean = PluginFn(__index, 16) + If P_OnPictureDrawn Then + ChDir2(ExePathCached) + If P_OnPictureDrawn(picture) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnCheckEventVisibility(event As Any Ptr) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnCheckEventVisibility As Function Cdecl (As Any Ptr) As Boolean = PluginFn(__index, 17) + If P_OnCheckEventVisibility Then + ChDir2(ExePathCached) + If P_OnCheckEventVisibility(event) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Function OnDrawEvent(event As Any Ptr, isHero As Boolean) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawEvent As Function Cdecl (As Any Ptr, As Boolean) As Boolean = PluginFn(__index, 18) + If P_OnDrawEvent Then + ChDir2(ExePathCached) + If P_OnDrawEvent(event, isHero) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnEventDrawn(event As Any Ptr, isHero As Boolean) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnEventDrawn As Function Cdecl (As Any Ptr, As Boolean) As Boolean = PluginFn(__index, 19) + If P_OnEventDrawn Then + ChDir2(ExePathCached) + If P_OnEventDrawn(event, isHero) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnDrawBattler(battler As Any Ptr, isMonster As Boolean, id As Integer) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawBattler As Function Cdecl (As Any Ptr, As Boolean, As Integer) As Boolean = PluginFn(__index, 20) + If P_OnDrawBattler Then + ChDir2(ExePathCached) + If P_OnDrawBattler(battler, isMonster, id) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnBattlerDrawn(battler As Any Ptr, isMonster As Boolean, id As Integer) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnBattlerDrawn As Function Cdecl (As Any Ptr, As Boolean, As Integer) As Boolean = PluginFn(__index, 21) + If P_OnBattlerDrawn Then + ChDir2(ExePathCached) + If P_OnBattlerDrawn(battler, isMonster, id) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnDrawBattleStatusWindow(x As Integer, selection As Integer, selActive As Boolean, isTargetSelection As Boolean, isVisible As Boolean) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawBattleStatusWindow As Function Cdecl (As Integer, As Integer, As Boolean, As Boolean, As Boolean) As Boolean = PluginFn(__index, 22) + If P_OnDrawBattleStatusWindow Then + ChDir2(ExePathCached) + If P_OnDrawBattleStatusWindow(x, selection, selActive, isTargetSelection, isVisible) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnBattleStatusWindowDrawn(x As Integer, selection As Integer, selActive As Boolean, isTargetSelection As Boolean, isVisible As Boolean) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnBattleStatusWindowDrawn As Function Cdecl (As Integer, As Integer, As Boolean, As Boolean, As Boolean) As Boolean = PluginFn(__index, 23) + If P_OnBattleStatusWindowDrawn Then + ChDir2(ExePathCached) + If P_OnBattleStatusWindowDrawn(x, selection, selActive, isTargetSelection, isVisible) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Function OnDrawBattleActionWindow(x As Integer Ptr, y As Integer Ptr, selection As Integer, selActive As Boolean, isVisible As Boolean) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDrawBattleActionWindow As Function Cdecl (As Integer Ptr, As Integer Ptr, As Integer, As Boolean, As Boolean) As Boolean = PluginFn(__index, 24) + If P_OnDrawBattleActionWindow Then + ChDir2(ExePathCached) + If P_OnDrawBattleActionWindow(x, y, selection, selActive, isVisible) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Function OnDoBattlerAction(battler As Any Ptr, firstTry As Boolean) As Boolean + If StopCallbacks Then Return TRUE + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnDoBattlerAction As Function Cdecl (As Any Ptr, As Boolean) As Boolean = PluginFn(__index, 25) + If P_OnDoBattlerAction Then + ChDir2(ExePathCached) + ' This also works with plugins with LINK_VERSION < 3 even though their onDoBattlerAction callback has a (RPG::Battler *) signature, + ' i.e. no firstTry parameter, due to CDecl calling convention under which the caller has to remove the parameters from the stack, + ' therefore the callee can safely get superfluous parameters passed without its knowing. + If P_OnDoBattlerAction(battler, firstTry) = FALSE Then Return FALSE + EndIf + EndIf + Next + Return TRUE +End Function + +Sub OnBattlerActionDone(battler As Any Ptr, successful As Boolean) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnBattlerActionDone As Function Cdecl (As Any Ptr, As Boolean) As Boolean = PluginFn(__index, 26) + If P_OnBattlerActionDone Then + ChDir2(ExePathCached) + If P_OnBattlerActionDone(battler, successful) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Sub OnSystemBackgroundDrawn(rect As RECT Ptr) + If StopCallbacks Then Return + For Each(Plugin In Plugins) + If Plugin Then + Dim P_OnSystemBackgroundDrawn As Function Cdecl (As RECT Ptr) As Boolean = PluginFn(__index, 27) + If P_OnSystemBackgroundDrawn Then + ChDir2(ExePathCached) + If P_OnSystemBackgroundDrawn(rect) = FALSE Then Return + EndIf + EndIf + Next +End Sub + +Sub DynRPG_Init Alias "DynRPG_Init" (Version As Integer, FnArray As Any Ptr Ptr) Export + ExePathCached = ExePath() + ChDir(ExePathCached) + If Version < LINK_VERSION Then + MessageBox(NULL, !"DynRPG Patch version too old!\r\n" & "Patch link version: " & Version & !"\r\nLoader link version: " & LINK_VERSION, "DynRPG Loader", MB_OK Or MB_ICONERROR) + End(34) + EndIf + Dim mbi As MEMORY_BASIC_INFORMATION + VirtualQuery(&h401000, @mbi, SizeOf(mbi)) + Dim oldp As DWORD + VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, @oldp) + FnArray[0] = @OnStartup + FnArray[1] = @OnInitFinished + FnArray[2] = @OnInitTitleScreen + FnArray[3] = @OnNewGame + FnArray[4] = @OnLoadGame + FnArray[5] = @OnSaveGame + FnArray[6] = @OnExit + FnArray[7] = @OnFrame + FnArray[8] = @OnSetVariable + FnArray[9] = @OnGetVariable + FnArray[10] = @OnSetSwitch + FnArray[11] = @OnGetSwitch + FnArray[12] = @OnEventCommand + FnArray[13] = @OnComment + FnArray[14] = @OnDrawScreen + FnArray[15] = @OnDrawPicture + FnArray[16] = @OnPictureDrawn + FnArray[17] = @OnCheckEventVisibility + FnArray[18] = @OnDrawEvent + FnArray[19] = @OnEventDrawn + FnArray[20] = @OnDrawBattler + FnArray[21] = @OnBattlerDrawn + FnArray[22] = @OnDrawBattleStatusWindow + FnArray[23] = @OnBattleStatusWindowDrawn + FnArray[24] = @OnDrawBattleActionWindow + FnArray[25] = @OnDoBattlerAction + FnArray[26] = @OnBattlerActionDone + FnArray[27] = @OnSystemBackgroundDrawn +End Sub diff --git a/loader/dynloader.bi b/loader/dynloader.bi new file mode 100644 index 0000000..900a3fc --- /dev/null +++ b/loader/dynloader.bi @@ -0,0 +1,104 @@ +#Include "windows.bi" +#Include "fbgfx.bi" +#Include "string.bi" +#Include "file.bi" +#Include "useful/file_obj_standalone.bi" + +#Macro Each(__iter__, __arr__) + __index As Integer = LBound(__arr__) To UBound(__arr__) + #Define __iter__ (__arr__(__index)) +#EndMacro +#Define In , + +#Define ChDir2(_d_) + +#Define MAX_PLUGIN_COUNT 50 + +Dim Shared Plugins(MAX_PLUGIN_COUNT - 1) As HMODULE +Dim Shared PluginNames(MAX_PLUGIN_COUNT - 1) As String +Dim Shared PluginLinkVersions(MAX_PLUGIN_COUNT - 1) As Integer +Dim Shared PluginFn(MAX_PLUGIN_COUNT - 1, 27) As Any Ptr +Dim Shared StopCallbacks As Boolean + +Dim Shared KeyNamesBuffer As ZString * 32766 +Dim Shared ValueBuffer As ZString * 32766 + +Data 0, 0, 0, 0, 0, 0, 1, 1, 1 +Data 0, 0, 0, 0, 0, 1, 0, 0, 1 +Data 0, 1, 0, 0, 1, 0, 0, 0, 1 +Data 1, 0, 1, 1, 0, 0, 0, 1, 0 +Data 1, 0, 1, 0, 0, 0, 1, 0, 0 +Data 0, 1, 0, 0, 0, 1, 0, 0, 0 +Data 0, 1, 0, 0, 1, 1, 0, 0, 0 +Data 1, 0, 1, 1, 0, 0, 1, 0, 0 +Data 1, 1, 0, 0, 1, 1, 0, 0, 0 + +Declare Sub OnExit() + +Dim Shared hWndMain As HWND + +Dim Shared PluginData As String + +Dim Shared ExePathCached As String + +Dim Shared CallbackStack As Integer = 0 + +Enum EParamType + PARAM_NUMBER + PARAM_STRING + PARAM_TOKEN +End Enum + +Type CommentParameter + ptype As EParamType + number As Double + text As ZString * 200 +End Type + +Type TCommentData + command As ZString * 200 + parametersCount As Integer + parameters(99) As CommentParameter +End Type + +Dim Shared CommentData As TCommentData + +Dim Shared LStrClr As Any Ptr = &h4044ec +Dim Shared GetFromList As Any Ptr = &h475740 +Dim Shared GetVarP As Any Ptr = &h48b398 + +Function GetVar(id As Integer) As Integer + Asm + mov eax, [&h4cdc7c] + mov eax, [eax] + mov edx, [id] + call [GetVarP] + mov [Function], eax + End Asm +End Function + +Function GetHeroName(id As Integer) As String + Dim s As ZString Ptr + Asm + mov eax, [&h4cddc8] + mov eax, [eax] + mov edx, [id] + call [GetFromList] + test eax, eax + jz Cont + mov ecx, [eax] + lea edx, [s] + call [ecx+24] + Cont: + End Asm + + If s = 0 Then Return "" + + Function = *s + + Asm + lea eax, [s] + call [LStrClr] + End Asm +End Function + diff --git a/loader/dynloader.fbp b/loader/dynloader.fbp new file mode 100644 index 0000000..b0ff679 --- /dev/null +++ b/loader/dynloader.fbp @@ -0,0 +1,36 @@ +[Project] +Version=3 +Description=DynRPG Loader +Api=fb (FreeBASIC),win (Windows) +Grouping=1 +AddMainFiles=1 +AddModuleFiles=1 +ResExport= +CompileIfNewer=0 +IncVersion=0 +RunCmd=0 +[Make] +Current=1 +1=Windows dll,fbc -s gui -dll -export -R -v +Recompile=2 +Module=Module Build,fbc -c +Output=..\dyndemo\dynloader.dll +Run= +Delete= +PreBuildBatch= +PostBuildBatch= +[TabOrder] +TabOrder=1,2,3 +CurrentTab=1 +[File] +1=dynloader.bas +2=dynloader.rc +3=dynloader.bi +[BreakPoint] +1= +3= +2= +[FileInfo] +1=0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +2=0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +3=0,14,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/loader/dynloader.rc b/loader/dynloader.rc new file mode 100644 index 0000000..17d15be --- /dev/null +++ b/loader/dynloader.rc @@ -0,0 +1,27 @@ +#define IDR_VERSION1 1 + +IDR_VERSION1 VERSIONINFO +FILEVERSION 0,2,0,0 +PRODUCTVERSION 0,2,0,0 +FILEOS 0x00000004 +FILETYPE 0x00000000 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "FFFF0000" + BEGIN + VALUE "FileVersion", "0.2.0.0\0" + VALUE "ProductVersion", "0.2.0.0\0" + VALUE "CompanyName", "CherryTree\0" + VALUE "FileDescription", "DynRPG Loader\0" + VALUE "LegalCopyright", "David 'Cherry' Trapp\0" + VALUE "OriginalFilename", "dynloader.dll\0" + VALUE "ProductName", "DynRPG - RM2k3 Plugin SDK\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xFFFF, 0x0000 + END +END + diff --git a/loader/rsrc.bi b/loader/rsrc.bi new file mode 100644 index 0000000..3e1a61a --- /dev/null +++ b/loader/rsrc.bi @@ -0,0 +1 @@ +#define IDR_VERSION1 1 diff --git a/loader/useful/file_obj_standalone.bi b/loader/useful/file_obj_standalone.bi new file mode 100644 index 0000000..a14a249 --- /dev/null +++ b/loader/useful/file_obj_standalone.bi @@ -0,0 +1,309 @@ +/' + +Copyright (C) 2006-2017, David "Cherry" Trapp +All rights reserved. + +1. Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the conditions laid out in the + following paragraphs are met. +2. Redistributions of source code (if available) must retain the above + copyright notice, this list of conditions and the following disclaimer. +3. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3.1. In case this software is redistributed in binary form inside of a + executable or library file belonging to Third Parties and/or + including modifications done by Third Parties (or done by the Author + in Third Parties' names), any license restrictions imposed by the + Third Parties which disallow modification and/or redistribution remain + valid and have to be adhered, overriding the rights described in + paragraph 1 of this license. This does not give the Third Parties + the right to claim ownership of those parts of the software which + were developed by the Author, nor does it affect the remaining + parts of this license. +4. All advertising materials by Third Parties mentioning features or use + of this software must display the following acknowledgement (unless + agreed otherwise through written notice): + This product includes software developed by David "Cherry" Trapp. + +DISCLAIMER: +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +'/ + +Namespace FileObj + Enum FileMode + MODE_NONE + MODE_OUTPUT + MODE_INPUT + MODE_APPEND + MODE_RANDOM + MODE_BINARY + End Enum + + Type File + handle As Integer + filename As String + mode As FileMode + valid As Boolean + fieldlen As Integer + Declare Constructor (filename As String, mode As FileMode, fieldlen As Integer = 1) + Declare Destructor () + Declare Function WriteLine(text As String, newline As Boolean = TRUE) As Integer + Declare Function ReadLine() As String + Declare Function EndReached() As Boolean + Declare Function WriteByte(value As UByte, position_ As LongInt = -1) As Integer + Declare Function ReadByte(position_ As LongInt = -1) As UByte + Declare Function WriteWord(value As UShort, position_ As LongInt = -1) As Integer + Declare Function ReadWord(position_ As LongInt = -1) As UShort + Declare Function WriteInt(value As Integer, position_ As LongInt = -1) As Integer + Declare Function ReadInt(position_ As LongInt = -1) As Integer + Declare Function WriteString(value As String, position_ As LongInt = -1) As Integer + Declare Function ReadString(length_ As UInteger, position_ As LongInt = -1) As String + Declare Function WriteStringAuto(value As String, position_ As LongInt = -1) As Integer + Declare Function ReadStringAuto(position_ As LongInt = -1) As String + Declare Property position() As LongInt + Declare Property position(newpos As LongInt) + Declare Function Length() As LongInt + Declare Function Save() As Integer + Declare Function CloseF() As Integer + End Type + + Type Stream + stream As String + position__ As LongInt + filename As String + Declare Constructor (filename As String, loadfromfile As Boolean = FALSE) + Declare Constructor () + Declare Function ReadLine() As String + Declare Function EndReached() As Boolean + Declare Property position() As LongInt + Declare Property position(newpos As LongInt) + Declare Function Length() As LongInt + Declare Function Save(filename As String) As Integer + Declare Function Load(filename As String) As Integer + End Type + + Constructor File(filename As String, mode As FileMode, fieldlen As Integer = 1) + This.valid = FALSE + This.handle = FreeFile + If This.handle = 0 Then Return + Select Case mode + Case MODE_OUTPUT + Open filename For Output As #(This.handle) + Case MODE_INPUT + Open filename For Input As #(This.handle) + Case MODE_APPEND + Open filename For Append As #(This.handle) + Case MODE_RANDOM + Open filename For Random As #(This.handle) Len = fieldlen + Case MODE_BINARY + Open filename For Binary As #(This.handle) + Case Else + Return + End Select + If Err = NULL Then This.valid = TRUE Else Return + This.filename = filename + This.mode = mode + This.fieldlen = fieldlen + End Constructor + + Destructor File() + This.CloseF() + End Destructor + + Function File.WriteLine(text As String, newline As Boolean = TRUE) As Integer + If This.valid = FALSE Then Return -1 + If newline Then Print #(This.handle), text Else Print #(This.handle), text; + Return Err + End Function + + Function File.ReadLine() As String + If This.valid = FALSE Then Return "" + Dim text As String + Line Input #(This.handle), text + Return text + End Function + + Function File.EndReached() As Boolean + If This.valid = FALSE Then Return Cast(Boolean, -1) + Return Eof(This.handle) + End Function + + Function File.WriteByte(value As UByte, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadByte(position_ As LongInt = -1) As UByte + If This.valid = FALSE Then Return 0 + Dim value As UByte + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteWord(value As UShort, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadWord(position_ As LongInt = -1) As UShort + If This.valid = FALSE Then Return 0 + Dim value As UShort + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteInt(value As Integer, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadInt(position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return 0 + Dim value As Integer + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteString(value As String, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + For i As Integer = 0 To Len(value) - 1 + This.WriteByte(value[i], position_ + IIf(position_ = -1, 0, i)) + Next + Return Err + End Function + + Function File.ReadString(length_ As UInteger, position_ As LongInt = -1) As String + If This.valid = FALSE Then Return "" + Dim value As String = String(length_, Chr(0)) + For i As Integer = 0 To length_ - 1 + value[i] = This.ReadByte(position_ + IIf(position_ = -1, 0, i)) + Next + Return value + End Function + + Function File.WriteStringAuto(value As String, position_ As LongInt = -1) As Integer + Var ret = This.WriteInt(Len(value), position_) + If ret Then Return ret + If Len(value) <> 0 Then Return This.WriteString(value) + Return 0 + End Function + + Function File.ReadStringAuto(position_ As LongInt = -1) As String + Var length_ = This.ReadInt(position_) + If length_ > 0 Then Return This.ReadString(length_) + Return "" + End Function + + Property File.position() As LongInt + If This.valid = FALSE Then Return -1 + Return Seek(This.handle) + End Property + + Property File.position(newpos As LongInt) + If This.valid = FALSE Then Return + Seek #(This.handle), newpos + End Property + + Function File.Length() As LongInt + If This.valid = FALSE Then Return -1 + Return Lof(This.handle) + End Function + + Function File.Save() As Integer + If This.valid = FALSE Then Return -1 + Dim oldpos As LongInt = This.position + Close #(This.handle) + This.valid = FALSE + Select Case mode + Case MODE_OUTPUT, MODE_APPEND + Open This.filename For Append As #(This.handle) + Case MODE_INPUT + Open This.filename For Input As #(This.handle) + Case MODE_RANDOM + Open This.filename For Random As #(This.handle) Len = This.fieldlen + Case MODE_BINARY + Open This.filename For Binary As #(This.handle) + Case Else + Return -1 + End Select + If Err = NULL Then This.valid = TRUE Else Return Err + This.position = oldpos + End Function + + Function File.CloseF() As Integer + If This.valid = FALSE Then Return -1 + Close #(This.handle) + This.valid = FALSE + Return Err + End Function + + Constructor Stream(source As String, loadfromfile As Boolean = FALSE) + This.stream = "" + This.position__ = 1 + If loadfromfile = FALSE Then + This.stream = source + Return + EndIf + If FileExists(source) Then + This.Load(source) + EndIf + End Constructor + + Constructor Stream() + This.stream = "" + This.position__ = 1 + End Constructor + + Function Stream.ReadLine() As String + Var e = InStr(This.position, This.stream, !"\13\10") + If e = 0 Then e = This.Length + 1 + Var ret = Mid(This.stream, This.position, e - This.position) + This.position = e + 2 + Return ret + End Function + + Function Stream.EndReached() As Boolean + Return (This.position > This.Length) And TRUE + End Function + + Property Stream.position() As LongInt + Return This.position__ + End Property + + Property Stream.position(newpos As LongInt) + This.position__ = min(max(1ll, newpos), This.Length + 1) + End Property + + Function Stream.Length() As LongInt + Return Len(This.stream) + End Function + + Function Stream.Save(filename As String) As Integer + Var f = File(filename, MODE_BINARY) + If f.valid = FALSE Then Return -1 + f.WriteString(This.stream) + This.filename = filename + End Function + + Function Stream.Load(filename As String) As Integer + Var f = File(filename, MODE_BINARY) + If f.valid = FALSE Then Return -1 + This.stream = f.ReadString(f.Length()) + This.position__ = 1 + This.filename = filename + End Function +End Namespace + diff --git a/patch/patch.asm b/patch/patch.asm new file mode 100644 index 0000000..e6adb4c --- /dev/null +++ b/patch/patch.asm @@ -0,0 +1,1905 @@ +; DynRPG Patch + +; FOR COMPATIBILITY: AFTER REMOVING PATCHES, WRITE THE ORIGINAL COMMANDS AS PATCH!!! (And also put them into the HPD) +; 442600..443A70 (442600..442680 < vars for DynRPG lib - 443900..4439A0 < CommonThisEventPatch) +; 45CDF4..45D84C + +<0045CDF4> + +@JmpHookOnDoBattlerAction: +jmp @HookOnDoBattlerAction ; For RPG::Battler::executeAction(false) + +<00442600> + +@BattleSpeed: +dd 100. +@TransparentWindowsEverywhere: +dd 0 + +<0045CE00> + +@LINK_VERSION: +dd 3 ; LINK_VERSION + +@DynRPGLoaderDLL: +dd 0 ; DynRPGLoaderDLL + +@DynRPGVTable: +@OnStartup: +dd 0 ; DynRPGVTable +@OnInitFinished: +dd 0 +@OnInitTitleScreen: +dd 0 +@OnNewGame: +dd 0 +@OnLoadGame: +dd 0 +@OnSaveGame: +dd 0 +@OnExit: +dd 0 +@OnFrame: +dd 0 +@OnSetVariable: +dd 0 +@OnGetVariable: +dd 0 +@OnSetSwitch: +dd 0 +@OnGetSwitch: +dd 0 +@OnEventCommand: +dd 0 +@OnComment: +dd 0 +@OnDrawScreen: +dd 0 +@OnDrawPicture: +dd 0 +@OnPictureDrawn: +dd 0 +@OnCheckEventVisibility: +dd 0 +@OnDrawEvent: +dd 0 +@OnEventDrawn: +dd 0 +@OnDrawBattler: +dd 0 +@OnBattlerDrawn: +dd 0 +@OnDrawBattleStatusWindow: +dd 0 +@OnBattleStatusWindowDrawn: +dd 0 +@OnDrawBattleActionWindow: +dd 0 +@OnDoBattlerAction: +dd 0 +@OnBattlerActionDone: +dd 0 +@OnSystemBackgroundDrawn: +dd 0 + +@CurrentEventID: +dd 0 +@CurrentEventPage: +dd 0 +@CurrentEventScriptLine: +dd 0 + +@ReadyForExit: +dd 0 +@NextLineOffset: +dd 0 +@AutoResetEvCmd: +dd 0 + +@LastEventScriptLine: +dd 0 +@SavedEventScriptLine: +dd 0 ; vTable +dd 0 ; command +dd 0 ; treeDepth +dd 0 ; stringParameter +dd 0 ; parameters.size +dd 0 ; parameters.array + +@LoadDLL: +pushad ; HookOnStartup proc +push @DLLName +call 406c14 ; LoadLibraryA +test eax, eax +jz @DLLError +push @FnName +push eax +call 406b5c ; GetProcAddress +test eax, eax +jz @DLLError +push @DynRPGVTable +push [@LINK_VERSION] +call eax +call [@OnStartup] +popad +retn + +@DLLError: +push 0 +push @ErrDLLNotFoundTitle +push @ErrDLLNotFound +push 0 +call 4012dc ; MessageBoxA +push 0 +call 4012d4 ; ExitProcess +int3 + +@DLLName: +"dynloader.dll\0" + +@FnName: +"DynRPG_Init@8\0" + +@ErrDLLNotFound: +"DynRPG Loader (dynloader.dll) could not be loaded!\0" + +@ErrDLLNotFoundTitle: +"DynRPG Patch\0" + + +@MorePictures: +push edi ; MorePictures proc +mov edi, [esp+8] +call [@PictureCallTable+edi*4] +pop edi +inc ebx +cmp ebx, 2001. +retn 4 + +@PictureCallTable: +dd 4755b8 ; PreparePicture +dd 4c1c20 ; UpdatePicture +dd @HookOnDrawPicture ; DrawPicture +dd 4c1bf8 ; ErasePicture +dd 4c21d4 ; PictureOperation5One +dd 4c2220 ; PictureOperation6One +dd 4c226c ; PictureOperation7One +dd 4c22b8 ; PictureOperation8One + + +@HookOnStartup: +call @LoadDLL ; HookOnStartup proc +jmp 406910 ; Sysinit::InitExe + + +@HookOnSetVariable: +pushad ; HookOnSetVariable proc +push ecx +push edx +call [@OnSetVariable] +test al, al +popad +jz 48b3d3 ; For compatibility with CustomSaveLoadPatch +mov esi, edx +mov ebx, eax +cmp esi, 1 +jmp 48b3bc ; For compatibility with CustomSaveLoadPatch + + +@HookOnGetVariable: +pushad ; HookOnGetVariable proc +push edx +call [@OnGetVariable] +popad +cmp edx, 1 +jl 48b3a2 +jmp 48b39d + + +@HookOnSetSwitch: +pushad ; HookOnSetSwitch proc +push ecx +push edx +call [@OnSetSwitch] +test al, al +popad +jz 48b362 +push ebx +push esi +push edi +mov ebx, ecx +jmp 48b341 + + +@HookOnGetSwitch: +pushad ; HookOnGetSwitch proc +push edx +call [@OnGetSwitch] +popad +cmp edx, 1 +jl 48b32e +jmp 48b329 + + +@HookOnDrawScreen: +pushad ; HookOnDrawScreen +mov eax, [4cdd4c] ; DebugParamPtr - is the last to be initialized, thus the testing here +mov eax, [eax] +test eax, eax +jz @NoOUSHook +call [@OnDrawScreen] + +@NoOUSHook: +popad +push ebp +mov ebp, esp +push ecx +mov [ebp-4], eax +jmp 46bc33 + + +@HookOnDrawPicture: +mov edx, [eax+10] ; HookOnDrawPicture proc +mov edx, [edx+608] +test edx, edx +jz @HODP_Ret2 +push eax +pushad +push eax +call [@OnDrawPicture] +test al, al +popad +jz @HODP_Ret +call 4c1e6c ; DrawPicture + +@HODP_Ret: +call [@OnPictureDrawn] + +@HODP_Ret2: +retn + + +@CopyEventScriptLine: +push ebp +mov ebp, esp +mov esi, [arg.1] +mov edi, [arg.2] +cmp byte ptr [arg.3], 0 +je @NoCCheck +cmp dword ptr [edi], 4791d0 +jne @AbortCESL +cmp dword ptr [edi+4], 0 +je @AbortCESL +cmp dword ptr [esi+4], 0 +je @AbortCESL + +@NoCCheck: +mov eax, [esi+4] +mov [edi+4], eax +mov eax, [esi+8] +mov [edi+8], eax +lea eax, [edi+0c] +mov edx, [esi+0c] +call 404540 ; LStrAsg +mov edx, [esi+10] +push edx +cmp byte ptr [arg.3], 0 +je @AlwaysResize +cmp edx, [edi+10] +jle @DontResize + +@AlwaysResize: +cmp edx, [edi+10] +pushfd +mov [edi+10], edx +popfd +jle @DontResize +lea eax, [edi+14] +shl edx, 2 +call 4027ac ; ResizeArray + +@DontResize: +pop ecx +mov esi, [esi+14] +mov edi, [edi+14] +test edi, edi +jz @AbortCESL +test esi, esi +jz @AbortCESL +rep movsd + +@AbortCESL: +mov esp, ebp +pop ebp +retn 0c + + +@HookOnEventCommand: +pushad ; HookOnEventCommand proc +mov [@CurrentEventScriptLine], edx +push [ebx+1c] +pop [@CurrentEventID] +mov dword ptr [@CurrentEventPage], 0 +mov eax, [4cdd74] +mov eax, [eax] +mov eax, [eax+18] +mov edx, [ebx+1c] +call 475740 ; GetFromList +test eax, eax +jz @SEIDVCont +call 4ab4f0 ; GetActiveEventPage +mov [@CurrentEventPage], eax + +@SEIDVCont: +popad +call 479710 ; GetEventScriptLine +and dword ptr [eax+4], 7fffffff +pushad +push eax +mov dword ptr [@NextLineOffset], -1 +mov dword ptr [@AutoResetEvCmd], 1 ; SET TO ZERO TO DISABLE AUTO RESET +mov [@LastEventScriptLine], eax +pushad +push 0 +push @SavedEventScriptLine +push eax +call @CopyEventScriptLine +popad +push @NextLineOffset +push [@CurrentEventScriptLine] +push [@CurrentEventPage] +push [@CurrentEventID] +push ebx +push eax +call [@OnEventCommand] +test al, al +pop eax +jnz @SEIDVHookOK +or dword ptr [eax+4], 80000000 + +@SEIDVHookOK: +popad +retn + + +@HookOnEventCommandExecuted: +mov edx, [@NextLineOffset] ; HookOnEventCommandExecuted proc +cmp edx, -1 +je @NoOffsetChange +cmp ebx, 0ffff ; If this code path is reached without any command executed, ebx is no valid pointer but a counter instead +jg @NoOffsetChange +mov [ebx+18], edx +cmp edx, [@NextLineOffset] +jne @NoOffsetChange +mov dword ptr [esi+14], 1 ; do a Wait 0.0 if we loop back to where we were otherwise the game may hang + +@NoOffsetChange: +mov dl, [@AutoResetEvCmd] +test dl, dl +jz @NoAutoReset +cmp edi, [@LastEventScriptLine] +jne @NoAutoReset +cmp dword ptr [@SavedEventScriptLine+4], 0 +je @NoAutoReset +cmp dword ptr [@LastEventScriptLine], 0 +je @NoAutoReset +pushad +push 1 +push edi +push @SavedEventScriptLine +call @CopyEventScriptLine +popad + +@NoAutoReset: +mov dword ptr [@LastEventScriptLine], 0 +pop edx +pop edi +pop esi +pop ebx +retn + + +@HookOnComment: +push ebx ; HookOnCommentProc +mov ebx, edx +push 0 +push 0 +lea eax, [esp] +mov edx, [ecx+0c] +call 404540 ; LStrAsg + +@L00000002: +mov edx, [ebx+18] +mov eax, [ebx+14] +call 479710 ; GetEventScriptLine +mov [esp+4], eax +mov ecx, eax +cmp dword ptr [ecx+4], 22410. +jnz @L00000003 +push ecx +lea eax, [esp+4] +mov edx, @NewLine +call 4047ac ; LStrCat +pop ecx +lea eax, [esp] +mov edx, [ecx+0c] +call 4047ac ; LStrCat +inc dword ptr [ebx+18] +jmp @L00000002 + +@L00000003: +lea eax, [esp] +lea edx, [esp+4] +push @NextLineOffset +push [@CurrentEventScriptLine] +push [@CurrentEventPage] +push [@CurrentEventID] +push ebx +push [edx] +push [eax] +call [@OnComment] +lea eax, [esp] +call 4044ec ; LStrClr +pop eax +pop eax +pop ebx +retn + +dd 0ffffffff +dd 2. +@NewLine: +"\r\n\0" + + +@HookOnInitFinished: +call 48ede4 ; HookOnInitFinished proc ; TLcfDebugScene__Constructor +pushad +call [@OnInitFinished] +popad +retn + + +@HookOnNewGame: +call 4a5578 ; HookOnNewGame proc +pushad +mov eax, [4cdf3c] ; LcfgPicture +mov eax, [eax] +push 1001. ; Erase pictures > 1000 on new game! +push 2000. +call @ErasePictures +call [@OnNewGame] +popad +retn + + +@HookOnLoadGame: +push edx ; HookOnLoadGame proc +call 4a541c ; LoadGame +call [@OnLoadGame] +retn + + +@HookOnSaveGame: +push edx ; HookOnSaveGame proc +call 4a5524 ; SaveGame +pop edx +pushad +push edx +call [@OnSaveGame] +popad +retn + + +@HookOnExit: +cmp dword ptr [ebx], WM_CLOSE +jne 439efc +cmp dword ptr [@ReadyForExit], 1 +je @HOE_Ret +pushad ; HookOnExit proc +mov dword ptr [@ReadyForExit], 1 +call [@OnExit] +popad +jmp 439efc + +@HOE_Ret: +retn + + +@HookOnDrawEvent: +push eax ; HookOnDrawEvent proc +pushad +push 0 +push eax +call [@OnDrawEvent] +test al, al +popad +jz @HODE_Ret +cmp dword ptr [eax+9c], 0 +je @HODE_Ret +call 4c5b98 ; TLcfgCharacter_Draw + +@HODE_Ret: +pop eax +push 0 +push eax +call [@OnEventDrawn] +retn + + +@HookOnDrawEvent_Party: +push eax ; HookOnDrawEvent_Party proc +pushad +push 1 +push eax +call [@OnDrawEvent] +test al, al +popad +jz @HODE2_Ret +cmp byte ptr [eax+99], 0 +jnz @HODE2_Ret +cmp byte ptr [eax+49], 0 +jnz @HODE2_Ret +call 4c5b98 ; TLcfgCharacter_Draw + +@HODE2_Ret: +pop eax +push 1 +push eax +call [@OnEventDrawn] +retn + + +@HookOnDrawBattler_Enemy: +push ebp ; HookOnDrawBattler_Enemy proc +mov ebp, esp +sub esp, 8 +mov [local.1], edx +pushad +push edx +push 1 +call 4be860 ; GetEnemy +push eax +mov [local.2], eax +call [@OnDrawBattler] +test al, al +popad +jz @HODB_Ret +call 4be860 ; GetEnemy +call 4bd900 ; DrawEnemy + +@HODB_Ret: +push [local.1] +push 1 +push [local.2] +call [@OnBattlerDrawn] +mov esp, ebp +pop ebp +retn + + +@HookOnDrawBattler_Hero: +push ebp ; HookOnDrawBattler_Hero proc +mov ebp, esp +sub esp, 8 +mov [local.1], edx +pushad +push edx +push 0 +call 4b4870 ; GetActor +push eax +mov [local.2], eax +call [@OnDrawBattler] +test al, al +popad +jz @HODB2_Ret +call 4b4870 ; GetActor +call 4bca30 ; DrawActorBattler + +@HODB2_Ret: +push [local.1] +push 0 +push [local.2] +call [@OnBattlerDrawn] +mov esp, ebp +pop ebp +retn + + +@HookOnInitTitleScreen: +cmp byte ptr [eax+0d], 0 ; HookOnInitTitleScreen proc +jz 4909a0 +cmp byte ptr [eax+0c], 0 +jnz 4909a0 +pushad +call [@OnInitTitleScreen] +popad +jmp 4909a0 + + +@HookOnDoBattlerAction: +pushad ; HookOnDoBattlerAction proc +mov eax, [edx+10] +movzx eax, byte ptr [eax+7] ; [TLcfgUnitActItem+7] = did last execution attempts fail? +xor eax, 1 ; Convert it to "is this the first try?" +push eax +push edx +call [@OnDoBattlerAction] +popad +push edx +call 49a04c ; ExecuteBattlerAction +pop edx +pushad +movzx eax, al +push eax +push edx +mov edx, [edx+10] +xor al, 1 +or [edx+7], al ; If execution failed, set [TLcfgUnitActItem+7] +;movzx ; WHAT WAS HERE?! +call [@OnBattlerActionDone] +popad +retn + + +@HookOnFrame_Map: +push 0 ; HookOnFrame_Map proc +call 4a37bc ; TLcfFieldScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Menu: +push 1 ; HookOnFrame_Menu proc +call 4a3314 ; TLcfMenuScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Battle: +push 2 ; HookOnFrame_Battle proc +call 498ca4 ; TLcfBattleScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Shop: +push 3 ; HookOnFrame_Shop proc +call 494a1c ; TLcfShopScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Name: +push 4 ; HookOnFrame_Name proc +call 492bb4 ; TLcfNameScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_SaveFile: +push 5 ; HookOnFrame_SaveFile proc +call 4916cc ; TLcfSaveFileScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Title: +push 6 ; HookOnFrame_Title proc +call 490b30 ; TLcfTitleScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_GameOver: +push 7 ; HookOnFrame_GameOver proc +call 48f6c0 ; TLcfGameOverScene_Draw +call [@OnFrame] +retn + + +@HookOnFrame_Debug: +push 8 ; HookOnFrame_Debug proc +call 48f424 ; TLcfDebugScene_Draw +call [@OnFrame] +retn + + +@HookOnCheckEventVisibility: +pushad ; HookOnCheckEventVisibility +push eax +call [@OnCheckEventVisibility] +test al, al +popad +jz @OCEV_Vis +push ebx +push esi +mov ebx, eax +jmp 4c42f2 + +@OCEV_Vis: +mov al, 1 +retn + + +@HookOnDrawBattleStatusWindow: +push eax +pushad +mov edx, [eax+8] +mov edx, [edx+608] +test edx, edx +setnz dl +movzx edx, dl +push edx +mov edx, [4cdd38] +mov edx, [edx] +cmp eax, [edx+24] +setne dl +movzx edx, dl +push edx +movzx edx, byte ptr [eax+50] +push edx +push [eax+44] +push [eax+14] +call [@OnDrawBattleStatusWindow] +test eax, eax +popad +jz @DontDrawBSW +call 496718 ; TLcfBattleStatusWindow_Draw + +@DontDrawBSW: +pop eax +pushad +mov edx, [eax+8] +mov edx, [edx+608] +test edx, edx +setnz dl +movzx edx, dl +push edx +mov edx, [4cdd38] +mov edx, [edx] +cmp eax, [edx+24] +setne dl +movzx edx, dl +push edx +movzx edx, byte ptr [eax+50] +push edx +push [eax+44] +push [eax+14] +call [@OnBattleStatusWindowDrawn] +popad +retn + + +@HookOnDrawBattleActionWindow: +mov edx, [eax+8] ; HookOnDrawBattleActionWindow proc +mov edx, [edx+608] +test edx, edx +jz @NoBAWHook +push eax +pushad +mov edx, [eax+8] +mov edx, [edx+608] +test edx, edx +setnz dl +movzx edx, dl +push edx +movzx edx, byte ptr [eax+50] +push edx +push [eax+44] +lea edx, [eax+18] +push edx +lea edx, [eax+14] +push edx +call [@OnDrawBattleStatusWindow] +test eax, eax +popad +jz @DontDrawBAW +mov edx, [eax] +call [edx+34] ; TLcfWindow_Draw + +@DontDrawBAW: +pop eax + +@NoBAWHook: +retn + + +@HookOnSystemBackgroundDrawn: +push edx ; HookOnSystemBackgroundDrawn proc +call @OriginalDrawSystemBackground +call [@OnSystemBackgroundDrawn] +retn + + +@OriginalDrawSystemBackground: +push ebx ; OriginalDrawSystemBackground proc +push esi +push edi +push ebp +add esp, -10 +jmp 4681c3 + + +@SetCommonEventID1: +call 47991c ; SetCommonEventID1 proc ; CallEvent +mov eax, ebx +neg eax +retn + + +@SetCommonEventID2: +call 47991c ; SetCommonEventID2 proc ; CallEvent +mov eax, edi +neg eax +mov [ebx+1c], eax +retn + + +@SetCommonEventID3: +call 47991c ; SetCommonEventID3 proc ; CallEvent +mov edx, 1 +mov eax, esi +call 47967c ; GetEvParam +neg eax +mov [ebx+1c], eax +retn + + +@SetCommonEventID4: +call 47991c ; SetCommonEventID4 proc ; CallEvent +xor edx, edx +mov eax, edi +call 47967c ; GetEvParam +neg eax +mov [ebx+1c], eax +retn + + +@ChoicePlayBuzzerSound: +cmp dword ptr [esi+0a0], 0 ; ChoicePlayBuzzerSound proc +pushfd +jnz @NoBuzzer +mov eax, [4cdc7c] +mov eax, [eax] +call 48bae4 ; GetBuzzerSound +mov edx, eax +mov eax, [4cdc7c] +mov eax, [eax] +call 48b538 ; CallHarmonyPlaySound + +@NoBuzzer: +popfd +retn + + +@GetVar: +push edx ; GetVar proc +push ecx +mov eax, [4cdc7c] +mov eax, [eax] +mov edx, [esp+0c] +call 48b398 ; GetVar +pop ecx +pop edx +retn 4 + + +@BetterInputNumber: +mov [edx+0b0], eax ; BetterInputNumber proc +push eax +call @GetVar +mov [edx+0a8], eax +retn + + +@CheckF11: +push 7a ; CheckF11 proc ; VK_F11 +call 407054 ; GetAsyncKeyState +movsx eax, ax +test ah, 80 +jz 407054 ; GetAsyncKeyState +mov eax, [4cdc7c] +mov eax, [eax] +mov byte ptr [eax+4], 5 +mov eax, [4cdfcc] +mov eax, [eax] +mov byte ptr [eax+50], 1 +mov byte ptr [eax+51], 0 +mov eax, [4cdc1c] +mov eax, [eax] +push 40240000 +push 0 +call 48ce04 ; FadeOut +mov eax, [4cdc1c] +mov eax, [eax] +mov byte ptr [eax+0c], 0 +xor ax, ax +retn 4 + + +@UpdateEventsAfterShop: +call 46bc2c ; UpdateEventsAfterShop proc ; UpdateScreen +mov eax, [4cdd74] +mov eax, [eax] +mov eax, [eax+18] +call 4ab8b4 ; UpdateEvents +retn + + + +@DoSmoothEventSpeed: +mov al, [esi+43] ; DoSmoothEventSpeed proc +test al, al +jz @NormalEvSpeed +xor edx, edx +cmp al, 0ff +je @EvSpeedRet +movzx edx, al +jmp @EvSpeedRet + +@NormalEvSpeed: +mov eax, [esi+38] +mov edx, [4cda90+eax*4] + +@EvSpeedRet: +mov eax, esi +mov ecx, [eax] +call [ecx+34] +retn + + +@GetEvScreenXWrapper: +push eax ; GetEvScreenXWrapper proc +push @ScreenXJumpBack +push ebx +push esi +mov esi, [4cdd74] +jmp 4c46f0 + +@ScreenXJumpBack: +pop edx ; ScreenXJumpBack proc +movsx edx, byte ptr [edx+41] +add eax, edx +retn + + +@GetEvScreenYWrapper: +push eax ; GetEvScreenYWrapper proc +push @ScreenYJumpBack +push ebx +push esi +mov esi, [4cdd74] +jmp 4c47cc + +@ScreenYJumpBack: +pop edx ; ScreenYJumpBack proc +movsx edx, byte ptr [edx+42] +add eax, edx +retn + + +@CheckRestartOnError: +mov ecx, [4cdb94] ; CheckRestartOnError proc +mov ecx, [ecx] +test ecx, ecx +jz @AbortGame +cmp dword ptr [ecx], 0 +jz @AbortGame +mov ecx, [ecx+10] +test ecx, ecx +jz @AbortGame +jmp 46ae95 + +@AbortGame: +mov eax, [4cde78] +mov eax, [eax] +call 455808 ; Forms::TApplication::Terminate +jmp 46ae95 + + +@PlayCancelOrder: +cmp byte ptr [esi+80], 1 ; PlayCancelOrder proc +jne 404510 +and byte ptr [esi+80], 1 +push eax +push edx +push ecx +mov eax, [4cdc7c] +mov eax, [eax] +push eax +call 48ba04 ; GetCancelSound +mov edx, eax +pop eax +call 48b538 ; CallHarmonyPlaySound +pop ecx +pop edx +pop eax +jmp 404510 + + +@GaugeSkillWindowFix: +push eax ; GaugeSkillWindowFix proc +mov eax, [4cdd60] +mov eax, [eax] +cmp byte ptr [eax+8], 2 ; in gauge layout only +pop eax +jz @GSKRet +mov edx, [eax] +call [edx+28] + +@GSKRet: +retn + + +@PlayEnemyAttackSound: +; PlayEnemyAttackSound proc +push eax +mov eax, [eax+10] +cmp byte ptr [eax+4], 4 ; On AK_NONE, don't flash and don't play sound +je @PEAS_NoAction +cmp word ptr [eax+4], 700 ; Same for BA_NONE +je @PEAS_NoAction +push edx +push ecx +mov eax, [4cdc7c] +mov eax, [eax] +push eax +call 48bc84 ; GetAttackingSound +mov edx, eax +pop eax +call 48b538 ; CallHarmonyPlaySound +pop ecx +pop edx +pop eax +jmp 4c1178 ; FlashBattler + +@PEAS_NoAction: +pop eax +retn 0c + +<00442680> + +@DontExitTooQuickly: +@DETQ_Loop: +push 1 ; DontExitTooQuickly proc +call 40d6bc ; Sleep +cmp dword ptr [@ReadyForExit], 0 +je @DETQ_Loop +push 3000. +call 40d6bc ; Sleep +call 41f528 +retn + + +@ApplyBattleSpeedSetting: +push eax ; ApplyBattleSpeedSetting proc +mov eax, [@BattleSpeed] +push edx +push ecx +xor edx, edx +imul eax, [esp+10] +mov ecx, 100. +idiv ecx +mov [esp+10], eax +pop ecx +pop edx +pop eax +retn + + +@ApplyBattleSpeedSetting1: +idiv ecx +push eax ; ApplyBattleSpeedSetting1 proc +call @ApplyBattleSpeedSetting +pop eax +add [ebx+44], eax +retn + + +@ApplyBattleSpeedSetting2: +call 4a6014 ; ApplyBattleSpeedSetting2 proc ; GetPartyMember +push ebp +call @ApplyBattleSpeedSetting +pop ebp +add [eax+44], ebp +retn + + +@ErasePictures: +push ebp ; ErasePictures proc +mov ebp, esp +push eax +push ebx +push esi +mov esi, eax +mov ebx, [arg.2] +inc dword ptr [arg.1] + +@ErasePicLoop: +mov edx, ebx +mov eax, esi +call 475740 ; GetFromList +test eax, eax +jz @EraseNull +call 4c1bf8 ; ErasePicture + +@EraseNull: +inc ebx +cmp ebx, [arg.1] +jnz @ErasePicLoop +pop esi +pop ebx +pop eax +mov esp, ebp +pop ebp +retn 8 + + +@SpecialErasePictures: +push 1. ; @SpecialErasePictures proc +push 1000. +call @ErasePictures +retn + + +@GetPartyMemberBattleBugfix: +call 4c33d0 ; GetPartyMemberBattleBugfix proc ; DrawWeather +mov eax, [ebp-4] +mov eax, [eax+24] +mov edx, [eax+44] +push eax +mov eax, [4cdb74] +mov eax, [eax] +call 4a6014 ; GetPartyMember +test eax, eax +pop eax +jnz @GPMBB_OK +mov dword ptr [eax+44], 0 + +@GPMBB_OK: +retn + + +@TransparentWindowInTitle: +mov edx, [4cdc7c] ; TransparentWindowInTitle proc +cmp al, 2 +jne @TrNextCmp +push eax +mov eax, [4cdd60] +mov eax, [eax] +cmp byte ptr [eax+8], 0 ; in traditional battle layout, disable transparency +pop eax +je 4c650a +;cmp dword ptr [@TransparentWindowsEverywhere], 0 +;je 4c650a +jmp 4c650e + +@TrNextCmp: +cmp al, 5 +je 4c650a +cmp al, 3 +je 4c650a +cmp dword ptr [@TransparentWindowsEverywhere], 0 +je 4c650a +jmp 4c650e + + +@CheckEventScriptLineDestruction: +cmp eax, [@LastEventScriptLine] ; CheckEventScriptLineDestruction proc +jne 47963c +mov dword ptr [@LastEventScriptLine], 0 +jmp 47963c + +@BattleActionBugfix: +push eax ; BattleActionBugfix proc +mov eax, [ebp] +mov eax, [eax+4c] +mov eax, [eax+10] +mov byte ptr [eax+4], 4 ; action->kind = RPG::AK_NONE +pop eax +jmp 47f7e0 ; GetBattleCommand2 + +@SmallWindowBattleMessageBugfix: +mov eax, [4cdd60] ; SmallWindowBattleMessageBugfix proc +mov eax, [eax] +cmp dword ptr [eax+10], 1 +jnz 4c643b +mov eax, [4cdef4] ; MessagePtr +mov eax, [eax] +cmp ebx, eax ; Is this the message window? +je 4c643b +jmp 4c6426 + + +@SmallWindowChoiceAmountBugfix: +mov eax, [ebx+20] ; SmallWindowChoiceAmountBugfix proc +sub eax, dword ptr [ebx+34] ; Subtract twice the top cursor offset instead of a fixed 0x10 +sub eax, dword ptr [ebx+34] +retn + + +@DivisionByZeroBugfix: +test edi, edi ; DivisionByZeroBugfix proc +jnz @DBZBRet +xor eax, eax + +@DBZBRet: +retn + +; !== END +; ================================================================================= +@RepairMistake1: +mov eax, [eax+0ac] ; RepairMistake1 proc +call 4047a4 +jmp 49338f + +@RepairMistake2: +push ebx ; RepairMistake2 proc +mov ebx, eax +mov eax, [4cdb24] +jmp 48cd48 + +@RepairMistake3: +mov ecx, 30. +mov edx, 20. +retn + +@RepairMistake4: +mov ecx, 40. +mov edx, 10. +retn + +@RepairMistake5: +push 44 +push 0 +lea ecx, [edi+0c] +jmp 4950de + + +<00443900> + +@CommonThisEventPatchHandler: +cmp edx, 10005. +je @CTEPIsThis + +@CTEPIsThisButOkay: +mov eax, edx +add eax, -10001. +jmp 4ac277 + +@CTEPIsThis: +cmp dword ptr [ecx+1c], 0 +jg @CTEPIsThisButOkay + +mov eax, [eax+4] +mov eax, [eax+8] +mov ecx, [eax+8] +mov eax, [eax+4] + +@CTEPLoop: +dec ecx +mov edx, [eax+ecx*4] +mov edx, [edx+1c] +cmp edx, 0 +jg 4ac2ba + +test ecx, ecx +jnz @CTEPLoop + +xor edx, edx +jmp 4ac2ba + + +@CommonThisEventPatchHandler2: +; push scripter +; push scriptdata +call 47967c ; GetEvParam +mov edx, eax +cmp edx, 10005. +jnz @CTEPReturn + +@CommonThisEventPatchHandler3: +mov ecx, [esp+4] +mov edx, [ecx+1c] +cmp edx, 0 +jg @CTEPReturn + +mov eax, [esp+8] +mov eax, [eax+4] +mov eax, [eax+8] +mov ecx, [eax+8] +mov eax, [eax+4] + +@CTEPLoop2: +dec ecx +mov edx, [eax+ecx*4] +mov edx, [edx+1c] +cmp edx, 0 +jg @CTEPReturn + +test ecx, ecx +jnz @CTEPLoop2 + +xor edx, edx + +@CTEPReturn: +mov eax, edx +retn 8 + + +; ================================================================================= + + + +<0045D840> + +int3 ; just for security +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 + +<00443A60> + +int3 ; just for security +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 +int3 + +<004C9C31> + +call @HookOnStartup + +<0048B3B5> ; For compatibility with CustomSaveLoadPatch + +jmp @HookOnSetVariable + +;<0048B398> + +;jmp @HookOnGetVariable ; TOO SLOW! + +<0048B33C> + +jmp @HookOnSetSwitch + +;<0048B324> + +;jmp @HookOnGetSwitch ; TOO SLOW! + +<0046BC2C> + +jmp @HookOnDrawScreen + +;<004C243E> + +;call @HookOnDrawPicture + +<004B1DEC> + +call @HookOnEventCommand + +<004B2A8B> + +call @HookOnComment + +<0048FD85> + +call @HookOnInitFinished + +<00490A62> + +call @HookOnNewGame + +<004915F0> + +call @HookOnLoadGame + +<00491532> + +call @HookOnSaveGame + +;<0048FDD0> +<0044F3B8> + +call @HookOnExit + +<004AB570> + +jmp @HookOnDrawEvent + +<004AA8B4> + +jmp @HookOnDrawEvent_Party + +<004990AD> + +call @HookOnDrawBattler_Enemy +jmp 4990d7 + +<00498964> + +call @HookOnDoBattlerAction + +<004990CD> + +call @HookOnDrawBattler_Hero +jmp 4990d7 + +<0049038A> + +call @HookOnInitTitleScreen + +<004A34A8> + +dd @HookOnFrame_Map + +<0049DF40> + +dd @HookOnFrame_Menu + +<00494ED8> + +dd @HookOnFrame_Battle + +<00492ED0> + +dd @HookOnFrame_Shop + +<004919A8> + +dd @HookOnFrame_Name + +<00490CF8> + +dd @HookOnFrame_SaveFile + +<0049054C> + +dd @HookOnFrame_Title + +<0048F514> + +dd @HookOnFrame_GameOver + +<0048E5EC> + +dd @HookOnFrame_Debug + +<004B2B81> + +jmp @HookOnEventCommandExecuted + +<004C42EC> + +jmp @HookOnCheckEventVisibility + +<00494D00> + +dd @HookOnDrawBattleStatusWindow + +<004994FA> + +call @HookOnDrawBattleActionWindow + +<004681BC> + +jmp @HookOnSystemBackgroundDrawn + +<004B3096> + +jle 4b30af ; Avoid problems with negative IDs for CEs + +<004B1952> + +jle 4b19aa ; Avoid problems with negative IDs for CEs + +<004B2DA6> + +call @SetCommonEventID1 ; set common event ID in +1C field +nop +nop + +<004B0ECC> + +call @SetCommonEventID2 + +<004B0D5A> + +call @SetCommonEventID3 + +<004B0F71> + +call @SetCommonEventID4 + +<004C834B> + +call @ChoicePlayBuzzerSound ; play buzzer sound when esc is pressed at choice when default = ignore (0) +nop +nop + +<004ACA31> + +call @BetterInputNumber ; preserve initial value of variable +nop + +<004A3717> + +call @CheckF11 ; in testplay, use F11 for saving the game + +<00493887> + +call @UpdateEventsAfterShop ; bugfix + +<00493384> + +jmp @RepairMistake1 ; I made a mistake there, now I am repairing it (1) + +<004C46E8> + +jmp @GetEvScreenXWrapper + +<004C47C4> + +jmp @GetEvScreenYWrapper + +<004C5B4A> + +call @DoSmoothEventSpeed +jmp 4c5b8c + +<004C416C> + +call 474d68 ; at [TLcfgCharacter+40], save dword instead of byte (so +41, +42 and +43 will be saved too). + +<004C3EA9> + +xor eax, eax ; initialize [TLcfgCharacter+40] as dword => erase +41, +42 and +43 too +mov [ebx+40], eax +nop + +<0046AE89> + +jmp @CheckRestartOnError ; don't close on error; just restart game + +<004A00F0> + +call @PlayCancelOrder ; play cancel sound when exiting order menu + +<0049FDCA> + +mov byte ptr [esi+80], 3 ; hint for cancel sound fix + +<004B1EFA> + +nop ; unlock pictures +nop +nop +nop +nop +nop + +<004950D7> + +jmp @RepairMistake5 + +<00498345> + +call @GaugeSkillWindowFix ; don't hide status window when skill window is opened in gauge layout + +<0049C4B2> + +nop ; fix reflect bug +mov eax, [4cddc8] +mov eax, [eax] +call 4b4870 ; GetActor + +<0049592D> + +call @ApplyBattleSpeedSetting1 + +<00495C87> + +call @ApplyBattleSpeedSetting2 +nop +nop +nop + +<0049A2D0> + +call @PlayEnemyAttackSound ; play sound + +<0049A2C0> + +push 20 ; more instense flashing of enemies +push 30 + +<0049B9F7> + +mov ecx, 50. ; skill info window longer visible for monster skills only +mov edx, 15. + +<0049A79C> + +;mov ecx, 90. ; skill info window longer visible --- UNDO CHANGES because of bug +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049A7FC> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049A87C> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049A8CA> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049A91C> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049A970> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<0049CCC2> + +;mov ecx, 90. +;mov edx, 15. +call @RepairMistake4 +nop +nop +nop +nop +nop + +<004BF29C> + +mov dword ptr [eax+4], 4 ; clear also [UnitActItem+6] and +7 +nop + +<004A3D5C> + +nop ; I *think* this is an obsolete loop (about event visibility) +nop +; Explanation: +; The RPG Maker seems to be doing something like this: +; for(int i = -1; i < 16; i++) { // WE CAN REMOVE THIS +; foreach(event in sameLevelHeroEvents) { +; if(event.y >= i && event.y < i + 16) { // AND THIS +; event.draw(); +; } +; } +; } +; We should be able to simplify it because sameLevelHeroEvents is already sorted by z-order! + +<004A3D73> + +nop +nop + +<004A3D85> + +nop +nop + +<004B4083> + +jmp 4b4089 ; skip event visibility check for ships + +<004C237D> + +push 0 +call @MorePictures +nop +nop + +<004C241E> + +push 1 +call @MorePictures +nop +nop + +<004C243E> + +push 2 +call @MorePictures +nop +nop + +<004C245E> + +push 3 +call @MorePictures +nop +nop + +<004C2483> + +push 4 +call @MorePictures +nop +nop + +<004C24AB> + +push 5 +call @MorePictures +nop +nop + +<004C24D3> + +push 6 +call @MorePictures +nop +nop + +<004C24FB> + +push 7 +call @MorePictures +nop +nop + +<004A4562> + +call @SpecialErasePictures + +<004522CC> + +jmp 4522ed ; Ignore "Attempt to focus on invalid window" message + +<00499482> + +call @GetPartyMemberBattleBugfix + +<00497136> + +nop ; allow transparent windows with classic battle layout +nop +nop +nop + +<004C6500> + +jmp @TransparentWindowInTitle ; make window in title screen transparent + +<004791CC> + +dd @CheckEventScriptLineDestruction ; prevent errors when an event script line is destroyed before HookOnEventCommandExecuted ran + +<0048CD40> + +jmp @RepairMistake2 + +<00490FF9> + +mov eax, 4956fc ; Change %3d to %4d so that HP can have 4 digits in the save menu, properly aligned + +<0049625A> + +call @BattleActionBugfix ; Bugfix for "Link to event" commands, see http://www.multimediaxis.de/threads/121175-RPG2000-und-2003-Sammelthread-f%C3%BCr-Probleme?p=2982219#post2982219 + +<004C6419> + +jmp @SmallWindowBattleMessageBugfix ; Bugfix for misaligned cursor in choices in battle using "Small window" + +<004C6445> + +call @SmallWindowChoiceAmountBugfix ; Bugfix for small windows displaying only 3 lines instead of 4, etc. +nop + +<00466B2C> + +call @DivisionByZeroBugfix ; Bugfix for division by zero error at picture (or generic: image) display using DrawAuroraSheet_Transform + +<004AC270> + +jmp @CommonThisEventPatchHandler + +<004AEF3A> + +push eax +push esi +mov eax, ebx +call @CommonThisEventPatchHandler2 +jmp 4aef56 + +<004AF0A9> + +push eax ; for second call +push eax +push edi +mov eax, esi +call @CommonThisEventPatchHandler2 +jmp 4af0c5 + +<004AF0CE> + +push edi +call @CommonThisEventPatchHandler2 +jmp 4af0eb + +<004AFA97> + +push eax +push ebp +mov eax, ebx +call @CommonThisEventPatchHandler2 +mov esi, eax +jmp 4afabd + +<004B0D77> + +push [ebp-10] ; scripter, from outer esi +push [ebp-4] +call @CommonThisEventPatchHandler2 +jmp 4b0d97 + +<004B0C95> + +push eax +push edx +call @CommonThisEventPatchHandler3 +cmp edx, 0 ; result is in eax AND edx +jle 4b0cc1 +jmp 4b0cae \ No newline at end of file diff --git a/patcher/.gitignore b/patcher/.gitignore new file mode 100644 index 0000000..8d91880 --- /dev/null +++ b/patcher/.gitignore @@ -0,0 +1,12 @@ +Bak/ + +*.asm +*.obj +*.dll.a +*.undo + +dynrpg_patcher.exe +dynrpg.hpd + +rpg_rt_original.exe + diff --git a/patcher/dynrpg.txt b/patcher/dynrpg.txt new file mode 100644 index 0000000..8436b83 --- /dev/null +++ b/patcher/dynrpg.txt @@ -0,0 +1,4 @@ +CREATE +.\dynrpg.hpd +..\dyndemo\RPG_RT.exe +..\dyndemo\RPG_RT2.exe diff --git a/patcher/dynrpg_patcher.bas b/patcher/dynrpg_patcher.bas new file mode 100644 index 0000000..89fd068 --- /dev/null +++ b/patcher/dynrpg_patcher.bas @@ -0,0 +1,140 @@ +#Include "windows.bi" +#Include "win/commdlg.bi" +#Include "rsrc.bi" +#Include "file.bi" +#Include "string.bi" +#Include "useful/file_obj_standalone.bi" +#Define _NO_HPA +#Include "rm2kdev/hpd.bi" +#Define ExtractPath(_st_) Left((_st_), InStrRev((_st_), "\") - 1) + +#Define VERSION "0.20" + +Dim Shared hInstance As HINSTANCE +hInstance = GetModuleHandle(NULL) + +Function CopyResourceToFile(id As Integer, filename As String) As Boolean + Var hRsrc = FindResource(hInstance, id, RT_RCDATA) + If hRsrc = NULL Then Return FALSE + Var hResData = LoadResource(hInstance, hRsrc) + If hResData = NULL Then Return FALSE + Var reslen = SizeofResource(hInstance, hRsrc) + If reslen = NULL Then FreeResource(hResData): Return FALSE + Var resptr = LockResource(hResData) + If resptr = NULL Then FreeResource(hResData): Return FALSE + Function = TRUE + Kill(filename) + Var ff = FreeFile() + Open filename For Binary As #ff + Put #ff, 1, *CPtr(UByte Ptr, resptr), reslen + Close #ff + If Err() Then Function = FALSE + FreeResource(hResData) +End Function + +If MessageBox(NULL, "This application will install the DynRPG Patch (version " & VERSION & ") on your RPG Maker 2003 game. After clicking ""OK"" in this window, you need to select your RPG_RT.exe file.", "DynRPG Patcher", MB_OKCANCEL Or MB_ICONINFORMATION) = IDCANCEL Then End(0) + +Dim target As ZString * MAX_PATH + 1 + +Dim ofn As OPENFILENAME +Const FILTER = !"RPG_RT.exe\0RPG_RT.exe\0All files (*.*)\0*.*\0\0" +With ofn + .lStructSize = SizeOf(ofn) + .hwndOwner = NULL + .hInstance = hInstance + .lpstrFilter = @FILTER + .lpstrFile = @target + .nMaxFile = MAX_PATH + .lpstrTitle = @"Select project's RPG_RT.exe file" + .Flags = OFN_EXPLORER Or OFN_PATHMUSTEXIST Or OFN_FILEMUSTEXIST Or OFN_HIDEREADONLY +End With + +If GetOpenFileName(@ofn) = FALSE Then End(0) + +Var fileh = FileObj.File(target, FileObj.MODE_BINARY) +If fileh.valid = FALSE Then + MessageBox(NULL, "The selected file couldn't be opened!", "DynRPG Patcher", MB_OK Or MB_ICONERROR) + End(0) +EndIf +Var s = fileh.ReadString(fileh.length()) +If InStr(s, "TLcfFieldScene") = 0 Then + fileh.CloseF() + MessageBox(NULL, "The selected file is no RPG Maker runtime file! Maybe you have renamed it in the past during installation of another patch...?", "DynRPG Patcher", MB_OK Or MB_ICONERROR) + End(0) +EndIf +If InStr(s, "TLcfJob") = 0 Then + fileh.CloseF() + MessageBox(NULL, "Your project seems to use RPG Maker 2000. DynRPG does only work with RPG Maker 2003, I am sorry. However, it might be possible for you to upgrade to RPG Maker 2003, use Google to find out more.", "DynRPG Patcher", MB_OK Or MB_ICONERROR) + End(0) +EndIf + +Dim EntryPoint As Integer + +If fileh.ReadByte(1) <> Asc("M") Or fileh.ReadByte(2) <> Asc("Z") Then GoTo Problem +Var pe_start = fileh.ReadInt(&h3C + 1) +If pe_start < 2 Or pe_start > fileh.Length() - &h14 Then GoTo Problem +Var opt_start = pe_start + &h18 +If opt_start < 2 Or opt_start > fileh.Length() - &h40 Then GoTo Problem +EntryPoint = fileh.ReadInt(opt_start + &h1C + 1) + fileh.ReadInt(opt_start + &h10 + 1) ' ImageBase + RVA + +Problem: +fileh.CloseF() + +Dim ok As Boolean = FALSE + +If EntryPoint <> &h4C9C1C Then + If MessageBox(NULL, "Your RPG_RT.exe version is not 1.08. DynRPG only works with version 1.08. Do you want to install a RPG_RT.exe with version 1.08? THIS WILL REMOVE ALL EXISTING PATCHES!", "DynRPG Patcher", MB_YESNO Or MB_ICONWARNING) = IDYES Then + Kill(target & ".bak") + FileCopy(target, target & ".bak") + Kill(target) + CopyResourceToFile(IDR_EXE, target) + ok = TRUE + EndIf +Else + Var tempfile = Environ("temp") & "\dynrpg.hpd" + Kill(tempfile) + CopyResourceToFile(IDR_HPD, tempfile) + Kill(target & ".bak") + FileCopy(target, target & ".bak") + ok = HPD_Apply(tempfile, target, TRUE) + Kill(tempfile) +EndIf + +Var p = ExtractPath(target) + +If ok Then + If FileExists(p & "\dynloader.dll") Then + Kill(p & "\dynloader.dll.bak") + FileCopy(p & "\dynloader.dll", p & "\dynloader.dll.bak") + Kill(p & "\dynloader.dll") + EndIf + CopyResourceToFile(IDR_DLL, p & "\dynloader.dll") + MkDir(p & "\DynPlugins") + MkDir(p & "\DynPatches") + Open p & "\DynRPG.ini" For Binary As #90 + Var s = Space(Lof(90)) + Get #90, 1, s + Close #90 + If InStr(s, "[QuickPatches]") = 0 Then + Open p & "\DynRPG.ini" For Append As #90 + Print #90, "[QuickPatches]" + Print #90, "; Paste quickpatches here" + Close #90 + EndIf +EndIf + +If ok = FALSE Then + If FileExists(target & ".bak") Then + Kill(target) + FileCopy(target & ".bak", target) + Kill(target & ".bak") + EndIf + If FileExists(p & "\dynloader.dll.bak") Then + Kill(p & "\dynloader.dll") + FileCopy(p & "\dynloader.dll.bak", p & "\dynloader.dll") + Kill(p & "\dynloader.dll.bak") + EndIf + MessageBox(NULL, "There was an error during patching. The backup has been restored.", "DynRPG Patcher", MB_OK Or MB_ICONERROR) +Else + MessageBox(NULL, "The DynRPG Patch was successfully installed! Have fun with the new world of plugins!", "DynRPG Patcher", MB_OK Or MB_ICONINFORMATION) +EndIf diff --git a/patcher/dynrpg_patcher.fbp b/patcher/dynrpg_patcher.fbp new file mode 100644 index 0000000..771290e --- /dev/null +++ b/patcher/dynrpg_patcher.fbp @@ -0,0 +1,36 @@ +[Project] +Version=3 +Description=DynRPG Patcher +Api=fb (FreeBASIC),win (Windows) +Grouping=1 +AddMainFiles=1 +AddModuleFiles=1 +ResExport= +CompileIfNewer=0 +IncVersion=0 +RunCmd=0 +[Make] +Module=Module Build,fbc -c +Recompile=2 +Current=4 +1=Windows Console (export all),fbc -g -s console -R -v -maxerr inf -Wl --export-all +2=Windows Console (debug),fbc -g -s console -R -v -maxerr inf +3=Windows GUI (debug),fbc -g -s gui -R -v -maxerr inf +4=Windows GUI,fbc -s gui -R -v +Output= +Run= +Delete= +[TabOrder] +TabOrder=1,3,2 +CurrentTab=2 +[File] +1=dynrpg_patcher.bas +2=dynrpg_patcher.rc +3=rm2kdev\hpd.bi +[BreakPoint] +1=98 +3= +[FileInfo] +1=0,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +2=0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +3=0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/patcher/dynrpg_patcher.rc b/patcher/dynrpg_patcher.rc new file mode 100644 index 0000000..4f6f565 --- /dev/null +++ b/patcher/dynrpg_patcher.rc @@ -0,0 +1,35 @@ +#define MANIFEST 24 +#define IDI_MAINICON 100 +#define IDR_HPD 101 +#define IDR_EXE 102 +#define IDR_DLL 103 +#define IDR_XPMANIFEST1 1 +#define IDR_VERSION1 1 + +IDI_MAINICON ICON DISCARDABLE "icon.ico" +IDR_HPD RCDATA DISCARDABLE "dynrpg.hpd" +IDR_EXE RCDATA DISCARDABLE "../dyndemo/rpg_rt2.exe" +IDR_DLL RCDATA DISCARDABLE "../dyndemo/dynloader.dll" + +IDR_XPMANIFEST1 MANIFEST "xpmanifest.xml" + +IDR_VERSION1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +FILEOS 0x00000004 +FILETYPE 0x00000000 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "FFFF0000" + BEGIN + VALUE "FileVersion", "1.0.0.0\0" + VALUE "ProductVersion", "1.0.0.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xFFFF, 0x0000 + END +END + diff --git a/patcher/hpdpa.exe b/patcher/hpdpa.exe new file mode 100644 index 0000000..2ac27b0 Binary files /dev/null and b/patcher/hpdpa.exe differ diff --git a/patcher/icon.ico b/patcher/icon.ico new file mode 100644 index 0000000..81f53ce Binary files /dev/null and b/patcher/icon.ico differ diff --git a/patcher/rm2kdev/hpd.bi b/patcher/rm2kdev/hpd.bi new file mode 100644 index 0000000..e347bc9 --- /dev/null +++ b/patcher/rm2kdev/hpd.bi @@ -0,0 +1,178 @@ +Const HPD_SIGNATURE = "HPD1" +Const HPA_SIGNATURE = "HPA1" + +Sub HPD_Create(patchfile_ As String, original_ As String, modified_ As String) + Kill(patchfile_) + Var patchfile = FileObj.File(patchfile_, FileObj.MODE_BINARY) + Var original = FileObj.File(original_, FileObj.MODE_BINARY) + Var modified = FileObj.File(modified_, FileObj.MODE_BINARY) + patchfile.WriteInt(*Cast(Integer Ptr, @HPD_SIGNATURE)) + patchfile.WriteInt(original.Length()) + Var ol = original.Length() + Var ml = modified.Length() + For i As Integer = 1 To max(ol, ml) + If original.ReadByte() <> modified.ReadByte() Or i > ol Then + Dim l As Integer + For j As Integer = i To max(ol, ml) + If original.ReadByte(j) = modified.ReadByte(j) And i <= ol Then Exit For + l += 1 + Next + patchfile.WriteInt(i) + patchfile.WriteInt(l) + For j As Integer = 0 To l - 1 + patchfile.WriteByte(modified.ReadByte(j + i)) + Next + i += l - 1 + original.position = i + 1 + modified.position = i + 1 + EndIf + Next +End Sub + +Function HPD_Apply(patchfile_ As String, target_ As String, ignoreLength As Boolean = FALSE) As Boolean + Var patchfile = FileObj.File(patchfile_, FileObj.MODE_BINARY) + Var target = FileObj.File(target_, FileObj.MODE_BINARY) + If patchfile.ReadInt() <> *Cast(Integer Ptr, @HPD_SIGNATURE) Then Return FALSE + If patchfile.ReadInt() <> target.Length() And ignoreLength = FALSE Then Return FALSE + Do Until patchfile.EndReached() + Var start = patchfile.ReadInt() + Var Length = patchfile.ReadInt() + For i As Integer = 0 To Length - 1 + target.WriteByte(patchfile.ReadByte(), start + i) + Next + Loop + Return TRUE +End Function + +Sub HPA_Create(archfile_ As String) + Kill(archfile_) + Var archfile = FileObj.File(archfile_, FileObj.MODE_BINARY) + archfile.WriteInt(*Cast(Integer Ptr, @HPA_SIGNATURE)) + For i As Integer = 1 To 4096 + archfile.WriteInt(0) ' Start Ptr + archfile.WriteInt(0) ' Ident->SizeOfCode + archfile.WriteInt(0) ' Ident->SizeOfInitializedData + Next +End Sub + +Function HPA_Add(archfile_ As String, patchfile_ As String, name_ As String, ident_ As TIdentData) As Boolean + Var archfile = FileObj.File(archfile_, FileObj.MODE_BINARY) + Var patchfile = FileObj.File(patchfile_, FileObj.MODE_BINARY) + If archfile.ReadInt() <> *Cast(Integer Ptr, @HPA_SIGNATURE) Then Return FALSE + If patchfile.ReadInt() <> *Cast(Integer Ptr, @HPD_SIGNATURE) Then Return FALSE + For i As Integer = 1 To 4096 + Var startptr = archfile.ReadInt() + archfile.position = archfile.position + 8 + If startptr = 0 Then + startptr = archfile.Length() + 1 + archfile.position = archfile.position - 12 + archfile.WriteInt(startptr) + archfile.WriteInt(ident_.SizeOfCode) + archfile.WriteInt(ident_.SizeOfInitializedData) + archfile.position = startptr + archfile.WriteByte(CUByte(Len(name_))) + archfile.WriteString(Left(name_, CUByte(Len(name_)))) + archfile.WriteInt(patchfile.Length() - 4) + archfile.WriteInt(patchfile.ReadInt()) + For j As Integer = 9 To patchfile.Length() + archfile.WriteByte(patchfile.ReadByte()) + Next + Return TRUE + EndIf + Next + Return FALSE +End Function + +Function HPA_Get(archfile_ As String, patchfile_ As String, name_ As String, ident_ As TIdentData) As Boolean + Var archfile = FileObj.File(archfile_, FileObj.MODE_BINARY) + Var patchfile = FileObj.File(patchfile_, FileObj.MODE_BINARY) + patchfile.WriteInt(*Cast(Integer Ptr, @HPD_SIGNATURE)) + If archfile.ReadInt() <> *Cast(Integer Ptr, @HPA_SIGNATURE) Then Return FALSE + For i As Integer = 1 To 4096 + Var startptr = archfile.ReadInt() + Var ident2_ = Type(archfile.ReadInt(), archfile.ReadInt()) + If ident2_.SizeOfCode = ident_.SizeOfCode And ident2_.SizeOfInitializedData = ident_.SizeOfInitializedData Then + Var oldpos = archfile.position + archfile.position = startptr + Var textlen = archfile.ReadByte() + Var name2_ = archfile.ReadString(textlen) + If Trim(UCase(name2_)) = Trim(UCase(name_)) Then + Var patchlen = archfile.ReadInt() + patchfile.WriteInt(archfile.ReadInt()) + For j As Integer = 3 To patchlen + patchfile.WriteByte(archfile.ReadByte()) + Next + Return TRUE + EndIf + archfile.position = oldpos + EndIf + Next + Return FALSE +End Function + +Function HPA_GetMem(archfile_ As String, name_ As String, ident_ As TIdentData) As UInteger Ptr + Var archfile = FileObj.File(archfile_, FileObj.MODE_BINARY) + If archfile.ReadInt() <> *Cast(Integer Ptr, @HPA_SIGNATURE) Then Return NULL + For i As Integer = 1 To 4096 + Var startptr = archfile.ReadInt() + Var ident2_ = Type(archfile.ReadInt(), archfile.ReadInt()) + If ident2_.SizeOfCode = ident_.SizeOfCode And ident2_.SizeOfInitializedData = ident_.SizeOfInitializedData Then + Var oldpos = archfile.position + archfile.position = startptr + Var textlen = archfile.ReadByte() + Var name2_ = archfile.ReadString(textlen) + If Trim(UCase(name2_)) = Trim(UCase(name_)) Then + Var patchlen = archfile.ReadInt() + archfile.position = archfile.position + 4 + Dim buffer As UByte Ptr = Callocate(max(patchlen, 1024)) + For j As Integer = 3 To patchlen + buffer[j - 3] = archfile.ReadByte() + Next + Return buffer + EndIf + archfile.position = oldpos + EndIf + Next + Return NULL +End Function + +Function HPA_GetInt(archfile As String, patchname As String, ident_ As TIdentData, id As Integer) As UInteger + If FileExists(archfile) = FALSE Then + Return 0 + EndIf + Var buffer = RM2kDev.HPA_GetMem(archfile, patchname, ident_) + If buffer = NULL Then Return 0 + Var ret = buffer[id] + DeAllocate(buffer) + Return ret +End Function + +Function HPA_Check(archfile_ As String, name_ As String, ident_ As TIdentData) As Boolean + Var archfile = FileObj.File(archfile_, FileObj.MODE_BINARY) + If archfile.ReadInt() <> *Cast(Integer Ptr, @HPA_SIGNATURE) Then Return NULL + For i As Integer = 1 To 4096 + Var startptr = archfile.ReadInt() + Var ident2_ = Type(archfile.ReadInt(), archfile.ReadInt()) + If ident2_.SizeOfCode = ident_.SizeOfCode And ident2_.SizeOfInitializedData = ident_.SizeOfInitializedData Then + Var oldpos = archfile.position + archfile.position = startptr + Var textlen = archfile.ReadByte() + Var name2_ = archfile.ReadString(textlen) + If Trim(UCase(name2_)) = Trim(UCase(name_)) Then + Return TRUE + EndIf + archfile.position = oldpos + EndIf + Next + Return FALSE +End Function + +Function HPA_Apply(archfile_ As String, target_ As String, name_ As String, ident_ As TIdentData, ignoreLength As Boolean = FALSE) As Boolean + Var tmp = Environ("Temp") & "\~hpa" & Hex(&h1000 + Rnd * &hEFFF) & ".tmp" + Var ret = HPA_Get(archfile_, tmp, name_, ident_) + If ret Then + ret And= HPD_Apply(tmp, target_, ignoreLength) + Kill(tmp) + EndIf + Return ret +End Function \ No newline at end of file diff --git a/patcher/rsrc.bi b/patcher/rsrc.bi new file mode 100644 index 0000000..e67b2a2 --- /dev/null +++ b/patcher/rsrc.bi @@ -0,0 +1,7 @@ +#define MANIFEST 24 +#define IDI_MAINICON 100 +#define IDR_HPD 101 +#define IDR_EXE 102 +#define IDR_DLL 103 +#define IDR_VERSION1 1 +#define IDR_XPMANIFEST1 1 diff --git a/patcher/useful/file_obj_standalone.bi b/patcher/useful/file_obj_standalone.bi new file mode 100644 index 0000000..a14a249 --- /dev/null +++ b/patcher/useful/file_obj_standalone.bi @@ -0,0 +1,309 @@ +/' + +Copyright (C) 2006-2017, David "Cherry" Trapp +All rights reserved. + +1. Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the conditions laid out in the + following paragraphs are met. +2. Redistributions of source code (if available) must retain the above + copyright notice, this list of conditions and the following disclaimer. +3. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3.1. In case this software is redistributed in binary form inside of a + executable or library file belonging to Third Parties and/or + including modifications done by Third Parties (or done by the Author + in Third Parties' names), any license restrictions imposed by the + Third Parties which disallow modification and/or redistribution remain + valid and have to be adhered, overriding the rights described in + paragraph 1 of this license. This does not give the Third Parties + the right to claim ownership of those parts of the software which + were developed by the Author, nor does it affect the remaining + parts of this license. +4. All advertising materials by Third Parties mentioning features or use + of this software must display the following acknowledgement (unless + agreed otherwise through written notice): + This product includes software developed by David "Cherry" Trapp. + +DISCLAIMER: +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +'/ + +Namespace FileObj + Enum FileMode + MODE_NONE + MODE_OUTPUT + MODE_INPUT + MODE_APPEND + MODE_RANDOM + MODE_BINARY + End Enum + + Type File + handle As Integer + filename As String + mode As FileMode + valid As Boolean + fieldlen As Integer + Declare Constructor (filename As String, mode As FileMode, fieldlen As Integer = 1) + Declare Destructor () + Declare Function WriteLine(text As String, newline As Boolean = TRUE) As Integer + Declare Function ReadLine() As String + Declare Function EndReached() As Boolean + Declare Function WriteByte(value As UByte, position_ As LongInt = -1) As Integer + Declare Function ReadByte(position_ As LongInt = -1) As UByte + Declare Function WriteWord(value As UShort, position_ As LongInt = -1) As Integer + Declare Function ReadWord(position_ As LongInt = -1) As UShort + Declare Function WriteInt(value As Integer, position_ As LongInt = -1) As Integer + Declare Function ReadInt(position_ As LongInt = -1) As Integer + Declare Function WriteString(value As String, position_ As LongInt = -1) As Integer + Declare Function ReadString(length_ As UInteger, position_ As LongInt = -1) As String + Declare Function WriteStringAuto(value As String, position_ As LongInt = -1) As Integer + Declare Function ReadStringAuto(position_ As LongInt = -1) As String + Declare Property position() As LongInt + Declare Property position(newpos As LongInt) + Declare Function Length() As LongInt + Declare Function Save() As Integer + Declare Function CloseF() As Integer + End Type + + Type Stream + stream As String + position__ As LongInt + filename As String + Declare Constructor (filename As String, loadfromfile As Boolean = FALSE) + Declare Constructor () + Declare Function ReadLine() As String + Declare Function EndReached() As Boolean + Declare Property position() As LongInt + Declare Property position(newpos As LongInt) + Declare Function Length() As LongInt + Declare Function Save(filename As String) As Integer + Declare Function Load(filename As String) As Integer + End Type + + Constructor File(filename As String, mode As FileMode, fieldlen As Integer = 1) + This.valid = FALSE + This.handle = FreeFile + If This.handle = 0 Then Return + Select Case mode + Case MODE_OUTPUT + Open filename For Output As #(This.handle) + Case MODE_INPUT + Open filename For Input As #(This.handle) + Case MODE_APPEND + Open filename For Append As #(This.handle) + Case MODE_RANDOM + Open filename For Random As #(This.handle) Len = fieldlen + Case MODE_BINARY + Open filename For Binary As #(This.handle) + Case Else + Return + End Select + If Err = NULL Then This.valid = TRUE Else Return + This.filename = filename + This.mode = mode + This.fieldlen = fieldlen + End Constructor + + Destructor File() + This.CloseF() + End Destructor + + Function File.WriteLine(text As String, newline As Boolean = TRUE) As Integer + If This.valid = FALSE Then Return -1 + If newline Then Print #(This.handle), text Else Print #(This.handle), text; + Return Err + End Function + + Function File.ReadLine() As String + If This.valid = FALSE Then Return "" + Dim text As String + Line Input #(This.handle), text + Return text + End Function + + Function File.EndReached() As Boolean + If This.valid = FALSE Then Return Cast(Boolean, -1) + Return Eof(This.handle) + End Function + + Function File.WriteByte(value As UByte, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadByte(position_ As LongInt = -1) As UByte + If This.valid = FALSE Then Return 0 + Dim value As UByte + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteWord(value As UShort, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadWord(position_ As LongInt = -1) As UShort + If This.valid = FALSE Then Return 0 + Dim value As UShort + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteInt(value As Integer, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + If position_ = -1 Then Put #(This.handle), , value Else Put #(This.handle), position_, value + Return Err + End Function + + Function File.ReadInt(position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return 0 + Dim value As Integer + If position_ = -1 Then Get #(This.handle), , value Else Get #(This.handle), position_, value + Return value + End Function + + Function File.WriteString(value As String, position_ As LongInt = -1) As Integer + If This.valid = FALSE Then Return -1 + For i As Integer = 0 To Len(value) - 1 + This.WriteByte(value[i], position_ + IIf(position_ = -1, 0, i)) + Next + Return Err + End Function + + Function File.ReadString(length_ As UInteger, position_ As LongInt = -1) As String + If This.valid = FALSE Then Return "" + Dim value As String = String(length_, Chr(0)) + For i As Integer = 0 To length_ - 1 + value[i] = This.ReadByte(position_ + IIf(position_ = -1, 0, i)) + Next + Return value + End Function + + Function File.WriteStringAuto(value As String, position_ As LongInt = -1) As Integer + Var ret = This.WriteInt(Len(value), position_) + If ret Then Return ret + If Len(value) <> 0 Then Return This.WriteString(value) + Return 0 + End Function + + Function File.ReadStringAuto(position_ As LongInt = -1) As String + Var length_ = This.ReadInt(position_) + If length_ > 0 Then Return This.ReadString(length_) + Return "" + End Function + + Property File.position() As LongInt + If This.valid = FALSE Then Return -1 + Return Seek(This.handle) + End Property + + Property File.position(newpos As LongInt) + If This.valid = FALSE Then Return + Seek #(This.handle), newpos + End Property + + Function File.Length() As LongInt + If This.valid = FALSE Then Return -1 + Return Lof(This.handle) + End Function + + Function File.Save() As Integer + If This.valid = FALSE Then Return -1 + Dim oldpos As LongInt = This.position + Close #(This.handle) + This.valid = FALSE + Select Case mode + Case MODE_OUTPUT, MODE_APPEND + Open This.filename For Append As #(This.handle) + Case MODE_INPUT + Open This.filename For Input As #(This.handle) + Case MODE_RANDOM + Open This.filename For Random As #(This.handle) Len = This.fieldlen + Case MODE_BINARY + Open This.filename For Binary As #(This.handle) + Case Else + Return -1 + End Select + If Err = NULL Then This.valid = TRUE Else Return Err + This.position = oldpos + End Function + + Function File.CloseF() As Integer + If This.valid = FALSE Then Return -1 + Close #(This.handle) + This.valid = FALSE + Return Err + End Function + + Constructor Stream(source As String, loadfromfile As Boolean = FALSE) + This.stream = "" + This.position__ = 1 + If loadfromfile = FALSE Then + This.stream = source + Return + EndIf + If FileExists(source) Then + This.Load(source) + EndIf + End Constructor + + Constructor Stream() + This.stream = "" + This.position__ = 1 + End Constructor + + Function Stream.ReadLine() As String + Var e = InStr(This.position, This.stream, !"\13\10") + If e = 0 Then e = This.Length + 1 + Var ret = Mid(This.stream, This.position, e - This.position) + This.position = e + 2 + Return ret + End Function + + Function Stream.EndReached() As Boolean + Return (This.position > This.Length) And TRUE + End Function + + Property Stream.position() As LongInt + Return This.position__ + End Property + + Property Stream.position(newpos As LongInt) + This.position__ = min(max(1ll, newpos), This.Length + 1) + End Property + + Function Stream.Length() As LongInt + Return Len(This.stream) + End Function + + Function Stream.Save(filename As String) As Integer + Var f = File(filename, MODE_BINARY) + If f.valid = FALSE Then Return -1 + f.WriteString(This.stream) + This.filename = filename + End Function + + Function Stream.Load(filename As String) As Integer + Var f = File(filename, MODE_BINARY) + If f.valid = FALSE Then Return -1 + This.stream = f.ReadString(f.Length()) + This.position__ = 1 + This.filename = filename + End Function +End Namespace + diff --git a/patcher/xpmanifest.xml b/patcher/xpmanifest.xml new file mode 100644 index 0000000..2eda1f2 --- /dev/null +++ b/patcher/xpmanifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/sdk/.gitignore b/sdk/.gitignore new file mode 100644 index 0000000..51d6776 --- /dev/null +++ b/sdk/.gitignore @@ -0,0 +1,3 @@ +lib/ +dynrpg.chm + diff --git a/sdk/include/DynRPG/Action.h b/sdk/include/DynRPG/Action.h new file mode 100644 index 0000000..e7b3c2f --- /dev/null +++ b/sdk/include/DynRPG/Action.h @@ -0,0 +1,67 @@ +namespace RPG { + //! Possible values for the RPG::Action::kind member + enum ActionKind { + AK_BASIC, //!< Basic action (attack, defense, escape, etc. - see RPG::BasicAction) + AK_SKILL, //!< Use a skill + AK_TRANSFORM, //!< Transform into another monster (do not use for actors) + AK_ITEM, //!< Use an item (do not use for monsters) + AK_NONE //!< No action (last action was already executed) + }; + + //! One-byte version of RPG::ActionKind + typedef unsigned char ActionKind_T; + + //! Possible values for the RPG::Action::basicActionId member + enum BasicAction { + BA_ATTACK, //!< Attack + BA_DOUBLE_ATTACK, //!< Double attack + BA_DEFEND, //!< Defend + BA_OBSERVE, //!< Observe battle + BA_CHARGE, //!< Charge up + BA_SELF_DESTRUCT, //!< Self-destruct + BA_ESCAPE, //!< Escape (will always succeed) + BA_NONE, //!< No action + BA_CHANGE_ROW //!< Change row (has no visible effects if used by monsters) + }; + + //! One-byte version of RPG::BasicAction + typedef unsigned char BasicAction_T; + + //! Possible values for the RPG::Action::target member + enum Target { + TARGET_NONE, //!< No target (the sounds of the battle animation will still be audible) + TARGET_ACTOR, //!< Target is an actor, specified in the RPG::Action::targetId member + TARGET_ALL_ACTORS, //!< Target are all actors at once + TARGET_MONSTER, //!< Target is a monster, specified in the RPG::Action::targetId member + TARGET_ALL_MONSTERS //!< Target are all mosnters at once + }; + + //! One-byte version of RPG::Target + typedef unsigned char Target_T; + + /*! \brief %Action of a battler (normal attack, skill, escape, etc.), including target + + This class is used to describe the action an actor or monster does in battle. + \note The action of a battler is always tied to the battler itself. + \sa RPG::Battler + \sa RPG::ActionKind + \sa RPG::BasicAction + \sa RPG::Target + */ + class Action { // TLcfgUnitActItem + public: + void **vTable; + ActionKind_T kind; //!< Kind of the action (see RPG::ActionKind) + BasicAction_T basicActionId; //!< If \c kind is RPG::AK_BASIC: Kind of the basic action (see RPG::BasicAction) + char _unknown_6; // Was "userData1" earlier + bool retrying; //!< \c true if the last try to execute the action failed + int skillId; //!< If \c kind is RPG::AK_SKILL: Database ID of the skill + int monsterId; //!< If \c kind is RPG::AK_TRANSFORM: Database ID of the monster to transform into + int itemId; //!< If \c kind is RPG::AK_ITEM: Database ID of the item + int _unknown_14; + int _unknown_18; + int _unknown_1C; + Target_T target; //!< %Target of the action (see RPG::Target) + int targetId; //!< If \c target is RPG::TARGET_ACTOR or RPG::TARGET_MONSTER: Zero-based party member index of the target + }; +} diff --git a/sdk/include/DynRPG/Actor.h b/sdk/include/DynRPG/Actor.h new file mode 100644 index 0000000..99131a4 --- /dev/null +++ b/sdk/include/DynRPG/Actor.h @@ -0,0 +1,120 @@ +namespace RPG { + /*! \brief Used for the data of actors which can be changed in-game. + + \note Many things are only stored in this class if they were changed + and are now different from the default in the database, thus you + should use the getter methods to access these things.\n\n + The members ending with \c Diff are "offsets" which are added to the + default value (which is calculated from the current level, class and + equipment). + \sa RPG::actors + \sa RPG::DBActor + \sa RPG::dbActors + \sa RPG::Battler + */ + class Actor : public Battler { // TLcfgPlayerItem + public: + // sizeof(Battler) == 0xD8 + DStringPtr name; //!< Name ("\x01" means database default) + DStringPtr degree; //!< Degree ("\x01" means database default) + DStringPtr charsetFilename; //!< Filename of the charset (empty means database default) + int charsetId; //!< ID of the sprite in the charset file (only valid if \c charsetFilename isn't empty) + int charsetTransparency; //!< Transparency of the charset (\c 0 to \c 8, only valid if \c charsetFilename isn't empty) + DStringPtr facesetFilename; //!< Filename of the faceset (empty means database default) + int facesetId; //!< ID of the sprite in the faceset file (only valid if \c facesetFilename isn't empty) + int level; //!< Current level + int exp; //!< Current experience points + int maxHpDiff; //!< Difference from the default maximal HP + int maxMpDiff; //!< Difference from the default maximal MP + int attackDiff; //!< Difference from the default attack value + int defenseDiff; //!< Difference from the default defense value + int intelligenceDiff; //!< Difference from the default intelligence value + int agilityDiff; //!< Difference from the default agility value + int _unknown_114; + int _unknown_118; + short weaponId; //!< Database ID of the current weapon (zero for none) + short shieldId; //!< Database ID of the current shield (or second-hand weapon, zero for none) + short armorId; //!< Database ID of the current armor (zero for none) + short helmetId; //!< Database ID of the current helmet (zero for none) + short accessoryId; //!< Database ID of the current accessory (zero for none) + bool twoWeapons; //!< Can the actor hold two weapons? + bool lockEquipemnt; //!< Is the actor's equipment unchangable by the player? + bool autoBattle; //!< Is the battle AI activated for this actor? + bool mightyGuard; //!< Is the "mighty guard" mode activated for this actor? + int battleGraphicId; //!< Database ID of the battle graphic (zero for database default) + bool customBattleCommands; //!< \c true if the \c battleCommands member is valid, otherwise the database default should be used + int battleCommands[7]; //!< The current battle commands for this actor (\c 0 and \c -1 both mean "no command at this position") + + /*! \brief Returns the current degree + \return Current degree + */ + std::string getDegree(); + + /*! \brief Returns the current charset filename + \return Current charset filename + \sa getCharsetId + \sa getCharsetTransparency + */ + std::string getCharsetFilename(); + + /*! \brief Returns the current charset ID + \return ID of sprite in charsets + \sa getCharsetFilename + \sa getCharsetTransparency + */ + int getCharsetId(); + + /*! \brief Returns the current charset transparency + \return Transparency value (see RPG::Character::transparency + documentation) + \sa getCharsetFilename + \sa getCharsetId + */ + int getCharsetTransparency(); + + /*! \brief Returns the current faceset filename + \return Current faceset filename + \sa getFacesetId + */ + std::string getFacesetFilename(); + + /*! \brief Returns the current faceset ID + \return ID of sprite in faceset + \sa getFacesetFilename + */ + int getFacesetId(); + + /*! \brief Returns the current battle graphic ID + \return Database ID of the current battle graphic + */ + int getBattleGraphicId(); + + /*! \brief Returns the current battle command on a certain position + \param index Zero-based index of the available commands for + this actor (\c 0 to \c 6) + \return Database ID of the battle command on the given position + or either \c 0 or \c -1 if there is none + */ + int getBattleCommand(int index); + + /*! \brief Returns a certain party member + \param index Zero-based party member index (\c 0 to \c 3) + \return Pointer to the RPG::Actor object of the particular actor + */ + static RPG::Actor *partyMember(int index); + }; + + /*! \ingroup game_objects + \brief Array of actors from the database, used for properties which + can change in-game. + + Use the database ID as index for accessing an actor. + + Example: + \code +int zackHp = RPG::actors[1]->hp; + \endcode + \sa RPG::dbActors + */ + static RPG::NamedCatalogPtr &actors = (**reinterpret_cast **>(0x4CDDC8)); +} diff --git a/sdk/include/DynRPG/ArrayBaseOne.h b/sdk/include/DynRPG/ArrayBaseOne.h new file mode 100644 index 0000000..f0cdcce --- /dev/null +++ b/sdk/include/DynRPG/ArrayBaseOne.h @@ -0,0 +1,21 @@ +namespace RPG { + /*! \brief Helper class for arrays with base one + + This class template is used for arrays in classes with should have one + as base (unlike normal arrays with base zero). + */ + template + class ArrayBaseOne { + public: + /*! \brief Simple indexing operator for accessing array elements + \param index One-based index + \return Value of the element + */ + inline T &operator [](int index) { + return array[index - 1]; + } + + private: + T array[size]; //!< Original array + }; +} diff --git a/sdk/include/DynRPG/BattleSettings.h b/sdk/include/DynRPG/BattleSettings.h new file mode 100644 index 0000000..9e7febb --- /dev/null +++ b/sdk/include/DynRPG/BattleSettings.h @@ -0,0 +1,35 @@ +namespace RPG { + //! Possible values for RPG::BattleSettings::layout + enum BattleLayout { + BL_TRADITIONAL, //!< "Traditional" layout + BL_ALTERNATIVE, //!< "Alternative" layout + BL_GAUGE //!< "Gauge" layout + }; + + //! One-byte version of RPG::BattleLayout + typedef unsigned char BattleLayout_T; + + /*! \brief Used for battle settings (layout, etc.) + \sa RPG::battleSettings + \sa RPG::System + */ + class BattleSettings { + public: + void **vTable; + int _unknown_4; + BattleLayout_T layout; //!< Battle layout + int _unknown_C; + bool largeWindows; //!< Are the "large windows" active? + bool _unknown_11; + bool _unknown_12; + bool _unknown_13; + bool transparentWindows; //!< Are transparent windows active? (This affects the whole game even though the %RPG Maker guys have put it into the battle settings.) + }; + + /*! \ingroup game_objects + \brief Battle settings + + Please mind that this object is not saved and loaded automatically, but only initialized once at startup. + */ + static RPG::BattleSettings *&battleSettings = (**reinterpret_cast(0x4CDD60)); +} diff --git a/sdk/include/DynRPG/Battler.h b/sdk/include/DynRPG/Battler.h new file mode 100644 index 0000000..2d3d590 --- /dev/null +++ b/sdk/include/DynRPG/Battler.h @@ -0,0 +1,236 @@ +namespace RPG { + //! Possible values used for the battle row in RPG::Battler + enum Row { + ROW_FRONT, //!< Front row + ROW_BACK //!< Back row + }; + + //! \cond + enum { + DPT_START = 0x83 + }; + //! \endcond + + //! \brief Possible values for RPG::Battler::actionStatus + enum ActionStatus { + AS_IDLE, //!< No action is active + AS_WAITING, //!< Info window is displayed or action is otherwise waiting + AS_FINAL_PHASE //!< Final phase, damage is displayed, etc. + }; + + /*! \brief Used for entities participating in battle, i.e. actors and + monsters + + Even though this is the base class of both RPG::Actor and RPG::Monster, + some members only apply to one of them. + \sa RPG::Row + \sa RPG::ActionStatus + \sa RPG::Actor + \sa RPG::Monster + */ + class Battler { // TLcfgUnitItem + public: + void **vTable; + /*! \brief One-based ID of the battler + + For actors this value is the database ID, for monsters it is the party member ID plus one (e.g. RPG::monsters[3]->id should always be \c 4). + + If you want to get the database ID of a monster, you have to use RPG::Monster::databaseId. + */ + int id; + int _unknown_8; + bool notHidden; //!< \c false if the battler is currently hidden (but not dead) + Action *action; //!< Current action of the battler + int hp; //!< Current HP + int mp; //!< Current MP + int _unknown_1C; + int _unknown_20; + int _unknown_24; + int _unknown_28; + DArray _unknown_2C; + /*! \brief Turns elapsed in a certain condition (see details) + + This is an array which has as much possible members as there + are conditions in the database. The values tell you how many + turns the battler has taken while being affected by a + certain conditions. If a value is zero, the particular + condition does not affect this battler. + + For example, if conditions[2] were 4, this battler + would have been infected by poison (by default, condition \#2 + is poison) for 4 turns. If it were zero, the battler would not + be poisoned at the moment. + + \warning If you remove all conditions from a hero in battle, + make sure that the \c animationId is not \c 9, otherwise the + RPG Maker will try to show the animation for condition \#0 + which doesn't exist. This would result in an error stating + that an "Event script referenced a condition that does not + exist". Use a failsafe like this (\c 0 stands for the idle + animation): + \code +if(battler->animationId == 9) battler->animationId = 0; + \endcode + */ + DArray conditions; + int _unknown_3C; + int _unknown_40; + /*! \brief Current value of the ATB bar (\c 0 to \c 300000 - see details) + + Internally, the ATB bar can have a value between \c 0 and + \c 300000 where \c 0 means empty and \c 300000 means full. + If you set a battler's ATB value to a value greater than or + equal to \c 300000, this will trigger his next action (in case + of a monster) or open the action window (in case of an actor). + */ + int atbValue; + bool mirrored; //!< \c true if the battler's image is mirrored + int frameCounter; //!< Internally used + /*! \brief ID of the battle graphic pose (see details) + + This member specifies which battle graphic pose is displayed. + Look into the "Animations 2" tab of the database to find out + what the different values mean (e.g. \c 6 means "Taking + damage"). + \note This member has no meaning to monsters. + */ + int animationId; + int x; //!< Current X coordinate (centered) + int y; //!< Current Y coordinate (centered) + int originalX; //!< Original X coordinate (used when an actor moves to attack) + int originalY; //!< Original Y coordinate (used when an actor moves to attack) + int _unknown_64; + int _unknown_68; + int _unknown_6C; + Row rowAlt; //!< Internally used, I do not understand the difference from \c row yet + Row row; //!< Current row (no visible effect on monsters) + int damagePopupTimer; //!< Frames left until damage popup has finished (zero: no damage popup active) + int _unknown_7C; + int flashR; //!< Red value for flashing the battler (\c 0 to \c 31) + int flashG; //!< Green value for flashing the battler (\c 0 to \c 31) + int flashB; //!< Blue value for flashing the battler (\c 0 to \c 31) + int _unknown_8C; + /*! \brief Intensity for flashing the battler (\c 0 to \c 31 - + will decrease until flashing is done) + + \note Values over 31 will cause the palette to go crazy. Of + course you can also use this as an intentional effect. + */ + double flashIntensity; + int flashTimer; //!< Frames left until flashing the battler finished (zero: no flashing active) + int _unknown_9C; + int _unknown_A0; + int _unknown_A4; + int _unknown_A8; + int _unknown_AC; + int turnsTaken; //!< Turns taken by this battler + bool longAction; //!< \c true if the last action takes longer (info window needed) - I am not completely sure about that + ActionStatus actionStatus; //!< Status of the current action + int _unknown_BC; + int _unknown_C0; + /*! \brief Conditions which will be displayed in the info window (see details) + + At target selection, there will be an info window displayed if + the target is affected by a condition. The info has five + columns for condition names. This array contains the database + IDs of the conditions which are displayed in this window. + The content of this array will be reset on several occasions. + You can change this array in your \c onDrawBattleStatusWindow + handler. + */ + int displayedConditions[5]; + + /*! \brief Returns the name of the actor or monster + \return The name + */ + std::string getName(); + + /*! \brief Returns the maximal HP + \return Maximal HP value + */ + int getMaxHp(); + + /*! \brief Returns the maximal MP + \return Maximal MP value + */ + int getMaxMp(); + + /*! \brief Returns the attack value + \return Attack value + */ + int getAttack(); + + /*! \brief Returns the defense value + \return Defense value + */ + int getDefense(); + + /*! \brief Returns the intelligence value + \return Intelligence value + */ + int getIntelligence(); + + /*! \brief Returns the agility value + \return Agility value + */ + int getAgility(); + + /*! \brief Sets the current row + \param newRow New row + \note This function has no visible effect on monsters + */ + void setRow(Row newRow); + + /*! \brief Shows a damage popup with a number + + This function will make a number pop up on a battler. + \param number The number to show + \param color Color to use (\c 0 to \c 19) + \sa damagePopup(std::string) + */ + void damagePopup(int number, int color); + + /*! \brief Shows a damage popup with a small text + + This function will make a small text pop up on a battler. + \param text Text to show + \note It is not possible to show string popups with a color + other than \c 0. + \sa damagePopup(int, int) + */ + void damagePopup(std::string text); + + /*! \brief Checks whether the battler is a monster or an actor + \return \c true if the battler is a monster, \c false if it is + an actor + */ + bool isMonster(); + + /*! \brief Flashes a battler in a certain color + \param r Red value (\c 0 to \c 31) + \param g Green value (\c 0 to \c 31) + \param b Blue value (\c 0 to \c 31) + \param intensity Intensity of the flash (\c 0 to \c 33.5) + \param duration Duration in frames + */ + void flash(int r, int g, int b, int intensity, int duration); + + /*! \brief Executes the action of a battler (highly experimental!) + + This function can be used to execute an action. You need to set + the content of the \c action object before. + \param skipPluginHandlers If \c true, no \ref onDoBattlerAction + and \ref onBattlerActionDone handlers will be called for this + action. + \return \c true if the action was successfully executed, + otherwise \c false (in this case try again next frame) + \warning This is a highly experimental function! During + testing, it has repeatedly caused strange errors and crashes + when executed under the wrong conditions or to the wrong time! + It's probably not safe to use it for anything else than + experiments, to be honest. + \sa RPG::Action + */ + bool executeAction(bool skipPluginHandlers = false); + }; +} diff --git a/sdk/include/DynRPG/Canvas.h b/sdk/include/DynRPG/Canvas.h new file mode 100644 index 0000000..f6889e3 --- /dev/null +++ b/sdk/include/DynRPG/Canvas.h @@ -0,0 +1,207 @@ +namespace RPG { + /*! \brief %Image buffer with 16 bit color depth, used as canvas for multiple 8-bit images + \sa RPG::Screen::canvas + \sa RPG::Image + */ + class Canvas { + public: + void **vTable; + DBitmap *bitmap; //!< Underlying 16-bit bitmap + /*! \brief Number of bytes you have to add to a pixel address to + get the address of the pixel in the same column of the next + pixel row (see details) + + Normally, this number is negative because bitmaps are stored + from bottom to top. + */ + int lineSize; + /*! \brief Brightness of the screen (see details) + + Supported values are from \c 0 (completely black) to \c 200 + (completely white). \c 100 is the normal value. This value is + changed during "fading" screen transitions. + + \note Values higher than \c 200 will cause the colors to go + crazy. Of course, this can also be used as an intentional + effect, for example the value \c 204 will only use the colors + blue, white and black. + */ + int brightness; + + /*! \brief Returns a reference to a pixel + \param x X coordinate + \param y Y coordinate + \return Reference to the pixel + */ + unsigned short &pixel(int x, int y); + + /*! \brief Returns a pointer to a row of pixel data + \param y Y coordinate + \return Pointer to the first pixel of the row + \note If you loop through rows, it is way faster to use + getScanline(0) once and then always add \c lineSize to + get to the next row instead of calling \c getScanline for every + row. + */ + unsigned short *getScanline(int y); + + //! Returns the width of the bitmap + int width(); + + //! Returns the height of the bitmap + int height(); + + /*! \brief Draws an RPG::Image or a part of it onto the canvas + + This function will draw a certain part of an RPG::Image onto + the canvas. You can omit the last four parameters to draw the + whole image. + + The image's brightness will automatically be adjusted to match + the canvas \c brightness. To avoid this, you can save the + canvas \c brightness, set it to 100, draw the image and then + restore the original \c brightness of the canvas. + \param x X coordinate to draw to (upper-left origin) + \param y Y coordinate to draw to (upper-left origin) + \param image %Image to draw + \param srcX X coordinate of the area to use from the source + image + \param srcY Y coordinate of the area to use from the source + image + \param srcWidth Width of the area to draw (defaults to the + whole image) + \param srcHeight Height of the area to draw (defaults to the + whole image) + \warning This function is quite slow, especially if you draw + an image which uses a mask color or an \c alpha value different + from \c 255. Please also see the \ref optimization guidelines! + \sa RPG::Image::draw + \sa RPG::Canvas::drawStretched + \sa RPG::Canvas::drawCenteredZoomed + */ + void draw(int x, int y, RPG::Image *image, int srcX = 0, int srcY = 0, int srcWidth = -1, int srcHeight = -1); + + /*! \brief Draws an RPG::Image or a part of it onto the canvas, + stretched to a certain rectangle + + This function will draw a certain part of an RPG::Image onto + the canvas. You can omit the last four parameters to draw the + whole image. The image (or the part of it) will be stretched + so it fits into the given rectangle + + The image's brightness will automatically be adjusted to match + the canvas \c brightness. To avoid this, you can save the + canvas \c brightness, set it to 100, draw the image and then + restore the original \c brightness of the canvas. + \param x X coordinate to draw to (upper-left origin) + \param y Y coordinate to draw to (upper-left origin) + \param width Target width of the image after stretching + \param height Target height of the image after stretching + \param image %Image to draw + \param srcX X coordinate of the area to use from the source + image + \param srcY Y coordinate of the area to use from the source + image + \param srcWidth Width of the area to draw (defaults to the + whole image) + \param srcHeight Height of the area to draw (defaults to the + whole image) + \warning This function is quite slow, especially if you draw + an image which uses a mask color or an \c alpha value different + from \c 255. Please also see the \ref optimization guidelines! + \sa RPG::Canvas::drawCenteredZoomed + \sa RPG::Canvas::draw + */ + void drawStretched(int x, int y, int width, int height, RPG::Image *image, int srcX = 0, int srcY = 0, int srcWidth = -1, int srcHeight = -1); + + /*! \brief Draws an RPG::Image or a part of it onto the canvas, + centered to a certain point, and zooms it as specified + + This function will draw a certain part of an RPG::Image onto + the canvas. You can omit the last four parameters to draw the + whole image. You can specify horizontal and vertical + magnification, and the image's center. + + The image's brightness will automatically be adjusted to match + the canvas \c brightness. To avoid this, you can save the + canvas \c brightness, set it to 100, draw the image and then + restore the original \c brightness of the canvas. + \param x X coordinate to draw to (center origin) + \param y Y coordinate to draw to (center origin) + \param zoomX Horizontal magnification (\c 1.0 is normal) + \param zoomY Vertical magnification (\c 1.0 is normal) + \param image %Image to draw + \param srcX X coordinate of the area to use from the source + image + \param srcY Y coordinate of the area to use from the source + image + \param srcWidth Width of the area to draw (defaults to the + whole image) + \param srcHeight Height of the area to draw (defaults to the + whole image) + \warning This function is quite slow, especially if you draw + an image which uses a mask color or an \c alpha value different + from \c 255 or \c zoomX and/or \c zoomY values different from + \c 1.0. Please also see the \ref optimization guidelines! + \sa RPG::Canvas::drawStretched + \sa RPG::Canvas::draw + */ + void drawCenteredZoomed(int x, int y, double zoomX, double zoomY, RPG::Image *image, int srcX = 0, int srcY = 0, int srcWidth = -1, int srcHeight = -1); + + /*! \brief Converts a 16-bit pixel value to 24 bit + \param pixel16 16-bit pixel value (\c RRRRRGGGGGGBBBBB) + \return 24-bit pixel value (\c + 00000000BBBBBBBBGGGGGGGGRRRRRRRR) + */ + static inline unsigned int convert16To24Bit(unsigned short pixel16) { + unsigned int ret = (unsigned int)(pixel16 & 0xF800) >> 8; + ret |= (unsigned int)(pixel16 & 0x7E0) << 5; + ret |= (unsigned int)(pixel16 & 0x3F) << 19; + return ret; + } + + /*! \brief Converts a 16-bit pixel value to 32 bit with 100% + opacity + \param pixel16 16-bit pixel value (\c RRRRRGGGGGGBBBBB) + \return 32-bit pixel value (\c + 11111111BBBBBBBBGGGGGGGGRRRRRRRR) + */ + static inline unsigned int convert16To32Bit(unsigned short pixel16) { + return convert16To24Bit(pixel16) | 0xFF000000; + } + + /*! \brief Converts a 24-bit pixel value to 16 bit + \param pixel24 24-bit pixel value (\c + 00000000BBBBBBBBGGGGGGGGRRRRRRRR) + \return 16-bit pixel value (\c RRRRRGGGGGGBBBBB) + */ + static inline unsigned short convert24To16Bit(unsigned int pixel24) { + unsigned short ret = (unsigned short)(pixel24 & 0xF8) << 8; + ret |= (unsigned int)(pixel24 & 0xFC00) >> 5; + ret |= (unsigned int)(pixel24 & 0xF80000) >> 19; + return ret; + } + + /*! \brief Converts a 32-bit pixel value to 16 bit by combining it + with an existing pixel + + The result is the 16-bit pixel value which is the result of + drawing the \c pixel32 "on top" of the \c prevPixel16. + \param pixel32 32-bit pixel value (\c AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR) + \param prevPixel16 16-bit pixel value to use as basis for the alpha channel + \return 16-bit pixel value (\c RRRRRGGGGGGBBBBB) + */ + static inline unsigned short convert32To16Bit(unsigned int pixel32, unsigned short prevPixel16) { + // 16 = RRRRRGGGGGGBBBBB + // 32 = AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR + unsigned char alpha = (unsigned char)(pixel32 >> 24); + if(!alpha) return convert24To16Bit(pixel32); + #define c(v1, v2) ((v1) * (alpha + 1) + (v2) * (256 - alpha)) + unsigned short ret = (unsigned short)(c((unsigned char)(pixel32), (unsigned char)(prevPixel16 << 3))) >> 3; + ret |= (unsigned short)(c((unsigned char)(pixel32 >> 8), (unsigned char)((prevPixel16 & 0x7E0) >> 3)) & 0xFC) << 3; + ret |= (unsigned short)(c((unsigned char)(pixel32 >> 16), (unsigned char)((prevPixel16 & 0xF800) >> 8)) & 0xF8) << 8; + #undef c + return ret; + } + }; +} diff --git a/sdk/include/DynRPG/Catalog.h b/sdk/include/DynRPG/Catalog.h new file mode 100644 index 0000000..1a87e9f --- /dev/null +++ b/sdk/include/DynRPG/Catalog.h @@ -0,0 +1,127 @@ +namespace RPG { + /*! \brief Wrapper class for RPG::DList which doesn't crash if the index + is out of bounds + \note Please do not ask me why this class is there. I didn't invent it. + \warning This class has more members than the one which is documented + (the others are used internally), so sizeof(RPG::Catalog\) + is not equal to sizeof(RPG::DList\ *)! + \sa RPG::CatalogPtr + \sa RPG::NamedCatalog + \sa RPG::NamedCatalogPtr + \sa RPG::DList + */ + template + class Catalog { + public: + void **vTable; + //! \cond + void **itemVTable; + //! \endcond + DListPtr list; //!< Pointer to the actual RPG::DList + + //! Array access operator + T operator[](int index) { + return get(index); + } + + //! Array access method + T get(int index) { + return list.get(index); + } + + //! Returns the number of items in the list + int count() { + return list.list->count; + } + }; + + /*! \brief Wrapper class for RPG::Catalog pointers (syntactic sugar) + + Allows you to write someCatalogPointer[i] instead of + (*someCatalogPointer)[i]. + \note The size of this class equals to + sizeof(Catalog\ *). + \sa RPG::Catalog + \sa RPG::NamedCatalogPtr + */ + template + class CatalogPtr { + public: + Catalog *ptr; //!< Pointer to the actual RPG::Catalog + + //! Array access operator + T operator[](int index) { + return ptr->get(index); + } + + //! Array access method + T get(int index) { + return ptr->get(index); + } + + //! Returns the number of items in the list + int count() { + return ptr ? ptr->count() : 0; + } + }; + + /*! \brief Class inherited from RPG::Catalog in which elements with + non-consecutive IDs are stored without waste of memory (i.e. + events on a map) + + If you need to enumerate all items in an RPG::NamedCatalog, use + \code +for(int i = 0; i < myCatalog.count(); i++) { + SomeObjectType *item = myCatalog.list[i]; + // Processing here... +} + \endcode + If you have an RPG::NamedCatalogPtr, it works the same way. + \sa RPG::Catalog + \sa RPG::NamedCatalogPtr + */ + template + class NamedCatalog : public Catalog { + public: + //! Array access operator + T operator[](int index) { + return get(index); + } + + //! Array access method + T get(int index) { + T ret = NULL; + asm volatile("call *%%esi" : "=a" (ret), "=d" (_edx) : "S" (0x475740), "a" (this), "d" (index) : "ecx", "cc", "memory"); // GetFromList + return ret; + } + }; + + /*! \brief Wrapper class for RPG::NamedCatalog pointers (syntactic sugar) + + Allows you to write RPG::actors[1]->hp instead of + (*RPG::actors)[1]->hp, for example. + \note The size of this class equals to + sizeof(NamedCatalog\ *). + \sa RPG::NamedCatalog + */ + template + class NamedCatalogPtr { + public: + NamedCatalog *ptr; + + //! Array access operator + T operator[](int index) { + return ptr->get(index); + } + + //! Array access method + T get(int index) { + return ptr->get(index); + } + + //! Returns the number of items in the list (not the highest ID!) + int count() { + return ptr ? ptr->count() : 0; + } + }; +} diff --git a/sdk/include/DynRPG/Character.h b/sdk/include/DynRPG/Character.h new file mode 100644 index 0000000..2eb41fe --- /dev/null +++ b/sdk/include/DynRPG/Character.h @@ -0,0 +1,357 @@ +namespace RPG { + //! Possible values for RPG::Character::facing + enum Facing { + FACE_UP, //!< %Character looks up + FACE_RIGHT, //!< %Character looks to the right + FACE_DOWN, //!< %Character looks down + FACE_LEFT //!< %Character looks to the left + }; + + //! One-byte version of RPG::Facing_T + typedef unsigned char Facing_T; + + //! Possible values for RPG::Character::direction + enum Direction { + DIR_UP, //!< %Character moves down + DIR_RIGHT, //!< %Character moves to the right + DIR_DOWN, //!< %Character moves down + DIR_LEFT, //!< %Character moves to the left + DIR_UP_RIGHT, //!< %Character moves diagonally up-right + DIR_DOWN_RIGHT, //!< %Character moves diagonally down-right + DIR_DOWN_LEFT, //!< %Character moves diagonally down-left + DIR_UP_LEFT //!< %Character moves diagonally up-left + }; + + //! One-byte version of RPG::Direction + typedef unsigned char Direction_T; + + //! Possible values for RPG::Character::animationType + enum AnimationType { + ANI_NORMAL, //!< "Non-continuous" + ANI_STEPPING, //!< "Continuous" (always stepping) + ANI_FIXED_DIR_NORMAL, //!< "Non-continous", fixed direction + ANI_FIXED_DIR_STEPPING, //!< "Continuous", fixed direction + ANI_FIXED_GRAPHIC, //!< Fixed graphic (no stepping, fixed direction) + ANI_SPIN_AROUND //!< Spinning around + }; + + //! One-byte version of RPG::AnimationType + typedef unsigned char AnimationType_T; + + //! Possible values for RPG::Character::layer + enum Layer { + LAYER_BELOW_HERO, //!< Below hero + LAYER_SAME_LEVEL_AS_HERO, //!< Same level as hero + LAYER_ABOVE_HERO //!< Above hero + }; + + //! One-byte version of RPG::Layer + typedef unsigned char Layer_T; + + /*! \brief Used for movable entities on the map, i.e. events, the hero (and vehicles, but they are not supported yet) + \sa RPG::Event + \sa RPG::Map::events + \sa RPG::Hero + \sa RPG::hero + \sa RPG::Direction + \sa RPG::Facing + \sa RPG::Layer + \sa RPG::AnimationType + \sa RPG::MoveRoute + */ + class Character { + public: + void **vTable; + int id; //!< ID of the event (zero if not an ordinary event) + int _unknown_8; + bool enabled; //!< Is the event visible and enabled? + int mapId; //!< %Map ID (only relevant for vehicles which are not supported yet) + int x; //!< X coordinate (tiles) + int y; //!< Y coordinate (tiles) + Direction_T direction; //!< Direction for moving (see RPG::Direction) + Facing_T facing; //!< Direction for facing (see RPG::Facing) + /*! \brief Current step value (see details) + + Possible values: +
  • \c 0: Left
  • +
  • \c 1: Middle
  • +
  • \c 2: Right
  • +
  • \c 3: Middle
+ */ + int step; + int transparency; //!< Transparency value, between \c 0 (completely visible) to \c 8 (completely invisible) + /*! \brief Frames left until movement is completed (see details) + + This value is zero if the movement is completed. Otherwise it + means the frames left until it is completed. This value, + together with \ref direction, is used to calculate the current + screen coordinates. + */ + int movementFramesLeft; + int frequency; //!< Current movement frequency (\c 1 to \c 8) + int originalFrequency; //!< Original movement frequency (use for "Move event" commands with a frequency different from the current one) + Layer_T layer; //!< %Layer (below/same level as/above hero, see RPG::Layer) + bool forbidEventOverlap; //!< \c true if the event cannot move onto a tile occupied by another event + /*! \brief Animation type of the event (see details and RPG::AnimationType) + + This member is used for the animation type as defined in the + event editor. However, it does not control whether the facing + is locked or not, i.e. if you set it to RPG::ANI_FIXED_GRAPHIC, + the event may still not have locked facing. Thus, you should + use the \ref setAnimationType function which automatically sets + the \ref fixedDirection member to the correct value. + \sa setAnimationType + \sa RPG::AnimationType + */ + AnimationType_T animationType; + bool fixedDirection; //!< Is the facing direction (\ref facing) fixed? + int speed; //!< Current speed of the character (\c 1 to \c 6, see also \ref customExactSpeed) + MoveRoute *moveRoute; //!< Current move route (can also be set by "Move Event" commands) + bool moving; //!< Is the character currently moving? + /*! \brief Horizontal offset for drawing the event graphic (see details) + + The \ref offsetX and \ref offsetY members can be used to control + the screen coordinates on which the event is drawn. You specify + an offset value which will be added to the normal value. + + For example, you might set offsetX = 8 and + offsetY = -16 - and then the event will always be + drawn 8 pixels to the right and 16 pixels higher than it would + normally be. This way, you can do a finer movement and even + do a "fake" pixel movement. + + \note This is a special feature of the DynRPG patch. + */ + char offsetX; + char offsetY; //!< Vertical offset for drawing the event graphic (see \ref offsetX) + /*! \brief Custom exact speed (see details) + + You can the speed of a character in a finer way than the normal + six speed values provide. One speed unit means 3.75 pixels per + second (or 1/16 pixel per frame). For example + customExactSpeed = 20 will set the speed to 75 pixels + per second (1.25 pixels per frame). + + If you set \ref customExactSpeed to \c 0, the speed which is set + in \ref speed will be used. + \note This is a special feature of the DynRPG patch. + */ + char customExactSpeed; + int _unknown_44; + int _unknown_48; + bool phasing; //!< Is the "phasing mode" on? + int stepFrameCounter; //!< Internally used, for stepping + int stepTimer; //!< Internally used, for stepping (\c -1 if a fixed step is used, see \ref setFixedStep) + int frequencyTimer; //!< Internall used, for movement frequency + int _unknown_5C; + int _unknown_60; + int _unknown_64; + int _unknown_68; + DStringPtr charsetFilename; //!< Filename of the current charset + int charsetId; //!< ID of the current charset + int _unknown_74; + int _unknown_78; + int _unknown_7C; + int _unknown_80; + int _unknown_84; + int _unknown_88; + int _unknown_8C; + int _unknown_90; + + int getScreenX(); //!< Returns the current X screen coordinate + int getScreenY(); //!< Returns the current Y screen coordinate + + /*! \brief Sets a fixed step + + You can use this function to set a fixed step position and keep + it until \ref setNormalStep is called. + \param newStep New step position, for possible values see + \ref step + \note This is a special feature of the DynRPG Patch. + \sa setNormalStep + \sa step + */ + void setFixedStep(int newStep); + + /*! \brief Removes a fixed step position and goes back to normal + \sa setFixedStep + */ + void setNormalStep(); + + /*! \brief Sets the animation type + + This function sets the \ref animationType and \ref fixedDirection + members to the correct values. + \param type New animation type + \sa animationType + \sa RPG::AnimationType + */ + void setAnimationType(RPG::AnimationType type); + + /*! \brief Checks whether a certain move is possible + + This function if the character will be able to complete a + certain move, taking event layer, \ref forbidEventOverlap, other + blocking events and the tileset attributes into account. + \param fromX X coordinate (tiles) of the source position + \param fromY Y coordinate (tiles) of the source position + \param toX X coordinate (tiles) of the destination position + \param toY Y coordinate (tiles) of the destination position + \return \c true if the move is possible, otherwise \c false + \warning This is an experimental function. + */ + bool isMovePossible(int fromX, int fromY, int toX, int toY); + + /*! \brief Returns the name of the character + + This function returns the event name which was set in the event + editor or the name of the first actor in the party in case the + character is the hero. + \return The name of the character (event or hero name) + */ + std::string getName(); + + /*! \brief Moves a character + + This function will move a character (event or hero) the same + way the "Move event" command does. + + The \c data parameter is a pointer to a \c char array containing + the encoded data. You can find a list of possible movement + commands at the RPG::MoveType documentation. For most + movement commands, you will just use one byte containing the + move type. + + Example: + \code +char moves[] = {RPG::MT_MOVE_UP, RPG::MT_MOVE_RIGHT, RPG::MT_MOVE_RIGHT, RPG::MT_TURN_RANDOMLY, RPG::MT_MOVE_FORWARD}; +RPG::hero->move(moves, sizeof(moves)); + \endcode + + There are, however, a few commands which take parameters: + RPG::MT_SWITCH_ON, RPG::MT_SWITCH_OFF, RPG::MT_CHANGE_GRAPHIC + and RPG::MT_PLAY_SE. If you want to use these commands, you + better use a \c std::string. You need to add the parameters to + the string right after the command byte, using the functions + \ref RPG::encode(int) for numerical parameters and + \ref RPG::encode(std::string) for string parameters. + + Example: + \code +std::string moves = ""; +moves += (char)RPG::MT_MOVE_UP; +moves += (char)RPG::MT_FACE_DOWN; +moves += (char)RPG::MT_PLAY_SE; +moves += RPG::encode("chicken"); // filename +moves += RPG::encode(100); // volume +moves += RPG::encode(100); // speed +moves += RPG::encode(50); // pan +moves += (char)RPG::MT_WAIT; +moves += (char)RPG::MT_TURN_AROUND; +RPG::hero->move(moves.c_str(), moves.length()); + \endcode + \param data Pointer to the movement data + \param length Length of the movement data + \param repeatPattern \c true if the pattern should be repeated + until \ref stop is called + \param ignoreImpossible Should impossible movements be ignored? + \param frequency Frequency of the movement + \note RPG::MT_INCREASE_FREQUENCY and RPG::MT_DECREASE_FREQUENCY + commands will not take permanent effect after the movement + ended unless the movement was started with the same frequency + as in the \ref frequency member of the character. + \warning This is an experimental function. + \sa RPG::MoveType + \sa stop + \sa doStep + */ + void move(const char* data, int length, bool repeatPattern = false, bool ignoreImpossible = true, int frequency = 8); + + /*! \brief Stops the current movement + \warning This is an experimental function. + \sa move + */ + void stop(); + + /*! \brief Does one step (moves the character one tile into a certain direction) + \param direction Direction to move into + \warning This is an experimental function. + \sa move + */ + void doStep(RPG::Direction direction); + }; + + /*! \brief Class used for storing special event data of a character + \note At the moment, only the event name can be accessed. + */ + class EventData { + public: + void **vTable; + int _unknown_4; + DStringPtr name; //!< Name of the event, as set in the event editor + }; + + /*! \brief Used for events as subtype of characters + \sa RPG::Map::events + */ + class Event : public Character { + public: + // sizeof(Character) == 0x94 + int _unknown_94; + EventData *eventData; //!< Pointer to the RPG::EventData of this event + + /*! \brief Checks whether a certain event page exists + + This function may be used to check for a certain event page + prior to calling it. + \param id Event page to check + \return \c true if the event page exists, \c false otherwise + */ + bool doesEventPageExist(int id); + }; + + //! Possible values for RPG::Hero::vehicle + enum HeroVehicle { + HV_NONE, //!< Hero is in no vehicle + HV_SKIFF, //!< Hero is in the skiff + HV_SHIP, //!< Hero is in the ship + HV_AIRSHIP //!< Hero is in the airship + }; + + //! Hero control mode (see RPG::Hero::setControlMode) + enum HeroControlMode { + CONTROL_EVERYTHING, //!< Everything works normally + CONTROL_EVERYTHING_EXCEPT_MOVEMENT, //!< Opening menu and activating events works, but movement is disabled + CONTROL_NOTHING //!< No control possible (checking key state still works, of course) + }; + + /*! \brief Used for the hero as subtype of characters + \sa RPG::hero + */ + class Hero : public Character { + public: + // sizeof(Character) == 0x94 + int _unknown_94; + int _unknown_98; + HeroVehicle vehicle; //!< Tells you whether the hero is in a vehicle at the moment + + /*! \brief Returns the current hero control mode + \note This is a special feature of the DynRPG patch. + \return Current control mode + \sa setControlMode + */ + RPG::HeroControlMode getControlMode(); + + /*! \brief Sets the hero control mode + \note This is a special feature of the DynRPG patch. + \param controlMode The new control mode + \sa getControlMode + */ + void setControlMode(RPG::HeroControlMode controlMode); + }; + + /*! \ingroup game_objects + \brief The hero (which moves around on the map, similar to an event) + */ + static RPG::Hero *&hero = (**reinterpret_cast(0x4CDE54)); +} diff --git a/sdk/include/DynRPG/DArray.h b/sdk/include/DynRPG/DArray.h new file mode 100644 index 0000000..4ce7580 --- /dev/null +++ b/sdk/include/DynRPG/DArray.h @@ -0,0 +1,38 @@ +namespace RPG { + //! Array class + template + class DArray { + public: + int size; //!< Size of the array + T *items; //!< Pointer to array items + + //! Returns the base of the array (zero in most cases) + inline int base() { + return base_; + } + + /*! \brief Array access operator + \note This operator will throw an error if you try to access + negative indexes. However, if you use an index which is higher + than the current maximum, the array is resized. + */ + T &operator[] (int index) { + index -= base_; + if(index < 0) throw "DArray index negative"; + if(index >= size) resize(index + 1); + return items[index]; + } + + /*! \brief Resizes the array + + New elements will be initialized with zero. + \param newSize The new number of elements in the array + */ + void resize(int newSize) { + int bytes = newSize * sizeof(T); + asm volatile("call *%%esi" : "=a" (_eax), "=d" (_edx) : "S" (0x4027AC), "a" (&items), "d" (bytes) : "ecx", "cc", "memory"); + for(int i = size; i < newSize; i++) items[i] = 0; + size = newSize; + } + }; +} diff --git a/sdk/include/DynRPG/DBActor.h b/sdk/include/DynRPG/DBActor.h new file mode 100644 index 0000000..3404f6f --- /dev/null +++ b/sdk/include/DynRPG/DBActor.h @@ -0,0 +1,87 @@ +namespace RPG { + //! Not implemented yet + typedef void ActorLearning; + + /*! \brief Used for the default data of actors which is defined in the + database + + \note The members of this class either mean default values of a + property or they are used for properties which aren't supposed to be + changed in-game, thus the members won't be saved and loaded + automatically (as it is the case with RPG::Actor), but only loaded once + at startup.\n\n + If you want to access data which could be changed in-game, use the + members and methods of RPG::Actor instead. + \sa RPG::dbActors + \sa RPG::Actor + \sa RPG::actors + */ + class DBActor { + public: + void **vTable; + int id; //!< ID of the actor + DStringPtr name; //!< Default name + DStringPtr degree; //!< Default degree + DStringPtr charsetFilename; //!< Default charset filename + int charsetId; //!< Default charset ID + /*! \brief Default charset transparency (see details) + + Unlike RPG::Actor::charsetTransparency, this member is a simple + boolean value. \c true means a transparency value of \c 3 while + \c false means a transparency value of \c 0. + */ + bool charsetTransparent; + int minLevel; //!< Minimum level + int maxLevel; //!< Maximum level + bool allowCriticalHit; //!< Critical hits allows? + int criticalHitProbability; //!< Probability of a critical hit + DStringPtr facesetFilename; //!< Default faceset filename + int facesetId; //!< Default faceset ID + bool twoWeapons; //!< Does the actor use a second weapon instead of the shield? + bool aiControl; //!< Is the actor controlled by the computer in battle? + bool lockEquipment; //!< Is the equipment locked? + bool mightyGuard; //!< Does defending reduce the damage more than usual? +#pragma pack(push, 2) + ArrayBaseOne maxHp; //!< Array of maximum HP values for each level + ArrayBaseOne maxMp; //!< Array of maximum MP values for each level + ArrayBaseOne attack; //!< Array of attack values for each level + ArrayBaseOne defense; //!< Array of defense values for each level + ArrayBaseOne intelligence; //!< Array of intelligence values for each level + ArrayBaseOne agility; //!< Array of agility values for each level +#pragma pack(pop) + int expPrimary; //!< Primary experience curve parameter + int expSecondary; //!< Secondary experience curve parameter + int expTertiary; //!< Tertiary experience curve parameter + short weaponId; //!< Default weapon ID + short shieldId; //!< Default shield ID + short armorId; //!< Default armor ID + short helmetId; //!< Default helmet ID + short accessoryId; //!< Default accessory ID + int unarmedBattleAnimationId; //!< Battle animation ID for attacks without weapon + ActorLearning *skillLearning; //!< Skill learning data (not yet implemented) + int _unknown_4FC; + int _unknown_500; + int _unknown_504; + int _unknown_508; + int _unknown_50C; + int _unknown_510; + int classId; //!< Default class ID + int battleGraphicId; //!< Battle graphic ID + int _unknown_51C; + int battleCommands[7]; //!< Default battle commands (\c 0 and \c -1 both mean "no command at this position") + }; + + /*! \ingroup game_objects + \brief Array of actors from the database, used for default values and + properties which are not supposed to be changed in-game. + + Use the database ID as index for accessing an actor. + + Example: + \code +int zackUnarmedAnimation = RPG::dbActors[1]->unarmedBattleAnimationId; + \endcode + \sa RPG::actors + */ + static RPG::NamedCatalogPtr &dbActors = (**reinterpret_cast **>(0x4CDD54)); +} diff --git a/sdk/include/DynRPG/DBSystem.h b/sdk/include/DynRPG/DBSystem.h new file mode 100644 index 0000000..7261653 --- /dev/null +++ b/sdk/include/DynRPG/DBSystem.h @@ -0,0 +1,112 @@ +namespace RPG { + //! Screen transitions + enum Transition { + TRANS_FADE, + TRANS_DISSOLVE, + TRANS_DISSOLVE_UP, + TRANS_DISSOLVE_DOWN, + TRANS_BLINDS, + TRANS_VERTICAL_STRIPES, + TRANS_HORIZONTAL_STRIPES, + TRANS_RECIDING_SQUARE, + TRANS_EXPANDING_SQUARE, + TRANS_SHIFT_UP, + TRANS_SHIFT_DOWN, + TRANS_SHIFT_LEFT, + TRANS_SHIFT_RIGHT, + TRANS_VERTICAL_SPLIT, + TRANS_HORIZONTAL_SPLIT, + TRANS_4_WAY_SPLIT, + TRANS_ZOOM, + TRANS_MOSAIC, + TRANS_WAVER_SCREEN, + TRANS_INSTANT, + TRANS_NONE, //!< Used for "Erase" transitions to indicate that the screen should not be erased + TRANS_DEFAULT = 255 //!< Default transition from the database + }; + + //! Possible values for RPG::DBSystem::systemFont + enum SystemFont { + SYSF_MSGOTHIC, //!< First font (normally MS Gothic) + SYSF_MSMINCHO //!< Second font (normally MS Mincho) + }; + + //! One-byte version of RPG::Transition + typedef unsigned char Transition_T; + + //! \cond + typedef void TestPlayer; + //! \endcond + + /*! \brief Used for the default system data which is defined in the + database + + \note The members of this class either mean default values of a + property or they are used for properties which aren't supposed to be + changed in-game, thus the members won't be saved and loaded + automatically (as it is the case with RPG::System), but only loaded + once at startup.\n\n + If you want to access data which could be changed in-game, use the + members and methods of RPG::System instead.\n\n + \sa RPG::dbSystem + \sa RPG::System + \sa RPG::system + */ + class DBSystem { + public: + void **vTable; + DStringPtr _unknown_4; + DStringPtr _unknown_8; + DStringPtr _unknown_C; + DStringPtr _unknown_10; + DStringPtr _unknown_14; + DStringPtr _unknown_18; + DStringPtr titleFilename; //!< Filename of the title screen + DStringPtr gameOverFilename; //!< Filename of the game over screen + DStringPtr systemGraphicFilename; //!< Default filename of the system graphic + int _unknown_28; + int _unknown_2C; + Music *titleBGM; //!< Default title screen music + Music *battleBGM; //!< Default battle music + Music *victoryBGM; //!< Default victory music + Music *innBGM; //!< Default inn music + Music *skiffBGM; //!< Default skiff music + Music *shipBGM; //!< Default ship music + Music *airshipBGM; //!< Default airship music + Music *gameOverBGM; //!< Default game over music + Sound *cursorSE; //!< Default cursor moving sound + Sound *decisionSE; //!< Default decision sound + Sound *cancelSE; //!< Default cancel sound + Sound *buzzerSE; //!< Default buzzer sound + Sound *battleStartSE; //!< Default sound played at battle start + Sound *fleeSE; //!< Default sound played when a battler escapes + Sound *enemyAttackSE; //!< Default sound played when a monster attacks + Sound *enemyDamageSE; //!< Default sound played when a monster is damaged + Sound *heroDamageSE; //!< Default sound played when an actor is damaged + Sound *evasionSE; //!< Default sound played when an attack is evaded + Sound *enemyDeathSE; //!< Default sound played when a monster is killed + Sound *itemSE; //!< Default sound played when an item is used + Transition_T teleportEraseTrans; //!< Default screen erasing transition on teleport (see RPG::Transition) + Transition_T teleportShowTrans; //!< Default screen showing transition on teleport (see RPG::Transition) + Transition_T battleStartEraseTrans; //!< Default screen erasing transition on battle start (see RPG::Transition) + Transition_T battleStartShowTrans; //!< Default screen showing transition on battle start (see RPG::Transition) + Transition_T battleEndEraseTrans; //!< Default screen erasing transition on battle end (see RPG::Transition) + Transition_T battleEndShowTrans; //!< Default screen showing transition on battle end (see RPG::Translation) + bool systemTiled; //!< Is the window background tiled? (Default value) + SystemFont systemFont; //!< Default system font + int _unknown_90; + int _unknown_94; + DStringPtr _unknown_98; + //! \cond + TestPlayer *testPlayer; + //! \endcond + int _unknown_A0; + }; + + /*! \ingroup game_objects + \brief Object of "system" data, used for default values and properties + which are not supposed to be changed in-game. + \sa RPG::system + */ + static RPG::DBSystem *&dbSystem = (**reinterpret_cast(0x4CDC0C)); +} diff --git a/sdk/include/DynRPG/DBitmap.h b/sdk/include/DynRPG/DBitmap.h new file mode 100644 index 0000000..9d90765 --- /dev/null +++ b/sdk/include/DynRPG/DBitmap.h @@ -0,0 +1,21 @@ +namespace RPG { + //! Wrapper class for windows' HBITMAPs + class DBitmap { + public: + void **vTable; + + //! Returns the HBITMAP + inline HBITMAP getHBITMAP() { + HBITMAP ret; + asm volatile("call *%%esi" : "=a" (ret) : "S" (0x428140), "a" (this) : "edx", "ecx", "cc", "memory"); + return ret; + } + + //! Returns the HDC + inline HDC getHDC() { + HDC ret; + asm volatile("call *%%esi; call *%%edi" : "=a" (ret) : "S" (0x4280F8), "D" (0x423634), "a" (this) : "edx", "ecx", "cc", "memory"); + return ret; + } + }; +} diff --git a/sdk/include/DynRPG/DList.h b/sdk/include/DynRPG/DList.h new file mode 100644 index 0000000..8965acd --- /dev/null +++ b/sdk/include/DynRPG/DList.h @@ -0,0 +1,47 @@ +namespace RPG { + /*! \brief Class representing Delphi's \c TList (without resizing for the moment) + \sa RPG::DListPtr + \sa RPG::Catalog + */ + template + class DList { + public: + void **vTable; + T *items; //!< Pointer to the actual array + int count; //!< Number of elements in the list + + //! Array access operator which will throw an error on invalid indexes + T &operator [](int index) { + if(index < 0 || index >= count) throw "DList index out of bounds (resizing not implemented)"; + return items[index]; + } + + //! Array access method which will return \c 0 on invalid indexes + T get(int index) { + if(index < 0 || index >= count) return NULL; + return items[index]; + } + }; + + /*! \brief Wrapper class for RPG::DList pointers (syntactic sugar) + + \note The size of this class equals to + sizeof(DList\ *). + \sa RPG::DList + */ + template + class DListPtr { + public: + DList *list; //!< Actual RPG::DList pointer + + //! Array access operator which will throw an error on invalid indexes + T &operator [](int index) { + return (*list)[index]; + } + + //! Array access method which will return \c 0 on invalid indexes + T get(int index) { + return list->get(index); + } + }; +} diff --git a/sdk/include/DynRPG/DString.h b/sdk/include/DynRPG/DString.h new file mode 100644 index 0000000..c57c856 --- /dev/null +++ b/sdk/include/DynRPG/DString.h @@ -0,0 +1,64 @@ +namespace RPG { + /*! \brief Helper class representing a Delphi string + + This class has no members. It is only "virtual", which means an + RPG::DString pointer can be used instead of a char * to be + able to access the length information of the string and provide a + nice automatic cast to std::string even when there are embedded nulls. + \note In most cases, the RPG::DStringPtr class is used instead of an + RPG::DString pointer. + \warning Please mind the \ref rules about strings! + \sa RPG::DStringPtr + */ + class DString { + public: + //! Cast operator returning a \c std::string (recommended) + operator std::string () const; + + //! Cast operator returning a char * + operator char *() const; + + //! Returns the length of the string + int length(); + }; + + /*! \brief Mighty wrapper class for RPG::DString pointers, the + string class for %RPG Maker strings + + This class can also be used to assign a Delphi string. The string will + then automatically be reallocated if necessary. + \warning Please mind the \ref rules about strings! + \sa DString + */ + class DStringPtr { + public: + DString *str; //!< Pointer to the actual string data + + DStringPtr(); //!< Constructor (intializes the pointer to zero) + DStringPtr(RPG::DStringPtr &s); //!< Copy constructor + DStringPtr(std::string s); //!< Constructor (uses a \c std::string as template) + ~DStringPtr(); //!< Destructor (deallocates the string when the class is destroyed) + + operator std::string (); //!< Cast operator for \c std::string (recommended) + operator char *(); //!< Cast operator for char * + const RPG::DStringPtr &operator =(std::string rhs); //!< Assignment operator for \c std::string (recommended) + const RPG::DStringPtr &operator =(char *rhs); //!< Assignment operator for char * + const RPG::DStringPtr &operator =(const char *rhs); //!< Assignment operator for const char * + const RPG::DStringPtr &operator =(RPG::DString *rhs); //!< Can be used to copy a string by writing newString = oldString.str; + bool operator ==(std::string rhs); //!< Comparison operator for \c std::string + bool operator ==(const char *rhs); //!< Comparison operator for \c char * + bool operator ==(RPG::DStringPtr &rhs); //!< Comparison oeprator for other RPG::DStringPtr classes + + //! Clears the string + void clear(); + + //! Assigns the string from a char * which may contain null bytes. + void assign(char *s, int len); + + //! Explicit conversion function to \c std::string (recommended) + std::string s_str(); + + //! Returns the length of the string + int length(); + }; +} diff --git a/sdk/include/DynRPG/DynRPG.h b/sdk/include/DynRPG/DynRPG.h new file mode 100644 index 0000000..8c93480 --- /dev/null +++ b/sdk/include/DynRPG/DynRPG.h @@ -0,0 +1,787 @@ +/* + DynRPG v0.20 + RM2k3 Plugin SDK + by David "Cherry" Trapp + http://cherrytree.at + + Include this file in your C++ project to work with the DynRPG SDK! +*/ + +#ifndef DYNRPG_H +#define DYNRPG_H + +#ifndef __GNUC__ +#error Sorry, DynRPG does only work with the GNU C++ compiler! See gcc.gnu.org +#endif // __GNUC__ + +#ifndef __cplusplus +#error Sorry, DynRPG is a C++ SDK! Mind the plus plus :-) +#endif // __cplusplus + +#if __GNUC__ < 4 || \ + (__GNUC__ == 4 && (__GNUC_MINOR__ < 7 || \ + (__GNUC_MINOR__ == 7 && \ + __GNUC_PATCHLEVEL__ < 1))) +#error Sorry, this DynRPG version needs at least GNU C++ version 4.7.1! See gcc.gnu.org +#endif + +#include +#include +#include + +#define LINK_VERSION 3 + +#ifndef NULL +#define NULL 0 +#endif + +//! \namespace RPG The one and only namespace in which all DynRPG classes, variables and functions reside, except for callbacks. +namespace RPG { + //! \cond + // Used for asm statements when input parameters may be written to + static void *_eax __attribute__((unused)); + static void *_edx __attribute__((unused)); + static void *_ecx __attribute__((unused)); + //! \endcond +} + +#include "DArray.h" +#include "ArrayBaseOne.h" +#include "DList.h" +#include "Catalog.h" +#include "DString.h" +#include "DBitmap.h" +#include "Image.h" +#include "Canvas.h" +#include "Music.h" +#include "Sound.h" +#include "Input.h" +#include "Picture.h" +#include "DBSystem.h" +#include "System.h" +#include "Screen.h" +#include "Variables.h" +#include "Switches.h" +#include "MoveRoute.h" +#include "Character.h" +#include "Action.h" +#include "Battler.h" +#include "DBActor.h" +#include "Actor.h" +#include "Monster.h" +#include "Map.h" +#include "EventScriptLine.h" +#include "EventScriptData.h" +#include "BattleSettings.h" +#include "ParsedCommentData.h" + +namespace RPG { + //! \cond + static void ***sceneObjects[] __attribute__((unused)) = { + (void ***)0x4CDC1C, (void ***)0x4CDC60, (void ***)0x4CDD38, + (void ***)0x4CDE4C, (void ***)0x4CDBF4, (void ***)0x4CDFCC, + (void ***)0x4CDB94, (void ***)0x4CE008, (void ***)0x4CDD4C + }; + //! \endcond + + //! The test play flag + /*! This flag may also be changed at runtime. */ + static bool &isTestPlay = (**reinterpret_cast(0x4CDD50)); + + //! The test play flag + /*! This flag may also be changed at runtime, but it probably wouldn't make sense. */ + static bool &isBattleTest = (**reinterpret_cast(0x4CDCB8)); + + //! Should the title screen be shown (according to the "Show Title" button in the %RPG Maker)? + /*! This flag may also be changed at runtime, but it probably wouldn't make sense. */ + static bool &showTitle = (**reinterpret_cast(0x4CDF90)); + + //! Speed of the ATB system in percent + /*! This value can be set to zero to pause the battle. + \note This is a special feature of the DynRPG patch. */ + static int &battleSpeed = (*reinterpret_cast(0x442600)); + + //! Allows transparent windows in outside of the map too + /*! Set this flag to \c true to allow transparent windows in the menu, on + the title screen, etc. + \note This is a special feature of the DynRPG patch. */ + static bool &transparentWindowsEverywhere = (*reinterpret_cast(0x442604)); + + //! Possible values of the \c mode parameter of RPG::updateBattleEvents + /*! \warning I am not completely sure about the effects these modes have. */ + enum BattleEventUpdateMode { + BEUM_BEFORE_ACTION, //!< Used before a battler executes its action + BEUM_AFTER_ACTION, //!< Used after a battler executes its action + BEUM_SWITCH_ACTIVATED, //!< Used when a skill or an item activates a switch + BEUM_BATTLE_START //!< Used to call events with start condition "Turns elapsed [0x+0]" + }; + + /*! \brief Shows an error message and asks whether the game should be continued or not. + + This function can be used to show an error message of any kind. + \param message Message to show + \param eventId %Event ID + \param pageId %Event page ID + \param lineId Zero-based line number (will be incremented before being shown to the user) + */ + void showError(std::string message, int eventId, int pageId, int lineId); + + /*! \brief Updates the battle, including actions, ATB, animations, etc. + + This function can be used if you want to do something which takes + longer than one frame, for example displaying some kind of animation + or taking and processing user input. + + \pre You must be in battle, otherwise the behavior is undefined. + \warning This function is experimental. + */ + void updateBattle(); + + /*! \brief Processes battle events + + This function can be used to update battle events and maybe call them + at a time where normally no battle event is processed. + \param mode Mode of the update (see RPG::BattleEventUpdateMode) + \param battler %Battler whose action is executed + \note \c battler can be \c 0 if \c mode is RPG::BEUM_BATTLE_START. + \pre You must be in battle, otherwise the behavior is undefined. + \warning This function is highly experimental! + \sa RPG::updateBattleEvents + */ + void updateBattleEvents(RPG::BattleEventUpdateMode mode, RPG::Battler *battler); + + /*! \brief Returns the index of the currently selected monster + + This function can be used to found out which monster is selected when + the player is selecting a target for an attack or skill. + \return Zero-based party member index of the selected monster + \pre You must be in battle, otherwise the behavior is undefined. + */ + int getSelectedMonsterIndex(); + + + /*! \brief Returns the name of an item + \param id Database ID of the item + \return Name of the item + \sa RPG::getItemDescription + */ + std::string getItemName(int id); + + /*! \brief Returns the description of an item + \param id Database ID of the item + \return Description of the item + \sa RPG::getItemName + */ + std::string getItemDescription(int id); + + /*! \brief Returns the name of a skill + \param id Database ID of the skill + \return Name of the skill + \sa RPG::getSkillDescription + */ + std::string getSkillName(int id); + + /*! \brief Returns the description of a skill + \param id Database ID of the skill + \return Description of the skill + \sa RPG::getSkillName + */ + std::string getSkillDescription(int id); + + /*! \brief Returns the name of a condition + \param id Database ID of the condition + \return Name of the condition + */ + std::string getConditionName(int id); + + + /*! \brief Returns a std::map containing configuration from an INI file + + This function should be used to load configuration for a plugin. See + the \ref configuration guidelines for more information. + \param sectionName Name of the section to load from the INI file + \param filename Name of the INI file (defaults to \c DynRPG.ini) + \return All keys and values of the specified section from the INI file + */ + std::map loadConfiguration(char *sectionName, char *filename = NULL); + + + /*! \brief Encodes a numerical value for use with RPG::Character::move + \param value Value to encode + \return Encoded value as string (may be 1 to 5 characters long) + */ + std::string encode(int value); + + /*! \brief Encodes a string for use with RPG::Character::move + \param value String to encode + \return Encoded string (including length information) + */ + std::string encode(std::string value); +} + +#ifndef DYNRPG_STATIC +extern "C" { +#ifndef NOT_MAIN_MODULE + int __declspec(dllexport) linkVersion = LINK_VERSION; +#ifndef CUSTOM_DLLMAIN + HINSTANCE hInstance; + + BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) { + if(reason == DLL_PROCESS_ATTACH) hInstance = hInst; + return TRUE; + } +#endif // CUSTOM_DLLMAIN +#endif // NOT_MAIN_MODULE + + /*! \defgroup callbacks Callbacks + @{ + */ + + /*! \brief Called when the plugin was loaded + + This callback handler should be used to check for fatal problems, like + missing files. You can abort the loading process from this function. + \param pluginName The name of the plugin. This is the filename with the + extension stripped. For its supposed usage, see \ref configuration. + \return \c true on success, \c false on failure. In the latter case, + other plugins which were already loaded will receive the \ref onExit + call and be unloaded and the game will not be started. + \warning Do not try to access RPG objects from this function, since the + game hasn't been initialized yet. + \sa onInitFinished + \sa onExit + */ + bool __declspec(dllexport) __cdecl onStartup(char *pluginName); + + /*! \brief Called after the RPG objects were initialized + + Unlike in \ref onStartup, it is safe to access RPG objects from this + function. + \sa onStartup + */ + void __declspec(dllexport) __cdecl onInitFinished(); + + /*! \brief Called before the title screen is initialized + + This function is called before the title screen fades in. + */ + void __declspec(dllexport) __cdecl onInitTitleScreen(); + + //! Called before the player starts a new game + void __declspec(dllexport) __cdecl onNewGame(); + + /*! \brief Called before the player loads a game from a savestate + + DynRPG loads plugin data which was previously saved in the + \ref onSaveGame function and passes it to this handler. See \ref ingame_data + for details. + \param id Savestate ID + \param data Pointer to plugin data + \param length Length of plugin data + \note \c data may be \c 0 if there is no data. + \sa onLoadGame + */ + void __declspec(dllexport) __cdecl onLoadGame(int id, char *data, int length); + + /*! \brief Called before the player saves a game + + Use the function passed in the \c savePluginData parameter to save + custom plugin data which will be passed back to the plugin when the + player loads the same savestate. See \ref ingame_data for details. + \param id Savestate ID + \param savePluginData Call this function to save custom plugin data + \note If you call \c savePluginData more than once, only the last + call will take effect. + \sa onLoadGame + */ + void __declspec(dllexport) __cdecl onSaveGame(int id, void __cdecl (*savePluginData)(char *data, int length)); + + /*! \brief Called before the game exits + + \note It's recommended to wrap your code in a try..catch block + because if the game exits after an error (before \ref onInitFinished was + called), the state of the memory is undefined. Also, if you want to save + data, check whether there is anything to save before you do it. + The RPG objects may or may not be initialized, depending on whether this + function is called before (early exit) or after \ref onInitFinished. + \warning This handler may also be called while another callback handler + is active, in case the other handler is pumping messages (for example, + it is currently displaying a message box). + */ + void __declspec(dllexport) __cdecl onExit(); + + /*! \brief Called every frame, before the screen is refreshed (see details!) + + This function is called after every frame (see details below!), right after the current game + scene was drawn, but before it becomes visible to the player. You may + draw on the screen in this function and it will appear on top of the + normal graphics. + + You can even define your own scene and use this callback to draw it. + + However: If the game is too slow, frames may be skipped. If + this happens, the screen is not refreshed every frame, to save time. In + this case, the \c onFrame handler is called only when the screen is + refreshed. You can use RPG::System::frameCounter to find out how many + frames were skipped (by comparing it with a value you saved at the last + \c onFrame call), because when the scene is updated (even though the + \c onFrame handler wasn't called), the RPG::System::frameCounter will + still be incremented. This way, the game won't be "slower" than normal + even when the framerate drops below 60. + + \param scene Game scene which was drawn + \note The \c scene parameter does not necessarily equal to + RPG::system->scene, e.g. when a transition from one scene to + another is active. + \sa RPG::System::scene + \sa RPG::System::frameCounter + */ + void __declspec(dllexport) __cdecl onFrame(RPG::Scene scene); + + /*! \brief Called before an in-game variable is set + + This function can be used to give "Change Variable" commands a special + meaning. This might be suitable for applications for which a full + \ref onComment implementation would be overkill, like a key check. + \param id ID of the variable to be changed + \param value Value to be assigned + \return \c false will prevent the variable from being changed and other + plugins from receiving this notification, use \c true otherwise + \note This callback is not only triggered by the "Change Variable" + command, but by any action which writes to a variable. + \sa onSetSwitch + */ + bool __declspec(dllexport) __cdecl onSetVariable(int id, int value); + + // TOO SLOW!!! + //! \cond + /*! \brief Called before an in-game variable is read + + This function can be used to give variables special functions, for + example reading the mouse position. You may change the variable in + this function for that reason. + \param id ID of the variable to be read + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \sa onSetVariable + \sa onSetSwitch + \sa onGetSwitch + */ + //bool __declspec(dllexport) __cdecl onGetVariable(int id); + //! \endcond + + /*! \brief Called before an in-game switch is set + + This function can be used to give "Change Switch" commands a special + meaning. + \param id ID of the switch to be changed + \param value Value to be assigned + \return \c false will prevent the switch from being changed and other + plugins from receiving this notification, use \c true otherwise + \note This callback is not only triggered by the "Change Switch" + command, but by any action which writes to a switch. + \sa onSetVariable + */ + bool __declspec(dllexport) __cdecl onSetSwitch(int id, bool value); + + // TOO SLOW!!! + //! \cond + /*! \brief Called before an in-game switch is read + + This function can be used to give switches special functions, for + example reading a key's status. You may change the switch in this + function for that reason. + \param id ID of the switch to be read + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \sa onSetVariable + \sa onGetVariable + \sa onSetSwitch + */ + //bool __declspec(dllexport) __cdecl onGetSwitch(int id); + //! \endcond + + /*! \brief Called before an event command is executed + + You can use this function to intercept event commands, use them for a + different purpose or change their parameters. + + By changing the \c nextLineId, you can decide which line in the + script is to be executed next. By default, the value of \c *nextLineId + is \c -1, which means that the default behavior is executed. You can + change it to another line number to jump to a different line. Use + *nextLineId = lineId; to repeat the command, this way you can + create a "wait until done" behavior by initiating some action the first + time and then repeatedly checking whether it is finished. + + You can use the \c scriptData parameter to read other event commands + in the current script. + \param scriptLine The event script line which is about to be executed + \param scriptData Pointer to the RPG::EventScriptData object of the + current event script + \param eventId The ID of the current event (negative for common events, + zero for battle events) + \param pageId The ID of the current event page (zero for common and + battle events - sorry, no battle event page ID yet) + \param lineId The zero-based line number + \param nextLineId Pointer to the next executed line number (\c -1 for + default) + \return \c false will prevent the event script line from being executed + and other plugins from receiving this notification, use \c true + otherwise + \note You may change the \c scriptLine object if you want, so that it is + executed with different parameters. After the line was executed, all changes + will be undone automatically.\n\n + The "don't execute if you return false" feature works by setting bit + 31 in the \c command member of the \c scriptLine so that it becomes an + invalid (and thus ignored) command. DynRPG automatically clears this bit + later. + \warning Do not create loops which include several commands without + a "Wait 0.0" (and also tell the user not to do so in case you provide + an event command which jumps back in the script), otherwise the game + will hang. If you loop to the same line using *nextLineId = + lineId;, an automatic one-frame wait (equal to a "Wait 0.0") is + inserted.\n\n + Do not use the \c nextLineId member if the current event command calls + another event or ends the current event (e.g. when the command is + RPG::EVCMD_STOP_EVENT). + \sa onComment + */ + bool __declspec(dllexport) __cdecl onEventCommand(RPG::EventScriptLine *scriptLine, RPG::EventScriptData *scriptData, int eventId, int pageId, int lineId, int *nextLineId); + + /*! \brief Called when a "Comment" event command is encountered + + You can use this function to provide functions which are executed when + a special event comment is encountered. Please stick to the + \ref event_comments guidelines! The \c parsedData parameter brings you + the data already parsed according to the guidelines. + + You will get all comment lines at once (separated by newline + characters) in the \c text parameter. This way you don't need to do + the parsing of the next event script lines (because internally, each + comment line is a new event command). + + You may use the comment function as "modifier" for event commands, thus + there is the \c nextScriptLine parameter which allows you to modify + the parameters of the next script line. For modifying event commands + please also read the note at the \ref onEventCommand documentation! + + \param text The comment's content as simple text + \param parsedData The already parsed data + \param nextScriptLine The next event script line after the comment + \param scriptData Pointer to the RPG::EventScriptData object of the + current event script + \param eventId The ID of the current event (negative for common events, + zero for battle events) + \param pageId The ID of the current event page (zero for common and + battle events - sorry, no battle event page ID yet) + \param lineId The zero-based line number + \param nextLineId Pointer to the next executed line number (\c -1 for + default) + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note For information how to use the \c nextLineId parameter, please + refer to the \ref onEventCommand documentation. + \sa onEventCommand + */ + bool __declspec(dllexport) __cdecl onComment(const char *text, const RPG::ParsedCommentData *parsedData, RPG::EventScriptLine *nextScriptLine, RPG::EventScriptData *scriptData, int eventId, int pageId, int lineId, int *nextLineId); + + /*! \brief Called when the screen is drawn on the game window + + Unlike \ref onFrame, this function is called when the screen content + is actually drawn on the game window. This means that if a section + of the window is invalidated (for example because it was overlapped + by another window or minimized), this function will be called again, + even though the game screen itself didn't change. + \warning The screen might already contain changes done by you in the + \ref onDrawScreen handler before. Also, it is possible that only + a part of the screen is invalidated and redrawn. Thus, you + should only use this callback if you need to draw something during + certain screen transitions (where \ref onFrame doesn't work). + \sa onFrame + */ + void __declspec(dllexport) __cdecl onDrawScreen(); + + /*! \brief Called before a picture is drawn + + You can use this function to draw something below a certain picture, + or instead of the picture. + \param picture The picture which is about to be drawn + \return \c false will prevent the original picture from being drawn + and other plugins from receiving this notification, use \c true + otherwise + \note If you return \c false, the \ref onPictureDrawn handlers will + still be called. + \sa onPictureDrawn + */ + bool __declspec(dllexport) __cdecl onDrawPicture(RPG::Picture *picture); + + /*! \brief Called after a picture was drawn (or was supposed to be drawn) + + You can use this function to draw something above a certain picture. + \param picture The picture which is was drawn (or was supposed to be + drawn) + \return \c false will other plugins from receiving this notification, + use \c true otherwise + \note This function will be called regardless if a plugin returned + \c false from its \ref onDrawPicture handler for this picture. + \sa onDrawPicture + */ + bool __declspec(dllexport) __cdecl onPictureDrawn(RPG::Picture *picture); + + /*! \brief Called every frame to check whether an event should be drawn + even though it is out of sight + + Use this function in case you want to draw larger graphics instead of an + event's normal graphic (using \ref onDrawEvent). Normally, events which + are out of sight are not drawn at all, thus neither \ref onDrawEvent + nor \ref onEventDrawn would be called for this event. Return \c false + from this function to force the drawing of the event. + \param character The event to be drawn (can also be the hero) + \return \c false if the event should be drawn even though it is + out of sight and also to prevent other plugins from receiving this + notification, use \c true otherwise + \warning Do not initiate any actions from this function, only check + whether you need to draw this event or not. If a previous plugin + returned \c false, your plugin won't receive this notification, even + though it might receive the \ref onDrawEvent and \ref onEventDrawn + notifications! + \sa onDrawEvent + \sa onEventDrawn + */ + bool __declspec(dllexport) __cdecl onCheckEventVisibility(RPG::Character *character); + + /*! \brief Called before an event or the hero is drawn + + You can use this function to draw something below a certain event, + or instead of the event. + \param character The character which is about to be drawn (can also be + the hero) + \param isHero \c true if the \c character is the hero + \return \c false will prevent the original event from being drawn + and other plugins from receiving this notification, use \c true + otherwise + \note If you return \c false, the \ref onEventDrawn handlers will + still be called.\n\n + Vehicles are not supported yet.\n\n + This function is only called when the event is in sight or an + \ref onCheckEventVisibility handler has returned \c false for this + event. + \sa onEventDrawn + */ + bool __declspec(dllexport) __cdecl onDrawEvent(RPG::Character *character, bool isHero); + + /*! \brief Called after an event or the hero was drawn (or was supposed to + be drawn) + + You can use this function to draw something above a certain event. + \param character The character which was drawn or supposed to be drawn + (can also be the hero) + \param isHero \c true if the \c character is the hero + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note This function will be called regardless if a plugin returned + \c false from its \ref onDrawEvent handler for this event.\n\n + Vehicles are not supported yet.\n\n + This function is only called when the event is in sight or an + \ref onCheckEventVisibility handler has returned \c false for this + event. + \sa onDrawEvent + */ + bool __declspec(dllexport) __cdecl onEventDrawn(RPG::Character *character, bool isHero); + + /*! \brief Called before a battler is drawn + + You can use this function to draw something below a certain battler, + or instead of the battler. + \param battler The battler which is about to be drawn + \param isMonster \c true if the \c battler is a monster + \param id Zero-based party member ID of the \c battler + \return \c false will prevent the original battler from being drawn + and other plugins from receiving this notification, use \c true + otherwise + \note If you return \c false, the \ref onBattlerDrawn handlers will + still be called.\n\n + This function is not called for hidden monsters. For dead monsters it + is only called while they are still partly visible (i.e. while they are + fading out). + \sa onBattlerDrawn + */ + bool __declspec(dllexport) __cdecl onDrawBattler(RPG::Battler *battler, bool isMonster, int id); + + /*! \brief Called after a battler was drawn (or supposed to be drawn) + + You can use this function to draw something above a certain battler. + \param battler The battler which was drawn (or supposed to be drawn) + \param isMonster \c true if the \c battler is a monster + \param id Zero-based party member ID of the \c battler + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note This function will be called regardless if a plugin returned + \c false from its \ref onDrawBattler handler for this event.\n\n + This function is not called for hidden monsters. For dead monsters it + is only called while they are still partly visible (i.e. while they are + fading out). + \sa onDrawBattler + */ + bool __declspec(dllexport) __cdecl onBattlerDrawn(RPG::Battler *battler, bool isMonster, int id); + + /*! \brief Called before the battle status window is drawn + + You can use this function to draw below the battle status window, or to + replace it entirely. + + In the "Traditional" and "Alternative" battle layouts, there are two + different status windows: One used as actual status window, one + used as target selection window for actions with actors as targets. + The latter is drawn above the skill/item selection window, while + the former is drawn below it. Use the \c isTargetSelection + parameter to find out which window you are dealing with. + + You can also use this function (when \c isTargetSelection is \c false) + to draw something above all battlers and below all windows. + \param x The current X coordinate of the left side of the window + \param selection The zero-based party member ID of the currently + selected actor + \param selActive \c true if the \c selection parameter contains a valid + value and a choice bar is drawn + \param isTargetSelection \c true if it is the target selection window, + \c false if it is the "normal" status window + \param isVisible \c true if the window is visible + \return \c false will prevent the original window from being drawn + and other plugins from receiving this notification, use \c true + otherwise + \note If you return \c false, the \ref onBattleStatusWindowDrawn + handlers will still be called. However, the "finger" cursor which + points to the selected hero will not be drawn if you return \c false + when the \c isTargetSelection parameter is \c true.\n\n + This function is also called when the window is invisible. In this + case, \c isVisible will be \c false. + \sa onBattleStatusWindowDrawn + */ + bool __declspec(dllexport) __cdecl onDrawBattleStatusWindow(int x, int selection, bool selActive, bool isTargetSelection, bool isVisible); + + /*! \brief Called after the battle status window was drawn (or supposed to + be drawn) + + You can use this function to draw something above the battle status + window. + \param x The current X coordinate of the left side of the window + \param selection The zero-based party member ID of the currently + selecter actor + \param selActive \c true if the \c selection parameter contains a valid + value and a choice bar is drawn + \param isTargetSelection \c true if it is the target selection window, + \c false if it is the "normal" status window + \param isVisible \c true if the window is visible + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note This function will be called regardless if a plugin returned + \c false from its \ref onDrawBattleStatusWindow handler for this + window.\n\n + This function is also called when the window is invisible. In this + case, \c isVisible will be \c false.\n\n + Please see the \ref onDrawBattleStatusWindow documentation to find out + more about the \c isTargetSelection parameter! + \sa onDrawBattleStatusWindow + */ + bool __declspec(dllexport) __cdecl onBattleStatusWindowDrawn(int x, int selection, bool selActive, bool isTargetSelection, bool isVisible); + + /*! \brief Called before the battle action window is drawn + + You can use this function to draw below the battle action window, or to + replace it entirely. + + You can also use this function to move the window by modifying \c *x + and \c *y. + \param x Pointer to the X coordinate of the upper-left corner of the + window + \param y Pointer to the Y coordinate of the upper-right corner of the + window + \param selection Zero-based index of the current selection + \param selActive \c true if the \c selection parameter contains a valid + value and a choice bar is drawn + \param isVisible \c true if the window is visible + \return \c false will prevent the original window from being drawn + and other plugins from receiving this notification, use \c true + otherwise + \note The \c selection parameter does not contain the database + ID of the selected battle command, but only a zero-based index based on all + choices which are displayed. Use the RPG::Actor object to find out which battle + commands are available for an actor. You probably need to store the + \c selection parameter from your \ref onDrawBattleStatusWindow to find + out which actor is currently selected. You can then use something like + RPG::Actor::partyMember(battleStatusWindowSelection)->getBattleCommand(battleActionWindowSelection) + to get the database ID of the currently selected battle command.\n\n + This function is also called when the window is invisible. In this + case, \c isVisible will be \c false. + \sa onBattleStatusWindowDrawn + */ + bool __declspec(dllexport) __cdecl onDrawBattleActionWindow(int *x, int *y, int selection, bool selActive, bool isVisible); + + /*! \brief Called before a battler's action is executed + + This function can be used to modify a battler's action before it is + executed. For example, you might add a "random" skill which randomly + executes certain skills and use this function to set the actual skill. + \param battler The battler which is executing its action + \param firstTry \c true if this is the first attempt to execute this + action. Make sure you include a check for this parameter to be \c true + if you want your code to be run only once per action! + \note If executing the action fails (due to another action being + executed), the %RPG Maker will repeatedly try again. You will then + receive multiple calls to this callback, but only at the first call + \c firstTry will be set to \c true. + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note Using this function, you can also use targets for a skill (or + the "Attack" and "Double Attack" functions) which are normally not + possible.\n\n + To prevent an action completely, change it to the basic action + RPG::BA_NONE. Do not use RPG::AK_NONE because this can cause errors + later in the battle. + \sa onBattlerActionDone + \sa RPG::Action + */ + bool __declspec(dllexport) __cdecl onDoBattlerAction(RPG::Battler *battler, bool firstTry); + + /*! \brief Called after a battler's action is executed + + \param battler The battler which is executing its action + \param success \c true if the action was successfully executed or + \c false if the action couldn't be executed yet because another + action or something else was active + \return \c false will prevent other plugins from receiving this + notification, use \c true otherwise + \note If \c success if \c false, the %RPG Maker will repeatedly try + again to execute the action, until it succeeds, at which point + \c success will be \c true. Please note that this will also lead + to multiple calls to \ref onDoBattlerAction. + \warning You must not modify the battler's action from this function, + because it might not be fully completed. For example, "Attack" + commands will immediately be finished although the attack animation + and damage display haven't been done yet. + \sa onDoBattlerAction + \sa RPG::Action + */ + bool __declspec(dllexport) __cdecl onBattlerActionDone(RPG::Battler *battler, bool success); + + /*! \brief Called after the system background was drawn + + This function can be used to draw your custom background in the menu, + etc. + \param rect Area which has been (re)drawn + \note In the save/load menu, there is only the small part at the top + drawn, in the other menus, the whole screen is painted. Pay attention + to the \c rect parameter. + */ + bool __declspec(dllexport) __cdecl onSystemBackgroundDrawn(RECT *rect); + //! @} +} +#endif // DYNRPG_STATIC + +#ifdef AUTO_DLLMAIN +#warning AUTO_DLLMAIN is deprecated as automatically adding a DllMain function is the default behaviour now. Use #define CUSTOM_DLLMAIN to achieve the reverse. +#endif + +#endif // DYNRPG_H diff --git a/sdk/include/DynRPG/EventScriptData.h b/sdk/include/DynRPG/EventScriptData.h new file mode 100644 index 0000000..4352be3 --- /dev/null +++ b/sdk/include/DynRPG/EventScriptData.h @@ -0,0 +1,28 @@ +namespace RPG { + /*! \brief List of event script lines + \note Do not ask me why this class is there, I didn't invent it. + */ + class EventScriptList { + public: + void **vTable; + DList *list; //!< The actual RPG::DList + }; + + //! Class used for the event script data of an event + class EventScriptData { + public: + void **vTable; + int _unknown_4; + int _unknown_8; + int _unknown_C; + int _unknown_10; + EventScriptList *lines; //!< %Event script lines + int currentLineId; //!< Current line number + + /*! \brief Returns a certain RPG::EventScriptLine + \param index Line number (zero-based) + \return %Event script line pointer + */ + RPG::EventScriptLine *line(int index); + }; +} diff --git a/sdk/include/DynRPG/EventScriptLine.h b/sdk/include/DynRPG/EventScriptLine.h new file mode 100644 index 0000000..90f0e68 --- /dev/null +++ b/sdk/include/DynRPG/EventScriptLine.h @@ -0,0 +1,160 @@ +namespace RPG { + /*! \brief %Event command type + + Each event command can have a number of parameters. Unfortunately, + documenting all of them (nearly 150) is beyond my time resources + at the moment. If you need to know how the parameters of a certain + command work, you can write a simple plugin which logs event commands + and their parameters and try it out yourself. + \sa RPG::EventScriptLine + \sa onEventCommand + \note Not all enumeration values are documented here, scroll to the top + to see all possible values (in the general enum overview)! + */ + enum EventCommand { + EVCMD_END_OF_EVENT = 0, //!< End of the event command list + EVCMD_EMPTY_LINE = 10, //!< Empty line (\<\>) + EVCMD_SHOW_MESSAGE = 10110, //!< First line of a "Show Message" command + EVCMD_ADD_LINE_TO_MESSAGE = 20110, //!< Additional lines of a "Show Message" command + EVCMD_MESSAGE_OPTIONS = 10120, + EVCMD_SELECT_FACE = 10130, + EVCMD_SHOW_CHOICE = 10140, //!< First line of a "Show Choice" command + EVCMD_CHOICE_CASE = 20140, //!< [XXXX] handler lines of a "Show Choice" command + EVCMD_CHOICE_END = 20141, //!< : End line of a "Show Choice" command + EVCMD_INPUT_NUMBER = 10150, + EVCMD_CHANGE_SWITCH = 10210, + EVCMD_CHANGE_VARIABLE = 10220, + EVCMD_CHANGE_TIMER = 10230, + EVCMD_CHANGE_MONEY = 10310, + EVCMD_CHANGE_ITEMS = 10320, + EVCMD_CHANGE_PARTY = 10330, + EVCMD_CHANGE_EXP = 10410, + EVCMD_CHANGE_LEVEL = 10420, + EVCMD_CHANGE_STATS = 10430, + EVCMD_CHANGE_SKILL = 10440, + EVCMD_CHANGE_EQUIPMENT = 10450, + EVCMD_CHANGE_HP = 10460, + EVCMD_CHANGE_MP = 10470, + EVCMD_CHANGE_CONDITION = 10480, + EVCMD_FULL_RECOVERY = 10490, + EVCMD_INFLICT_DAMAGE = 10500, + EVCMD_CHANGE_HERO_NAME = 10610, + EVCMD_CHANGE_HERO_TITLE = 10620, + EVCMD_CHANGE_HERO_GRAPHIC = 10630, + EVCMD_CHANGE_HERO_FACE = 10640, + EVCMD_CHANGE_VEHICLE_GRAPHIC = 10650, + EVCMD_CHANGE_SYSTEM_BGM = 10660, + EVCMD_CHANGE_SYSTEM_SE = 10670, + EVCMD_CHANGE_SYSTEM_GRAPHIC = 10680, + EVCMD_CHANGE_TRANSITION = 10690, + EVCMD_START_COMBAT = 10710, //!< First line of a "Start Combat" command + EVCMD_BATTLE_VICTORY = 20710, //!< Victory handler line of a "Start Combat" command + EVCMD_BATTLE_ESCAPE = 20711, //!< Escape handler line of a "Start Combat" command + EVCMD_BATTLE_DEFEAT = 20712, //!< Defeat handler line of a "Start Combat" command + EVCMD_BATTLE_END = 20713, //!< : End line of a "Start Combat" command + EVCMD_CALL_SHOP = 10720, //!< First line of a "Call Shop" command + EVCMD_SHOP_TRANSACTION = 20720, //!< Transaction handler line of a "Call Shop" command + EVCMD_SHOP_CANCEL = 20721, //!< Cancel handler line of a "Call Shop" command + EVCMD_SHOP_END = 20722, //!< : End line of "Call Shop" command + EVCMD_CALL_INN = 10730, //!< First line of a "Call Inn" command + EVCMD_INN_REST = 20730, //!< Rest handler line of a "Call Inn" command + EVCMD_INN_CANCEL = 20731, //!< Cancel handler line of a "Call Inn" command + EVCMD_INN_END = 20732, //!< : End line of a "Call Inn" command + EVCMD_ENTER_HERO_NAME = 10740, + EVCMD_TELEPORT = 10810, + EVCMD_MEMORIZE_LOCATION = 10820, + EVCMD_GO_TO_MEMORIZED_LOCATION = 10830, + EVCMD_RIDE_VEHICLE = 10840, + EVCMD_TELEPORT_VEHICLE = 10850, + EVCMD_SET_EVENT_LOCATION = 10860, + EVCMD_SWAP_TWO_EVENT_LOCATIONS = 10870, + EVCMD_GET_TERRAIN_ID = 10910, + EVCMD_GET_EVENT_ID = 10920, + EVCMD_ERASE_SCREEN = 11010, + EVCMD_SHOW_SCREEN = 11020, + EVCMD_SET_SCREEN_TONE = 11030, + EVCMD_FLASH_SCREEN = 11040, + EVCMD_SHAKE_SCREEN = 11050, + EVCMD_PAN_SCREEN = 11060, + EVCMD_WEATHER_EFFECTS = 11070, + EVCMD_SHOW_PICTURE = 11110, + EVCMD_MOVE_PICTURE = 11120, + EVCMD_ERASE_PICTURE = 11130, + EVCMD_SHOW_BATTLE_ANIMATION = 11210, //!< "Show Battle Animation" in map/common events + EVCMD_SET_HERO_OPACITY = 11310, + EVCMD_FLASH_EVENT = 11320, + EVCMD_MOVE_EVENT = 11330, + EVCMD_WAIT_UNTIL_MOVED = 11340, + EVCMD_STOP_ALL_MOVEMENT = 11350, + EVCMD_WAIT = 11410, + EVCMD_PLAY_BGM = 11510, + EVCMD_FADE_OUT_BGM = 11520, + EVCMD_MEMORIZE_BGM = 11530, + EVCMD_PLAY_MEMORIZED_BGM = 11540, + EVCMD_PLAY_SOUND_EFFECT = 11550, + EVCMD_PLAY_MOVIE = 11560, + EVCMD_KEY_INPUT_PROCESSING = 11610, + EVCMD_CHANGE_TILESET = 11710, + EVCMD_CHANGE_PANORAMA = 11720, + EVCMD_CHANGE_ENCOUNTER_RATE = 11740, + EVCMD_CHANGE_SINGLE_TILE = 11750, + EVCMD_CHANGE_TELEPORT_TARGET = 11810, + EVCMD_ENABLE_TELEPORT = 11820, + EVCMD_SET_ESCAPE_LOCATION = 11830, + EVCMD_ENABLE_ESCAPE = 11840, + EVCMD_CALL_SAVE_MENU = 11910, + EVCMD_ENABLE_SAVE = 11930, + EVCMD_CALL_MAIN_MENU = 11950, + EVCMD_ENABLE_MAIN_MENU = 11960, + EVCMD_FORK = 12010, //!< First line of a "Conditional Branch" in map/common events + EVCMD_FORK_ELSE_CASE = 22010, //!< : Else Case line of a "Conditional Branch" in map/common events + EVCMD_FORK_END = 22011, //!< : End Case line of a "Conditional Branch" in map/common events + EVCMD_LABEL = 12110, + EVCMD_JUMP_TO_LABEL = 12120, + EVCMD_START_LOOP = 12210, //!< "Loop" command + EVCMD_END_LOOP = 22210, //!< : End line of a "Loop" + EVCMD_BREAK_LOOP = 12220, + EVCMD_STOP_EVENT = 12310, + EVCMD_DELETE_EVENT = 12320, + EVCMD_CALL_EVENT = 12330, //!< "Call Event" in map/common events + EVCMD_COMMENT = 12410, //!< First line of a comment + EVCMD_ADD_LINE_TO_COMMENT = 22410, //!< Additional lines of a comment + EVCMD_GAME_OVER = 12420, + EVCMD_GO_TO_TITLE_SCREEN = 12510, + EVCMD_CHANGE_CLASS = 1008, + EVCMD_CHANGE_BATTLE_COMMANDS = 1009, + EVCMD_CHANGE_ENEMY_HP = 13110, + EVCMD_CHANGE_ENEMY_MP = 13120, + EVCMD_CHANGE_ENEMY_CONDITION = 13130, + EVCMD_REVIVE_ENEMY = 13150, + EVCMD_CHANGE_BACKDROP = 13210, + EVCMD_SHOW_BATTLE_ANIMATION_IN_BATTLE = 13260, //!< "Show Battle Animation" in battle events + EVCMD_ENABLE_COMBO = 1007, + EVCMD_FORCE_FLEE = 1006, + EVCMD_END_BATTLE = 13410, + EVCMD_FORK_IN_BATTLE = 13310, //!< First line of a "Conditional Branch" in battle events + EVCMD_FORK_IN_BATTLE_ELSE_CASE = 23310, //!< : Else Case line of a "Conditional Branch" in battle events + EVCMD_FORK_IN_BATTLE_END = 23311, //!< : End Case line of a "Conditional Branch" in battle events + EVCMD_CALL_COMMON_EVENT = 1005 //!< "Call Common Event" in battle events + }; + + /*! \brief Represents an event script line + + %Event script lines can have one string parameter and unlimited integer + parameters. + */ + class EventScriptLine { + public: + void **vTable; + EventCommand command; //!< The command type + int treeDepth; //!< The level of indention (\c 0 for none) + DStringPtr stringParameter; //!< The string parameter + DArray parameters; //!< The integer parameters + + /*! \brief Returns an integer parameter (\c 0 if the parameter doesn't exist) + \param index Parameter index (zero-based) + \return The parameter's value or \c 0 if the parameter doesn't exist + */ + int parameter(int index); + }; +} diff --git a/sdk/include/DynRPG/Image.h b/sdk/include/DynRPG/Image.h new file mode 100644 index 0000000..622b469 --- /dev/null +++ b/sdk/include/DynRPG/Image.h @@ -0,0 +1,223 @@ +namespace RPG { + //! \cond + class Image; + //! \endcond + + enum { + MASK_NONE = -1 //!< Used for RPG::Image::draw if no transparent color should be used + }; + + /*! \brief Color effect settings for RPG::Image objects + \sa RPG::Image + */ + class ColorControl { + public: + void **vTable; + Image *parentImage; //!< Pointer to the image to which the color effect belongs + int red; //!< Red value (\c 0 to \c 255) + int green; //!< Green value (\c 0 to \c 255) + int blue; //!< Blue value (\c 0 to \c 255) + int chroma; //!< Chroma value (\c 0 to \c 255) + }; + + /*! \brief Used for image buffers (8 bit) + + This class is the only class of which instances may be created by the + plugin developer, using the \ref create and \ref destroy methods. It is + used for all kinds of images (8 bit). There are two palette arrays: The + \ref palette array is used to store the actual 24-bit colors, and the + \ref appliedPalette array is used to store special calculated values + corresponding to the current screen brightness. It uses 16-bit colors. + The \ref applyPalette method is used to recalculate the + \ref appliedPalette values. The \ref appliedPaletteBrightness member + stores the brightness value for which the \ref appliedPalette was + created. If it doesn't equal to the current screen brightness, the + %RPG Maker will automatically call \ref applyPalette when the image is + drawn. + + I know that this is overkill and it would have been easier to + draw the images to the screen first and then reduce the brightness of + the pixels on the screen, but the %RPG Maker decided to do it this way. + \note Drawing images to a RPG::Canvas is very slow, as well as the + \ref drawText method. Please see the \ref optimization section! + \sa RPG::ColorControl + \sa RPG::Canvas + \sa RPG::Canvas::brightness + */ + class Image { + public: + void **vTable; + unsigned char *pixels; //!< Pointer to direct pixel data (stored from top to bottom) + int palette[256]; //!< Palette array (24 bit) + short appliedPalette[256]; //!< Processed palette array (16 bit - do not use directly) + int width; //!< Width of the image + int height; //!< Height of the image + bool useMaskColor; //!< If \c true, color \c 0 will be used as transparent color + int alpha; //!< Alpha value (\c 0 is invisible, \c 255 is fully visible) + bool autoResize; //!< If \c true, the image will automatically resize when loaded from a file + ColorControl *colorControl1; //!< First color effect + ColorControl *colorControl2; //!< Second color effect + int appliedPaletteBrightness; //!< Brightness for which the \ref appliedPalette was calculated + + //! Applies palette changes + void applyPalette(); + + /*! \brief Returns a reference to a certain pixel + \param x X coordinate of the pixel + \param y Y coordinate of the pixel + \return Reference to the pixel + */ + unsigned char &pixel(int x, int y); + + /*! \brief Frees the image and sets its size to zero + \sa init + \sa clear + \sa destroy + */ + void free(); + + /*! \brief Clears the image and initializes it to a new size + \param newWidth New image width + \param newHeight New image height + \sa free + */ + void init(int newWidth, int newHeight); + + /*! \brief Copies a palette to the image and applies it + \param newPalette Pointer to the palette array to copy + \sa setSystemPalette + \sa copy + */ + void setPalette(int* newPalette); + + /*! \brief Copies an RPG::Image with all its attributes to another + + Instead of *image2 = *image1;, you must use + image2->copy(image1);. + \param image The image to copy (source) + \sa draw(int, int, Image *, int, int, int, int, int) + \sa create(RPG::Image *) + */ + void copy(RPG::Image *image); + + /*! \brief Loads an image from a file + + This function will load an image from a BMP, PNG or XYZ file. + \param filename Path and filename of the file to load, + including folder name and file extension. + \param throwErrors If \c true, an error will be shown when the + image doesn't exist, otherwise the image will just be empty. + \param autoResize If \c true, the image will automatically resize + to the size of the image in the file. + */ + void loadFromFile(std::string filename, bool throwErrors = true, bool autoResize = true); + + /*! \brief Copies pixels into the image + \param x X coordinate to start drawing to + \param y Y coordinate to start drawing to + \param newPixels Pointer to the pixel data to copy + \param srcWidth Width of area to copy + \param srcHeight Height of the area to copy + \param srcLineWidth Width of a pixel row in the source image + \param maskColor Color which should be transparent (can also be + RPG::MASK_NONE) + \note Please also see the \ref optimization section! + \sa draw(int, int, RPG::Image *, int, int, int, int, int) + */ + void draw(int x, int y, unsigned char *newPixels, int srcWidth, int srcHeight, int srcLineWidth, int maskColor = 0); + + /*! \brief Draws another image (or a part of it) onto the image + + This part can be used to blit another image, or a certain part + of it. Please keep in mind that this will produce strange + results if the other image has a different palette. + \param x Upper-left X coordinate at the destination image + \param y Upper-left Y coordinate at the destination image + \param image %Image to draw + \param srcX Upper-left X coordinate at the source image + \param srcY Upper-left Y coordinate at the source image + \param srcWidth Width of the area to copy (defaults to the + whole image) + \param srcHeight Height of the area to copy (defaults to the + whole image) + \param maskColor Color which should be transparent (can also be + RPG::MASK_NONE) + \note Please also see the \ref optimization section! + \sa draw(int, int, unsigned char *, int, int, int, int) + */ + void draw(int x, int y, RPG::Image *image, int srcX = 0, int srcY = 0, int srcWidth = -1, int srcHeight = -1, int maskColor = 0); + + /*! \brief Clears the image without resizing or freeing it + \sa free + \sa destroy + */ + void clear(); + + /*! \brief Copies the palette from the system (necessary for + \ref drawText) + \sa drawText + \sa setPalette + */ + void setSystemPalette(); + + /*! \brief Draws text onto the image + + This method will draw text onto the image, using the current + system font and system graphic. Glyphs (like $A) work + too. + \param x Upper-left X position + \param y Upper-left Y position + \param text Text to draw + \param color Text color to use (\c 0 to \c 19) + \pre The image should have the same palette as the system + graphic (use \ref setSystemPalette). + \warning This method is quite slow. Do not use it too often. + Please also read the \ref optimization section!\n\n + In the image, there must be at least 8 pixels of extra space + to the right, otherwise it + will corrupt memory! The text itself needs 16 pixels vertically + and 6 pixels horizontally (per character). + \sa setSystemPalette + */ + void drawText(int x, int y, std::string text, int color); + + /*! \brief Creates an empty image + \return Pointer to the image + \sa create(int, int) + \sa create(RPG::Image *) + \sa destroy + */ + static RPG::Image *create(); + + /*! \brief Creates an image with a certain width and height + \param newWidth Width of the new image + \param newHeight Height of the new image + \return Pointer to the image + \sa create() + \sa create(RPG::Image *) + \sa destroy + \sa init + */ + static RPG::Image *create(int newWidth, int newHeight); + + /*! \brief Creates a copy of an image + \param templateImage %Image to copy + \return Pointer to the new image + \sa create() + \sa create(int, int) + \sa destroy + \sa copy + */ + static RPG::Image *create(RPG::Image *templateImage); + + /*! \brief Destroys an image + \param image Pointer to the image which should be destroyed + \note This function automatically sets the pointer to zero + after destroying the image. + \sa create + \sa free + \sa clear + */ + static void destroy(RPG::Image *&image); + }; +} diff --git a/sdk/include/DynRPG/Input.h b/sdk/include/DynRPG/Input.h new file mode 100644 index 0000000..1bd492c --- /dev/null +++ b/sdk/include/DynRPG/Input.h @@ -0,0 +1,113 @@ +namespace RPG { + /*! \brief %RPG Maker key names + \note The \c Shift key is handled differently by the %RPG Maker, thus + it can't be used the way other keys can be used by DynRPG. + \sa RPG::Input + \sa RPG::Input::pressed + \note Not all enumeration values are documented here, scroll to the top + to see all possible values (in the general enum overview)! + */ + enum Key { + KEY_DOWN, //!< Keys which are used for moving down + KEY_LEFT, //!< Keys which are used for moving left + KEY_RIGHT, //!< Keys which are used for moving right + KEY_UP, //!< Keys which are used for moving up + KEY_DECISION, //!< Keys which are used to confirm an action + KEY_CANCEL, //!< Keys which are used to cancel an action or open the menu + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_ADD, + KEY_SUBTRACT, + KEY_MULTIPLY, + KEY_DIVIDE, + KEY_DECIMAL + }; + + /*! \brief Used for key input + \sa RPG::input + */ + class Input { + public: + void **vTable; + int _unknown_4; + int _unknown_8; + /*! \brief Array of key codes assigned to the different RPG::Key + values (part 1) + + This array contains the key assignments for those key functions + which exist both in %RPG Maker 2000 and %RPG Maker 2003. Use + the \ref key method for easy access. + \sa keys2k3 + \sa RPG::Key + \sa key + */ + int keys[48]; + int _unknown_CC[32]; + /*! \brief Array of key codes assigned to the different RPG::Key + values (part 2) + + This array contains the key assignments for those key functions + which exist only in %RPG Maker 2003. Use the \ref key method + for easy access. + \sa keys + \sa RPG::Key + \sa key + */ + int keys2k3[120]; + + /*! \brief Provides easy access to the key assignments + + This function returns a pointer to the "block" of 8 key codes + in the \c keys or \c keys2k3 array which corresponds to the + given RPG::Key value. The result should be used with the + [] syntax with an index from \c 0 to \c 7. + + Example: + \code +RPG::input->key(RPG::KEY_DECISION)[3] = VK_TAB; + \endcode + This example would assign the \c TAB key as a new decision key + (the default decision keys are \c Enter, \c Space and \c Z, + indexes \c 3 to \c 7 are not assigned by default). + + The values used for key assignments are + virtual key codes, + zero meaning "not assigned". + \param keyId RPG::Key for which the key codes should be read or + changed + \return Pointer to the first key code used for this RPG::Key + \sa RPG::Key + */ + int *key(RPG::Key keyId); + + /*! \brief Checks whether a RPG::Key is pressed + + This function checks if one of the physical keys asiigned to a + RPG::Key is currently held down. This function does not use the + %RPG Maker's internal key cache. + \param keyId RPG::Key to check + \return \c true if the key is pressed, \c false otherwise + */ + bool pressed(RPG::Key keyId); + + /*! \brief Updates the %RPG Maker's internal key cache + + The %RPG Maker uses an internal key cache which is normally + updated every frame. This function updates the key cache. + */ + void update(); + }; + + /*! \ingroup game_objects + \brief Object used for key assignments and key input checking. + */ + static RPG::Input *&input = (**reinterpret_cast(0x4CDAEC)); +} diff --git a/sdk/include/DynRPG/Map.h b/sdk/include/DynRPG/Map.h new file mode 100644 index 0000000..a50de6c --- /dev/null +++ b/sdk/include/DynRPG/Map.h @@ -0,0 +1,64 @@ +namespace RPG { + //! Not implemented yet + typedef void Chipset; + + /*! \brief Used for accessing and manipulating the current map environment + \sa RPG::map + */ + class Map { + public: + void **vTable; + int cameraSubX; //!< X position of the camera in units of 1/16th of a pixel + int cameraSubY; //!< Y position of the camera in units of 1/16th of a pixel + int _unknown_C; + int _unknown_10; + Chipset *chipset; //!< Pointer to the map's chipset (not yet implemented) + NamedCatalogPtr events; //!< Array of events (use event ID as index) + + //! Returns the current X position of the camera in pixels (this value means the position of the upper-left screen pixel of the screen on the map) + int getCameraX(); + + //! Returns the current Y position of the camera in pixels (this value means the position of the upper-left screen pixel of the screen on the map) + int getCameraY(); + + /*! \brief Sets a new camera position + \param x New X position (pixels) + \param y New Y position (pixels) + \note This method also updates the camera "memory", so that the + "Return to origin" function works + */ + void setCamera(int x, int y); + + /*! \brief Moves the camera (pixel-exact) + + This function can move the camera the specified amount of + pixels in the specified speed. + \param offsetX Amount of pixels to move horizontally (may also be negative) + \param offsetY Amount of pixels to move vertically (may also be negative) + \param speed Exact speed, in units of 3.75 pixels per second (1/16 tile per frame) + \sa RPG::Character::customExactSpeed + */ + void moveCamera(int offsetX, int offsetY, int speed); + + //! Returns the width of the current map + int getWidth(); + + //! Returns the height of the current map + int getHeight(); + + /*! \brief Updates the start conditions of events after a change + + This function can be used to re-check the start conditions of + all events. This is necessary if you modify a switch from + DynRPG which is start condition of an event, for example. + */ + void updateEvents(); + }; + + /*! \ingroup game_objects + \brief The current map environment (camera, events, etc.) + + For accessing events, use RPG::map->events[event ID]. + */ + static RPG::Map *&map = (**reinterpret_cast(0x4CDD74)); +} diff --git a/sdk/include/DynRPG/Monster.h b/sdk/include/DynRPG/Monster.h new file mode 100644 index 0000000..31941d0 --- /dev/null +++ b/sdk/include/DynRPG/Monster.h @@ -0,0 +1,39 @@ +namespace RPG { + /*! \brief Used for monsters as subtype of battlers + \sa RPG::monsters + \sa RPG::Battler + \sa RPG::Actor + */ + class Monster : public Battler { // TLcfgMonsterItem + public: + // sizeof(Battler) == 0xD8 + int databaseId; //!< The database ID of the monster + Image *image; //!< The image of the monster's graphic + Image *imageMirrored; //!< The mirrored image of the monster's graphic (used when \ref RPG::Battler::mirrored is \c true) + /*! \brief Frames left until damage blinking is done + + If a monster takes damage, it blinks a few time. The blinking + is started by setting \c blinkTimer to the number of frames the + blinking should take. The \c blinkTimer is then increased by + one each frame (while the image will be shown and hidden + repeatedly), until it reaches zero at which point the blinking + will be stopped. + */ + int blinkTimer; + }; + + /*! \ingroup game_objects + \brief Array of monsters in the current monster group. + + Use the zero-based party member ID as index for accessing a monster. + + Example: + \code +int slimeHp = RPG::monsters[2]->hp; // read HP of third monster + \endcode + \sa RPG::Battler + \sa RPG::actors + \sa RPG::Actor::partyMember + */ + static RPG::CatalogPtr &monsters = (**reinterpret_cast **>(0x4CDE64)); +} diff --git a/sdk/include/DynRPG/MoveRoute.h b/sdk/include/DynRPG/MoveRoute.h new file mode 100644 index 0000000..1e4e68d --- /dev/null +++ b/sdk/include/DynRPG/MoveRoute.h @@ -0,0 +1,97 @@ +namespace RPG { + /*! \brief "Move event" command type + + A few of these commands take parameters, see details. For information + how to use these commands, see the RPG::Character::move documentation. + \sa RPG::Character::move + \note Not all enumeration values are documented here, scroll to the top + to see all possible values (in the general enum overview)! + */ + enum MoveType { + MT_MOVE_UP, + MT_MOVE_RIGHT, + MT_MOVE_DOWN, + MT_MOVE_LEFT, + MT_MOVE_UP_RIGHT, + MT_MOVE_DOWN_RIGHT, + MT_MOVE_DOWN_LEFT, + MT_MOVE_UP_LEFT, + MT_MOVE_RANDOMLY, + MT_MOVE_TOWARD_HERO, + MT_MOVE_AWAY_FROM_HERO, + MT_MOVE_FORWARD, + MT_FACE_UP, + MT_FACE_RIGHT, + MT_FACE_DOWN, + MT_FACE_LEFT, + MT_TURN_RIGHT, + MT_TURN_LEFT, + MT_TURN_AROUND, + MT_TURN_RANDOMLY, + MT_FACE_RANDOMLY, + MT_FACE_TOWARD_HERO, + MT_FACE_AWAY_FROM_HERO, + MT_WAIT, + MT_BEGIN_JUMP, + MT_END_JUMP, + MT_LOCK_FACING, + MT_UNLOCK_FACING, + MT_INCREASE_SPEED, + MT_DECREASE_SPEED, + MT_INCREASE_FREQUENCY, + MT_DECREASE_FREQUENCY, + /*! \brief Turns a switch ON + + This command takes one integer parameter: The switch ID. + \sa RPG::MT_SWITCH_OFF + \sa RPG::Switches + */ + MT_SWITCH_ON, + /*! \brief Turns a switch OFF + + This command takes one integer parameter: The switch ID. + \sa RPG::MT_SWITCH_ON + \sa RPG::Switches + */ + MT_SWITCH_OFF, + /*! \brief Changes the charset graphic of the character + + This command takes two parameters: +
  • The charset filename (string)
  • +
  • The charset sprite ID (integer)
+ */ + MT_CHANGE_GRAPHIC, + /*! \brief Plays a sound effect + + This command takes four parameters: +
  • The sound filename (string)
  • +
  • The sound volume (integer)
  • +
  • The sound speed (integer)
  • +
  • The sound pan value (integer)
+ \sa RPG::Sound + */ + MT_PLAY_SE, + MT_PHASING_MODE_ON, + MT_PHASING_MODE_OFF, + MT_STOP_ANIMATION, + MT_RESUME_ANIMATION, + MT_INCREASE_TRANSPARENCY, + MT_DECREASE_TRANSPARENCY + }; + + //! Not implemented yet + typedef void MoveRouteItem; + + /*! \brief Used for the move route of an character (also set by the "Move Event" command) + \sa RPG::MoveType + \sa RPG::Character::move + */ + class MoveRoute { + public: + void **vTable; + DListPtr moves; //!< List of movement commands (internal storage, not yet implemented) + DArray encodedMoves; //!< Encoded movement command list (see RPG::Character::move) + bool repeatPattern; //!< \c true if the movement should be repeated until RPG::Character::stop (or "Halt all movement") is called + bool ignoreImpossible; //!< \c true if impossible movement commands should be skipped + }; +} diff --git a/sdk/include/DynRPG/Music.h b/sdk/include/DynRPG/Music.h new file mode 100644 index 0000000..cfa909e --- /dev/null +++ b/sdk/include/DynRPG/Music.h @@ -0,0 +1,70 @@ +namespace RPG { + /*! \brief Used for background music settings + + This class is used to store the settings of a background music "item". + This class is one of the exceptions to the "do not instantiate" rule, + because it may be created and destroyed like any other C++ object. + However, RPG::Music pointers in RPG classes still shouldn't be + assigned, you have to use the \ref set method instead. + \sa set + \sa RPG::Sound + */ + class Music { + public: + void **vTable; + DStringPtr filename; //!< Filename + int fadeInTime; //!< Time to fade in (in milliseconds) + int volume; //!< Volume (\c 0 to \c 100) + int speed; //!< Speed (\c 100 is normal) + int pan; //!< Pan (\c 0 to \c 100, \c 50 is normal) + + //! Simple constructor, creates an \c (OFF) music item which will stop the music when played + Music(); + + /*! \brief Copy constructor + \param ref RPG::Music item to copy + \sa set + */ + Music(RPG::Music &ref); + + /*! \brief Extended constructor, creates a music item based on the given settings + \param filename Filename + \param fadeInTime Time to fade in + \param volume Volume + \param speed Speed + \param pan Pan value + */ + Music(std::string filename, int fadeInTime, int volume, int speed, int pan); + + //! Destructor + ~Music(); + + /*! \brief Sets a music item to the settings of another + + This method should be used to "assign" a music item to an + RPG::Music pointer in an RPG class. + + Example: + \code +RPG::Music newMusic("Boss1", 0, 100, 100, 50); +RPG::system->battleBGM->set(newMusic); + \endcode + \sa Music(RPG::Music &) + */ + void set(RPG::Music &ref); + + //! Plays the music + void play(); + + //! Stops the current music + static void stop(); + + /*! \brief Fades out the current music + \param time Duration (in milliseconds) + */ + static void fadeOut(int time); + + private: + void init(); + }; +} diff --git a/sdk/include/DynRPG/ParsedCommentData.h b/sdk/include/DynRPG/ParsedCommentData.h new file mode 100644 index 0000000..5e49505 --- /dev/null +++ b/sdk/include/DynRPG/ParsedCommentData.h @@ -0,0 +1,31 @@ +namespace RPG { + /*! \brief Type of a parsed comment parameter + \sa RPG::ParsedCommentParameter + \sa RPG::ParsedCommentData + */ + enum ParsedCommentParameterType { + PARAM_NUMBER, //!< The parameter is a number + PARAM_STRING, //!< The parameter is a string + PARAM_TOKEN //!< The parameter is a token + }; + + /*! \brief Used for parameters of parsed event comments (see \ref event_comments guidelines) + \sa RPG::ParsedCommentData + */ + class ParsedCommentParameter { + public: + ParsedCommentParameterType type; //!< Type of the parameter + double number; //!< Numerical value (if \c type is RPG::PARAM_NUMBER) + char text[200]; //!< Text value (if \c type is RPG::PARAM_STRING or RPG::PARAM_TOKEN) + }; + + /*! \brief Used for parsed event comments (see \ref event_comments guidelines) + \sa RPG::ParsedCommentParameter + */ + class ParsedCommentData { + public: + char command[200]; //!< Command name (empty if it's no "special" comment at all) + int parametersCount; //!< Number of parameters + ParsedCommentParameter parameters[100]; //!< Parsed parameters + }; +} diff --git a/sdk/include/DynRPG/Picture.h b/sdk/include/DynRPG/Picture.h new file mode 100644 index 0000000..c5183c2 --- /dev/null +++ b/sdk/include/DynRPG/Picture.h @@ -0,0 +1,147 @@ +namespace RPG { + //! Special effects for pictures + enum PictureEffect { + PFX_NONE, //!< No effect + PFX_ROTATE, //!< Rotation + PFX_RIPPLE //!< Ripple effect ("Waver") + }; + + /*! \brief Used for in-game pictures + + Pictures have two image buffers. The first one (\ref image) is + used for the top half of the image, the second one (\ref image2) + is used for the bottom half of the image. When the picture is + drawn, the second buffer is drawn on top of the first buffer. I know + that this is crazy, but it's the way the people from Enterbrain decided + to do it to allow two different transparency values (a feature which, + in my opinion, is also crazy and useless). Because this is impractical + for plugin developers, there is a method called \ref merge which will + draw the content of the bottom buffer on top of the top buffer and + clear the bottom buffer afterwards. You may still put your own stuff + into the \ref image2 buffer, it will be shown on top of \ref image, but + please remember that when the game is loaded, the %RPG Maker splits + the picture again. As a "marker" that the image is already merged + (so that you don't have to do it every frame), you might change a + palette entry of the bottom image. + \sa RPG::pictures + \sa RPG::Image + \sa RPG::PictureEffect + */ + class Picture { + public: + void **vTable; + int id; //!< Picture ID + int _unknown_8; + Image *image; //!< RPG::Image buffer of the top half (see class description) + Image *image2; //!< RPG::Image buffer of the bottom half (see class description) + DStringPtr filename; //!< Filename of the picture + double originX; //!< X coordinate of original position (changes automatically when "Move with map" is used) + double originY; //!< Y coordinate of original position (changes automatically when "Move with map" is used) + double x; //!< Current X coordinate on screen (use \c std::lround to convert to an integer!) + double y; //!< Current Y coordinate on screen (use \c std::lround to convert to an integer!) + bool moveWithMap; //!< Is "Move with map" active? + int _unknown_3C; + double magnification; //!< Current magnification + double transparency; //!< Current transparency for top half + double transparency2; //!< Current transparency for bottom half + bool useMaskColor; //!< Use a transparent color? + int _unknown_5C; + double red; //!< Current red color effect value + double green; //!< Current green color effect value + double blue; //!< Current blue color effect value + double chroma; //!< Current chroma color effect value + PictureEffect effect; //!< Current picture effect + int _unknown_84; + /*! \brief Strength of picture effect (see details) + + For RPG::PFX_ROTATE, negative values will rotate the picture + conter-clockwise, while zero will pause the rotation. + */ + double effectStrength; + double targetX; //!< Target X coordinate (if moving) + double targetY; //!< Target Y coordainte (if moving) + int targetMagnification; //!< Target magnification (if moving) + int targetTransparency; //!< Target transparency of the top half (if moving) + int targetTransparency2; //!< Target transparency of the bottom half (if moving) + int targetRed; //!< Target red color effect value (if moving) + int targetGreen; //!< Target green color effect value (if moving) + int targetBlue; //!< Target blue color effect value (if moving) + int targetChroma; //!< Target chroma color effect value (if moving) + int targetEffectStrength; //!< Target picture effect strength (if moving) + int movementTimer; //!< Number of frames left until movement is completed (zero means not moving) + int _unknown_C4; + double angle; //!< Current picture angle (\c 256 units equal to 360 degree!) + + //! Draws the content of the bottom buffer onto the top buffer and clears the bottom buffer afterwards + void merge(); + + /*! \brief Loads and shows a picture + \param filename Filename + \param x X position + \param y Y position + \param moveWithMap "Move with map" active? + \param magnification Magnification + \param transparency Top half transparency + \param transparency2 Bottom half transparency + \param useMaskColor Use a transparent color? + \param red Red color effect value + \param green Target green color effect value + \param blue Blue color effect value + \param chroma Chroma color effect value + \param effect Picture effect + \param effectStrength Picture effect strength + \warning This is an experimental function. + */ + void show( + std::string filename, int x, int y, bool moveWithMap, + int magnification, int transparency, int transparency2, + bool useMaskColor, int red, int green, int blue, int chroma, + RPG::PictureEffect effect, int effectStrength + ); + + /*! \brief Initiates a picture movement + \param x Target X position + \param y Target Y position + \param magnification Target magnification + \param transparency Target top half transparency + \param transparency2 Target bottom half transparency + \param red Target red color effect value + \param green Target green color effect value + \param blue Target blue color effect value + \param chroma Target chroma color effect value + \param effect New picture effect + \param effectStrength Target picture effect strength + \param duration Duration of the movement in frames + \warning This is an experimental function. + */ + void move( + int x, int y, int magnification, int transparency, int transparency2, + int red, int green, int blue, int chroma, RPG::PictureEffect effect, int effectStrength, + int duration + ); + + /*! \brief Erases a picture + \warning This is an experimental function. + */ + void erase(); + + /*! \brief Updates picture movement and effects + + This function can be used to update picture movement and + effects even in different game scenes than the map. + \warning If this function is called more than once per frame, + the movement or animation will be too fast. + */ + void update(); + + //! Draws a picture to the screen, even in different game scenes than the map + void draw(); + }; + + /*! \ingroup game_objects + \brief Array of pictures + + Use the picture ID as index for accessing a picture. + */ + static RPG::NamedCatalogPtr &pictures = (**reinterpret_cast **>(0x4CDF3C)); +} diff --git a/sdk/include/DynRPG/Screen.h b/sdk/include/DynRPG/Screen.h new file mode 100644 index 0000000..20bcff8 --- /dev/null +++ b/sdk/include/DynRPG/Screen.h @@ -0,0 +1,95 @@ +namespace RPG { + //! Not implemented yet + typedef void AuroraDrawMain; + + /*! \brief Used for the screen, including window properties and FPS + \sa RPG::screen + */ + class Screen { // TAuroraDraw + public: + void **vTable; + AuroraDrawMain *auroraDrawMain; //!< Not implemented yet + int _unknown_8; + int _unknown_C; + int _unknown_10; + int _unknown_14; + int _unknown_18; + int _unknown_1C; + int _unknown_20; + int _unknown_24; + int _unknown_28; + int _unknown_2C; + int _unknown_30; + int _unknown_34; + int _unknown_38; + bool fullScreen; //!< Is fullscreen active? + bool largeWindow; //!< Is the large window (640x480) active? + Canvas *canvas; //!< RPG::Canvas which should be used for drawing on the screen + int _unknown_44; + int _unknown_48; + int _unknown_4C; + int _unknown_50; + int _unknown_54; + int _unknown_58; + int _unknown_5C; + int _unknown_60; + int _unknown_64; + int _unknown_68; + int _unknown_6C; + int _unknown_70; + int _unknown_74; + int _unknown_78; + int _unknown_7C; + int _unknown_80; + int _unknown_84; + int _unknown_88; + int _unknown_8C; + int _unknown_90; + int _unknown_94; + int _unknown_98; + int _unknown_9C; + int _unknown_A0; + int _unknown_A4; + int _unknown_A8; + int _unknown_AC; + int _unknown_B0; + int _unknown_B4; + int _unknown_B8; + int _unknown_BC; + double millisecondsPerFrame; //!< Milliseconds a frame should take + int maxFPS; //!< Maximum FPS + + /*! \brief Returns the HWND of the window control on which the + screen is drawn + \note In windowed mode, this is not the window itself, but a + child of it. + */ + HWND getCanvasHWND(); + + /*! \brief Changes the framerate (and thus the overall speed of the + game) + + This function changes the speed of the whole game by changing + the number of frames rendered per second. The default is \c 60. + \param fps New framerate + */ + void setFPS(int fps); + + /*! \brief Redraws the screen for a certain scene + + This function completely redraws the screen and uses the + drawing method of the specified scene. Normally, you would use + the current scene for that. This function will also wait for + the next frame without using 100% CPU, so that you can use this + function to do something which takes longer than one frame. + \param scene Scene to draw + */ + void update(RPG::Scene scene); + }; + + /*! \ingroup game_objects + \brief The screen, including window properties, FPS and the drawing + canvas + */ + static RPG::Screen *&screen = (**reinterpret_cast(0x4CDB24)); +} diff --git a/sdk/include/DynRPG/Sound.h b/sdk/include/DynRPG/Sound.h new file mode 100644 index 0000000..37bc19b --- /dev/null +++ b/sdk/include/DynRPG/Sound.h @@ -0,0 +1,63 @@ +namespace RPG { + /*! \brief Used for sound effect settings + + This class is used to store the settings of a sound effect "item". + This class is one of the exceptions to the "do not instantiate" rule, + because it may be created and destroyed like any other C++ object. + However, RPG::Sound pointers in RPG classes still shouldn't be + assigned, you have to use the \ref set method instead. + \sa set + \sa RPG::Music + */ + class Sound { + public: + void **vTable; + DStringPtr filename; //!< Filename + int volume; //!< Volume (\c 0 to \c 100) + int speed; //!< Speed (\c 100 is normal) + int pan; //!< Pan (\c 0 to \c 100, \c 50 is normal) + + //! Simple constructor, creates an \c (OFF) sound item which will stop all sounds when played + Sound(); + + /*! \brief Copy constructor + \param ref RPG::Sound item to copy + \sa set + */ + Sound(RPG::Sound &ref); + + /*! \brief Extended constructor, creates a sound item based on the given settings + \param filename Filename + \param volume Volume + \param speed Speed + \param pan Pan value + */ + Sound(std::string filename, int volume, int speed, int pan); + + //! Destructor + ~Sound(); + + /*! \brief Sets a sound item to the settings of another + + This method should be used to "assign" a sound item to an + RPG::Sound pointer in an RPG class. + + Example: + \code +RPG::Sound newSound("Cursor2", 100, 100, 50); +RPG::system->cursorSE->set(newSound); + \endcode + \sa Sound(RPG::Sound &) + */ + void set(RPG::Sound &ref); + + //! Plays the sound + void play(); + + //! Stops all sounds + static void stop(); + + private: + void init(); + }; +} diff --git a/sdk/include/DynRPG/Switches.h b/sdk/include/DynRPG/Switches.h new file mode 100644 index 0000000..8781bf9 --- /dev/null +++ b/sdk/include/DynRPG/Switches.h @@ -0,0 +1,25 @@ +namespace RPG { + /*! \brief Provides easy access to in-game switches + + You may also use RPG::System::switches, but the RPG::Switches class + will also tolerate negative indexes and is less to type. + \sa RPG::switches + */ + class Switches { + public: + //! Array access operator + inline bool &operator[](int index) { + if(index > 0) return system->switches[index]; + return dummy = false; + } + + //! \cond + bool dummy; + //! \endcond + }; + + /*! \ingroup game_objects + \brief %Switches array + */ + static RPG::Switches switches __attribute__((unused)); +} diff --git a/sdk/include/DynRPG/System.h b/sdk/include/DynRPG/System.h new file mode 100644 index 0000000..b565bfd --- /dev/null +++ b/sdk/include/DynRPG/System.h @@ -0,0 +1,218 @@ +namespace RPG { + /*! \brief In-game scenes + + Each scene has its own drawing method and its own data. + You may also "invent" a new scene and draw its contents using the + \ref onFrame callback. + \sa onFrame + \sa RPG::Screen::update + */ + enum Scene { + SCENE_MAP, //!< %Map + SCENE_MENU, //!< Game menu + SCENE_BATTLE, //!< Battle + SCENE_SHOP, //!< Shop + SCENE_NAME, //!< %Hero naming screen + SCENE_FILE, //!< Save or load menu + SCENE_TITLE, //!< Title screen + SCENE_GAME_OVER, //!< Game over screen + SCENE_DEBUG //!< Debug screen (\c F9 menu) + }; + + //! One-byte version of RPG::Scene + typedef unsigned char Scene_T; + + /*! \brief Used to store the system and "system2" graphics + \sa RPG::System + \sa RPG::Image::setSystemPalette + */ + class SystemGraphic { + public: + void **vTable; + Image *systemImage; //!< \c %System image + int _unknown_8; + //! \cond + Canvas *font; + //! \endcond + int _unknown_10; + int _unknown_14; + Image *system2Image; //!< \c System2 image + + /*! \brief Loads the font used for text drawing + \param fontName Name of the font + \warning This is an experimental function. + */ + void loadFont(std::string fontName); + }; + + //! Possible values for RPG::System::messagePosition + enum MessagePosition { + MSGPOS_TOP, //!< Top + MSGPOS_MIDDLE, //!< Middle + MSGPOS_BOTTOM //!< Bottom + }; + + //! Possible values for RPG::System::facePosition + enum FacePosition { + FACEPOS_LEFT, //!< Left + FACEPOS_RIGHT //!< Right + }; + + //! Possible values for RPG::System::atbMode + enum ATBMode { + ATBM_ACTIVE, //!< "Active" mode (enemies also attack in selection menus) + ATBM_WAIT //!< "Wait" mode + }; + + //! One-byte version or RPG::ATBMode + typedef unsigned char ATBMode_T; + + + /*! \brief Used for system data which can change in-game + + \note Many things are only stored in this class if they were changed + and are now different from the default in the database, thus you + should use the getter methods to access these things. + \sa RPG::system + \sa RPG::DBSystem + \sa RPG::dbSystem + */ + class System { + public: + void **vTable; + Scene_T scene; //!< Current game scene (see RPG::Scene) + /*! \brief Internal frame counter (see details!) + + This frame counter will count every update of the game scene. + Please read the \ref onFrame documentation too! + \sa onFrame + */ + int frameCounter; + DStringPtr systemGraphicFilename; //!< Filename of the system graphic (empty for default) + bool systemTiled; //!< Is the window background tiled? + SystemFont systemFont; //!< Current system font + SystemGraphic *systemGraphic; //!< Current system and system2 graphic + DArray switches; //!< %Switches (see also RPG::Switches!) + DArray variables; //!< %Variables (see also RPG::Variables!) + bool messageTransparent; //!< Is the message background invisible? (see also RPG::BattleSettings::transparentWindows) + MessagePosition messagePosition; //!< Position of the message + bool messageAutoPos; //!< Prevent hero from being overlapped by a message? + bool messageModal; //!< Should messages pause other event activites? + DStringPtr faceFilename; //!< Filename of the current face + int faceID; //!< ID of the sprite in the faceset + FacePosition facePosition; //!< Position of the face + bool faceMirrored; //!< Is the face mirrored? + Image *faceImage; //!< RPG::Image of the face + bool messageActive; //!< Is a message active? + bool musicFade; //!< Is the music fading? + Music *currentBGM; //!< Current background music + Music *pedestrianBGM; //!< Background music which should be restored after the vehicle has been exited + Music *mapBGM; //!< Background music on the map (used to restore music after battle) + Music *memorizedBGM; //!< Memorized music + Music *titleBGM; //!< Current title screen music (empty for default) + Music *battleBGM; //!< Current battle music (empty for default) + Music *victoryBGM; //!< Current victory music (empty for default) + Music *innBGM; //!< Current inn music (empty for default) + Music *skiffBGM; //!< Current skiff music (empty for default) + Music *shipBGM; //!< Current ship music (empty for default) + Music *airshipBGM; //!< Current airship music (empty for default) + Music *gameOverBGM; //!< Current game over music (empty for default) + Sound *cursorSE; //!< Current cursor sound (empty for default) + Sound *decisionSE; //!< Current decision sound (empty for default) + Sound *cancelSE; //!< Current cancel sound (empty for default) + Sound *buzzerSE; //!< Current buzzer sound (empty for default) + Sound *battleStartSE; //!< Current sound played at battle start (empty for default) + Sound *fleeSE; //!< Current sound played when a battler escapes (empty for default) + Sound *enemyAttackSE; //!< Current sound played when a monster attacks (empty for default) + Sound *enemyDamageSE; //!< Current sound played when a monster is damaged (empty for default) + Sound *heroDamageSE; //!< Current sound played when an actor is damaged (empty for default) + Sound *evasionSE; //!< Current sound played when an attack is evaded (empty for default) + Sound *enemyDeathSE; //!< Current sound played when a monster is killed (empty for default) + Sound *itemSE; //!< Current sound played when an item is used (empty for default) + Transition_T teleportEraseTrans; //!< Current screen erasing transition on teleport (see RPG::Transition) + Transition_T teleportShowTrans; //!< Current screen showing transition on teleport (see RPG::Transition) + Transition_T battleStartEraseTrans; //!< Current screen erasing transition on battle start (see RPG::Transition) + Transition_T battleStartShowTrans; //!< Current screen showing transition on battle start (see RPG::Transition) + Transition_T battleEndEraseTrans; //!< Current screen erasing transition on battle end (see RPG::Transition) + Transition_T battleEndShowTrans; //!< Current screen showing transition on battle end (see RPG::Translation) + bool teleportAllowed; //!< Are teleport skills allowed? + bool escapeAllowed; //!< Are escaped skills allowed? + bool saveAllowed; //!< Is saving allows? + bool menuAllowed; //!< Is the game menu allowed? + DStringPtr defaultBackdrop; //!< Filename of default backdrop + int saveCount; //!< Number of times saved + int _unknown_C4; + ATBMode_T atbMode; //!< ATB mode + + #define defaultAccessorBGM(_member_, _function_) RPG::Music *_function_() + #define defaultAccessorSE(_member_, _function_) RPG::Sound *_function_() + #define defaultAccessorTrans(_member_, _function_) RPG::Transition _function_() + + //! Returns the current title screen music + defaultAccessorBGM(titleBGM, getTitleBGM); + //! Returns the current battle music + defaultAccessorBGM(battleBGM, getBattleBGM); + //! Returns the current victory music + defaultAccessorBGM(victoryBGM, getVictoryBGM); + //! Returns the current inn music + defaultAccessorBGM(innBGM,getInnBGM); + //! Returns the current skiff music + defaultAccessorBGM(skiffBGM, getSkiffBGM); + //! Returns the current ship music + defaultAccessorBGM(shipBGM, getShipBGM); + //! Returns the current airship music + defaultAccessorBGM(airshipBGM, getAirshipBGM); + //! Returns the current game over music + defaultAccessorBGM(gameOverBGM, getGameOverBGM); + + //! Returns the current cursor sound + defaultAccessorSE(cursorSE, getCursorSE); + //! Returns the current decision sound + defaultAccessorSE(decisionSE, getDecisionSE); + //! Returns the current cancel sound + defaultAccessorSE(cancelSE, getCancelSE); + //! Returns the current buzzer sound + defaultAccessorSE(buzzerSE, getBuzzerSE); + //! Returns the current battle start sound + defaultAccessorSE(battleStartSE, getBattleStartSE); + //! Returns the current escape sound + defaultAccessorSE(fleeSE, getFleeSE); + //! Returns the current monster attack sound + defaultAccessorSE(enemyAttackSE, getEnemyAttackSE); + //! Returns the current monster damage sound + defaultAccessorSE(enemyDamageSE, getEnemyDamageSE); + //! Returns the current actor damage sound + defaultAccessorSE(heroDamageSE, getHeroDamageSE); + //! Returns the current evasion sound + defaultAccessorSE(evasionSE, getEvasionSE); + //! Returns the current monster death sound + defaultAccessorSE(enemyDeathSE, getEnemyDeathSE); + //! Returns the current item sound + defaultAccessorSE(itemSE, getItemSE); + + //! Returns the current teleport screen erasing transition + defaultAccessorTrans(teleportEraseTrans, getTeleportEraseTrans); + //! Returns the current teleport screen showing transition + defaultAccessorTrans(teleportShowTrans, getTeleportShowTrans); + //! Returns the current battle start screen erasing transition + defaultAccessorTrans(battleStartEraseTrans, getBattleStartEraseTrans); + //! Returns the current battle start screen showing transition + defaultAccessorTrans(battleStartShowTrans, getBattleStartShowTrans); + //! Returns the current battle end screen erasing transition + defaultAccessorTrans(battleEndEraseTrans, getBattleEndEraseTrans); + //! Returns the current battle end screen showing transition + defaultAccessorTrans(battleEndShowTrans, getBattleEndShowTrans); + + #undef defaultAccessorBGM + #undef defaultAccessorSE + #undef defaultAccessorTrans + + }; + + /*! \ingroup game_objects + \brief Object of "system" data, used for values which can be changed + in-game + \sa RPG::dbSystem + */ + static RPG::System *&system = (**reinterpret_cast(0x4CDC7C)); +} diff --git a/sdk/include/DynRPG/Variables.h b/sdk/include/DynRPG/Variables.h new file mode 100644 index 0000000..327ae49 --- /dev/null +++ b/sdk/include/DynRPG/Variables.h @@ -0,0 +1,25 @@ +namespace RPG { + /*! \brief Provides easy access to in-game variables + + You may also use RPG::System::variables, but the RPG::Variables class + will also tolerate negative indexes and is less to type. + \sa RPG::variables + */ + class Variables { + public: + //! Array access operator + inline int &operator[](int index) { + if(index > 0) return system->variables[index]; + return dummy = 0; + } + + //! \cond + int dummy; + //! \endcond + }; + + /*! \ingroup game_objects + \brief %Variables array + */ + static RPG::Variables variables __attribute__((unused)); +} diff --git a/sdk/include/DynRPG/_Documentation.h b/sdk/include/DynRPG/_Documentation.h new file mode 100644 index 0000000..a701410 --- /dev/null +++ b/sdk/include/DynRPG/_Documentation.h @@ -0,0 +1,700 @@ +/*! + \mainpage About DynRPG + + \author David "Cherry" Trapp + + Also visit the main page, Cherry + Tree! + + \section download Download + Yes, this is the first paragraph, because I know people are looking for it + most of the time, probably. So be it. + + Click me hard! + + \section contact Contact + And yes, this is the second paragraph, because people seek this information + very often too. + + If you have any questions, you may either ask in of the following forum + threads: + + ...or write me an e-mail at dynrpg@cherrytree.at! + + Oh, and if you find errors in this documentation, or bugs in the patch or + the SDK, please tell me too! + + \section introduction Introduction + DynRPG is a plugin SDK for %RPG Maker 2003. "SDK" means "Standard Development + Kit", and in this case it means that everyone can create his own + extensions to the %RPG Maker software now, as long as he knows how to use + C++. DynRPG not only offers the average programmer access to the world of + "patching", but it also provides the basis for far more powerful extensions + than all "patches" made for the %RPG Maker before. + + DynRPG works using plugins. Plugins can be written in C++, they will be + loaded when the game starts and they are notified of certain events (like + the drawing of a new frame, the writing to a variable, etc.) and are + allowed to react to these events. + + What in past were "patches" are now going to be simple plugins. Any game + using DynRPG can be extended by a new feature by simply putting a plugin + file into a folder called \c DynPlugins. That's far easier than "patching", + something which many game makers are even afraid of, because they think it + might harm their game. And if somebody doesn't like a certain plugin, all + he needs to do is deleting it. + + So, DynRPG is beneficial to both plugin makers and game + makers: +
  • Plugin makers can use a simple C++ library to write powerful + plugins and distribute them to other game makers!
  • +
  • Game makers get many new possibilities just by adding these plugins + to their game!
  • +
  • Professional game makers are able to write plugins which exactly fit + to their game's needs, for example they might write part of their action + battle system in C++ or apply a custom design to the default battle + system, or maybe they even create a whole minigame using DynRPG... the + possibilities are endless!
+ + \section important_links Important links + Are you a game maker? Then look at \ref patch to find out how to + install and use the DynRPG Patch and what features it has! + + Are you a plugin maker? Then you might start with the + \ref getting_started section, and make sure you follow the \ref guidelines! + Of course, you can also explore the SDK documentation using the navigation + bar and the search function. The two main sections you need are the RPG + namespace and the \ref callbacks. + + \section parts Parts + The name "DynRPG" means this project as a whole... but actually, it consists + of several parts: +
  • The DynRPG Patch: This is the only real patch here. Yes, + I was not completely honest: The game makers don't get completely + rid of "patching", since they have to install this one patch. It is a + small patch for %RPG Maker 2003 version 1.08, which loads the DynRPG + Loader at startup, notifies it of game events and also applies several + bugfixes to the %RPG Maker. The DynRPG Loader then looks for plugins, + loads them and later forwards game events to them. The DynRPG Patch is + compatible with most of the other %RPG Maker 2003 patches out + there. More information here: \ref patch
  • +
  • The DynRPG Patcher: This simple tool installs the DynRPG + Patch for you.
  • +
  • The DynRPG Loader: That's a little DLL file called + \c dynloader.dll which is the middle-man between the DynRPG Patch + and the plugins.
  • +
  • The DynRPG SDK: That's the library and the C++ header files + which allow you to create your own plugins for DynRPG very easily. (If + you are no programmer but just a game maker looking for ready-made + plugins, you don't need to bother yourself with this.)
  • +
  • The plugins: Although not actually part of the DynRPG + project, the plugins are what makes the whole thing useful. They can + extend the features of the %RPG Maker (as in the past patches did), but + in a far more powerful way. A plugin is a simple DLL file which is + placed in the \c DynPlugins folder of a game.
+ + \section Credits + I want to thank Bananen-Joe for helping me when I had questions - + all the time since I got to know him... and also for his Destiny Patch + because it gave me the competition I needed. :-) + + I also want to thank MagicMaker for testing all my stuff before. + Although he wasn't able to test DynRPG itself, his contribution also + helped me with my previous research... and that research is the base + of DynRPG. + + And last but not least, I want to thank Crash-Override alias + WordsBG for trying to "own me" years ago when I created my first + "patch" (the RM2k(3) Font Changer)... I think if he hadn't challenged me, + I wouldn't have dug into reverse engineering and I would never have come + this far. (Explanation: After I published the font changer tool, he + created a thingy called "RM Binary Patcher" which basically did the same + as my font changer and Miroku's "Maker Ultimative" patcher combined. The + latter had several bugs, and because he commented his tool with "because + I just wanted to own you", I took that as a challenge and created a better + tool, Hyper Patcher 1, + which did the same as his tool, but without bugs and with more features. + He then admitted that I had won.) + + \page patch The Patch + \section installation_patch Installation + It couldn't be easier: You just run the patcher (that's the file called + \c dynrpg_patcher.exe), select your project's \c RPG_RT.exe file and that's + it, at least in most of the cases. DynRPG should be compatible with all + other 1.08-based patches. + + In case you don't have \c RPG_RT.exe version 1.08, the patcher will offer + you to install it. However, this will remove all existing modifications + (other patches, custom icon, etc.). But don't worry, in case anything goes + wrong there is always a backup (that's the file with the .bak + extension). If you install the patch "over" an existing (older) version of + the DynRPG Patch, there will also be a backup of the \c dynloader.dll + file. + + You don't need to include the backup files (ending with .bak) in + your finished game. Also, players don't need to install anything special to + run a game which uses DynRPG. + + The patcher will also automatically create a \c DynPlugins folder for you, + so you can immediately start adding and using plugins. + + \section features_patch Extra Features + Of course, the main feature of the DynRPG Patch is interfacing the DynRPG + Loader, which then loads the plugins. (See \ref parts for more information.) + \note You cannot use more than 50 plugins at the same time. + + But that's not everything, the patch also comes with several improvements + and bugfixes for the %RPG Maker: +
  • Improvement: More pictures! You can now use 2000 pictures instead of + 50, and pictures \#1001 to \#2000 are not erased when the player goes + to a new map! Please read the \ref more_pics section below to find + out what you need to know about this feature.
  • +
  • Improvement: On-the-fly application of IPS patches! + This means that IPS patches can now be used in a similar manner as plugins, + by simply copying them to a folder. This means they can easily be removed + again by deleting the file. Please read the \ref onthefly_ips section + for further details.
  • +
  • Improvement: Quickpatches! This feature allows you to + add simple patches as small lines of text which can easily be shared on + the Internet. Those simple patches can also be customized (such as having + a configurable value for something). Please read the \ref quickpatches + section below for detailed instructions!
  • +
  • Improvement: Monsters are now flashed more intensively + when they do their turn. Before, it was hard to follow what was going on + in battle, especially if a monster used the "Attack" command.
  • +
  • Improvement: Picture operations now also work while a message + is displayed. (Yes, that's the same thing the + UnlockPics Patch + does.)
  • +
  • Improvement: The game doesn't completely close when an error + occurs. Instead it goes back to the title screen.
  • +
  • Improvement: You can now press \c F11 to go to the save + menu at any time (in test play only).
  • +
  • Improvement: The "Input Number" event command will now use + the existing value in the variable as initial value. Before, it always + started with zero.
  • +
  • Improvement: When you press \c ESC at a "Show Choice" + command where the cancel behavior is set to "Ignore", now the buzzer + sound is played.
  • +
  • Improvement: Transparent message windows will now also work + with the "Traditional" battle layout (at least out of the battle). You + have to change the battle layout so that the "Transparent" checkbox + becomes enabled, check or uncheck it and then change the battle layout + back.
  • +
  • Bugfix: The game would crash when you removed an actor in + battle when this actor was the last to do his turn.
  • +
  • Bugfix: The "Enemy Attack" sound was never played. +
  • Bugfix: The game would crash if a skill was reflected on an + actor with an ID higher than the number of actors in the party.
  • +
  • Bugfix: The battle status window was gone while the skill + selection window was open.
  • +
  • Bugfix: If you had selected "Small Window" in the "Battle + Layout" tab of the database, the action selection window would only + display 3 lines plus an ugly empty one at the bottom and also the item + and skill selection windows would not display the last line correctly. + Additionally, the selection cursor for "Show choice" windows was + misaligned in battle.
  • +
  • Bugfix: The "Order" menu (used for rearranging party members) + didn't play the cancel sound when you exited.
  • +
  • Bugfix: When the shop system was used, the events weren't + updated, which means that if you bought an item in the shop, events + which used this item as start condition wouldn't execute + immediately.
  • +
  • Bugfix: HP display in the save menu was misaligned when the + HP had 4 digits.
  • +
  • Bugfix: The game would crash if the player would open the + item window in battle, then close it again using ESC and then execute + a battle command of type "Link to Event".
  • +
  • Bugfix: The game would crash with a "Division by zero" + error on certain edge cases of picture operations (especially pictures + with small zoom level partly outside the screen).
  • +
  • Bugfix: Enemies were flashed even when they executed the + "Do nothing" action.
+ + \section more_pics About the pictures + The DynRPG patch increases the picture limit to 2000. You might have heard + that Hyper Patcher 2 is + able to increase this limit to a crazy 9999, but this is not so healthy in + this case. Using that many pictures takes several seconds to load on + starting or loading a game or going to title screen, plus you would have + very bad performance with DynRPG because the DynRPG SDK allows plugins to + intercept picture drawing. Each plugin is called once before and once after + the picture is to draw, so you can imagine that 9999 pictures would mean 5 + times more plugin calls than 2000 pictures, so I decided that 2000 pictures + would be the best compromise. + + Please keep in mind that only pictures \#1 to \#1000 will be erased on + map change! The fact that pictures with an ID greater than 1000 won't be + erased automatically allows you to use pictures for cross-map purposes more + easily. + + However, there is one thing you need to do (unless you are already using + PicPointerPatch): You + need to modify the %RPG Maker editor itself too, otherwise you won't be able + to select picture IDs greater than 50 in the event editor. There are two + ways to do this: +
  • The easy way: You need to use + %RPG Maker 2009 Ultimate. + You then just need to create a file called \c morepictures.ini (or + whatever name you like) in %RPG Maker 2009 Ultimate's \c uimod folder + and put the following text into it: + \code +[FormEvCmd11110] +DialEdit1.MaxValue=100000 + +[FormEvCmd11120] +DialEdit1.MaxValue=100000 + +[FormEvCmd11130] +DialEdit1.MaxValue=100000 + \endcode + Then you need to edit the \c ultimate.ini file: Open it in a text + editor, go to the section [UIMod] and add your file at the end + of the section.
  • +
  • The hard way: If you do not want to use %RPG Maker 2009 + Ultimate, you need to directly edit your \c RPG2003.exe file: +
    1. Download + Resource + Hacker.
    2. +
    3. Open your \c RPG2003.exe file in it.
    4. +
    5. Navigate to RCDATA \> TFORMEVCMD11110 \> 0.
    6. +
    7. In the script on the right side, look for the following line: + \code +MaxValue = 50 + \endcode + If you have an older %RPG Maker version, it might be \c 40 + instead of \c 50. Increase this value, for example, to + \c 100000. The reason we use such a high value is that higher + values might be used for extra features (for example, with the + PicPointerPatch).
    8. +
    9. Click Compile Script.
    10. +
    11. Repeat steps 4 and 5 for the pages RCDATA \> TFORMEVCMD11120 + \> 0 and RCDATA \> TFORMEVCMD11130 \> 0. +
    12. Save your changes and exit Resource Hacker.
+ + \section onthefly_ips On-the-fly IPS patches + DynRPG can parse IPS files and apply them to the game in memory. This means + you can add IPS patches without actually modifying any file on your harddisk, + making it easy to remove the patch again. There is a folder \c DynPatches + in which the loader will look for IPS files and apply them on-the-fly. Please + note that the loader will fail to apply a patch if it tries to modify regions + of the \c RPG_RT.exe which would affect DynRPG itself or lie outside of the + areas which are mapped to memory. (Don't worry, nothing will explode, it will + just trigger an error message.) + + \section quickpatches Quickpatches + Quickpatches are simple text "codes" which instruct DynRPG to modify certain + bytes in the game's memory. They are added to a special section in your + \c DynRPG.ini file called [QuickPatches]. Each quickpatch has a name, + which can be arbitrary and is completely ignored by the loader. + + End users: Simply copy and paste a quickpatch from the Internet into + your [QuickPatches] section (create the section if it does not exist). + If you don't like it, remove it again or disable it by prepending a + semicolon. Quickpatches may contain configurable values, the developer + should normally tell you what their effect is. + + Developers: The format of quickpatches is very simple: + \code +PatchName=Address1,Values1,Address2,Values2,Address3,Values3,... + \endcode + You can specify one of more virtual address to modify, together with the + values to write to that address. These "values" may use one of those 3 + formats: +
  • Hex bytes: One or more bytes in simple two-digit hexadecimal + notation. For example, 401234,90 will write byte \c 0x90 at address + \c 0x401234, 401234,1A2B3C will write byte \c 0x1A at address + \c 0x401234, byte \c 0x2B at address \c 0x401235 and byte \c 0x3C at address + \c 0x401236.
  • +
  • 8-bit decimal value: Decimal value (may be negative) prepended by + a percent sign, which will occupy one byte. Meant to be easily customizable + by end users. For example, 401234,%32 will write byte \c 0x20 at + address \c 0x401234.
  • +
  • 32-bit decimal value: Decimal value (may be negative) prepended by + a sharp sign, which will occupy four bytes. Meant to be easily customizable + by end users. For example, 401234,#1000 will write byte \c 0xE8 at + address \c 0x401234, byte \c 0x03 at address \c 0x401235, and two \c 0x00 bytes + at addresses \c 0x401236 and \c 0x401237.
+ + Example for two "real-life" quickpatches: + \code +; Hides EXP in main menu and save screen +HideEXP=49E148,EB71,49F1CA,EB67,49F095,EB21 +; Moves the window on the title screen to coordinates 144/56 +MoveTitleWindow=490821,#144,490828,#56 + \endcode + For this example please note that the %RPG Maker uses the X coordinate for the + middle of the window, while the Y coordinate is used for the top of the window. + + \page guidelines Rules and guidelines for plugin developers + \section rules Rules + The %RPG Maker is written in Delphi (and I didn't have access to the source + code of its classes, etc.), while my SDK uses C++. Thus, many things are + not working the way you might expect. + + There is a set of rules which you must follow under all circumstances when + you are developing a DynRPG Plugin: +
  • Do not try to use members which are not documented. They + are either unknown or used internally and dangerous. (Of course, if you + know what a member does, it's a different story.)
  • +
  • Do not instantiate RPG classes. Always use pointers to + existing instances you get from DynRPG. It is especially dangerous to + use these "home-made" objects with functions from the RPG namespace. It + might seem to work, but will most likely corrupt data. This will cause + the game to behave strangely or suddenly crash some minutes later. + An exception to this rule are the RPG::Music and RPG::Sound + classes.
  • +
  • Do not assign RPG objects. The result is mostly undefined. + An exception are pointers to RPG::Image objects, as long as you don't + forget to destroy the old object using RPG::Image::destroy (unless you + want to use it before).
  • +
  • Do not randomly return \c false from a callback + function. This will "lock out" all plugins which are called after + yours. Only return \c false if you really want this behavior.
  • +
  • Never change the \c vTable member of a class. This will + make the game crash sooner or later (probably sooner).
  • +
  • Never assign a char * to an RPG::DString pointer. + It will appear to work, but it will cause the game to crash with an + "Invalid pointer operation" error when the %RPG Maker tries to free the + string. Also, do not store RPG::DStringPtr objects or RPG::DString + pointers inside your plugin, but copy their content to a + \c std::string instead, since RPG::DString objects may suddenly + vanish.
  • +
  • Do not change the current directory.
  • +
  • Do not do stuff every frame which takes longer than one + millisecond. This is alredy the very maximum. The less time + you use, the better. If you need to do something which takes + longer, do it in another thread. An exception are things which + happen only rarely, like when a game is loaded or saved, or once + when a battle starts, etc. If something should intentionally take + longer than one frame, you could use the \ref RPG::Screen::update or + RPG::updateBattle function, respectively.
+ + \section guidelines_sec Guidelines + There is also a set of guidelines which you are strongly advised to follow, + but there might be cases in which there is a better solution. + + \subsection event_comments Event comments + Comments in event scripts are a great way to let events scripts invoke + functions of your plugin. Please follow the following guidelines: +
  • Use the following pattern for "special comments": + \code +@command parameter1, parameter2, parameter3, ... + \endcode +
  • +
  • New-line characters should be generally ignored.
  • +
  • The comment has to start with an \@ sign, immediately + followed by the command name.
  • +
  • The command name is case-insensitive.
  • +
  • There should be three possible types of parameters: +
    • Number: A simple number. Can also use the decimal + point and the scientific notation (e.g. 5.5e+6 for 5.5 + million).
    • +
    • String: A simple string. Must be put between + doublequotes. To use a doublequote in a string, it is + written twice (e.g. He said ""hello"" and smiled)
    • +
    • Token: Some identifier. Tokens are not put between + quotes, and they may not contain spaces (spaces are removed). + Tokens are case-insensitive. They may be used for keywords.
    + There are special tokens for referencing variables and actor + names: +
    • Variables: To reference a variable, the user should + be able to write a \c V character prior to the variable ID. This + should also work with multiple levels of dereferencing.
    • +
    • Actor names: To reference an actor's name, the user + should be able to write a \c N character prior the the actor ID. + This should also work together with \c V.
    +
  • The command name and tokens should be case-insensitive.
  • +
  • Always return \c false from \ref onComment when you found + a known command, regardless whether the parameters were valid or + not.
  • +
  • Always return \c true from \ref onComment when you didn't + find a known command, even though you may have found an \@ + sign at the beginning of the comment.
+ + Use the \c parsedData parameter of your \ref onComment handler to get + the comment data in an already nicely parsed form! + \note The maximum number of parameters is 100. The maximum number of + characters per parameter (or command name) is 200. You have to parse the + comment yourself if you need more. + + Example for a "special" comment: + \code +@FooBar 123, "abc", V55, VV66, N7, NV8, Nothing + \endcode + The command name is \c foobar.\n + The first parameter is numerical.\n + The second parameter is a string.\n + The third parameter is a numerical value read from variable \#55.\n + The fourth parameter is a numerical value read from the variable + whose ID is stored in variable \#66.\n + The fifth parameter is a string, read from the name of actor \#7.\n + The sixth parameter is a string, read from the name of the actor + whose ID is stored in variable \#8.\n + The seventh parameter is a token named \c nothing. + + You might advise users to download + RPG Maker 2009 Ultimate + if they need to enter comments longer than 4 lines. + + \subsection configuration Configuration + Many plugins need some kind of configuration. An important rule is: + Make as many things configurable as possible. + + If possible, store configuration in a \c DynRPG.ini file. Also, + you should use your plugin's name which you get as parameter to the + \ref onStartup function as section name. If you need several sections, + you can append an underscore and an additional identifier to the name + and use it as section name. This will prevent conflicts with other + plugins while still combining all relevant configuration of a game in + one file. + + You may use the RPG::loadConfiguration function as a convenient way to + load configuration data to a std::map\ in the \ref onStartup function. + + If you need more or more complex configuration, like XML data, use a + filename containing your plugin's name. + + \subsection ingame_data In-game data + Your plugin may also use data which is changed in-game and needs to be + preserved. Savestate-independent data (like a highscore) should be + stored in the \c DynRPG.ini file together with configuration + (use the WinAPI function + WritePrivateProfileString). + + Savestate-related data (data which should be saved when the user saves + the game and loaded when the use loads a saved game) should be saved + using the function passed as \c savePluginData parameter to the + \ref onSaveGame function. When the user loads the savestate again, you + will get the same data back, in the parameters to the \ref onLoadGame + function. Internally, this data is saved in a file called + \c SaveXX.dyn where \c XX is the savestate ID. + + An example usage of savestate-related plugin data is shown here: + \code +// Plugin-related data +int score; +int level; + +// ... + +void onLoadGame(int id, char *data, int length) { + if(length == sizeof(int) * 2) { // make sure it is valid data + int *dataArray = (int *)data; + score = dataArray[0]; + level = dataArray[1]; + } +} + +void onSaveGame(int id, void __cdecl (*savePluginData)(char *data, int length)) { + int[2] dataArray; + dataArray[0] = score; + dataArray[1] = level; + savePluginData((char *)dataArray, sizeof(dataArray)); +} + \endcode + (Of course, the same result could have been achieved by saving \c score + and \c level in in-game variables which are automatically saved.) + + \subsection optimization Optimization + Time is a very important factor. Especially with many plugins, + it is important to use as little time as possible in your callback + handlers, otherwise the game will eventually start lagging. Thus, try to + optimize your code where you can. If possible, always test your plugin + with several other plugins in a "real-life situation" to see whether + your plugin slows the game down too much. Remember that most of your + code will be executed a minimum of 60 times per second (many parts more + often than that, for example \ref onCheckEventVisibility will be called + 900 times per second if there are 150 events on the map). + + Here is a bit of advice how to optimize your plugin code: +
  • Do not allocate and deallocate memory or objects over and + over again. Try to use static variables wherever + possible.
  • +
  • Try to use functions in the RPG::Image and RPG::Canvas classes + as little as possible. The slowest functions are + RPG::Image::drawText and RPG::Canvas::draw. +
  • Try to cache text in an RPG::Image if possible, only + update it if necessary.
  • +
  • Try to cache as much with the same palette as possible on + the same RPG::Image so that you don't have to call + RPG::Canvas::draw too often.
  • +
  • If possible, don't use a transparent color in + RPG::Image::draw (set \c maskColor to + RPG::MASK_NONE). The same rule applies for RPG::Canvas::draw, + see also RPG::Image::useMaskColor.
  • +
  • Try to skip frames if possible. This means: Try to update some + things only every 2 or 3 frames if possible.
  • +
  • If you are "WinAPI-literate", you can use the + RPG::Canvas::bitmap member and the + RPG::DBitmap::getHBITMAP and RPG::DBitmap::getHDC functions to get + handles to the corresponding GDI objects and manipulate them + directly.
  • +
  • If you need to calculate something more complex (like a 3D + image, etc.) you better do this in a new thread, cache its graphics + and draw them to the screen only after calculation was finished, + without letting the main thread wait.
+ + \page changelog Changelog + \section v0_20 Version 0.20 (2013/12/31) +
  • On-the-fly patching using IPS files or quick patches + in DynRPG.ini added. See the corresponding \ref onthefly_ips and + \ref quickpatches sections.
  • +
  • Partial Hyper Patcher 2 picture limit changing support removed, + it never worked correctly in the first place.
  • +
  • \c AUTO_DLLMAIN define removed, now a \c DllMain function is always + inserted by default, use \#define CUSTOM_DLLMAIN to prevent + this behaviour.
  • +
  • The automatic \c DllMain function now stores the plugin's instance + handle in the global variable \c hInstance (only if \c CUSTOM_DLLMAIN + is not defined).
  • +
  • Critical bug fixed: Game could hang when loading a game after + a new plugin has been added due to an infinite loop bug during \c Save??.dyn + file parsing.
  • +
  • Critical bug fixed: Transparency of events (including the hero) + behaved weirdly (changed depending on Y position) and was thus unusable. + This bug also slowed down the event rendering a lot.
  • +
  • Bug fixed: Class RPG::DList had members \c count and \c items + swapped. Because DynRPG classes need to have the same memory layout as the + %RPG Maker's internal Delphi counterparts, all accesses of RPG::DList + classes (most notably RPG::monsters) crashed the game.
  • +
  • Bug fixed: RPG::Catalog::count didn't work (tried to access + \c list.count where it should have been \c list.list->count, causing a + compiler error.)
  • +
  • Bug fixed: RPG::Image::copy was broken (didn't set the new image + size but silently leaked an RPG::Image instance instead).
  • +
  • Bug fixed: RPG::Actor and RPG::System methods sometimes returned + wrong strings (i.e. for RPG::Actor::getName) if they encountered a default + value in the database.
  • +
  • Bug fixed: Due to missing string termination, the + RPG::ParsedCommentParameter::text member of a comment command's last + parameter often had garbage appended at the end.
  • +
  • Bug fixed: Negative numbers in comment command parameters were + incorrectly parsed as RPG::PARAM_TOKEN instead of RPG::PARAM_NUMBER.
  • +
  • Bug fixed: RPG::Event::doesEventPageExist was broken.
  • +
  • Bug fixed: RPG::transparentWindowsEverywhere was + broken.
  • +
  • Modified library to work with newer GCC compilers. Now GCC version + 4.7.1 is required. (For tech-guys: Why the hell can GCC now use the \c ESP + register for an inline asm parameter with the \c "g" constraint?!)
  • +
  • Bug fixed: The "cross-map" pictures \#1001 to \#2000 were not + erased when a new game was started.
  • +
  • Fixed an %RPG Maker bug which caused the HP display in the save menu + to be misaligned when the HP had 4 digits.
  • +
  • Removed the longer skill/item window visibility "improvement" for most + scenarious because it turned out to disrupt battle event processing. + Only the info window shown when a monster executes a skill is still shown + longer, but now only for 50 frames (old DynRPG used 90 frames which + turned out to be annoyingly long, original %RPG Maker used 30 frames which + I think is too short to be readable).
  • +
  • Fixed an %RPG Maker bug which would cause the game to crash when + a "Link to Event" battle command was used right after the item menu + has been opened and then closed with ESC.
  • +
  • Added RPG::Actor::twoWeapons, RPG::Actor::lockEquipment, + RPG::Actor::autoBattle and RPG::Actor::mightyGuard fields.
  • +
  • RPG::System::pedestrianBGM added. Funny name, I know.
  • +
  • The maximum number of plugins has been raised from 30 to 50.
  • +
  • Bug fixed: Under some circumstances, the game would crash + during event command execution. It's hard to describe the exact triggers, + but they included "Erase event" commands in common events, loading a game + which was saved while a "Wait until key press" was active and some other, + rarer situations.
  • +
  • Fixed two %RPG Maker bugs with "Small window" mode in battle: The + action, item and skill selection windows had an empty line at the bottom + even though there would have been enough space. This was especially + confusing for the battle action window because it looked like the actor + had only 3 commands available. Also, the selection cursor for "Show choice" + windows in battle was not correctly aligned with the choice texts.
  • +
  • Removed the "higher action window" workaround for the small battle + window mode because a real fix has been implemented now.
  • +
  • Bug fixed: DynRPG would sometimes refuse to load a plugin + with no valid reason, depending on the constellation of files in the + DynPlugins directory.
  • +
  • Fixed an %RPG Maker bug which would crash the game with a "Division + by zero" error on certain edge cases of picture operations (especially + pictures with small zoom level partially outside the screen). This bug also + affected RPG::Canvas::drawCenteredZoomed.
  • +
  • Bug fixed: The enemy attack sound was also played if the enemy + wasn't doing anything at all. Additionally, sometimes sleeping or paralyzed + enemies would even flash white and the "Punch A" sound would play.
  • +
  • Fixed an %RPG Maker bug which caused enemies to be flashed even when + they executed the "Do nothing" action.
  • +
  • The \ref onDoBattlerAction callback has now a second parameter + \c firstTry which will be \c true only at the first attempt of executing + the action. This allows plugins to execute code only once per action. Before, + the \ref onDoBattlerAction callback could be called multiple times without + a way to distinguish between a new action and a new attempt to execute + the same action. Because the information about an action's success has + to be stored somewhere, the RPG::Action::userData2 member has been + repurposed and is now called RPG::Action::retrying. Old plugin DLLs which + are unaware of the new \c firstTry parameter will still work, but if any + old plugin tries to use the RPG::Action::userData2 member it will cause + problems. However I've got the impression that it's unlikely that there + is such a plugin out there.
  • +
  • The member RPG::Action::userData1 has been removed from public access + because I realized it's not a good idea to have generic fields without + defined purpose, as this could easily cause conflicts between different + plugins.
+ + \section v0_14a Version 0.14a (2012/02/15) + Only the SDK was updated. The patch still shows version 0.13b. +
  • RPG::Character::mapID was renamed to RPG::Character::mapId to + follow the naming convention used at all other places.
  • +
  • The documentation now doesn't show inherited members anymore unless + you click List of all members.
  • +
  • Bug fixed: RPG::Map::getWidth and RPG::Map::getHeight were + returning nonsense due to a typo (again).
+ + \section v0_14 Version 0.14 (2012/02/15) + Only the SDK was updated. The patch still shows version 0.13b. +
  • RPG::isBattleTest and RPG::showTitle added.
  • +
  • Critical bug fixed: The big bugfix done in version 0.13 created + new bugs because I forgot to update a few things in the changed \c asm + statements. Sorry for that.
  • +
  • Bug fixed: I had confused the parameters of RPG::Character::move.
  • +
  • Bug fixed: Nasty typo in RPG::encode caused it to produce garbage.
  • +
  • Type of \c message parameter of RPG::showError changed from char * + to std::string.
  • +
  • Type of \c data parameter of RPG::Character::move changed from char * + to const char*.
+ + \section v0_13b Version 0.13b (2012/02/15) +
  • Bug fixed: If version 0.13a was patched over version 0.13, + the game wouldn't start anymore. Patching 0.13b over 0.13a should fix the + problem.
+ \section v0_13a Version 0.13a (2012/02/13) +
  • Bug fixed: Due to a silly typo the game crashed as soon + as you would try to buy something in a shop.
+ \section v0_13 Version 0.13 (2012/02/11) +
  • Critical bug fixed: The \c asm statements in the SDK didn't + properly tell the compiler that the \c eax, \c edx and \c ecx registers may + be changed even though they often aren't used as output registers. This could + randomly lead to faulty code (depending on the surrounding code and the + compiler options) which would then result in strange crashes. Please + recompile all modules of your plugin with the new version of the header files + and the library!
  • +
  • Bug fixed: The RPG::ParsedCommentData::command string wasn't + terminated properly.
  • +
  • I realized that Code::Blocks is far better than Dev-C++ and changed the + \ref getting_started page accordingly.
  • +
  • The RPG::showError function was added.
+ + \section v0_12 Version 0.12 (2012/02/07) +
  • RPG::Canvas::drawStretched and RPG::Canvas::drawCenteredZoomed added.
  • +
  • Bug fixed: The DynRPG Patch caused the battle status window to be always + fully opaque in battle layout "alternative", even if "transparent" was + enabled. If the latter was the case, additionally the ATB bar wasn't + shown.
  • +
  • Added "Powered by" on top of the DynRPG logo.
+ + \section v0_11 Version 0.11 (2012/02/06) + Only the SDK was updated. The patch still shows version 0.10. +
  • RPG::BattleSettings class and RPG::battleSettings object added.
+ + \section v0_10 Version 0.10 (2012/02/05) + This is the first release. I started this project on 2012/01/23, by the way. Just in case somebody wants to know. +*/ +//! \defgroup game_objects Game objects diff --git a/sdk/include/DynRPG/_GettingStarted.h b/sdk/include/DynRPG/_GettingStarted.h new file mode 100644 index 0000000..4cbf29a --- /dev/null +++ b/sdk/include/DynRPG/_GettingStarted.h @@ -0,0 +1,374 @@ +/*! + \page getting_started Getting Started + + \note This page describes how to get started with the SDK. If you + want to know how to get started with the Patch, see \ref patch. + + \section sdk_preconditions The right C++ Compiler + The DynRPG SDK works on a very low level. This means, small differences + between compilers can break everything. The DynRPG was developed and tested + using GCC, thus you should use GCC too. + This DynRPG version only works with GCC version 4.7.1 and higher. + You might use the Code::Blocks + IDE, for example. + + \section sdk_installation Installation + Installing the SDK is easy - all you need to do is copying the files from + the \c include and \c lib directories of the download archive into the + corresponding folders of your compiler environment. + + \section sdk_header Header and library + In order to use the DynRPG in your C++ project, you need to include + DynRPG/DynRPG.h: + \code +#include + \endcode + \warning If you use more than one code module, you need to put the + following line before the include statement in all modules except one: + \code +#define NOT_MAIN_MODULE + \endcode + + DynRPG automatically creates a \c DllMain function for you which stores + the plugin's instance handle in a global variable called \c hInstance. + You can suppress this behaviour by defining \c CUSTOM_DLLMAIN before + including the header file. + + The header file automatically includes the headers \c string, \c map, + \c windows.h because they are needed for the declarations. + + \warning Since the %RPG Maker is Non-Unicode, your plugin should be + Non-Unicode too! + + You also need to add the library \c DynRPG (\c libDynRPG.a) to your + project. See your IDE's help file if you don't know how to do this. + (Normally you need to add the parameter -lDynRPG to the linker's + command line.) + + \section sdk_callbacks Callbacks + Together with the \ref sdk_game_objects, callbacks are important ways to + interface your plugin with the game. Callbacks are functions which you can + define in your plugin. On certain events in the game (for example, a + picture is drawn - see \ref onDrawPicture) certain callbacks will be + called by DynRPG. Callbacks either return \c void or \c bool. If you return + \c false in \c bool callbacks, this will prevent other plugins from + receiveing the same notification and sometimes it will also prevent some + event from happening in the game. For example, if you return \c false from + your \c onDrawPicture callback, the picture won't be drawn and other + plugins (after yours) won't receive \c onDrawPicture for that picture. + + You only need to define those callback functions which you actually use. + + For a list of available callbacks, click here: \ref callbacks + + \section sdk_game_objects Game objects + The game objects are the second important way to interface your plugin with + the game. Most of the RPG classes are tied to a game object and should only + be used through it. For example, the game object tied to RPG::Actor is + called RPG::actors. + + Game objects represent certain "things" in the game. For example, the + RPG::map object (the corresponding class is called RPG::Map) represents the + current map. So, to get the width of the current map, you may call the + RPG::Map::getWidth function like this: + \code +int mapWidth = RPG::map->getWidth(); + \endcode + + For a list of available game objects, click here: \ref game_objects + + \section sdk_hello_world Hello World - Our first plugin + It's time to create our first plugin. It's going to be really + simple - all it is going to do is displaying a message box asking whether + we really want to play before actually starting the game. We'll call + it \c are_you_sure. + + First, create an %RPG Maker 2003 project to test the plugin and apply + \ref patch to it. Then, create a new C++ project in your favorite IDE and + select DLL as project type. It might be convinient to store the + source code in a subfolder of the \c DynPlugins directory of your test + project and set the compiler output directory to the \c DynPlugins + directory. + + \warning If you are using Windows Vista or Windows 7, make sure you + have write access to your project directory! You better put it into + your \c Documents folder. Otherwise make sure you run both %RPG Maker + 2003 and your IDE (e.g. Code::Blocks) with administrator privileges! + + Okay, I'll be give a bit more step-by-step instructions now - of course + you can do it differently if you know how, but this should help people who + are not familiar with Code::Blocks to get started: +
  1. Download Code::Blocks here. + Make sure you select the "bigger" package which contains MinGW which + includes the GNU C++ compiler (which we need).
  2. +
  3. Install Code::Blocks. It's okay if you don't change the default + feature selection. Please remember or write down to path you are + installing Code::Blocks to (e.g. C:\\Program Files (x86)\\CodeBlocks)!
  4. +
  5. Open the path where you installed Code::Blocks in Windows Explorer.
  6. +
  7. There should be a subfolder called \c MinGW. Open it. There should be folders + called \c include and \c lib inside, among others.
  8. +
  9. Copy the \c include and \c lib folders from your DynRPG download + (in the \c sdk subfolder) into the \c MinGW folder. Confirm merging + the folders.
  10. +
  11. Start Code::Blocks.
  12. +
  13. Click Create new project....
  14. +
  15. Select Dynamic Link Library and click \c Go.
  16. +
  17. Click \c Next.
  18. +
  19. Enter the name of your plugin (here: \c are_you_sure). To avoid + problems later, do not use spaces.
  20. +
  21. In the second field, select the \c DynPlugins folder of your + RM2k3 test project. The actual filename of the Code::Blocks project + file (shown in the last field) should be similar to this: + C:\\Users\\My Username\\Documents\\My Test Project\\DynPlugins\\are_you_sure\\are_you_sure.cbp
  22. +
  23. Click \c Next.
  24. +
  25. Make sure GNU GCC Compiler is selected in the first field.
  26. +
  27. Uncheck Create "Debug" configuration. + \note Of course, if you know how you use them, you may create debug builds + too. As said, these step-by-step instructions are for beginners.
  28. +
  29. Change the Output dir. at the "Release" options to + ..\\ (two dots and then a backslash). This will create the plugin + DLL directly in the \c DynRPG folder if you have followed step 11 + correctly.
  30. +
  31. Click \c Finish.
  32. +
  33. Open the \c Project menu, select Build options....
  34. +
  35. Go to the Linker settings tab.
  36. +
  37. At the Link libraries section, click \c Add.
  38. +
  39. Enter DynRPG and click \c OK.
  40. +
  41. Go to the pre/post build steps tab.
  42. +
  43. Enter the following line into the bottom box: cmd /c del ..\*.a & del ..\*.def
  44. +
  45. Click \c OK again.
  46. +
  47. Open the \c Project menu, select Set programs' arguments....
  48. +
  49. Click the button at the right end of the Host application field + and select your game's \c RPG_RT.exe file. This will allow you to use the + \c Run and Build and run buttons in Code::Blocks to run your game.
  50. +
  51. If you want the game to automatically start in windowed test play mode + when you start it from Code::Blocks, put TestPlay ShowTitle Window into + the Program arguments field.
  52. +
  53. Click \c OK.
  54. +
  55. Now, Code::Blocks has created two files for you: \c main.cpp (find it in + the \c Sources folder of the tree view) and \c main.h (find it in the \c Headers + folder of the tree view). Delete the contents of both of them. In our examples, + we don't need the \c main.h file at all, you may right-click it and choose + Remove file from project if you want. In \c main.cpp, copy the + code provided below:
+ + \code +#include + +// Handler called on startup +bool onStartup(char *pluginName) { + if(MessageBox( + NULL, // We don't need a window handle + "This is such a haaaaard game. Are you SURE you want to play it now?", // Text + "The Are You Sure Plugin", // Title + MB_YESNO | MB_ICONQUESTION // Flags (yes/no buttons and question icon) + ) == IDYES) { + // The user clicked "Yes", we may continue + return true; + } else { + // The user clicked "No", so we need to abort + return false; + } +} + \endcode + Okay, that's really simple. It uses Windows' MessageBox + function to display a message. If the user clicked "Yes", the game will + continue, otherwise it will not start. + + This simple plugin uses the \ref onStartup callback. This callback is + called before the game starts. If you return \c false in this callback, + the game won't start. (You only need to define those callbacks which you + want to use.) + + So, if you compile this plugin, make sure the DLL file (\c are_you_sure.dll) + was put into the \c DynPlugins directory and your test project was + successfully patched using \ref patch, you should see the DynRPG logo when + you start the game, followed by our message box. + + By the way, the DynRPG logo cannot be removed. Yes, that's intentional. + + \section sdk_condition_icons Condition Icons - More Advanced + Enough of nonsense. Now we are going to create something useful. We are + going to create a plugin which displays the conditions of actors and + monsters over their head, as icons. + + These are its features: +
  • It will read the filenames of the icons from the configuration + file.
  • +
  • It will load the files on demand (when they are needed the first + time).
  • +
  • It will display them over the head of the battlers, horizontally + centered, vertically aligned at the bottom (in case the images don't + have the same height).
  • +
  • It will disable the default info window which is shown on target + selection so that we don't show the conditions twice.
+ + First, in the \ref onStartup handler, we will load the configuration and + store it in a global variable called \c configuration. + + Then, in the \ref onBattlerDrawn handler, we will iterate through all + conditions the battler has, check if the images we need are loaded, if not, + load them. We will also calculate the total width of all icons for that + battler here. Then we will draw all the icons and finally clear the + RPG::Battler::displayedConditions array so that no info window is displayed + when the target selection is active. + + Finally, in the \ref onExit handler, we will unload all images. + + This is the content of our \c condition_icons.cpp file: + \code +#include +#include // For std::stringstream + +// We store the configuration here +std::map configuration; + +// We store the images of the conditions here +std::map images; + +// This handler is called on startup +bool onStartup(char *pluginName) { + // We load the configuration from the DynRPG.ini file here + configuration = RPG::loadConfiguration(pluginName); + return true; // Don't forget to return true so that the start of the game will continue! +} + +// This handler is called after a battler is drawn +bool onBattlerDrawn(RPG::Battler *battler, bool isMonster, int id) { + int totalWidth = 0; // We store the total width of the condition icons here + + // We loop through all the elements of the battler's "conditions" array here + // Note that the "condition" array is one-based, thus we start at index 1 + for(int i = 1; i <= battler->conditions.size; i++) { + // If the battler has the condition (see documentation)... + if(battler->conditions[i] > 0) { + // If the image isn't loaded yet... + if(!images[i]) { + // First, we create an RPG::Image object + images[i] = RPG::Image::create(); + + // Yes, we want to use the transparent color + images[i]->useMaskColor = true; + + // Now, we put the key name for the configuration entry together + // It should be "Condition12" for condition 12, for example + std::stringstream keyName; + keyName << "Condition" << i; + + // Now, we try to load the image. If loading the image fails, + // nothing special will happen (because of the "false" at the + // "showErrors" parameter), the image will just be empty. + images[i]->loadFromFile(configuration[keyName.str()], false); + } + + // We add the image's width to the total width + totalWidth += images[i]->width; + } + } + + // Now we need to know the Y coordinate of the top of the battler + int topY; + if(isMonster) { + // It is a monster. We just use the monster's image to find out + // its size. + RPG::Monster *monster = (RPG::Monster *)battler; // First, we cast the "battler" to a "Monster" + topY = monster->y - monster->image->height / 2; // Now we calculate the top position + } else { + // Okay, since we don't have a way to find out the size of an actor's + // battle graphic, we will just "guess" that it's a normal BattleCharSet + // which is 48 pixels tall. + // In a "good" plugin, there would be a way to set the actual height + // for each actor in the configuration, but this would be too much + // for this tutorial. + topY = battler->y - 48 / 2; + } + + // We will use this variable to store the current X coordinate while we + // draw the images. We will increase this variable every time we draw an + // image. + int currentX = battler->x - totalWidth / 2; + + // Okay, let's loop again through the conditions. This is necessary + // because we first had to find out the total width before we could + // start drawing the images. Now we will draw them. + for(int i = 1; i <= battler->conditions.size; i++) { + // If the battler has the condition (see documentation)... + if(battler->conditions[i] > 0) { + // Okay, here we actually draw the image on the screen! + RPG::screen->canvas->draw(currentX, topY - images[i]->height, images[i]); + + // And we increase the current X coordinate. + currentX += images[i]->width; + } + } + + // Clear the condition cache which is normally used to determine which + // conditions should be shown in the "info window" on top of the screen + // during target selection (we don't need to display the conditions twice!) + for(int i = 0; i < 5; i++) { + battler->displayedConditions[i] = 0; + } + + return true; // It's okay that the battler is drawn, so we return true. Don't forget that! +} + +// This handler is called when the game exits +void onExit() { + // We will unload all images here. + // If you are not familiar with C++ iterators: This "for" loop just iterates + // through all items in "images". + for(std::map::const_iterator iter = images.begin(); iter != images.end(); ++iter ) { + // The reason we don't use images[iter->first] instead of iter->second + // is that RPG::Image::destroy also takes a reference and sets the + // parameter to zero at the end. + RPG::Image::destroy(images[iter->first]); + } +} + \endcode + + To try it, we just need to put the compiled DLL into the \c DynPlugins + folder (if it isn't already there). Then we need to get some icons. For + testing, I made some very simple 16x16 icons and put them into the + \c Picture folder. + + Then we need to open our DynRPG.ini and put the filenames in it, like this: + \code +[condition_icons] +Condition2=Picture\poison.png +Condition3=Picture\blind.png +Condition5=Picture\berserk.png +Condition6=Picture\confused.png +Condition7=Picture\sleep.png + \endcode + + And hey presto, this is what we get: + + + + You can download the source code as well as the finished plugin here. + + \section sdk_what_next What next? + You may now start developing your own plugins. You may first take a look + at the \ref callbacks, the \ref game_objects, and the members of the RPG + namespace, to get an overview of what is possible and how to get to the + result you want. Then, you might start with something easy (like a + DynRPG-based version of the PicPointerPatch - + hint: take a look at \ref onEventCommand, RPG::EventScriptLine and + \ref RPG::variables), then expand your knowledge until you can do nearly + everything you want... or something like that. :-) + + Yes, I know, I am just throwing you out into the wilderness. Sorry for + not providing you more examples how to use all the features. I just had + no time for it yet. If you are clever, you will probably be able to create + something useful with what you got in this documentation anyway. If not, + more examples will come. I will create nice plugins and publish them with + source code, etc. + + Oh, and don't forget to read and follow the \ref guidelines! + + By the way: If you want to publish your plugin, it would be nice if you + would publish the source code too. + + Have fun!\n + Best regards, Cherry +*/ diff --git a/sdk/include/DynRPG/doxygen.cfg b/sdk/include/DynRPG/doxygen.cfg new file mode 100644 index 0000000..42bf75c --- /dev/null +++ b/sdk/include/DynRPG/doxygen.cfg @@ -0,0 +1,1784 @@ +# Doxyfile 1.7.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = DynRPG + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = v0.20 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "RM2k3 Plugin SDK" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = logo_small.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../../docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 15 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 23 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = _unknown_* \ + vTable + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = ../../sdk/dynrpg.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = ../../htmlhelp/hhc.exe + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = __declspec(dllexport)= \ + __attribute__((unused))= + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/sdk/include/DynRPG/logo_small.png b/sdk/include/DynRPG/logo_small.png new file mode 100644 index 0000000..5fd642b Binary files /dev/null and b/sdk/include/DynRPG/logo_small.png differ