/*++ Player flee the battle. --*/ VOID PAL_BattlePlayerEscape(void) { int i, j; WORD wPlayerRole; SOUND_Play(45); PAL_BattleUpdateFighters(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { g_Battle.rgPlayer[i].wCurrentFrame = 0; } } for (i = 0; i < 16; i++) { for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++) { wPlayerRole = gpGlobals->rgParty[j].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { // // TODO: This is still not the same as the original game // switch (j) { case 0: if (gpGlobals->wMaxPartyMemberIndex > 0) { g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 6); break; } case 1: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 4); break; case 2: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 6, PAL_Y(g_Battle.rgPlayer[j].pos) + 3); break; // @@@ - extra 4th role: case 3: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 6, PAL_Y(g_Battle.rgPlayer[j].pos) + 3); break; default: assert(FALSE); // Not possible break; } } } PAL_BattleDelay(1, 0, FALSE); } // // Remove all players from the screen // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { g_Battle.rgPlayer[i].pos = PAL_XY(9999, 9999); } PAL_BattleDelay(1, 0, FALSE); g_Battle.BattleResult = kBattleResultFleed; }
/*++ Start a battle. Parameters: [IN] wEnemyTeam - the number of the enemy team. [IN] fIsBoss - TRUE for boss fight (not allowed to flee). Return value: The result of the battle. --*/ BATTLERESULT PAL_StartBattle(WORD wEnemyTeam, BOOL fIsBoss) { int i; WORD w, wPrevWaveLevel; SHORT sPrevWaveProgression; // // Set the screen waving effects // wPrevWaveLevel = gpGlobals->wScreenWave; sPrevWaveProgression = gpGlobals->sWaveProgression; gpGlobals->sWaveProgression = 0; gpGlobals->wScreenWave = gpGlobals->g.lprgBattleField[gpGlobals->wNumBattleField].wScreenWave; // // Make sure everyone in the party is alive, also clear all hidden // EXP count records // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { w = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0) { gpGlobals->g.PlayerRoles.rgwHP[w] = 1; gpGlobals->rgPlayerStatus[w][kStatusPuppet] = 0; } gpGlobals->Exp.rgHealthExp[w].wCount = 0; gpGlobals->Exp.rgMagicExp[w].wCount = 0; gpGlobals->Exp.rgAttackExp[w].wCount = 0; gpGlobals->Exp.rgMagicPowerExp[w].wCount = 0; gpGlobals->Exp.rgDefenseExp[w].wCount = 0; gpGlobals->Exp.rgDexterityExp[w].wCount = 0; gpGlobals->Exp.rgFleeExp[w].wCount = 0; } // // Clear all item-using records // for (i = 0; i < MAX_INVENTORY; i++) { gpGlobals->rgInventory[i].nAmountInUse = 0; } // // Store all enemies // for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { memset(&(g_Battle.rgEnemy[i]), 0, sizeof(BATTLEENEMY)); w = gpGlobals->g.lprgEnemyTeam[wEnemyTeam].rgwEnemy[i]; if (w == 0xFFFF) { break; } if (w != 0) { g_Battle.rgEnemy[i].e = gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[w].enemy.wEnemyID]; g_Battle.rgEnemy[i].wObjectID = w; g_Battle.rgEnemy[i].state = kFighterWait; g_Battle.rgEnemy[i].wScriptOnTurnStart = gpGlobals->g.rgObject[w].enemy.wScriptOnTurnStart; g_Battle.rgEnemy[i].wScriptOnBattleEnd = gpGlobals->g.rgObject[w].enemy.wScriptOnBattleEnd; g_Battle.rgEnemy[i].wScriptOnReady = gpGlobals->g.rgObject[w].enemy.wScriptOnReady; g_Battle.rgEnemy[i].iColorShift = 0; g_Battle.rgEnemy[i].dwMaxHealth = g_Battle.rgEnemy[i].e.wHealth; #ifndef PAL_CLASSIC g_Battle.rgEnemy[i].flTimeMeter = 50; // // HACK: Otherwise the black thief lady will be too hard to beat // if (g_Battle.rgEnemy[i].e.wDexterity == 164) { g_Battle.rgEnemy[i].e.wDexterity /= ((gpGlobals->wMaxPartyMemberIndex == 0) ? 6 : 3); } // // HACK: Heal up automatically for final boss // if (g_Battle.rgEnemy[i].e.wHealth == 32760) { for (w = 0; w < MAX_PLAYER_ROLES; w++) { gpGlobals->g.PlayerRoles.rgwHP[w] = gpGlobals->g.PlayerRoles.rgwMaxHP[w]; gpGlobals->g.PlayerRoles.rgwMP[w] = gpGlobals->g.PlayerRoles.rgwMaxMP[w]; } } // // Yet another HACKs // if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -32) { g_Battle.rgEnemy[i].e.wDexterity = 0; // for Grandma Knife } else if (g_Battle.rgEnemy[i].e.wDexterity == 20) { // // for Fox Demon // if (gpGlobals->g.PlayerRoles.rgwLevel[0] < 15) { g_Battle.rgEnemy[i].e.wDexterity = 8; } else if (gpGlobals->g.PlayerRoles.rgwLevel[4] > 28 || gpGlobals->Exp.rgPrimaryExp[4].wExp > 0) { g_Battle.rgEnemy[i].e.wDexterity = 60; } } else if (g_Battle.rgEnemy[i].e.wExp == 250 && g_Battle.rgEnemy[i].e.wCash == 1100) { g_Battle.rgEnemy[i].e.wDexterity += 12; // for Snake Demon } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -60) { g_Battle.rgEnemy[i].e.wDexterity = 15; // for Spider } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -30) { g_Battle.rgEnemy[i].e.wDexterity = (WORD)-10; // for Stone Head } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -16) { g_Battle.rgEnemy[i].e.wDexterity = 0; // for Zombie } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -20) { g_Battle.rgEnemy[i].e.wDexterity = -8; // for Flower Demon } else if (g_Battle.rgEnemy[i].e.wLevel < 20 && gpGlobals->wNumScene >= 0xD8 && gpGlobals->wNumScene <= 0xE2) { // // for low-level monsters in the Cave of Trial // g_Battle.rgEnemy[i].e.wLevel += 15; g_Battle.rgEnemy[i].e.wDexterity += 25; } else if (gpGlobals->wNumScene == 0x90) { g_Battle.rgEnemy[i].e.wDexterity += 25; // for Tower Dragons } else if (g_Battle.rgEnemy[i].e.wLevel == 2 && g_Battle.rgEnemy[i].e.wCash == 48) { g_Battle.rgEnemy[i].e.wDexterity += 8; // for Miao Fists } else if (g_Battle.rgEnemy[i].e.wLevel == 4 && g_Battle.rgEnemy[i].e.wCash == 240) { g_Battle.rgEnemy[i].e.wDexterity += 18; // for Fat Miao } else if (g_Battle.rgEnemy[i].e.wLevel == 16 && g_Battle.rgEnemy[i].e.wMagicRate == 4 && g_Battle.rgEnemy[i].e.wAttackEquivItemRate == 4) { g_Battle.rgEnemy[i].e.wDexterity += 50; // for Black Spider } #endif } } g_Battle.wMaxEnemyIndex = i - 1; // // Store all players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { g_Battle.rgPlayer[i].flTimeMeter = 15.0f; #ifndef PAL_CLASSIC g_Battle.rgPlayer[i].flTimeSpeedModifier = 2.0f; g_Battle.rgPlayer[i].sTurnOrder = -1; #endif g_Battle.rgPlayer[i].wHidingTime = 0; g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].action.sTarget = -1; g_Battle.rgPlayer[i].fDefending = FALSE; g_Battle.rgPlayer[i].wCurrentFrame = 0; g_Battle.rgPlayer[i].iColorShift = FALSE; } // // Load sprites and background // PAL_LoadBattleSprites(); PAL_LoadBattleBackground(); // // Create the surface for scene buffer // g_Battle.lpSceneBuf = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (g_Battle.lpSceneBuf == NULL) { TerminateOnError("PAL_StartBattle(): creating surface for scene buffer failed!"); } #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(g_Battle.lpSceneBuf, gpScreen->format->palette); #else SDL_SetPalette(g_Battle.lpSceneBuf, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif PAL_UpdateEquipments(); g_Battle.iExpGained = 0; g_Battle.iCashGained = 0; g_Battle.fIsBoss = fIsBoss; g_Battle.fEnemyCleared = FALSE; g_Battle.fEnemyMoving = FALSE; g_Battle.iHidingTime = 0; g_Battle.wMovingPlayerIndex = 0; g_Battle.UI.szMsg[0] = '\0'; g_Battle.UI.szNextMsg[0] = '\0'; g_Battle.UI.dwMsgShowTime = 0; g_Battle.UI.state = kBattleUIWait; g_Battle.UI.fAutoAttack = FALSE; g_Battle.UI.wSelectedIndex = 0; g_Battle.UI.wPrevEnemyTarget = 0; memset(g_Battle.UI.rgShowNum, 0, sizeof(g_Battle.UI.rgShowNum)); g_Battle.lpSummonSprite = NULL; g_Battle.sBackgroundColorShift = 0; gpGlobals->fInBattle = TRUE; g_Battle.BattleResult = kBattleResultPreBattle; PAL_BattleUpdateFighters(); // // Load the battle effect sprite. // i = PAL_MKFGetChunkSize(10, gpGlobals->f.fpDATA); g_Battle.lpEffectSprite = UTIL_malloc(i); PAL_MKFReadChunk(g_Battle.lpEffectSprite, i, 10, gpGlobals->f.fpDATA); #ifdef PAL_CLASSIC g_Battle.Phase = kBattlePhaseSelectAction; g_Battle.fRepeat = FALSE; g_Battle.fForce = FALSE; g_Battle.fFlee = FALSE; #endif #ifdef PAL_ALLOW_KEYREPEAT SDL_EnableKeyRepeat(120, 75); #endif // // Run the main battle routine. // i = PAL_BattleMain(); #ifdef PAL_ALLOW_KEYREPEAT SDL_EnableKeyRepeat(0, 0); PAL_ClearKeyState(); g_InputState.prevdir = kDirUnknown; #endif if (i == kBattleResultWon) { // // Player won the battle. Add the Experience points. // PAL_BattleWon(); } // // Clear all item-using records // for (w = 0; w < MAX_INVENTORY; w++) { gpGlobals->rgInventory[w].nAmountInUse = 0; } // // Clear all player status, poisons and temporary effects // PAL_ClearAllPlayerStatus(); for (w = 0; w < MAX_PLAYER_ROLES; w++) { PAL_CurePoisonByLevel(w, 3); PAL_RemoveEquipmentEffect(w, kBodyPartExtra); } // // Free all the battle sprites // PAL_FreeBattleSprites(); free(g_Battle.lpEffectSprite); // // Free the surfaces for the background picture and scene buffer // SDL_FreeSurface(g_Battle.lpBackground); SDL_FreeSurface(g_Battle.lpSceneBuf); g_Battle.lpBackground = NULL; g_Battle.lpSceneBuf = NULL; gpGlobals->fInBattle = FALSE; PAL_PlayMUS(gpGlobals->wNumMusic, TRUE, 1); // // Restore the screen waving effects // gpGlobals->sWaveProgression = sPrevWaveProgression; gpGlobals->wScreenWave = wPrevWaveLevel; return i; }
VOID PAL_BattleStartFrame( VOID ) /*++ Purpose: Called once per video frame in battle. Parameters: None. Return value: None. --*/ { int i; int iMax; BOOL fEnded; WORD wPlayerRole; WORD wDexterity; FLOAT flMax; PAL_BattleUpdateFighters(); // // Update the scene // PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); // // Check if the battle is over // fEnded = TRUE; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID != 0) { fEnded = FALSE; break; } } if (fEnded) { // // All enemies are cleared. Won the battle. // g_Battle.BattleResult = kBattleResultWon; SOUND_Play(-1); return; } else { fEnded = TRUE; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] != 0) { fEnded = FALSE; break; } } if (fEnded) { // // All players are dead. Lost the battle. // g_Battle.BattleResult = kBattleResultLost; return; } } // // Run the logic for all enemies // for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } if (g_Battle.rgEnemy[i].fTurnStart) { g_Battle.rgEnemy[i].wScriptOnTurnStart = PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnTurnStart, i); g_Battle.rgEnemy[i].fTurnStart = FALSE; } } for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } switch (g_Battle.rgEnemy[i].state) { case kFighterWait: flMax = PAL_GetTimeChargingSpeed(PAL_GetEnemyDexterity(i)); if (flMax != 0) { g_Battle.rgEnemy[i].flTimeMeter += flMax; if (g_Battle.rgEnemy[i].flTimeMeter > 100 && flMax > 0) { g_Battle.rgEnemy[i].state = kFighterCom; } } break; case kFighterCom: g_Battle.rgEnemy[i].wScriptOnReady = PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnReady, i); g_Battle.rgEnemy[i].state = kFighterAct; break; case kFighterAct: ////TEST/////////////////////////////////////////////////////////// SOUND_Play(g_Battle.rgEnemy[i].e.wAttackSound); if (g_Battle.rgEnemy[i].fFirstMoveDone) PAL_BattleUIShowText(va("enemy %d attack (2nd)",i), 500); else PAL_BattleUIShowText(va("enemy %d attack",i), 500); g_Battle.rgEnemy[i].flTimeMeter =0; g_Battle.rgEnemy[i].state = kFighterWait; //////////////////////////////////////////////////////////////////// if (!g_Battle.rgEnemy[i].fFirstMoveDone) { if (g_Battle.rgEnemy[i].e.wDualMove >= 2 || (g_Battle.rgEnemy[i].e.wDualMove != 0 && RandomLong(0, 1))) { g_Battle.rgEnemy[i].flTimeMeter = 100; g_Battle.rgEnemy[i].state = kFighterWait; g_Battle.rgEnemy[i].fFirstMoveDone = TRUE; break; } } g_Battle.rgEnemy[i].fFirstMoveDone = FALSE; g_Battle.rgEnemy[i].fTurnStart = TRUE; break; } } // // Update the battle UI // PAL_BattleUIUpdate(); // // Run the logic for all players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; // // Skip dead players // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 && gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0) { g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].flTimeMeter = 0; continue; } switch (g_Battle.rgPlayer[i].state) { case kFighterWait: wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole); g_Battle.rgPlayer[i].flTimeMeter += PAL_GetTimeChargingSpeed(wDexterity) * g_Battle.rgPlayer[i].flTimeSpeedModifier; break; case kFighterCom: if (g_Battle.UI.state == kBattleUIWait) { PAL_BattleUIPlayerReady(i); } break; case kFighterAct: wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole); g_Battle.rgPlayer[i].action.flRemainingTime -= PAL_GetTimeChargingSpeed(wDexterity); if (g_Battle.rgPlayer[i].action.flRemainingTime < 0) { // // Perform the action for this player. // PAL_BattlePlayerPerformAction(i); // // Reduce the time for other players when uses coopmagic // if (g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic) { for (iMax = 0; iMax <= gpGlobals->wMaxPartyMemberIndex; iMax++) { g_Battle.rgPlayer[iMax].flTimeMeter = 0; g_Battle.rgPlayer[iMax].flTimeSpeedModifier = 2.0f; } } else { g_Battle.rgPlayer[i].flTimeMeter = 0; } // // Revert this player back to waiting state. // g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].flTimeSpeedModifier = 1.0f; } break; } } // // Start the UI for the fastest and ready player // flMax = 0; iMax = 0; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom || (g_Battle.rgPlayer[i].state == kFighterAct && g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic)) { flMax = 0; break; } else if (g_Battle.rgPlayer[i].state == kFighterWait) { if (g_Battle.rgPlayer[i].flTimeMeter > flMax) { iMax = i; flMax = g_Battle.rgPlayer[i].flTimeMeter; } } } if (flMax > 100.0f) { g_Battle.rgPlayer[iMax].state = kFighterCom; g_Battle.rgPlayer[iMax].fDefending = FALSE; } ////TEST/////////////////////////////////////////////////////////-START if (g_InputState.dwKeyPress & kKeyFlee){ for (i = 0; i < 5; i++){ gpGlobals->g.PlayerRoles.rgwHP[i] = 0; } return; } ////TEST/////////////////////////////////////////////////////////-END }
VOID PAL_BattlePlayerEscape( VOID ) /*++ Purpose: Player flee the battle. Parameters: None. Return value: None. --*/ { int i, j; WORD wPlayerRole; UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattlePlayerEscape, "PAL_BattlePlayerEscape", __FILE__, "start"); SOUND_Play(45); PAL_BattleUpdateFighters(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { g_Battle.rgPlayer[i].wCurrentFrame = 0; } } for (i = 0; i < 16; i++) { for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++) { wPlayerRole = gpGlobals->rgParty[j].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { // // TODO: This is still not the same as the original game // switch (j) { case 0: if (gpGlobals->wMaxPartyMemberIndex > 0) { g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 6); break; } case 1: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 4); break; case 2: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 6, PAL_Y(g_Battle.rgPlayer[j].pos) + 3); break; default: assert(FALSE); // Not possible break; } } } PAL_BattleDelay(1, 0, FALSE); } // // Remove all players from the screen // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { g_Battle.rgPlayer[i].pos = PAL_XY(9999, 9999); } PAL_BattleDelay(1, 0, FALSE); g_Battle.BattleResult = kBattleResultFleed; UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattlePlayerEscape, "PAL_BattlePlayerEscape", __FILE__, "end"); }
VOID PAL_BattlePlayerPerformAction( WORD wPlayerIndex ) /*++ Purpose: Perform the selected action for a player. Parameters: [IN] wPlayerIndex - the index of the player. Return value: None. --*/ { // TODO SHORT sDamage; WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole; SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget; int x, y; int i, t; WORD str, def, res, wObject; BOOL fCritical, fPoisoned; PAL_BattlePlayerValidateAction(wPlayerIndex); PAL_BattleBackupStat(); switch (g_Battle.rgPlayer[wPlayerIndex].action.ActionType) { case kBattleActionAttack: if (sTarget != -1) { // // Attack one enemy // if (g_Battle.rgEnemy[sTarget].wObjectID == 0) { sTarget = PAL_BattleSelectAutoTarget(); g_Battle.rgPlayer[wPlayerIndex].action.sTarget = sTarget; } for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[sTarget].e.wDefense; def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[sTarget].e.wAttackResistance; fCritical = FALSE; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (RandomLong(0, 5) == 0) { // // Critical Hit // sDamage *= 3; fCritical = TRUE; } if (wPlayerRole == 0 && RandomLong(0, 11) == 0) { // // Bonus hit for Li Xiaoyao // sDamage *= 2; fCritical = TRUE; } if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[sTarget].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[sTarget].e.wHealth = 0; } if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[sTarget].pos); y = PAL_Y(g_Battle.rgEnemy[sTarget].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); } } else { // // Attack all enemies // for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { int division = 1; const int index[MAX_ENEMIES_IN_TEAM] = {2, 1, 0, 4, 3}; fCritical = (RandomLong(0, 5) == 0); if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { if (g_Battle.rgEnemy[index[i]].wObjectID == 0 || index[i] > g_Battle.wMaxEnemyIndex) { continue; } str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[index[i]].e.wDefense; def += (g_Battle.rgEnemy[index[i]].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[index[i]].e.wAttackResistance; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (fCritical) { // // Critical Hit // sDamage *= 3; } sDamage /= division; if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[index[i]].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[index[i]].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[index[i]].e.wHealth = 0; } // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[index[i]].pos); y = PAL_Y(g_Battle.rgEnemy[index[i]].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); division++; if (division > 3) { division = 3; } } } } PAL_BattleUpdateFighters(); PAL_BattleMakeScene(); PAL_BattleDelay(5, 0); break; case kBattleActionAttackMate: break; case kBattleActionCoopMagic: break; case kBattleActionDefend: g_Battle.rgPlayer[wPlayerIndex].fDefending = TRUE; break; case kBattleActionFlee: break; case kBattleActionMagic: break; case kBattleActionThrowItem: break; case kBattleActionUseItem: wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID; PAL_BattleShowPlayerUseItemAnim(wPlayerIndex, wObject, sTarget); // // Run the script // gpGlobals->g.rgObject[wObject].item.wScriptOnUse = PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].item.wScriptOnUse, (sTarget == -1) ? 0xFFFF : gpGlobals->rgParty[sTarget].wPlayerRole); // // Remove the item if the item is consuming and the script succeeded // if ((gpGlobals->g.rgObject[wObject].item.wFlags & kItemFlagConsuming) && g_fScriptSuccess) { PAL_AddItemToInventory(wObject, -1); } PAL_BattleUpdateFighters(); PAL_BattleDisplayStatChange(); PAL_BattleDelay(8, 0); break; case kBattleActionPass: break; } PAL_BattlePostActionCheck(FALSE); // // Check for poisons // fPoisoned = FALSE; PAL_BattleBackupStat(); for (i = 0; i < MAX_POISONS; i++) { wObject = gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonID; if (wObject != 0) { fPoisoned = TRUE; gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript = PAL_RunTriggerScript(gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript, wPlayerRole); } } if (fPoisoned) { PAL_BattleDelay(3, 0); PAL_BattleUpdateFighters(); if (PAL_BattleDisplayStatChange()) { PAL_BattleDelay(12, 0); } } // // Update statuses // for (i = 0; i < kStatusAll; i++) { if (gpGlobals->rgPlayerStatus[wPlayerRole][i] > 0) { gpGlobals->rgPlayerStatus[wPlayerRole][i]--; } } }