mirror of
https://github.com/pret/pmd-red.git
synced 2026-04-24 23:17:03 -05:00
478 lines
14 KiB
C
478 lines
14 KiB
C
#include "global.h"
|
|
#include "globaldata.h"
|
|
#include "dungeon_engine.h"
|
|
#include "run_dungeon.h"
|
|
#include "dungeon_vram.h"
|
|
#include "dungeon_main.h"
|
|
#include "constants/dungeon.h"
|
|
#include "dungeon_action_execution.h"
|
|
#include "dungeon_ai.h"
|
|
#include "dungeon_range.h"
|
|
#include "dungeon_misc.h"
|
|
#include "dungeon_util.h"
|
|
#include "dungeon_leveling.h"
|
|
#include "dungeon_turn_effects.h"
|
|
#include "structs/dungeon_entity.h"
|
|
#include "structs/str_dungeon.h"
|
|
#include "constants/ability.h"
|
|
#include "dungeon_logic.h"
|
|
#include "dungeon_cutscene.h"
|
|
#include "menu_input.h"
|
|
#include "weather.h"
|
|
#include "dungeon_wild_mon_spawn.h"
|
|
#include "dungeon_entity_movement.h"
|
|
#include "dungeon_wind.h"
|
|
|
|
static void sub_8044454_Async(void);
|
|
static bool8 RunLeaderTurn_Async(bool8);
|
|
static void sub_8044574_Async(void);
|
|
static void sub_8044820_Async(void);
|
|
static void TrySpawnMonsterAndActivatePlusMinus_Async(void);
|
|
static void sub_8044AB4(void);
|
|
|
|
EWRAM_DATA DungeonPos gLeaderPosition = {0};
|
|
EWRAM_DATA MenuInputStruct gDungeonMenu = {0};
|
|
|
|
const s16 gSpeedTurns[NUM_SPEED_COUNTERS][25] = {
|
|
[0] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0},
|
|
[1] = {0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0},
|
|
[2] = {0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0},
|
|
[3] = {0, 22, 23, 24, 0, 25, 26, 27, 0, 28, 29, 30, 0, 31, 32, 33, 0, 34, 35, 36, 0, 37, 38, 39, 0},
|
|
[4] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64},
|
|
};
|
|
|
|
void RunFractionalTurn_Async(bool8 param_1)
|
|
{
|
|
bool8 cVar2;
|
|
|
|
if (IsFloorOver())
|
|
return;
|
|
|
|
TrySpawnMonsterAndActivatePlusMinus_Async();
|
|
if (IsFloorOver())
|
|
return;
|
|
|
|
cVar2 = RunLeaderTurn_Async(param_1);
|
|
if (IsFloorOver())
|
|
return;
|
|
if (cVar2) {
|
|
UpdateWindTurns();
|
|
if (IsFloorOver())
|
|
return;
|
|
}
|
|
if (IsFloorOver())
|
|
return;
|
|
|
|
sub_8044574_Async();
|
|
if (IsFloorOver())
|
|
return;
|
|
|
|
sub_8044820_Async();
|
|
if (IsFloorOver())
|
|
return;
|
|
|
|
sub_8044AB4();
|
|
if (++gDungeon->unk644.fractionalTurn == 24)
|
|
gDungeon->unk644.fractionalTurn = 0;
|
|
}
|
|
|
|
static bool8 RunLeaderTurn_Async(bool8 param_1)
|
|
{
|
|
EntityInfo *entityInfo;
|
|
s32 movSpeed;
|
|
Entity *entity = GetLeader();
|
|
if (entity == NULL)
|
|
return FALSE;
|
|
|
|
TryActivateArtificialWeatherAbilities();
|
|
movSpeed = CalcSpeedStage(entity);
|
|
if (gSpeedTurns[movSpeed][gDungeon->unk644.fractionalTurn] == 0)
|
|
return FALSE;
|
|
if (GetEntInfo(entity)->attacking)
|
|
return FALSE;
|
|
|
|
while (TRUE) {
|
|
entity = GetLeader();
|
|
if (entity == NULL)
|
|
return FALSE;
|
|
if (!DisplayActions_Async(NULL) && (gDungeon->unk644.unk28 != 0 || gDungeon->unk644.unk2F != 0)) {
|
|
DungeonRunFrameActions(12);
|
|
}
|
|
GetEntInfo(entity)->speedStageChanged = FALSE;
|
|
if (IsFloorOver())
|
|
return FALSE;
|
|
gDungeon->unkB8 = entity;
|
|
gDungeon->unkBC = 0;
|
|
if (param_1) {
|
|
param_1 = FALSE;
|
|
}
|
|
else {
|
|
TickStatusAndHealthRegen(entity);
|
|
}
|
|
|
|
if (IsFloorOver())
|
|
return FALSE;
|
|
EnemyEvolution(entity);
|
|
gDungeon->noActionInProgress = TRUE;
|
|
DungeonHandlePlayerInput();
|
|
gDungeon->noActionInProgress = FALSE;
|
|
if (IsFloorOver())
|
|
break;
|
|
ExecuteEntityDungeonAction_Async(entity);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
if (IsFloorOver())
|
|
break;
|
|
entityInfo = GetEntInfo(entity);
|
|
if (entityInfo->flags & MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY) {
|
|
GetEntInfo(entity)->flags = (entityInfo->flags & ~(MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY)) | MOVEMENT_FLAG_UNK_14;
|
|
}
|
|
if (IsFloorOver())
|
|
break;
|
|
sub_8044454_Async();
|
|
if (IsFloorOver())
|
|
break;
|
|
|
|
if (gDungeon->unkBC != 0) {
|
|
sub_805F02C();
|
|
gDungeon->unkBC = 0;
|
|
param_1 = TRUE;
|
|
}
|
|
else {
|
|
if (!GetEntInfo(entity)->speedStageChanged)
|
|
break;
|
|
gDungeon->unk644.fractionalTurn = 0;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void sub_8044454_Async(void)
|
|
{
|
|
Entity *entity;
|
|
EntityInfo *entityInfo;
|
|
s32 index;
|
|
|
|
if (gDungeon->unkE) {
|
|
gDungeon->unkE = 0;
|
|
|
|
for(index = 0; index < DUNGEON_MAX_POKEMON; index++)
|
|
{
|
|
entity = gDungeon->activePokemon[index];
|
|
if ((EntityIsValid(entity)) && (entityInfo = GetEntInfo(entity), (entityInfo->flags & MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY))) {
|
|
if (IsFloorOver()) break;
|
|
TickStatusAndHealthRegen(entity);
|
|
if (EntityIsValid(entity)) {
|
|
EnemyEvolution(entity);
|
|
RunMonsterAI(entity, 0);
|
|
ExecuteEntityDungeonAction_Async(entity);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
entityInfo->flags = (entityInfo->flags & ~(MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY)) | MOVEMENT_FLAG_UNK_14;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void sub_80444F4_Async(Entity *pokemon)
|
|
{
|
|
Entity *entity;
|
|
EntityInfo *entityInfo;
|
|
s32 index;
|
|
|
|
if (pokemon == GetLeader() && gDungeon->unkE) {
|
|
gDungeon->unkE = 0;
|
|
|
|
for(index = 0; index < DUNGEON_MAX_POKEMON; index++)
|
|
{
|
|
entity = gDungeon->activePokemon[index];
|
|
if ((EntityIsValid(entity)) && (pokemon != entity) && (entityInfo = GetEntInfo(entity), (entityInfo->flags & MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY))) {
|
|
if (IsFloorOver()) break;
|
|
RunMonsterAI(entity, 0);
|
|
ExecuteEntityDungeonAction_Async(entity);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Struct_8044574
|
|
{
|
|
Entity *entityPtr;
|
|
struct Struct_8044574 *next;
|
|
};
|
|
|
|
static void sub_8044574_Async(void)
|
|
{
|
|
s32 i, id;
|
|
struct Struct_8044574 sp0[4];
|
|
struct Struct_8044574 sp40[4];
|
|
|
|
Entity *leader = GetLeader();
|
|
for (i = 0; i < MAX_TEAM_MEMBERS; i++) {
|
|
Entity *teamMon = gDungeon->teamPokemon[i];
|
|
if (EntityIsValid(teamMon)) {
|
|
EntityInfo *teamMonInfo = GetEntInfo(teamMon);
|
|
if (!teamMonInfo->isTeamLeader) {
|
|
s32 spdStage;
|
|
|
|
if (IsFloorOver())
|
|
break;
|
|
gDungeon->unkB8 = teamMon;
|
|
TryActivateArtificialWeatherAbilities();
|
|
teamMonInfo->aiAllySkip = FALSE;
|
|
|
|
spdStage = CalcSpeedStage(teamMon);
|
|
if (gSpeedTurns[spdStage][gDungeon->unk644.fractionalTurn] != 0
|
|
&& !teamMonInfo->attacking
|
|
&& !(teamMonInfo->flags & 0x8000))
|
|
{
|
|
if (teamMonInfo->flags & 0x4000) {
|
|
teamMonInfo->flags &= ~(0x4000);
|
|
}
|
|
else {
|
|
teamMonInfo->recalculateFollow = FALSE;
|
|
TickStatusAndHealthRegen(teamMon);
|
|
if (EntityIsValid(teamMon)) {
|
|
s32 j;
|
|
|
|
EnemyEvolution(teamMon);
|
|
for (j = 0; j < 3; j++) {
|
|
RunMonsterAI(teamMon, 0);
|
|
if (IsFloorOver() || !ExecuteEntityDungeonAction_Async(teamMon))
|
|
break;
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
if (IsFloorOver())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (id = 0; id < 3; id++) {
|
|
struct Struct_8044574 *ptr;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
sp0[i].entityPtr = NULL;
|
|
sp0[i].next = &sp0[i+1];
|
|
}
|
|
sp0[3].entityPtr = NULL;
|
|
sp0[3].next = NULL;
|
|
|
|
for (i = 0; i < MAX_TEAM_MEMBERS; i++) {
|
|
Entity *teamMon = gDungeon->teamPokemon[i];
|
|
if (EntityIsValid(teamMon)) {
|
|
EntityInfo *teamMonInfo = GetEntInfo(teamMon);
|
|
if (teamMonInfo->aiAllySkip) {
|
|
if (teamMonInfo->isTeamLeader) {
|
|
teamMonInfo->recalculateFollow = FALSE;
|
|
teamMonInfo->aiAllySkip = FALSE;
|
|
}
|
|
else {
|
|
s32 x = abs(leader->pos.x - teamMon->pos.x);
|
|
s32 y = abs(leader->pos.y - teamMon->pos.y);
|
|
s32 distance = max(x, y);
|
|
|
|
if (distance >= 3)
|
|
distance = 2;
|
|
|
|
sp40[i].entityPtr = teamMon;
|
|
sp40[i].next = sp0[distance].next;
|
|
sp0[distance].next = &sp40[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = &sp0[0];
|
|
while (ptr != NULL) {
|
|
Entity *entity = ptr->entityPtr;
|
|
if (entity != NULL) {
|
|
EntityInfo *info = GetEntInfo(entity);
|
|
info->recalculateFollow = TRUE;
|
|
info->aiAllySkip = FALSE;
|
|
RunMonsterAI(entity,1);
|
|
ExecuteEntityDungeonAction_Async(entity);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
EntityIsValid(entity); // Does nothing
|
|
}
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
if (!IsFloorOver()) {
|
|
for (i = 0; i < MAX_TEAM_MEMBERS; i++) {
|
|
Entity *teamMon = gDungeon->teamPokemon[i];
|
|
if (EntityIsValid(teamMon)) {
|
|
EntityInfo *teamMonInfo = GetEntInfo(teamMon);
|
|
if (teamMonInfo->aiAllySkip) {
|
|
DoEndOfTurnEffects_Async(teamMon);
|
|
if (EntityIsValid(teamMon)) {
|
|
EnemyEvolution(teamMon);
|
|
teamMonInfo->aiAllySkip = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sub_8044820_Async(void)
|
|
{
|
|
s32 movSpeed;
|
|
EntityInfo *entityInfo;
|
|
EntityInfo *entityInfo2;
|
|
Entity * entity;
|
|
Entity * entity2;
|
|
s32 index;
|
|
|
|
for (index = 0; index < DUNGEON_MAX_WILD_POKEMON; index++) {
|
|
entity = gDungeon->wildPokemon[index];
|
|
if (EntityIsValid(entity)) {
|
|
if (IsFloorOver()) break;
|
|
entityInfo = GetEntInfo(entity);
|
|
gDungeon->unkB8 = entity;
|
|
TryActivateArtificialWeatherAbilities();
|
|
if ((entityInfo->flags & MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY) == 0) {
|
|
if ((u16)(entityInfo->flags & MOVEMENT_FLAG_UNK_14) != 0) {
|
|
entityInfo->flags &= ~(MOVEMENT_FLAG_UNK_14);
|
|
}
|
|
else
|
|
{
|
|
entityInfo->aiAllySkip = FALSE;
|
|
movSpeed = CalcSpeedStage(entity);
|
|
if (gSpeedTurns[movSpeed][gDungeon->unk644.fractionalTurn] != 0) {
|
|
if (!entityInfo->attacking) {
|
|
entityInfo->flags &= ~(MOVEMENT_FLAG_UNK_14 | MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY);
|
|
entityInfo->recalculateFollow = FALSE;
|
|
TickStatusAndHealthRegen(entity);
|
|
if (EntityIsValid(entity)) {
|
|
EnemyEvolution(entity);
|
|
RunMonsterAI(entity, 0);
|
|
if (IsFloorOver()) break;
|
|
ExecuteEntityDungeonAction_Async(entity);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
if (IsFloorOver()) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (IsFloorOver() == 0) {
|
|
for(index = 0; index < DUNGEON_MAX_WILD_POKEMON; index++)
|
|
{
|
|
entity2 = gDungeon->wildPokemon[index];
|
|
if ((EntityIsValid(entity2)) && (entityInfo2 = GetEntInfo(entity2), entityInfo2->aiAllySkip))
|
|
{
|
|
DoEndOfTurnEffects_Async(entity2);
|
|
if (EntityIsValid(entity2)) {
|
|
EnemyEvolution(entity2);
|
|
entityInfo2->aiAllySkip = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void TrySpawnMonsterAndActivatePlusMinus_Async(void)
|
|
{
|
|
EntityInfo * entityInfo;
|
|
Entity *entity;
|
|
u32 isNotEnemy;
|
|
s32 index;
|
|
|
|
if (gSpeedTurns[1][gDungeon->unk644.fractionalTurn] != 0) {
|
|
TrySpawnWildMonster();
|
|
gDungeon->plusIsActive[0] = FALSE;
|
|
gDungeon->plusIsActive[1] = FALSE;
|
|
gDungeon->minusIsActive[0] = FALSE;
|
|
gDungeon->minusIsActive[1] = FALSE;
|
|
gDungeon->lightningRodPokemon = NULL;
|
|
gDungeon->unk17B38 = 2;
|
|
|
|
for(index = 0; index < DUNGEON_MAX_POKEMON; index++)
|
|
{
|
|
entity = gDungeon->activePokemon[index];
|
|
if (EntityIsValid(entity)) {
|
|
entityInfo = GetEntInfo(entity);
|
|
entityInfo->attacking = FALSE;
|
|
|
|
if(entityInfo->isNotTeamMember)
|
|
{
|
|
isNotEnemy = FALSE;
|
|
}
|
|
else {
|
|
isNotEnemy = TRUE;
|
|
}
|
|
|
|
if (AbilityIsActive(entity, ABILITY_LIGHTNINGROD)) {
|
|
gDungeon->lightningRodPokemon = entity;
|
|
gDungeon->unk17B38 = entityInfo->dungeonSpriteId;
|
|
}
|
|
if (AbilityIsActive(entity, ABILITY_MINUS)) {
|
|
gDungeon->minusIsActive[isNotEnemy] = TRUE;
|
|
}
|
|
if (AbilityIsActive(entity, ABILITY_PLUS)) {
|
|
gDungeon->plusIsActive[isNotEnemy] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
TryForcedLoss_Async(FALSE);
|
|
}
|
|
}
|
|
|
|
static void sub_8044AB4(void)
|
|
{
|
|
s32 index;
|
|
|
|
if (gSpeedTurns[1][gDungeon->unk644.fractionalTurn + 1] != 0) {
|
|
for (index = 0; index < DUNGEON_MAX_POKEMON; index++) {
|
|
if (EntityIsValid(gDungeon->activePokemon[index])) {
|
|
DisplayActions_Async(0);
|
|
break;
|
|
}
|
|
}
|
|
sub_807EAA0(1,0);
|
|
sub_8086AC0();
|
|
TryForcedLoss_Async(FALSE);
|
|
}
|
|
}
|
|
|
|
bool8 IsFloorOver(void)
|
|
{
|
|
if (gDungeon->unk4 == 0) {
|
|
if (GetLeader() == NULL) {
|
|
gDungeon->unk644.unk10 = 1;
|
|
}
|
|
else if (gDungeon->unk2 == DUNGEON_UNK2_1) {
|
|
gDungeon->unk644.unk10 = 2;
|
|
}
|
|
else if (gDungeon->unk2 != DUNGEON_UNK2_PITFALL_TRAP) {
|
|
return FALSE;
|
|
}
|
|
else {
|
|
gDungeon->unk644.unk10 = 2;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 sub_8044B84(void)
|
|
{
|
|
if (gDungeon->unk10 != 0)
|
|
return TRUE;
|
|
|
|
return IsFloorOver();
|
|
}
|