Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ add_library(${PROJECT_NAME} OBJECT
src/scene.cpp
src/scene_debug.cpp
src/scene_debug.h
src/scene_debug_picture.cpp
src/scene_debug_picture.h
src/scene_end.cpp
src/scene_end.h
src/scene_equip.cpp
Expand Down Expand Up @@ -420,6 +422,8 @@ add_library(${PROJECT_NAME} OBJECT
src/window_command.h
src/window_command_horizontal.cpp
src/window_command_horizontal.h
src/window_debug_picture.cpp
src/window_debug_picture.h
src/window.cpp
src/window_equip.cpp
src/window_equip.h
Expand Down
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ libeasyrpg_player_a_SOURCES = \
src/scene_battle_rpg2k3.h \
src/scene_debug.cpp \
src/scene_debug.h \
src/scene_debug_picture.cpp \
src/scene_debug_picture.h \
src/scene_end.cpp \
src/scene_end.h \
src/scene_equip.cpp \
Expand Down Expand Up @@ -426,6 +428,8 @@ libeasyrpg_player_a_SOURCES = \
src/window_numberinput.h \
src/window_paramstatus.cpp \
src/window_paramstatus.h \
src/window_debug_picture.cpp \
src/window_debug_picture.h \
src/window_savefile.cpp \
src/window_savefile.h \
src/window_selectable.cpp \
Expand Down
236 changes: 234 additions & 2 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4967,12 +4967,244 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con
return true;
}

bool Game_Interpreter::CommandManiacChangePictureId(lcf::rpg::EventCommand const&) {
bool Game_Interpreter::CommandManiacChangePictureId(lcf::rpg::EventCommand const& com) {
/*
TPC Structure Reference:
@pic[target1].setId .move(target2, size) .ignoreError
@pic[target1].setId .swap(target2, size) .ignoreError
@pic[target1].setId .slide(distance, size) .ignoreError

Parameters:
[0] Operation: 0 = Move, 1 = Swap, 2 = Slide
[1] Packing:
Bits 0-3: Target 1 Mode (0: Const, 1: Var, 2: Indirect)
Bits 4-7: Size Mode (0: Const, 1: Var, 2: Indirect)
Bits 8-11: Object 2 / Distance Mode (0: Const, 1: Var, 2: Indirect)
[2] Target 1 Value
[3] Size Value
[4] Object 2 / Distance Value
[5] Ignore Error (1 = Ignore)
*/

if (!Player::IsPatchManiac()) {
return true;
}

Output::Warning("Maniac Patch: Command ChangePictureId not supported");
int operation = com.parameters[0];
int target1 = ValueOrVariableBitfield(com, 1, 0, 2);
int size = ValueOrVariableBitfield(com, 1, 1, 3);
int arg3 = ValueOrVariableBitfield(com, 1, 2, 4); // Target 2 or Distance

bool ignore_error = com.parameters.size() > 5 && com.parameters[5] != 0;

if (size <= 0) {
return true;
}

auto& pictures = *Main_Data::game_pictures;
auto& windows = *Main_Data::game_windows;

auto isValidId = [](int id) {
return id > 0;
};

// Helper to move a single picture from src to dst
auto move_picture = [&](int src, int dst) {
// Ensure existence in vectors to avoid reference invalidation during assignments
int max_id = std::max(src, dst);
pictures.GetPicture(max_id);
windows.GetWindow(max_id);

auto& src_pic = pictures.GetPicture(src);
auto& dst_pic = pictures.GetPicture(dst);

// If source is empty, erase destination
if (!src_pic.Exists() && !src_pic.IsWindowAttached()) {
dst_pic.Erase();
return;
}

// 1. Handle Window Data (String Pictures)
if (src_pic.IsWindowAttached()) {
auto& src_win = windows.GetWindow(src);
auto& dst_win = windows.GetWindow(dst);
dst_win.data = src_win.data;
dst_win.data.ID = dst;
src_win.Erase();
}
else {
// If overwriting a window picture with a normal one, clear the old window data
// (Safe to call even if dst wasn't a window before)
windows.GetWindow(dst).Erase();
}

// 2. Handle Picture Data
BitmapRef src_bmp = src_pic.sprite ? src_pic.sprite->GetBitmap() : nullptr;
auto request_id = src_pic.request_id;
src_pic.request_id = nullptr; // Prevent cancellation on Erase

dst_pic.data = src_pic.data;
dst_pic.data.ID = dst;
dst_pic.request_id = request_id;

src_pic.Erase();

// 3. Refresh Sprite
if (dst_pic.IsWindowAttached()) {
// Re-attach window to generate sprite
bool async;
windows.GetWindow(dst).Refresh(async);
}
else if (!dst_pic.data.name.empty()) {
if (!dst_pic.sprite) dst_pic.CreateSprite();
if (src_bmp) {
dst_pic.sprite->SetBitmap(src_bmp);
dst_pic.sprite->OnPictureShow();
dst_pic.sprite->SetVisible(true);
}
}
else {
dst_pic.sprite.reset();
}
};

// Helper to swap two pictures
auto swap_picture = [&](int id1, int id2) {
// Ensure existence in vectors to avoid reference invalidation during assignments
int max_id = std::max(id1, id2);
pictures.GetPicture(max_id);
windows.GetWindow(max_id);

auto& p1 = pictures.GetPicture(id1);
auto& p2 = pictures.GetPicture(id2);

// Swap Window Data
auto& w1 = windows.GetWindow(id1);
auto& w2 = windows.GetWindow(id2);
std::swap(w1.data, w2.data);
w1.data.ID = id1;
w2.data.ID = id2;

// Swap Picture Data
BitmapRef b1 = p1.sprite ? p1.sprite->GetBitmap() : nullptr;
BitmapRef b2 = p2.sprite ? p2.sprite->GetBitmap() : nullptr;

using std::swap;
swap(p1.data, p2.data);
swap(p1.request_id, p2.request_id);

p1.data.ID = id1;
p2.data.ID = id2;

// Refresh Sprites Helper
auto refresh = [&](Game_Pictures::Picture& p, BitmapRef bmp) {
if (p.IsWindowAttached()) {
bool async;
windows.GetWindow(p.data.ID).Refresh(async);
}
else if (!p.data.name.empty()) {
if (!p.sprite) p.CreateSprite();
if (bmp) {
p.sprite->SetBitmap(bmp);
p.sprite->OnPictureShow();
p.sprite->SetVisible(true);
}
}
else {
p.sprite.reset();
}
};

refresh(p1, b2);
refresh(p2, b1);
};

if (operation == 0 || operation == 2) {
// Move (0) or Slide (2)
int target2 = (operation == 0) ? arg3 : (target1 + arg3);

int start = 0;
int end = size;
int step = 1;

// Handle overlapping ranges
if (target2 > target1) {
start = size - 1;
end = -1;
step = -1;
}

for (int i = start; i != end; i += step) {
int src_id = target1 + i;
int dst_id = target2 + i;

if (!isValidId(src_id)) {
if (!ignore_error) {
Output::Warning("Maniac ChangePictureId {}: Invalid Picture ID {}", (operation == 0 ? "Move (Source)" : "Slide (Source)"), src_id);
return true;
}
continue;
}

if (!isValidId(dst_id)) {
if (!ignore_error) {
Output::Warning("Maniac ChangePictureId {}: Invalid Picture ID {}", (operation == 0 ? "Move (Dest)" : "Slide (Dest)"), dst_id);
return true;
}

// "If you use the "Ignore out-of-range errors" setting, moving from/to an out-of-range ID will be replaced by a simple delete operation."
// If destination is invalid, delete source.
auto& src_pic = pictures.GetPicture(src_id);
if (src_pic.Exists() || src_pic.IsWindowAttached()) {
pictures.Erase(src_id);
}
continue;
}

if (src_id != dst_id) {
move_picture(src_id, dst_id);
}
}
}
else if (operation == 1) {
// Swap
int target2 = arg3;

for (int i = 0; i < size; ++i) {
int id1 = target1 + i;
int id2 = target2 + i;

bool valid1 = isValidId(id1);
bool valid2 = isValidId(id2);

if (!valid1 && !ignore_error) {
Output::Warning("Maniac ChangePictureId Swap: Invalid Picture ID {}", id1);
return true;
}
if (!valid2 && !ignore_error) {
Output::Warning("Maniac ChangePictureId Swap: Invalid Picture ID {}", id2);
return true;
}

if (valid1 && valid2) {
swap_picture(id1, id2);
}
else if (valid1 && !valid2) {
// Valid swap with invalid -> erase valid
pictures.Erase(id1);
}
else if (!valid1 && valid2) {
// Invalid swap with valid -> erase valid
pictures.Erase(id2);
}
}
}
else {
Output::Warning("Maniac ChangePictureId: Unknown operation {}", operation);
}

Game_Map::SetNeedRefresh(true);

return true;
}

Expand Down
7 changes: 5 additions & 2 deletions src/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
std::shared_ptr<Scene> Scene::instance;
std::vector<std::shared_ptr<Scene> > Scene::old_instances;
std::vector<std::shared_ptr<Scene> > Scene::instances;
const char Scene::scene_names[SceneMax][12] =
const char Scene::scene_names[SceneMax][13] =
{
"Null",
"Title",
Expand All @@ -69,7 +69,8 @@ const char Scene::scene_names[SceneMax][12] =
"GameBrowser",
"Teleport",
"Settings",
"Language"
"Language",
"DebugPicture"
};

enum PushPopOperation {
Expand Down Expand Up @@ -116,6 +117,8 @@ lcf::rpg::SaveSystem::Scene Scene::rpgRtSceneFromSceneType(SceneType t) {
return lcf::rpg::SaveSystem::Scene_game_over;
case Debug:
return lcf::rpg::SaveSystem::Scene_debug;
case DebugPicture:
return lcf::rpg::SaveSystem::Scene_debug;
}
return lcf::rpg::SaveSystem::Scene(-1);
}
Expand Down
3 changes: 2 additions & 1 deletion src/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Scene {
Teleport,
Settings,
LanguageMenu,
DebugPicture,
SceneMax
};

Expand Down Expand Up @@ -203,7 +204,7 @@ class Scene {
static std::vector<std::shared_ptr<Scene> > old_instances;

/** Contains name of the Scenes. For debug purposes. */
static const char scene_names[SceneMax][12];
static const char scene_names[SceneMax][13];

/**
* Called by the graphic system to request drawing of a background, usually a system color background
Expand Down
6 changes: 6 additions & 0 deletions src/scene_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "scene_menu.h"
#include "scene_save.h"
#include "scene_map.h"
#include "scene_debug_picture.h"
#include "scene_battle.h"
#include "player.h"
#include "window_command.h"
Expand Down Expand Up @@ -621,6 +622,10 @@ void Scene_Debug::vUpdate() {
PushUiRangeList();
}
break;
case ePictureTool:
Scene::Push(std::make_shared<Scene_DebugPicture>());
mode = eMain;
return;
case eInterpreter:
if (sz == 3) {
auto action = interpreter_window->GetSelectedAction();
Expand Down Expand Up @@ -776,6 +781,7 @@ void Scene_Debug::UpdateRangeListWindow() {
addItem("Call MapEvent", Scene::Find(Scene::Map) != nullptr);
addItem("Call BtlEvent", is_battle);
addItem("Strings", Player::IsPatchManiac());
addItem("Pictures");
addItem("Interpreter");
addItem("Open Menu", !is_battle);
}
Expand Down
1 change: 1 addition & 0 deletions src/scene_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Scene_Debug : public Scene {
eCallMapEvent,
eCallBattleEvent,
eString,
ePictureTool,
eInterpreter,
eOpenMenu,
eLastMainMenuOption,
Expand Down
Loading
Loading