Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Maniacs Command 3009: ControlBattle #3295

Merged
merged 6 commits into from
Dec 21, 2024

Conversation

MakoInfused
Copy link
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. :)

Copy link
Member

@Ghabry Ghabry left a comment

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.

src/game_interpreter_battle.h Outdated Show resolved Hide resolved
src/game_battle.h Show resolved Hide resolved
src/game_battlealgorithm.cpp Outdated Show resolved Hide resolved
src/game_battlealgorithm.cpp Outdated Show resolved Hide resolved
src/game_battlealgorithm.cpp Outdated Show resolved Hide resolved
src/game_battlealgorithm.cpp Show resolved Hide resolved
src/game_battlealgorithm.h Outdated Show resolved Hide resolved
src/game_interpreter_battle.cpp Outdated Show resolved Hide resolved
src/scene_battle_rpg2k3.h Show resolved Hide resolved
src/scene_battle_rpg2k3.cpp Show resolved Hide resolved
…tles & dual attack not being represented. Also made stylistic changes requested by Ghabry.
@MakoInfused
Copy link
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
Copy link
Member

Ghabry commented Nov 24, 2024

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.

InitBattleCondition(Game_Battle::GetBattleCondition());
CreateEnemySprites();
CreateActorSprites();

Game_Battle::GetInterpreterBattle();
Copy link
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
Copy link
Member

Ghabry commented Dec 1, 2024

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
13 checks passed
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.

3 participants