Skip to content
50 changes: 50 additions & 0 deletions src/exe_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(c
uint32_t sectionsOfs = optional_header + GetU16(ofs + 0x14); // skip opt header
uint32_t data_directory_ofs = (format_pe32 ? 0x60 : 0x70);
resource_rva = GetU32(optional_header + data_directory_ofs + 16);

if (!resource_rva) {
// Is some kind of encrypted EXE -> Give up
return;
Expand All @@ -137,6 +138,7 @@ EXEReader::EXEReader(Filesystem_Stream::InputStream core) : corefile(std::move(c

if (secName == 0x45444F43) { // CODE
file_info.code_size = sectVs;
file_info.code_ofs = GetU32(sectionsOfs + 0x14);
} else if (secName == 0x52454843) { // CHER(RY)
file_info.cherry_size = sectVs;
} else if (secName == 0x50454547) { // GEEP
Expand Down Expand Up @@ -536,4 +538,52 @@ int EXEReader::FileInfo::GetEngineType(bool& is_maniac_patch) const {
return Player::EngineNone;
}

std::map<Player::GameConstantType, int32_t> EXEReader::GetOverriddenGameConstants() {
std::map<Player::GameConstantType, int32_t> game_constants;

auto apply_known_config = [&](Player::Constants::KnownPatchConfigurations conf) {
Output::Debug("Assuming known patch config '{}'", Player::Constants::kKnownPatchConfigurations.tag(static_cast<int>(conf)));
auto it_conf = Player::Constants::known_patch_configurations.find(conf);
assert(it_conf != Player::Constants::known_patch_configurations.end());

for (auto it = it_conf->second.begin(); it != it_conf->second.end(); ++it) {
game_constants[it->first] = it->second;
}
};

auto check_for_string = [&](uint32_t offset, const char* p) {
while (*p) {
if (GetU8(offset++) != *p++)
return false;
}
return true;
};

switch (file_info.code_size) {
case 0x9CC00: // RM2K 1.62
if (check_for_string(file_info.code_ofs + 0x07DAA6, "XXX" /* 3x "POP EAX" */)) {
apply_known_config(Player::Constants::KnownPatchConfigurations::StatDelimiter);
}
break;
case 0xC8E00: // RM2K3 1.0.8.0
// For all known Italian translations, the "WhiteDragon" patch seems to be the only one
// to translate this string in RPG_RT. So this segment can be used to reliably detect
// the patch without having to read all individual constant values from the EXE
if (check_for_string(file_info.code_ofs + 0x08EBE0, "NoTitolo")) {
apply_known_config(Player::Constants::KnownPatchConfigurations::Rm2k3_Italian_WD_108);
}
if (check_for_string(file_info.code_ofs + 0x09D279, "XXX" /* 3x "POP EAX" */)) {
apply_known_config(Player::Constants::KnownPatchConfigurations::StatDelimiter);
}
break;
case 0xC9000: // RM2K3 1.0.9.1
if (check_for_string(file_info.code_ofs + 0x09C5AD, "XXX" /* 3x "POP EAX" */)) {
apply_known_config(Player::Constants::KnownPatchConfigurations::StatDelimiter);
}
break;
}

return game_constants;
}

#endif
3 changes: 3 additions & 0 deletions src/exe_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ class EXEReader {
uint32_t geep_size = 0;
MachineType machine_type = MachineType::Unknown;
bool is_easyrpg_player = false;
uint32_t code_ofs = 0;

int GetEngineType(bool& is_maniac_patch) const;
void Print() const;
};

const FileInfo& GetFileInfo();

std::map<Player::GameConstantType, int32_t> GetOverriddenGameConstants();

private:
// Bounds-checked unaligned reader primitives.
// In case of out-of-bounds, returns 0 - this will usually result in a harmless error at some other level,
Expand Down
39 changes: 6 additions & 33 deletions src/game_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,47 +35,24 @@
#include "rand.h"
#include "algo.h"

constexpr int max_level_2k = 50;
constexpr int max_level_2k3 = 99;

int Game_Actor::MaxHpValue() const {
auto& val = lcf::Data::system.easyrpg_max_actor_hp;
if (val == -1) {
return Player::IsRPG2k() ? 999 : 9999;
}
return val;
return Player::Constants::MaxActorHpValue();
}

int Game_Actor::MaxSpValue() const {
auto& val = lcf::Data::system.easyrpg_max_actor_sp;
if (val == -1) {
return 999;
}
return val;
return Player::Constants::MaxActorSpValue();
}

int Game_Actor::MaxStatBattleValue() const {
auto& val = lcf::Data::system.easyrpg_max_stat_battle_value;
if (val == -1) {
return 9999;
}
return val;
return Player::Constants::MaxStatBattleValue();
}

int Game_Actor::MaxStatBaseValue() const {
auto& val = lcf::Data::system.easyrpg_max_stat_base_value;
if (val == -1) {
return 999;
}
return val;
return Player::Constants::MaxStatBaseValue();
}

int Game_Actor::MaxExpValue() const {
auto& val = lcf::Data::system.easyrpg_max_exp;
if (val == -1) {
return Player::IsRPG2k() ? 999999 : 9999999;
}
return val;
return Player::Constants::MaxExpValue();
}

Game_Actor::Game_Actor(int actor_id) {
Expand Down Expand Up @@ -744,11 +721,7 @@ int Game_Actor::GetAccessoryId() const {
}

int Game_Actor::GetMaxLevel() const {
int max_level = Player::IsRPG2k() ? max_level_2k : max_level_2k3;
if (lcf::Data::system.easyrpg_max_level > -1) {
max_level = lcf::Data::system.easyrpg_max_level;
}
return Utils::Clamp<int32_t>(max_level, 1, dbActor->final_level);
return Utils::Clamp<int32_t>(Player::Constants::MaxLevel(), 1, dbActor->final_level);
}

void Game_Actor::SetExp(int _exp) {
Expand Down
2 changes: 1 addition & 1 deletion src/game_actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ class Game_Actor final : public Game_Battler {

/**
* Sets exp of actor.
* The value is adjusted to the boundary 0 up 999999.
* The value is adjusted to the boundary 0 up to a maximum (dependent on engine type & patch).
* Other actor attributes are not altered. Use ChangeExp to do a proper
* experience change.
*
Expand Down
2 changes: 1 addition & 1 deletion src/game_battlealgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
#include "feature.h"

static inline int MaxDamageValue() {
return lcf::Data::system.easyrpg_max_damage == -1 ? (Player::IsRPG2k() ? 999 : 9999) : lcf::Data::system.easyrpg_max_damage;
return Player::Constants::MaxDamageValue();
}

Game_BattleAlgorithm::AlgorithmBase::AlgorithmBase(Type ty, Game_Battler* source, Game_Battler* target) :
Expand Down
11 changes: 11 additions & 0 deletions src/game_config_game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) {
}
continue;
}
if (cp.ParseNext(arg, 1, "--engine-path")) {
if (arg.NumValues() > 0) {
std::string path = arg.Value(0);
path = FileFinder::MakeCanonical(path, 0);
if (!path.empty()) {
engine_path.Set(path);
}
}
continue;
}
if (cp.ParseNext(arg, 0, "--no-patch")) {
patch_support.Set(false);
patch_dynrpg.Lock(false);
Expand Down Expand Up @@ -192,6 +202,7 @@ void Game_ConfigGame::LoadFromStream(Filesystem_Stream::InputStream& is) {

new_game.FromIni(ini);
engine_str.FromIni(ini);
engine_path.FromIni(ini);
fake_resolution.FromIni(ini);

if (patch_easyrpg.FromIni(ini)) {
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 @@ -37,6 +37,7 @@ struct Game_ConfigGame {

BoolConfigParam new_game{ "Start new game", "Skips the title screen and starts a new game directly", "Game", "NewGame", false };
StringConfigParam engine_str{ "Engine", "", "Game", "Engine", std::string() };
StringConfigParam engine_path{ "Engine Path", "Sets the executable to be used by the engine auto-detection", "Game", "EnginePath", 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 };
Expand Down
24 changes: 4 additions & 20 deletions src/game_enemy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,19 @@ Game_Enemy::Game_Enemy(const lcf::rpg::TroopMember* member)
}

int Game_Enemy::MaxHpValue() const {
auto& val = lcf::Data::system.easyrpg_max_enemy_hp;
if (val == -1) {
return Player::IsRPG2k() ? 9999 : 99999;
}
return val;
return Player::Constants::MaxEnemyHpValue();
}

int Game_Enemy::MaxSpValue() const {
auto& val = lcf::Data::system.easyrpg_max_enemy_sp;
if (val == -1) {
return 9999;
}
return val;
return Player::Constants::MaxEnemySpValue();
}

int Game_Enemy::MaxStatBattleValue() const {
auto& val = lcf::Data::system.easyrpg_max_stat_battle_value;
if (val == -1) {
return 9999;
}
return val;
return Player::Constants::MaxStatBattleValue();
}

int Game_Enemy::MaxStatBaseValue() const {
auto& val = lcf::Data::system.easyrpg_max_stat_base_value;
if (val == -1) {
return 999;
}
return val;
return Player::Constants::MaxStatBaseValue();
}

int Game_Enemy::GetStateProbability(int state_id) const {
Expand Down
6 changes: 3 additions & 3 deletions src/game_party.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,20 @@ int Game_Party::GetItemTotalCount(int item_id) const {
int Game_Party::GetMaxItemCount(int item_id) const {
const lcf::rpg::Item* item = lcf::ReaderUtil::GetElement(lcf::Data::items, item_id);
if (!item || item->easyrpg_max_count == -1) {
return (lcf::Data::system.easyrpg_max_item_count == -1 ? 99 : lcf::Data::system.easyrpg_max_item_count);
return Player::Constants::MaxItemCount();
} else {
return item->easyrpg_max_count;
}
}

void Game_Party::GainGold(int n) {
data.gold = data.gold + n;
data.gold = std::min<int32_t>(std::max<int32_t>(data.gold, 0), 999999);
data.gold = std::min<int32_t>(std::max<int32_t>(data.gold, 0), Player::Constants::MaxGoldValue());
}

void Game_Party::LoseGold(int n) {
data.gold = data.gold - n;
data.gold = std::min<int32_t>(std::max<int32_t>(data.gold, 0), 999999);
data.gold = std::min<int32_t>(std::max<int32_t>(data.gold, 0), Player::Constants::MaxGoldValue());
}

void Game_Party::AddItem(int item_id, int amount) {
Expand Down
8 changes: 4 additions & 4 deletions src/game_variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class Game_Variables {
using Variables_t = std::vector<Var_t>;

static constexpr int max_warnings = 10;
static constexpr Var_t min_2k = -999999;
static constexpr Var_t max_2k = 999999;
static constexpr Var_t min_2k3 = -9999999;
static constexpr Var_t max_2k3 = 9999999;
static constexpr Var_t min_2k = -999'999;
static constexpr Var_t max_2k = 999'999;
static constexpr Var_t min_2k3 = -9'999'999;
static constexpr Var_t max_2k3 = 9'999'999;

Game_Variables(Var_t minval, Var_t maxval);

Expand Down
Loading
Loading