Skip to content

Commit

Permalink
Merge pull request #3131 from drxgb/master
Browse files Browse the repository at this point in the history
Destiny Patch support
  • Loading branch information
Ghabry authored Nov 18, 2024
2 parents 2cb2956 + c079b72 commit d472587
Show file tree
Hide file tree
Showing 12 changed files with 933 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ add_library(${PROJECT_NAME} OBJECT
src/game_config.h
src/game_config_game.cpp
src/game_config_game.h
src/game_destiny.cpp
src/game_destiny.h
src/game_dynrpg.cpp
src/game_dynrpg.h
src/game_enemy.cpp
Expand Down
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ libeasyrpg_player_a_SOURCES = \
src/game_config.h \
src/game_config_game.cpp \
src/game_config_game.h \
src/game_destiny.cpp \
src/game_destiny.h \
src/game_dynrpg.cpp \
src/game_dynrpg.h \
src/game_enemy.cpp \
Expand Down Expand Up @@ -736,6 +738,7 @@ test_runner_SOURCES = \
tests/game_character_flash.cpp \
tests/game_character_move.cpp \
tests/game_character_moveto.cpp \
tests/game_destiny.cpp \
tests/game_enemy.cpp \
tests/game_event.cpp \
tests/game_player_input.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/game_config_game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ void Game_ConfigGame::PrintActivePatches() {
};

add_bool(patch_easyrpg);
add_bool(patch_destiny);
add_bool(patch_dynrpg);
add_bool(patch_common_this_event);
add_bool(patch_unlock_pics);
Expand Down
1 change: 1 addition & 0 deletions src/game_config_game.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct Game_ConfigGame {
StringConfigParam engine_str{ "Engine", "", "Game", "Engine", std::string() };
BoolConfigParam fake_resolution{ "Fake Metrics", "Makes games run on higher resolutions (with some success)", "Game", "FakeResolution", false };
BoolConfigParam patch_easyrpg{ "EasyRPG", "EasyRPG Engine Extensions", "Patch", "EasyRPG", false };
BoolConfigParam patch_destiny{ "Destiny Patch", "", "Patch", "Destiny", false };
BoolConfigParam patch_dynrpg{ "DynRPG", "", "Patch", "DynRPG", false };
ConfigParam<int> patch_maniac{ "Maniac Patch", "", "Patch", "Maniac", 0 };
BoolConfigParam patch_common_this_event{ "Common This Event", "Support \"This Event\" in Common Events", "Patch", "CommonThisEvent", false };
Expand Down
343 changes: 343 additions & 0 deletions src/game_destiny.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

// Headers
#include "game_destiny.h"
#include "filefinder.h"

#ifndef EMSCRIPTEN
#include "exe_reader.h"
#endif // !EMSCRIPTEN
#include "output.h"

using Destiny::InterpretFlag;
using Destiny::MainFunctions::Interpreter;

using lcf::ToString;
using lcf::rpg::EventCommand;
using lcf::rpg::SaveEventExecFrame;


// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Game_Destiny implementations
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void Game_Destiny::Load()
{
// Do not load Destiny whether player cannot find "Destiny.dll"
if (! FileFinder::Game().Exists(DESTINY_DLL))
{
return;
}

uint32_t dllVersion = 0;
uint32_t language = 0;
uint32_t gameVersion = 0;
uint32_t extra = 0;
uint32_t dwordSize = 0;
uint32_t floatSize = 0;
uint32_t stringSize = 0;

#ifndef EMSCRIPTEN
Filesystem_Stream::InputStream exe = FileFinder::Game().OpenFile(EXE_NAME);

if (exe)
{
exe.seekg(0x00030689, std::ios_base::beg);
exe.read(reinterpret_cast<char*>(&stringSize), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&floatSize), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&dwordSize), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&extra), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&gameVersion), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&language), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
exe.read(reinterpret_cast<char*>(&dllVersion), sizeof(uint32_t));
exe.seekg(1, std::ios_base::cur);
}
#else
// TODO [XGB]: Find to manage Destiny initialization parameters on Emscripten
dllVersion = 0x20000;
language = Destiny::Language::ENGLISH;
gameVersion = 0x20000107;
extra = 0x01;
dwordSize = floatSize = stringSize = 0x64;
#endif // !EMSCRIPTEN

Initialize(dllVersion, language, gameVersion, extra, dwordSize, floatSize, stringSize);
}

Game_Destiny::Game_Destiny()
{
_dllVersion = {};
_gameVersion = {};
_language = Destiny::Language::DEUTSCH;
_extra = 0U;
_trueColor = 0U;
_decimalComma = false;
_rm2k3 = false;
_protect = false;
}

Game_Destiny::~Game_Destiny()
{
Terminate();
}

