Skip to content

Implement Maniacs Command 3009: ControlBattle#3295

Merged
Ghabry merged 6 commits into
EasyRPG:masterfrom
MakoInfused:ManiacControlBattle
Dec 21, 2024
Merged

Implement Maniacs Command 3009: ControlBattle#3295
Ghabry merged 6 commits into
EasyRPG:masterfrom
MakoInfused:ManiacControlBattle

Conversation

@MakoInfused

Copy link
Copy Markdown
Contributor

With all of these Control Battle events set:
image
image
image
image
image
image

Game developers have a way to inject events hooks into the battle system that might look something like this:
EasyRPG-ManiacsControlBattleCommand

This allows them to handle all kinds of events including:

  • ATB Changes (parallel process like event)
  • Health Changes (custom damage popup visualization)
  • Targets being selected (before turn event)
  • State Changes (custom status effects)
  • Other Stat Changes (custom stat change popup visualization)

One small difference from the maniacs version (Maniacs 210414) I use:
🐛 I unintentionally fixed a bug: when the battle begins in Maniacs, it only fire an event for the first state to change (or maybe it's just not waiting for the message box to close for the others?).
✅ In EasyRPG it will definitely provide the callback for all state changes, regardless of if it's at the beginning of the battle or during it and regardless of how many state changes happened. However, it works the same as maniacs in that it doesn't block the battle from ending in order to complete a callback.

Everything else should match identically.

My Testing Included:

  1. Every single variable value is sets before the callbacks.
  2. Every single callback.
  3. Every single callbacks handling of things that block it, such as event messages.

There was a lot to test with many different permutation combinations, so it's always possible something slipped. If so, please let me know. :)

@Ghabry Ghabry left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I havn't fully reviewed yet is this sub-interpreter stuff. Have to test this while running a real game in Maniacs vs Easy.

Comment thread src/game_interpreter_battle.h Outdated
Comment thread src/game_battle.h
Comment thread src/game_battlealgorithm.cpp Outdated
Comment thread src/game_battlealgorithm.cpp Outdated
Comment thread src/game_battlealgorithm.cpp Outdated
Comment thread src/game_battlealgorithm.cpp
Comment thread src/game_battlealgorithm.h Outdated
Comment thread src/game_interpreter_battle.cpp Outdated
Comment thread src/scene_battle_rpg2k3.h
Comment thread src/scene_battle_rpg2k3.cpp
…tles & dual attack not being represented. Also made stylistic changes requested by Ghabry.
@MakoInfused

Copy link
Copy Markdown
Contributor Author

What I havn't fully reviewed yet is this sub-interpreter stuff. Have to test this while running a real game in Maniacs vs Easy.

Sounds good, let me know if you need anything from me. I have a test project that I'm using if you like I can provide it for your testing. It's the same one I've used to create the gif in this pull request. I believe also @jetrotal tested it on Beloved Rapture, so using an existing project is also an option.

@MakoInfused MakoInfused requested a review from Ghabry November 23, 2024 16:39
@Ghabry

Ghabry commented Nov 24, 2024

Copy link
Copy Markdown
Member

besides that one comment this looks fine now. So after this no further code changes required by you. Thanks.

I will report back when I did some testing.

Comment thread src/scene_battle_rpg2k3.cpp Outdated
CreateEnemySprites();
CreateActorSprites();

Game_Battle::GetInterpreterBattle();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function has no side effects and the return value is ignored. Can be removed?

@Ghabry

Ghabry commented Dec 1, 2024

Copy link
Copy Markdown
Member

Besides Maniacs being strange when a message box is open this works for me 👍


And I made one more change:

I didn't want to push this directly to your branch as I want to have 2 more eyes to look at the code if this breaks anything xD:

By moving the ManiacBattleHookType::Targetting to Scene_Battle::ActionSelectedCallback it will work for the 2000 battle system.

And then I copy-pasted the event processing to the 2k battle event loop to make the hooks execute in 2k.

Made a quick test and this makes all callbacks work in a 2k battle except damage pop (2k has no floating numbers) and ATB change (makes no sense for 2k).

diff --git a/src/scene_battle.cpp b/src/scene_battle.cpp
index aaf6219f0..d388e8f5a 100644
--- a/src/scene_battle.cpp
+++ b/src/scene_battle.cpp
@@ -570,6 +570,21 @@ void Scene_Battle::RemoveCurrentAction() {
 void Scene_Battle::ActionSelectedCallback(Game_Battler* for_battler) {
 	assert(for_battler->GetBattleAlgorithm() != nullptr);
 
+	auto single_target = for_battler->GetBattleAlgorithm()->GetOriginalSingleTarget();
+	auto group_targets = for_battler->GetBattleAlgorithm()->GetOriginalPartyTarget();
+	// Target: 0 None, 1 Single Enemy, 2 All Enemies, 3 Single Ally, 4 All Allies
+	Game_Battle::ManiacBattleHook(
+		Game_Interpreter_Battle::ManiacBattleHookType::Targetting,
+		for_battler->GetType() == Game_Battler::Type_Enemy,
+		for_battler->GetPartyIndex(),
+		for_battler->GetBattleAlgorithm()->GetActionType(),
+		for_battler->GetBattleAlgorithm()->GetActionId(),
+		single_target
+			? (single_target->GetType() != Game_Battler::Type_Enemy ? 1 : 3)
+			: (group_targets->GetRandomActiveBattler()->GetType() != Game_Battler::Type_Enemy ? 2 : 4),
+		single_target ? single_target->GetPartyIndex() : 0
+	);
+
 	if (for_battler->GetBattleAlgorithm() == nullptr) {
 		Output::Warning("ActionSelectedCallback: Invalid action for battler {} ({})",
 				for_battler->GetId(), for_battler->GetName());
diff --git a/src/scene_battle_rpg2k.cpp b/src/scene_battle_rpg2k.cpp
index 1026e3c9d..9d61a317d 100644
--- a/src/scene_battle_rpg2k.cpp
+++ b/src/scene_battle_rpg2k.cpp
@@ -205,6 +205,12 @@ void Scene_Battle_Rpg2k::vUpdate() {
 			break;
 		}
 
+		// this is checked separately because we want normal events to be processed
+		// just not sub-events called by maniacs battle hooks.
+		if (state != State_Victory && state != State_Defeat && Game_Battle::ManiacProcessSubEvents()) {
+			break;
+		}
+
 		if (!CheckWait()) {
 			break;
 		}
diff --git a/src/scene_battle_rpg2k3.cpp b/src/scene_battle_rpg2k3.cpp
index 68f163f0f..c258d9094 100644
--- a/src/scene_battle_rpg2k3.cpp
+++ b/src/scene_battle_rpg2k3.cpp
@@ -2855,21 +2855,6 @@ void Scene_Battle_Rpg2k3::RowSelected() {
 }
 
 void Scene_Battle_Rpg2k3::ActionSelectedCallback(Game_Battler* for_battler) {
-	auto single_target = for_battler->GetBattleAlgorithm()->GetOriginalSingleTarget();
-	auto group_targets = for_battler->GetBattleAlgorithm()->GetOriginalPartyTarget();
-	// Target: 0 None, 1 Single Enemy, 2 All Enemies, 3 Single Ally, 4 All Allies
-	Game_Battle::ManiacBattleHook(
-		Game_Interpreter_Battle::ManiacBattleHookType::Targetting,
-		for_battler->GetType() == Game_Battler::Type_Enemy,
-		for_battler->GetPartyIndex(),
-		for_battler->GetBattleAlgorithm()->GetActionType(),
-		for_battler->GetBattleAlgorithm()->GetActionId(),
-		single_target
-			? (single_target->GetType() != Game_Battler::Type_Enemy ? 1 : 3)
-			: (group_targets->GetRandomActiveBattler()->GetType() != Game_Battler::Type_Enemy ? 2 : 4),
-		single_target ? single_target->GetPartyIndex() : 0
-	);
-
 	for_battler->SetAtbGauge(0);
 
 	if (for_battler == active_actor) {

@Ghabry Ghabry merged commit 3bd1298 into EasyRPG:master Dec 21, 2024
@MakoInfused MakoInfused deleted the ManiacControlBattle branch December 13, 2025 20:26
sevenc-nanashi pushed a commit to sevenc-nanashi/easyrpg-player that referenced this pull request May 31, 2026
Implement Maniacs Command 3009: ControlBattle
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants