static VOID PAL_BattlePostActionCheck( BOOL fCheckPlayers ) /*++ Purpose: Essential checks after an action is executed. Parameters: [IN] fCheckPlayers - TRUE if check for players, FALSE if not. Return value: None. --*/ { int i; BOOL fFade = FALSE; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } if (g_Battle.rgEnemy[i].e.wHealth == 0) { // // This enemy is KO'ed // SOUND_Play(g_Battle.rgEnemy[i].e.wDeathSound); g_Battle.rgEnemy[i].wObjectID = 0; fFade = TRUE; } } if (fCheckPlayers) { } if (fFade) { PAL_BattleBackupScene(); PAL_BattleMakeScene(); PAL_BattleFadeScene(); } }
/*++ Enemy flee the battle. --*/ VOID PAL_BattleEnemyEscape(void) { int j, x, y, w; BOOL f = TRUE; SOUND_Play(45); // // Show the animation // while (f) { f = FALSE; for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { if (g_Battle.rgEnemy[j].wObjectID == 0) { continue; } x = PAL_X(g_Battle.rgEnemy[j].pos) - 5; y = PAL_Y(g_Battle.rgEnemy[j].pos); g_Battle.rgEnemy[j].pos = PAL_XY(x, y); w = PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[j].lpSprite, 0)); if (x + w > 0) { f = TRUE; } } PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); VIDEO_UpdateScreen(NULL); UTIL_Delay(10); } UTIL_Delay(500); g_Battle.BattleResult = kBattleResultTerminated; }
/*++ 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; }
VOID PAL_BattleEnemyEscape( VOID ) /*++ Purpose: Enemy flee the battle. Parameters: None. Return value: None. --*/ { int j, x, y, w; BOOL f = TRUE; UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattleEnemyEscape, "PAL_BattleEnemyEscape", __FILE__, "start"); SOUND_Play(45); // // Show the animation // while (f) { f = FALSE; for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { if (g_Battle.rgEnemy[j].wObjectID == 0) { continue; } x = PAL_X(g_Battle.rgEnemy[j].pos) - 5; y = PAL_Y(g_Battle.rgEnemy[j].pos); g_Battle.rgEnemy[j].pos = PAL_XY(x, y); w = PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[j].lpSprite, 0)); if (x + w > 0) { f = TRUE; } } PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); VIDEO_UpdateScreen(NULL); UTIL_Delay(10); } UTIL_Delay(500); g_Battle.BattleResult = kBattleResultTerminated; UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattleEnemyEscape, "PAL_BattleEnemyEscape", __FILE__, "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_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 }
static VOID PAL_BattleShowPlayerUseItemAnim( WORD wPlayerIndex, WORD wObjectID, SHORT sTarget ) /*++ Purpose: Show the "use item" effect for player. Parameters: [IN] wPlayerIndex - the index of the player. [IN] wObjectID - the object ID of the item to be used. [IN] sTarget - the target player of the action. Return value: None. --*/ { int i, j; PAL_BattleDelay(4, 0); g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) - 15, PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) - 7); g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5; SOUND_Play(28); for (i = 0; i <= 6; i++) { if (sTarget == -1) { for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++) { g_Battle.rgPlayer[j].iColorShift = i; } } else { g_Battle.rgPlayer[sTarget].iColorShift = i; } PAL_BattleDelay(1, wObjectID); } for (i = 5; i >= 0; i--) { if (sTarget == -1) { for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++) { g_Battle.rgPlayer[j].iColorShift = i; } } else { g_Battle.rgPlayer[sTarget].iColorShift = i; } PAL_BattleDelay(1, wObjectID); } }
static VOID PAL_BattleShowPlayerAttackAnim( WORD wPlayerIndex, BOOL fCritical ) /*++ Purpose: Show the physical attack effect for player. Parameters: [IN] wPlayerIndex - the index of the player. [IN] fCritical - TRUE if this is a critical hit. Return value: None. --*/ { WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole; SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget; int index, i, j; int enemy_x = 0, enemy_y = 0, enemy_h = 0, x, y, dist = 0; int w, h; DWORD dwTime; if (sTarget != -1) { enemy_x = PAL_X(g_Battle.rgEnemy[sTarget].pos); enemy_y = PAL_Y(g_Battle.rgEnemy[sTarget].pos); enemy_x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; enemy_h = PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)); enemy_y += enemy_h; if (sTarget >= 3) { dist = (sTarget - wPlayerIndex) * 8; } } else { enemy_x = 150; enemy_y = 100; } index = gpGlobals->g.rgwBattleEffectIndex[gpGlobals->g.PlayerRoles.rgwSpriteNumInBattle[wPlayerRole]][1]; index *= 3; // // Play the attack voice // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { if (!fCritical) { SOUND_Play(gpGlobals->g.PlayerRoles.rgwAttackSound[wPlayerRole]); } else { SOUND_Play(gpGlobals->g.PlayerRoles.rgwCriticalSound[wPlayerRole]); } } // // Show the animation // x = enemy_x - dist + 64; y = enemy_y + dist + 20; g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 8; w = PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[wPlayerIndex].lpSprite, 8)); h = PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[wPlayerIndex].lpSprite, 8)); g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x - w / 2, y - h); PAL_BattleDelay(2, 0); x -= 10; y -= 2; g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x - w / 2, y - h); PAL_BattleDelay(1, 0); g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9; x -= 16; y -= 4; SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]); x = enemy_x; y = enemy_y - enemy_h / 3 + 10; dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME; for (i = 0; i < 3; i++) { LPCBITMAPRLE b = PAL_SpriteGetFrame(g_Battle.lpEffectSprite, index++); // // Clear the input state of previous frame. // PAL_ClearKeyState(); // // Wait for the time of one frame. Accept input here. // PAL_ProcessEvent(); while (SDL_GetTicks() <= dwTime) { PAL_ProcessEvent(); SDL_Delay(1); } // // Set the time of the next frame. // dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME; // // Update the gesture of enemies. // for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { if (g_Battle.rgEnemy[j].wObjectID == 0) { continue; } if (--g_Battle.rgEnemy[j].e.wIdleAnimSpeed == 0) { g_Battle.rgEnemy[j].wCurrentFrame++; g_Battle.rgEnemy[j].e.wIdleAnimSpeed = gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[j].wObjectID].enemy.wEnemyID].wIdleAnimSpeed; } if (g_Battle.rgEnemy[j].wCurrentFrame >= g_Battle.rgEnemy[j].e.wIdleFrames) { g_Battle.rgEnemy[j].wCurrentFrame = 0; } } PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b))); x -= 16; y += 16; PAL_BattleUIUpdate(); if (i == 0) { if (sTarget == -1) { for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { g_Battle.rgEnemy[j].iColorShift = 6; } } else { g_Battle.rgEnemy[sTarget].iColorShift = 6; } // // Flash the screen if it's a critical hit // if (fCritical) { SDL_FillRect(gpScreen, NULL, 15); } } VIDEO_UpdateScreen(NULL); if (i == 1) { g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) + 2, PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) + 1); } } dist = 8; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { g_Battle.rgEnemy[i].iColorShift = 0; } if (sTarget == -1) { for (i = 0; i < 3; i++) { for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { x = PAL_X(g_Battle.rgEnemy[j].pos); y = PAL_Y(g_Battle.rgEnemy[j].pos); x -= dist; y -= dist / 2; g_Battle.rgEnemy[j].pos = PAL_XY(x, y); } PAL_BattleDelay(1, 0); dist /= -2; } } else { x = PAL_X(g_Battle.rgEnemy[sTarget].pos); y = PAL_Y(g_Battle.rgEnemy[sTarget].pos); for (i = 0; i < 3; i++) { x -= dist; dist /= -2; y += dist; g_Battle.rgEnemy[sTarget].pos = PAL_XY(x, y); PAL_BattleDelay(1, 0); } } }