diff --git a/src/app/asm/script.cc b/src/app/asm/script.cc index c55b1935..6203353f 100644 --- a/src/app/asm/script.cc +++ b/src/app/asm/script.cc @@ -10,6 +10,7 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "app/core/constants.h" #include "app/rom.h" @@ -18,30 +19,97 @@ namespace yaze { namespace app { namespace snes_asm { -absl::Status Script::ApplyPatchToROM(ROM& rom) { - char* data = (char*) rom.data(); - int size = 0; +static auto string_replace(std::string &str, const std::string &from, + const std::string &to) -> bool { + size_t start = str.find(from); + if (start == std::string::npos) return false; + + str.replace(start, from.length(), to); + return true; +} + +std::string GenerateBytePool(char mosaic_tiles[core::kNumOverworldMaps]) { + std::string to_return = ""; + int column = 0; + for (int i = 0; i < core::kNumOverworldMaps; ++i) { + std::string to_add = ""; + + // if start of line, define byte + if (i == 0 || i % 8 == 0) { + to_add += " db "; + } + + // set byte + to_add += "$00"; + if (mosaic_tiles[i] > 0) { + if (i == 0 || i % 8 == 0) { + to_add = " db $01"; + } else { + to_add = "$01"; + } + } + + // newline or comma separated + if (column == 7) { + column = 0; + to_add += " \n"; + } else { + column++; + to_add += ", "; + } + + to_return += to_add; + } + return to_return; +} + +absl::Status Script::ApplyPatchToROM(ROM &rom) { + char *data = (char *)rom.data(); + int size = rom.GetSize(); + int count = 0; if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) { - return absl::InternalError("Unable to apply patch"); + auto asar_error = asar_geterrors(&count); + auto full_error = asar_error->fullerrdata; + return absl::InternalError(absl::StrCat("ASAR Error: ", full_error)); } return absl::OkStatus(); } -absl::StatusOr Script::GenerateMosaicChangeAssembly( - std::array mosaic_tiles) { +absl::Status Script::GenerateMosaicChangeAssembly( + ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset) { std::fstream file("assets/asm/mosaic_change.asm", std::ios::out | std::ios::in); if (!file.is_open()) { return absl::InvalidArgumentError( "Couldn't open mosaic change template file"); } - std::stringstream assembly; - assembly << "org "; - assembly << kDefaultMosaicHook; - assembly << file.rdbuf(); + std::stringstream assembly; + assembly << file.rdbuf(); file.close(); - return assembly.str(); + + auto assembly_string = assembly.str(); + if (!string_replace(assembly_string, "", kMosaicChangeOffset)) { + return absl::InternalError( + "Mosaic template did not have proper `` to replace."); + } + + if (!string_replace( + assembly_string, "", + absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) { + return absl::InternalError( + "Mosaic template did not have proper `` to replace."); + } + + assembly_string += GenerateBytePool(mosaic_tiles); + patch_filename_ = "assets/asm/mosaic_change_generated.asm"; + std::ofstream new_file(patch_filename_, std::ios::out); + if (new_file.is_open()) { + new_file.write(assembly_string.c_str(), assembly_string.size()); + new_file.close(); + } + + return ApplyPatchToROM(rom); } } // namespace snes_asm diff --git a/src/app/asm/script.h b/src/app/asm/script.h index af6a9836..e5edcfe9 100644 --- a/src/app/asm/script.h +++ b/src/app/asm/script.h @@ -11,6 +11,7 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "app/core/constants.h" #include "app/rom.h" @@ -19,18 +20,19 @@ namespace yaze { namespace app { namespace snes_asm { -constexpr char kDefaultMosaicHook[] = "$02AADB"; +const std::string kMosaicChangeOffset = "$02AADB"; +constexpr int kSNESToPCOffset = 0x138000; class Script { public: - Script() { asar_init_with_dll_path("C:/Users/starw/Code/yaze/assets/asar.dll"); } + Script() { asar_init_with_dll_path("assets/libasar.dll"); } - absl::Status ApplyPatchToROM(ROM& rom); - - absl::StatusOr GenerateMosaicChangeAssembly( - std::array mosaic_tiles); + absl::Status GenerateMosaicChangeAssembly( + ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset); private: + absl::Status ApplyPatchToROM(ROM& rom); + int64_t patch_size_; std::string patch_filename_; std::string patch_contents_;