Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a63fdba
Refactor & fix: Moved several instances of safe file name creation to…
florianessl Mar 4, 2025
a1979ac
Refactor: Moved some parts of the custom "Load/Save <slot>" code from…
florianessl Mar 4, 2025
b79fbcc
Refactor: Make execution of Ineluki scripts behave synchronously so e…
florianessl Mar 4, 2025
1747a81
Fix: Ineluki scripts could also be handled via PlayBGM (Fixes usage i…
florianessl Mar 4, 2025
4443002
Implemented some commonly used "ppcomp" commands and added a simple h…
florianessl Mar 4, 2025
ababdf6
KeyPatch: Only force synchronous mode when one of a few known externa…
florianessl Mar 4, 2025
2e77ba0
Added new AsyncOp "eLoadParallel" for emulating PowerPatch "LOAD" beh…
florianessl Mar 5, 2025
842ab86
KeyPatch: Implemented commonly encountered command "LS.DAT" (Calling …
florianessl Mar 5, 2025
892c692
Implemented support for the "BetterAEP" patch (Very common among game…
florianessl Mar 5, 2025
e88cc18
Fixing some GCC build issues that MSVC doesn't care about.
florianessl Mar 5, 2025
1648060
Commented out all the code related to checking for the new Ineluki-Sc…
florianessl Mar 5, 2025
558d6f3
Fix Emscripten build
florianessl Mar 5, 2025
a9573b5
Minor: Also print a compatility warning if PowerMode2003 is encountered.
florianessl Mar 5, 2025
0fb6ebe
BetterAEP: Emulate patch "CustomSaveLoad" which depends on BetterAEP
florianessl Mar 10, 2025
70579c2
Scene_Title: Refactor handling of command options:
florianessl Mar 10, 2025
fa01f3a
PPCOMP: Implemented setting of cursor position for subcommands "CallG…
florianessl Mar 10, 2025
ff87311
PPCOMP: Implemented command "SimulateKeyPress" (Needs testing)
florianessl Mar 23, 2025
99c559d
PPCOMP "CallTitleScreen": Comment out the title force flag
florianessl Mar 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ add_library(${PROJECT_NAME} OBJECT
src/game_pictures.h
src/game_player.cpp
src/game_player.h
src/game_powerpatch.cpp
src/game_powerpatch.h
src/game_quit.cpp
src/game_quit.h
src/game_screen.cpp
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ libeasyrpg_player_a_SOURCES = \
src/game_pictures.h \
src/game_player.cpp \
src/game_player.h \
src/game_powerpatch.cpp \
src/game_powerpatch.h \
src/game_screen.cpp \
src/game_screen.h \
src/game_strings.cpp \
Expand Down
12 changes: 10 additions & 2 deletions src/async_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class AsyncOp {
eTerminateBattle,
eSave,
eLoad,
eLoadParallel,
eYield,
eYieldRepeat,
eCloneMapEvent,
Expand Down Expand Up @@ -78,6 +79,9 @@ class AsyncOp {
/** @return a Load async operation */
static AsyncOp MakeLoad(int save_slot);

/** @return a LoadParallel async operation (to be used for patch compatibility) */
static AsyncOp MakeLoadParallel(int save_slot);

/** @return a Yield for one frame to e.g. fetch an important asset */
static AsyncOp MakeYield();

Expand Down Expand Up @@ -128,7 +132,7 @@ class AsyncOp {

/**
* @return the desired slot to save or load
* @pre If GetType() is not eSave or eLoad, the return value is undefined.
* @pre If GetType() is not eSave, eLoad, eLoadParallel, the return value is undefined.
**/
int GetSaveSlot() const;

Expand Down Expand Up @@ -220,7 +224,7 @@ inline int AsyncOp::GetBattleResult() const {
}

inline int AsyncOp::GetSaveSlot() const {
assert(GetType() == eSave || GetType() == eLoad);
assert(GetType() == eSave || GetType() == eLoad || GetType() == eLoadParallel);
return _args[0];
}

Expand Down Expand Up @@ -305,6 +309,10 @@ inline AsyncOp AsyncOp::MakeLoad(int save_slot) {
return AsyncOp(eLoad, save_slot);
}

inline AsyncOp AsyncOp::MakeLoadParallel(int save_slot) {
return AsyncOp(eLoadParallel, save_slot);
}

inline AsyncOp AsyncOp::MakeYield() {
return AsyncOp(eYield);
}
Expand Down
22 changes: 18 additions & 4 deletions src/filefinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,8 @@ bool FileFinder::HasSavegame() {
int FileFinder::GetSavegames() {
auto fs = Save();

for (int i = 1; i <= 15; i++) {
std::stringstream ss;
ss << "Save" << (i <= 9 ? "0" : "") << i << ".lsd";
std::string filename = fs.FindFile(ss.str());
for (int i = 1; i <= Player::Constants::MaxSaveFiles(); i++) {
std::string filename = fs.FindFile(GetSaveFilename(i));

if (!filename.empty()) {
return true;
Expand All @@ -411,6 +409,22 @@ int FileFinder::GetSavegames() {
return false;
}

std::string FileFinder::GetSaveFilename(int slot) {
std::stringstream ss;
ss << "Save" << (slot <= 9 ? "0" : "") << (slot) << ".lsd";
return ss.str();
}

std::string FileFinder::GetSaveFilename(const FilesystemView& fs, int slot, bool validate_exists) {
auto filename = GetSaveFilename(slot);
auto filename_fs = fs.FindFile(filename);

if (filename_fs.empty() && !validate_exists) {
return filename;
}
return filename_fs;
}

std::string find_generic(const DirectoryTree::Args& args) {
if (!Tr::GetCurrentTranslationId().empty()) {
auto tr_fs = Tr::GetCurrentTranslationFilesystem();
Expand Down
3 changes: 3 additions & 0 deletions src/filefinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ namespace FileFinder {
/** @returns Amount of savegames in the save directory */
int GetSavegames();

std::string GetSaveFilename(int slot);
std::string GetSaveFilename(const FilesystemView& fs, int slot, bool validate_exists = true);

/**
* Known file sizes
*/
Expand Down
18 changes: 18 additions & 0 deletions src/game_config_game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) {
patch_rpg2k3_commands.Lock(false);
patch_anti_lag_switch.Lock(0);
patch_direct_menu.Lock(0);
patch_better_aep.Lock(0);
patch_override = true;
continue;
}
Expand Down Expand Up @@ -155,6 +156,18 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) {
}
continue;
}
if (cp.ParseNext(arg, 1, { "--patch-better-aep", "--no-patch-better-aep" })) {
if (arg.ArgIsOn() && arg.ParseValue(0, li_value)) {
patch_better_aep.Set(li_value);
patch_override = true;
}

if (arg.ArgIsOff()) {
patch_better_aep.Set(0);
patch_override = true;
}
continue;
}
if (cp.ParseNext(arg, 6, "--patch")) {
// For backwards compatibility only
for (int i = 0; i < arg.NumValues(); ++i) {
Expand Down Expand Up @@ -229,6 +242,10 @@ void Game_ConfigGame::LoadFromStream(Filesystem_Stream::InputStream& is) {
if (patch_direct_menu.FromIni(ini)) {
patch_override = true;
}

if (patch_better_aep.FromIni(ini)) {
patch_override = true;
}
}

void Game_ConfigGame::PrintActivePatches() {
Expand Down Expand Up @@ -257,6 +274,7 @@ void Game_ConfigGame::PrintActivePatches() {
add_int(patch_maniac);
add_int(patch_anti_lag_switch);
add_int(patch_direct_menu);
add_int(patch_better_aep);

if (patches.empty()) {
Output::Debug("Patch configuration: None");
Expand Down
3 changes: 3 additions & 0 deletions src/game_config_game.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ struct Game_ConfigGame {
BoolConfigParam patch_common_this_event{ "Common This Event", "Support \"This Event\" in Common Events", "Patch", "CommonThisEvent", false };
BoolConfigParam patch_unlock_pics{ "Unlock Pictures", "Allow picture commands while a message is shown", "Patch", "PicUnlock", false };
BoolConfigParam patch_key_patch{ "Ineluki Key Patch", "Support \"Ineluki Key Patch\"", "Patch", "KeyPatch", false };
//BoolConfigParam patch_key_patch_no_async{ "Ineluki Key Patch", "Force KeyPatch scripts to behave synchronously", "Patch", "KeyPatch.NoAsync", false };
BoolConfigParam patch_rpg2k3_commands{ "RPG2k3 Event Commands", "Enable support for RPG2k3 event commands", "Patch", "RPG2k3Commands", false };
ConfigParam<int> patch_anti_lag_switch{ "Anti-Lag Switch", "Disable event page refreshes when switch is set", "Patch", "AntiLagSwitch", 0 };
ConfigParam<int> patch_direct_menu{ "Direct Menu", " Allows direct access to subscreens of the default menu", "Patch", "DirectMenu", 0 };
ConfigParam<int> patch_better_aep{ "BetterAEP", "Emulates the \"BetterAEP\" patch, commonly used for custom title screens.", "Patch", "BetterAEP", 0 };
ConfigParam<int> patch_custom_save_load{ "BetterAEP", "Emulates the \"BetterAEP\" addon which allows for saving/loading by save slot.", "Patch", "BetterAEP.CustomSaveLoad", 0 };

// Command line only
BoolConfigParam patch_support{ "Support patches", "When OFF all patch support is disabled", "", "", true };
Expand Down
64 changes: 48 additions & 16 deletions src/game_ineluki.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// Headers
#include "game_ineluki.h"
#include "game_powerpatch.h"
#include "async_handler.h"
#include "filefinder.h"
#include "utils.h"
Expand All @@ -27,6 +28,7 @@
#include "system.h"

#include <lcf/inireader.h>
#include <scene_load.h>

namespace {
#if defined(SUPPORT_KEYBOARD)
Expand Down Expand Up @@ -66,19 +68,28 @@ bool Game_Ineluki::Execute(const lcf::rpg::Sound& se) {

std::string ini_file = FileFinder::FindSound(se.name);
if (!ini_file.empty()) {
return Execute(ini_file);
Execute(ini_file);
return true;
} else {
Output::Debug("Ineluki: Script {} not found", se.name);
}
return false;
}

bool Game_Ineluki::Execute(std::string_view ini_file) {
AsyncOp Game_Ineluki::Execute(std::string_view ini_file) {
auto p = FileFinder::GetPathAndFilename(ini_file);
if (StartsWith(Utils::LowerCase(p.second), "saves.script")) {
// Support for the script written by SaveCount.dat
// It counts the amount of savegames and outputs the result
output_mode = OutputMode::Output;
output_list.push_back(FileFinder::GetSavegames());
return {};
}
auto ini_file_s = ToString(ini_file);

if (functions.find(ini_file_s) == functions.end()) {
if (!Parse(ini_file)) {
return false;
return {};
}
}

Expand All @@ -88,15 +99,7 @@ bool Game_Ineluki::Execute(std::string_view ini_file) {
if (cmd.name == "writetolog") {
Output::InfoStr(cmd.arg);
} else if (cmd.name == "execprogram") {
// Fake execute some known programs
if (StartsWith(cmd.arg, "exitgame") ||
StartsWith(cmd.arg, "taskkill")) {
Player::exit_flag = true;
} else if (StartsWith(cmd.arg, "SaveCount.dat")) {
// no-op, detected through saves.script access
} else {
Output::Warning("Ineluki ExecProgram {}: Not supported", cmd.arg);
}
return ExecProgram(Utils::LowerCase(cmd.arg));
} else if (cmd.name == "mcicommand") {
Output::Warning("Ineluki MciProgram {}: Not supported", cmd.arg);
} else if (cmd.name == "miditickfunction") {
Expand Down Expand Up @@ -156,7 +159,7 @@ bool Game_Ineluki::Execute(std::string_view ini_file) {
}
} else if (cmd.name == "getmouseposition") {
if (!mouse_support) {
return true;
return {};
}

Point mouse_pos = Input::GetMousePosition();
Expand All @@ -176,7 +179,7 @@ bool Game_Ineluki::Execute(std::string_view ini_file) {
} else if (cmd.name == "setmouseasreturn") {
// This command is only found in a few uncommon versions of the patch
if (!mouse_support) {
return true;
return {};
}
std::string arg_lower = Utils::LowerCase(cmd.arg);
if (arg_lower == "left") {
Expand All @@ -194,7 +197,7 @@ bool Game_Ineluki::Execute(std::string_view ini_file) {
} else if (cmd.name == "setmousewheelaskeys") {
// This command is only found in a few uncommon versions of the patch
if (!mouse_support) {
return true;
return {};
}
std::string arg_lower = Utils::LowerCase(cmd.arg);
if (arg_lower == "updown") {
Expand All @@ -210,7 +213,7 @@ bool Game_Ineluki::Execute(std::string_view ini_file) {
}
}

return true;
return {};
}

bool Game_Ineluki::ExecuteScriptList(std::string_view list_file) {
Expand Down Expand Up @@ -338,6 +341,13 @@ void Game_Ineluki::Update() {
if (mouse_support) {
UpdateMouse();
}
for (auto& [ key, frames ] : Game_PowerPatch::simulate_keypresses) {
if (frames == 0) {
continue;
}
Input::GetInputSource()->SimulateKeyPress(key);
frames--;
}
}

void Game_Ineluki::UpdateKeys() {
Expand Down Expand Up @@ -403,6 +413,28 @@ void Game_Ineluki::UpdateMouse() {
#endif
}

AsyncOp Game_Ineluki::ExecProgram(std::string_view command) {
// Fake execute some known programs
if (StartsWith(command, "exitgame") || StartsWith(command, "taskkill")) {
Player::exit_flag = true;
} else if (StartsWith(command, "savecount.dat")) {
// no-op, detected through saves.script access
} else if (StartsWith(command, "ls.dat")) {
// (arg1 commonly given for "LS.dat" refers to the version-dependent
// virtual address of the RPG_RT loading mechanism)
Scene::instance->SetRequestedScene(std::make_shared<Scene_Load>());
} else if (StartsWith(command, "ppcomp")) {
auto args = Utils::Tokenize(command, [&](char32_t c) { return std::isspace(c); });
if (args.size() > 1) {
return Game_PowerPatch::ExecutePPC(Utils::UpperCase(args[1]), Span<std::string>(args).subspan(2));
}
} else {
Output::Warning("Ineluki ExecProgram {}: Not supported", command);
}

return {};
}

void Game_Ineluki::OnScriptFileReady(FileRequestResult* result) {
auto it = std::find_if(async_scripts.begin(), async_scripts.end(), [&](const auto& a) {
return a.script_name == result->file;
Expand Down
5 changes: 4 additions & 1 deletion src/game_ineluki.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "keys.h"
#include "string_view.h"
#include "async_handler.h"
#include "async_op.h"

/**
* Implements Ineluki's Key Patch
Expand All @@ -52,7 +53,7 @@ class Game_Ineluki {
* @param ini_file INI file to execute
* @return Whether the file is a valid script
*/
bool Execute(std::string_view ini_file);
AsyncOp Execute(std::string_view ini_file);

/**
* Executes a file containing a list of script files.
Expand Down Expand Up @@ -97,6 +98,8 @@ class Game_Ineluki {
*/
bool Parse(std::string_view ini_file);

AsyncOp ExecProgram(std::string_view command);

struct InelukiCommand {
std::string name;
std::string arg;
Expand Down
Loading
Loading