void Game_Destiny::Initialize(
uint32_t dllVersion,
uint32_t language,
uint32_t gameVersion,
uint32_t extra,
uint32_t dwordSize,
uint32_t floatSize,
uint32_t stringSize
)
{
_dllVersion = Destiny::Version(dllVersion);
_gameVersion = Destiny::Version(gameVersion);
_language = language <= 1
? static_cast<Destiny::Language>(language)
: Destiny::Language::ENGLISH;
_extra = extra;
_decimalComma = _language == Destiny::Language::DEUTSCH;

EvaluateExtraFlags();
CheckVersionInfo();

// Init containers
_dwords.resize(dwordSize);
_floats.resize(floatSize);
_strings.resize(stringSize);

// TODO: Init File container
// TODO: Init ClientSocket container

// Debug
Output::Debug("[Destiny] Initialized");
Output::Debug("[Destiny] Language: {}", _decimalComma ? "Deutsch" : "English");
Output::Debug("[Destiny] DLL Version: {}", _dllVersion.toString());
Output::Debug("[Destiny] Dwords: {}", dwordSize);
Output::Debug("[Destiny] Floats: {}", floatSize);
Output::Debug("[Destiny] Strings: {}", stringSize);
Output::Debug("[Destiny] RPG Maker version: {}", _rm2k3 ? 2003 : 2000);
}

void Game_Destiny::Terminate()
{
_dwords.clear();
_floats.clear();
_strings.clear();

// TODO [XGB]: Clear File container
// TODO [XGB]: Clear ClientSocket container
}

bool Game_Destiny::Main(SaveEventExecFrame& frame)
{
const char* script;
InterpretFlag flag;

script = _interpreter.MakeString(frame);
flag = InterpretFlag::IF_EXIT;

_interpreter.CleanUpData();
_interpreter.LoadInterpretStack();

while (! _interpreter.IsEndOfScript())
{
if (_interpreter.IsEndOfLine())
{
_interpreter.ScriptNextChar();
}

flag = _interpreter.Interpret();
if (flag == InterpretFlag::IF_EXIT)
{
break;
}
}

Output::Debug("DestinyScript Code:\n{}", script);
_interpreter.FreeString();

return true;
}

void Game_Destiny::EvaluateExtraFlags()
{
_trueColor = (_extra & Destiny::DF_TRUECOLOR) << 9;
_protect = _extra & Destiny::DF_PROTECT;
}

void Game_Destiny::CheckVersionInfo()
{
uint32_t gameVersionMajor;

gameVersionMajor = _gameVersion.major;

if (! (gameVersionMajor == 0x2000 || gameVersionMajor == 0x2003))
{
Output::Error("[Destiny]: {} is not a valid version", gameVersionMajor);
}

_rm2k3 = gameVersionMajor == 0x2003;
}


// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// MainFunctions / Interpreter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Interpreter::Interpreter()
{
CleanUpData();
_scriptPtr = nullptr;
}

const char* Interpreter::MakeString(SaveEventExecFrame& frame)
{
std::string code;

int32_t& current = frame.current_command;
const std::vector<EventCommand>& cmdList = frame.commands;
std::vector<EventCommand>::const_iterator it = cmdList.begin() + current++;

code = ToString((*it++).string);

while (it != cmdList.cend() && it->code == static_cast<int32_t>(EventCommand::Code::Comment_2))
{
code += '\n';
code += ToString((*it++).string);
++current;
}

_destinyScript = code;
return _scriptPtr = _destinyScript.data();
}

void Interpreter::FreeString()
{
_destinyScript = "";
_scriptPtr = _destinyScript.data();
}

void Interpreter::SkipWhiteSpace()
{
while (IsWhiteSpace(*_scriptPtr))
{
++_scriptPtr;
}
}

const size_t Interpreter::GetWordLen()
{
char* endPtr = _scriptPtr;

while (IsWordChar(*endPtr))
{
++endPtr;
}

return endPtr - _scriptPtr;
}

const InterpretFlag Interpreter::Interpret()
{
char* code;
//uint8_t flags[4];
InterpretFlag returnType;

size_t wordLen;

code = nullptr;
returnType = IF_COMMAND;

SkipSpace();
wordLen = GetWordLen();

return IF_EXIT;
}

void Interpreter::LoadInterpretStack()
{
//
}

void Interpreter::SkipSpace()
{
bool finished = false;
char next = '\0';

while (! finished)
{
if (! IsWhiteSpace(*++_scriptPtr))
{
if (*_scriptPtr == '/')
{
next = *(_scriptPtr + 1);

if (next == '/')
{
finished = LineComment();
}
else if (next == '*')
{
finished = BlockComment();
}
}
else
{
finished = true;
}
}
}
}

const bool Interpreter::LineComment()
{
_scriptPtr += 2;

while (*(++_scriptPtr))
{
if (*_scriptPtr == 0x0A)
{
return false;
}
}

return true;
}

const bool Interpreter::BlockComment()
{
_scriptPtr += 2;

while (*(++_scriptPtr))
{
if (*_scriptPtr == '*' && *(++_scriptPtr) == '/')
{
return false;
}
}

return true;
}
Loading

0 comments on commit d472587

Please sign in to comment.