diff options
| author | MegaMech <MegaMech@users.noreply.github.com> | 2025-12-16 15:45:10 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-16 15:45:10 -0700 |
| commit | 99b56300556434580ed23edc27e5e7d982751e47 (patch) | |
| tree | 17d614ceff265db085e2b236bbb4af86b527b445 /src | |
| parent | 1a5c79b641517e38d6a2925ba1f332dffdafc1e8 (diff) | |
Impl Triple Shells, fix CPU items (#597)
* Impl triple shell
* CPUs can throw greenshells backwards
---------
Authored-by: Luiz Henrique <luizlink64@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/actors/green_shell/update.inc.c | 6 | ||||
| -rw-r--r-- | src/code_80005FD0.c | 293 | ||||
| -rw-r--r-- | src/code_80005FD0.h | 10 | ||||
| -rw-r--r-- | src/racing/actors_extended.c | 31 |
4 files changed, 200 insertions, 140 deletions
diff --git a/src/actors/green_shell/update.inc.c b/src/actors/green_shell/update.inc.c index 891f0c943..bd8db149e 100644 --- a/src/actors/green_shell/update.inc.c +++ b/src/actors/green_shell/update.inc.c @@ -59,7 +59,7 @@ void update_actor_green_shell(struct ShellActor* shell) { controller = &gControllers[shell->playerId]; if ((controller->buttonDepressed & Z_TRIG) != 0) { controller->buttonDepressed &= ~Z_TRIG; - if (controller->rawStickY < -0x2D) { + if (controller->rawStickY < THROW_SHELL_BACKWARDS) { var_f2 = 8.0f; if (player->speed > 8.0f) { var_f2 = player->speed * 1.2f; @@ -71,14 +71,14 @@ void update_actor_green_shell(struct ShellActor* shell) { shell->velocity[0] = somePosVel[0]; shell->velocity[1] = somePosVel[1]; shell->velocity[2] = somePosVel[2]; - shell->state = 2; + shell->state = MOVING_SHELL; func_800C9060(shell->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04)); func_800C90F4(shell->playerId, (player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00)); add_green_shell_in_unexpired_actor_list(CM_FindActorIndex(shell)); return; } else { - shell->state = 1; + shell->state = RELEASED_SHELL; if (player->unk_0C0 > 0) { shell->rotAngle = 0x78E3; } else { diff --git a/src/code_80005FD0.c b/src/code_80005FD0.c index 5c597c9e4..9d49040d7 100644 --- a/src/code_80005FD0.c +++ b/src/code_80005FD0.c @@ -7092,7 +7092,7 @@ void cpu_decisions_branch_item(UNUSED s32 playerId, s16* branch, s32 itemId) { break; } - if (CVarGetInteger("gHarderCPU", 0) == 1) { + if (CVarGetInteger("gHarderCPU", false) == true) { switch (itemId) { case ITEM_NONE: value = -1; @@ -7109,12 +7109,12 @@ void cpu_decisions_branch_item(UNUSED s32 playerId, s16* branch, s32 itemId) { case ITEM_RED_SHELL: value = CPU_STRATEGY_ITEM_RED_SHELL; break; - // case ITEM_TRIPLE_GREEN_SHELL: - // value = CPU_STRATEGY_ITEM_TRIPLE_GREEN_SHELL; - // break; - // case ITEM_TRIPLE_RED_SHELL: - // value = CPU_STRATEGY_ITEM_TRIPLE_RED_SHELL; - // break; + case ITEM_TRIPLE_GREEN_SHELL: + value = CPU_STRATEGY_ITEM_TRIPLE_GREEN_SHELL; + break; + case ITEM_TRIPLE_RED_SHELL: + value = CPU_STRATEGY_ITEM_TRIPLE_RED_SHELL; + break; case ITEM_DOUBLE_MUSHROOM: value = CPU_STRATEGY_ITEM_DOUBLE_MUSHROOM; break; @@ -7222,7 +7222,7 @@ void cpu_use_item_strategy(s32 playerId) { } } else if (cpuStrategy->branch == CPU_STRATEGY_ITEM_BANANA) { cpuStrategy->actorIndex = use_banana_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { + if (cpuStrategy->actorIndex >= 0) { player->triggers |= DRAG_ITEM_EFFECT; cpuStrategy->branch = CPU_STRATEGY_HOLD_BANANA; cpuStrategy->timer = 0; @@ -7239,13 +7239,6 @@ void cpu_use_item_strategy(s32 playerId) { actor = GET_ACTOR(cpuStrategy->actorIndex); if ((!(BANANA_ACTOR(actor)->flags & 0x8000)) || (BANANA_ACTOR(actor)->type != ACTOR_BANANA) || (BANANA_ACTOR(actor)->state != HELD_BANANA) || (playerId != BANANA_ACTOR(actor)->playerId)) { - - // FAKE - if (!(BANANA_ACTOR(actor)->flags & 0x8000)) {} - if (BANANA_ACTOR(actor)->type != 6) {} - if (BANANA_ACTOR(actor)->state != 0) {} - if (BANANA_ACTOR(actor)->rot[0] != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; player->triggers &= ~DRAG_ITEM_EFFECT; @@ -7259,13 +7252,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(BANANA_ACTOR(actor)->flags & 0x8000)) || (BANANA_ACTOR(actor)->type != ACTOR_BANANA)) || (BANANA_ACTOR(actor)->state != HELD_BANANA)) || (playerId != BANANA_ACTOR(actor)->playerId)) { - - // FAKE - if (!(BANANA_ACTOR(actor)->flags & 0x8000)) {} - if (BANANA_ACTOR(actor)->type != 6) {} - if (BANANA_ACTOR(actor)->state != 0) {} - if (BANANA_ACTOR(actor)->rot[0] != playerId) {} - } else { BANANA_ACTOR(actor)->state = DROPPED_BANANA; BANANA_ACTOR(actor)->velocity[0] = 0.0f; @@ -7284,7 +7270,7 @@ void cpu_use_item_strategy(s32 playerId) { case CPU_STRATEGY_THROW_BANANA: cpuStrategy->actorIndex = use_banana_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { + if (cpuStrategy->actorIndex >= 0) { actor = GET_ACTOR(cpuStrategy->actorIndex); BANANA_ACTOR(actor)->state = BANANA_ON_GROUND; player->triggers |= DRAG_ITEM_EFFECT; @@ -7311,13 +7297,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(BANANA_ACTOR(actor)->flags & 0x8000)) || (BANANA_ACTOR(actor)->type != ACTOR_BANANA)) || (BANANA_ACTOR(actor)->state != BANANA_ON_GROUND)) || (playerId != BANANA_ACTOR(actor)->playerId)) { - - // FAKE - if (!(BANANA_ACTOR(actor)->flags & 0x8000)) {} - if (BANANA_ACTOR(actor)->type != 6) {} - if (BANANA_ACTOR(actor)->state != 0) {} - if (BANANA_ACTOR(actor)->rot[0] != playerId) {} - cpuStrategy->timer = 0; cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; player->triggers &= ~DRAG_ITEM_EFFECT; @@ -7337,13 +7316,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(BANANA_ACTOR(actor)->flags & 0x8000)) || (BANANA_ACTOR(actor)->type != ACTOR_BANANA)) || (BANANA_ACTOR(actor)->state != BANANA_ON_GROUND)) || (playerId != BANANA_ACTOR(actor)->playerId)) { - - // FAKE - if (!(BANANA_ACTOR(actor)->flags & 0x8000)) {} - if (BANANA_ACTOR(actor)->type != 6) {} - if (BANANA_ACTOR(actor)->state != 0) {} - if (BANANA_ACTOR(actor)->rot[0] != playerId) {} - } else { BANANA_ACTOR(actor)->state = DROPPED_BANANA; BANANA_ACTOR(actor)->velocity[0] = 0.0f; @@ -7360,16 +7332,12 @@ void cpu_use_item_strategy(s32 playerId) { break; case CPU_STRATEGY_ITEM_GREEN_SHELL: - if (gNumActors < 80) { - cpuStrategy->actorIndex = use_green_shell_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { - cpuStrategy->branch = CPU_STRATEGY_HOLD_GREEN_SHELL; - cpuStrategy->timer = 0; - cpuStrategy->numItemUse += 1; - cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 10; - } else { - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; - } + cpuStrategy->actorIndex = use_green_shell_item(player); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_HOLD_GREEN_SHELL; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 10; } else { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } @@ -7380,13 +7348,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (actor->type != ACTOR_GREEN_SHELL)) || (SHELL_ACTOR(actor)->state != HELD_SHELL)) || (playerId != SHELL_ACTOR(actor)->playerId)) { - - // FAKE - if (!(SHELL_ACTOR(actor)->flags & 0x8000)) {} - if (SHELL_ACTOR(actor)->type != 7) {} - if (SHELL_ACTOR(actor)->state != 0) {} - if (SHELL_ACTOR(actor)->rotVelocity != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; } else if (cpuStrategy->timeBeforeThrow < cpuStrategy->timer) { @@ -7400,33 +7361,56 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (actor->type != ACTOR_GREEN_SHELL)) || (SHELL_ACTOR(actor)->state != HELD_SHELL)) || (playerId != SHELL_ACTOR(actor)->playerId)) { - - // FAKE - if (!(actor->flags & 0x8000)) {} - if (actor->type != 7) {} - if (actor->state != 0) {} - if (actor->rot[0] != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; } else { - SHELL_ACTOR(actor)->state = RELEASED_SHELL; + // Check for players behind the CPU and throw shell backwards + s16 highestHumanRank = gPlayerOne->currentRank; + // Handle two players + //! @warning Likely needs an update to support more than two human players + if ((gPlayerTwo->type & PLAYER_HUMAN) && gPlayerTwo->currentRank > highestHumanRank) { + highestHumanRank = gPlayerTwo->currentRank; + } + + if (player->currentRank < highestHumanRank) { + // Code for backwards firing is the same for CPUs and humans + Vec3f somePos2; + Vec3f somePosVel; + f32 var_f2; + + var_f2 = 8.0f; + if (player->speed > 8.0f) { + var_f2 = player->speed * 1.2f; + } + somePosVel[0] = 0.0f; + somePosVel[1] = 0.0f; + somePosVel[2] = -var_f2; + func_802B64C4(somePosVel, player->rotation[1] + player->unk_0C0); + SHELL_ACTOR(actor)->velocity[0] = somePosVel[0]; + SHELL_ACTOR(actor)->velocity[1] = somePosVel[1]; + SHELL_ACTOR(actor)->velocity[2] = somePosVel[2]; + SHELL_ACTOR(actor)->state = MOVING_SHELL; + func_800C9060(SHELL_ACTOR(actor)->playerId, SOUND_ARG_LOAD(0x19, 0x00, 0x80, 0x04)); + func_800C90F4(SHELL_ACTOR(actor)->playerId, + (player->characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x00)); + add_green_shell_in_unexpired_actor_list(CM_FindActorIndex(SHELL_ACTOR(actor))); + } + else + { + SHELL_ACTOR(actor)->state = RELEASED_SHELL; + } cpuStrategy->timer = 0; cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } break; case CPU_STRATEGY_ITEM_RED_SHELL: - if (gNumActors < 80) { - cpuStrategy->actorIndex = use_red_shell_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { - cpuStrategy->branch = CPU_STRATEGY_HOLD_RED_SHELL; - cpuStrategy->timer = 0; - cpuStrategy->numItemUse += 1; - cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 10; - } else { - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; - } + cpuStrategy->actorIndex = use_red_shell_item(player); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_HOLD_RED_SHELL; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 10; } else { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } @@ -7437,13 +7421,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_RED_SHELL)) || (SHELL_ACTOR(actor)->state != HELD_SHELL)) || (playerId != SHELL_ACTOR(actor)->playerId)) { - - // FAKE - if (!(actor->flags & 0x8000)) {} - if (actor->type != 8) {} - if (actor->state != 0) {} - if (actor->rot[0] != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; } else if (cpuStrategy->timeBeforeThrow < cpuStrategy->timer) { @@ -7457,13 +7434,6 @@ void cpu_use_item_strategy(s32 playerId) { if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_RED_SHELL)) || (SHELL_ACTOR(actor)->state != HELD_SHELL)) || (playerId != SHELL_ACTOR(actor)->playerId)) { - - // FAKE - if (!(actor->flags & 0x8000)) {} - if (actor->type != 8) {} - if (actor->state != 0) {} - if (actor->rot[0] != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; } else { @@ -7474,16 +7444,12 @@ void cpu_use_item_strategy(s32 playerId) { break; case CPU_STRATEGY_ITEM_BANANA_BUNCH: - if (gNumActors < 80) { - cpuStrategy->actorIndex = use_banana_bunch_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { - cpuStrategy->branch = CPU_STRATEGY_WAIT_INIT_BANANA_BUNCH; - cpuStrategy->timer = 0; - cpuStrategy->numItemUse += 1; - cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 60; - } else { - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; - } + cpuStrategy->actorIndex = use_banana_bunch_item(player); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_WAIT_INIT_BANANA_BUNCH; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 60; } else { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } @@ -7493,10 +7459,6 @@ void cpu_use_item_strategy(s32 playerId) { actor = GET_ACTOR(cpuStrategy->actorIndex); if (BANANA_BUNCH_ACTOR(actor)->state == 6) { - // FAKE - if (BANANA_BUNCH_ACTOR(actor)->state != -1) {} - if (BANANA_BUNCH_ACTOR(actor)->state == 6) {} - isValidBanana2 = false; if (BANANA_BUNCH_ACTOR(actor)->bananaIndices[4] != (-1)) { @@ -7578,7 +7540,7 @@ void cpu_use_item_strategy(s32 playerId) { case CPU_STRATEGY_ITEM_FAKE_ITEM_BOX: cpuStrategy->actorIndex = use_fake_itembox_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 100)) { + if (cpuStrategy->actorIndex >= 0) { cpuStrategy->branch = CPU_STRATEGY_HOLD_FAKE_ITEM_BOX; cpuStrategy->timer = 0; cpuStrategy->numItemUse += 1; @@ -7595,32 +7557,18 @@ void cpu_use_item_strategy(s32 playerId) { (FAKE_ITEMBOX_ACTOR(actor)->state != 0)) || (playerId != ((s32) FAKE_ITEMBOX_ACTOR(actor)->playerId))) { - // FAKE - if (!(actor->flags & 0x8000)) {} - if (actor->type != 13) {} - if (actor->state != 0) {} - if (actor->rot[0] != playerId) {} - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; cpuStrategy->timer = 0; } else if (cpuStrategy->timeBeforeThrow < cpuStrategy->timer) { cpuStrategy->branch = CPU_STRATEGY_THROW_FAKE_ITEM_BOX; } break; - case CPU_STRATEGY_THROW_FAKE_ITEM_BOX: actor = GET_ACTOR(cpuStrategy->actorIndex); if ((((!(FAKE_ITEMBOX_ACTOR(actor)->flags & 0x8000)) || (FAKE_ITEMBOX_ACTOR(actor)->type != ACTOR_FAKE_ITEM_BOX)) || (FAKE_ITEMBOX_ACTOR(actor)->state != 0)) || (playerId != ((s32) FAKE_ITEMBOX_ACTOR(actor)->playerId))) { - - // FAKE - if (!(FAKE_ITEMBOX_ACTOR(actor)->flags & 0x8000)) {} - if (FAKE_ITEMBOX_ACTOR(actor)->type != 13) {} - if (FAKE_ITEMBOX_ACTOR(actor)->state != 0) {} - if (FAKE_ITEMBOX_ACTOR(actor)->rot[0] != playerId) {} - } else { func_802A1064((struct FakeItemBox*) actor); if (D_801631E0[playerId] == true) { @@ -7718,23 +7666,19 @@ void cpu_use_item_strategy(s32 playerId) { } break; case CPU_STRATEGY_ITEM_BLUE_SPINY_SHELL: - if (((s32) gNumActors) < 80) { - cpuStrategy->actorIndex = use_blue_shell_item(player); - if ((cpuStrategy->actorIndex >= 0) && (cpuStrategy->actorIndex < 0x64)) { - cpuStrategy->branch = CPU_STRATEGY_HOLD_BLUE_SPINY_SHELL; - cpuStrategy->timer = 0; - cpuStrategy->numItemUse += 1; - cpuStrategy->timeBeforeThrow = (random_int(3U) * 0x14) + 0xA; - } else { - cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; - } + cpuStrategy->actorIndex = use_blue_shell_item(player); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_HOLD_BLUE_SPINY_SHELL; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 10; } else { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } break; case CPU_STRATEGY_HOLD_BLUE_SPINY_SHELL: actor = GET_ACTOR(cpuStrategy->actorIndex); - if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (actor->type != ACTOR_BLUE_SPINY_SHELL)) || + if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_BLUE_SPINY_SHELL)) || (SHELL_ACTOR(actor)->state != HELD_SHELL)) || (playerId != SHELL_ACTOR(actor)->playerId)) { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; @@ -7757,6 +7701,103 @@ void cpu_use_item_strategy(s32 playerId) { cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; } break; + case CPU_STRATEGY_ITEM_TRIPLE_GREEN_SHELL: + cpuStrategy->actorIndex = use_triple_shell_item(player, ACTOR_TRIPLE_GREEN_SHELL); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_ORBIT_TRIPLE_GREEN_SHELL; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(10) * 20) + 50; // Delays firing until the shells have spawned + } else { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + break; + case CPU_STRATEGY_ORBIT_TRIPLE_GREEN_SHELL: + actor = GET_ACTOR(cpuStrategy->actorIndex); + if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_TRIPLE_GREEN_SHELL))) || + (playerId != SHELL_ACTOR(actor)->playerId)) { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + cpuStrategy->timer = 0; + } else if (cpuStrategy->timeBeforeThrow < cpuStrategy->timer) { + + TripleShellParent* parent = (TripleShellParent*) actor; + if (parent->state == ORBIT_PLAYER) { + cpuStrategy->branch = CPU_STRATEGY_THROW_TRIPLE_GREEN_SHELL; + } else { + cpuStrategy->timer = 0; + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + } + break; + + case CPU_STRATEGY_THROW_TRIPLE_GREEN_SHELL: + actor = GET_ACTOR(cpuStrategy->actorIndex); + if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_TRIPLE_GREEN_SHELL))) || + (playerId != SHELL_ACTOR(actor)->playerId)) { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + cpuStrategy->timer = 0; + } else { + cpuStrategy->timer = 0; + TripleShellParent* parent = (TripleShellParent*) actor; + if (parent->state == ORBIT_PLAYER && 0 < parent->shellsAvailable) { + cpuStrategy->branch = CPU_STRATEGY_ORBIT_TRIPLE_GREEN_SHELL; + parent->firePressed += 1.0f; + cpuStrategy->timeBeforeThrow = (random_int(2) * 20); + } else { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + } + break; + + case CPU_STRATEGY_ITEM_TRIPLE_RED_SHELL: + cpuStrategy->actorIndex = use_triple_shell_item(player, ACTOR_TRIPLE_RED_SHELL); + if (cpuStrategy->actorIndex >= 0) { + cpuStrategy->branch = CPU_STRATEGY_ORBIT_TRIPLE_RED_SHELL; + cpuStrategy->timer = 0; + cpuStrategy->numItemUse += 1; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 50; // Delays firing until the shells have spawned + } else { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + break; + + case CPU_STRATEGY_ORBIT_TRIPLE_RED_SHELL: + actor = GET_ACTOR(cpuStrategy->actorIndex); + if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_TRIPLE_RED_SHELL))) || + (playerId != SHELL_ACTOR(actor)->playerId)) { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + cpuStrategy->timer = 0; + } else if (cpuStrategy->timeBeforeThrow < cpuStrategy->timer) { + + TripleShellParent* parent = (TripleShellParent*) actor; + if (parent->state == ORBIT_PLAYER) { + cpuStrategy->branch = CPU_STRATEGY_THROW_TRIPLE_RED_SHELL; + } else { + cpuStrategy->timer = 0; + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + } + break; + + case CPU_STRATEGY_THROW_TRIPLE_RED_SHELL: + actor = GET_ACTOR(cpuStrategy->actorIndex); + if ((((!(SHELL_ACTOR(actor)->flags & 0x8000)) || (SHELL_ACTOR(actor)->type != ACTOR_TRIPLE_RED_SHELL))) || + (playerId != SHELL_ACTOR(actor)->playerId)) { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + cpuStrategy->timer = 0; + } else { + + cpuStrategy->timer = 0; + TripleShellParent* parent = (TripleShellParent*) actor; + if (parent->state == ORBIT_PLAYER && 0 < parent->shellsAvailable) { + cpuStrategy->branch = CPU_STRATEGY_ORBIT_TRIPLE_RED_SHELL; + parent->firePressed += 1.0f; + cpuStrategy->timeBeforeThrow = (random_int(3) * 20) + 90; // Delay so that the CPU fires the next shell after the player has finished tumbling + } else { + cpuStrategy->branch = CPU_STRATEGY_WAIT_NEXT_ITEM; + } + } + break; default: break; diff --git a/src/code_80005FD0.h b/src/code_80005FD0.h index 67c437f7b..7acb6e80b 100644 --- a/src/code_80005FD0.h +++ b/src/code_80005FD0.h @@ -34,7 +34,7 @@ typedef struct { /* 0x08 */ s16 numDroppedBananaBunch; /* 0x0A */ s16 unk_0A; /* 0x0C */ s16 unk_0C; - /* 0x0E */ s16 timeBeforeThrow; + /* 0x0E */ s16 timeBeforeThrow; // Allows time for spawning the shells before they can be spawned } CpuItemStrategyData; // size = 0x10 typedef struct { @@ -89,6 +89,14 @@ enum CpuItemStrategyEnum { CPU_STRATEGY_ITEM_BLUE_SPINY_SHELL, CPU_STRATEGY_THROW_BLUE_SPINY_SHELL, CPU_STRATEGY_HOLD_BLUE_SPINY_SHELL, + + CPU_STRATEGY_ITEM_TRIPLE_GREEN_SHELL, + CPU_STRATEGY_ORBIT_TRIPLE_GREEN_SHELL, + CPU_STRATEGY_THROW_TRIPLE_GREEN_SHELL, + + CPU_STRATEGY_ITEM_TRIPLE_RED_SHELL, + CPU_STRATEGY_ORBIT_TRIPLE_RED_SHELL, + CPU_STRATEGY_THROW_TRIPLE_RED_SHELL, }; /* Function Prototypes */ diff --git a/src/racing/actors_extended.c b/src/racing/actors_extended.c index e8072798b..e05ae4388 100644 --- a/src/racing/actors_extended.c +++ b/src/racing/actors_extended.c @@ -391,8 +391,8 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { parent->state = 3; } break; - case 3: - parent->state = 4; + case SHELL_COLLISION: + parent->state = ORBIT_PLAYER; shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[0]); shell->flags |= 0x4000; shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[1]); @@ -400,7 +400,7 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[2]); shell->flags |= 0x4000; break; - case 4: + case ORBIT_PLAYER: shellCount = 0; if (is_shell_exist(parent->shellIndices[0]) == 1) { shellCount = 1; @@ -422,10 +422,14 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { break; } if ((gControllers[parent->playerId].buttonPressed & Z_TRIG) != 0) { - parent->unk_08 += 1.0f; + /** + * Fires shell. Uses += 1.0f because this code is ran multiple times per frame. + * A bool would be turned on and off again resulting in no change + */ + parent->firePressed += 1.0f; gControllers[parent->playerId].buttonPressed &= ~Z_TRIG; } - if (parent->unk_08 > 0.0f) { + if (parent->firePressed > 0.0f) { // Fires a shell and resets firePressed to zero if (parent->shellIndices[0] > 0.0f) { shell = (struct ShellActor*) GET_ACTOR((s16) parent->shellIndices[0]); if ((shell->rotAngle < 0x38E) || (shell->rotAngle >= -0x38D)) { @@ -448,7 +452,7 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { } parent->shellIndices[0] = -1.0f; parent->shellsAvailable -= 1; - parent->unk_08 -= 1.0f; + parent->firePressed -= 1.0f; break; } } @@ -474,7 +478,7 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { } parent->shellIndices[1] = -1.0f; parent->shellsAvailable -= 1; - parent->unk_08 -= 1.0f; + parent->firePressed -= 1.0f; break; } } @@ -500,7 +504,7 @@ void update_actor_triple_shell(TripleShellParent* parent, s16 shellType) { } parent->shellIndices[2] = -1.0f; parent->shellsAvailable -= 1; - parent->unk_08 -= 1.0f; + parent->firePressed -= 1.0f; break; } } @@ -548,7 +552,7 @@ s32 use_triple_shell_item(Player* player, s16 tripleShellType) { parent->rotAngle = -0x8000; parent->playerId = player - gPlayerOne; parent->shellsAvailable = 0; - parent->unk_08 = 0.0f; + parent->firePressed = 0.0f; return actorIndex; } @@ -681,7 +685,14 @@ s32 use_red_shell_item(Player* player) { // Interestingly blue shells start their life as a red shell, // and then just change the type from red to blue shell s32 use_blue_shell_item(Player* player) { - GET_ACTOR(use_red_shell_item(player))->type = ACTOR_BLUE_SPINY_SHELL; + // GET_ACTOR(use_red_shell_item(player))->type = ACTOR_BLUE_SPINY_SHELL; // Original code was just this line, without return statement! So I commented out. + + // Fix the CPU strategy not properly releasing the blue shell. This function originally doesnt have a return value, so it returns UB. + // The actor index range check on the cpu strategy fails because the actual actor index of blue shell was never returned by this function! + s16 actorIndex = use_red_shell_item(player); + GET_ACTOR(actorIndex)->type = ACTOR_BLUE_SPINY_SHELL; + + return actorIndex; } #include "actors/banana/update.inc.c" |
