/*++ 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; }
WORD PAL_ItemSelectMenuUpdate( VOID ) /*++ Purpose: Initialize the item selection menu. Parameters: None. Return value: The object ID of the selected item. 0 if cancelled, 0xFFFF if not confirmed. --*/ { #ifndef PAL_WIN95 int i, j, k; WORD wObject; #else int i, j, k, line; WORD wObject, wScript; #endif BYTE bColor; static BYTE bufImage[2048]; static WORD wPrevImageIndex = 0xFFFF; // // Process input // if (g_InputState.dwKeyPress & kKeyUp) { gpGlobals->iCurInvMenuItem -= 3; } else if (g_InputState.dwKeyPress & kKeyDown) { gpGlobals->iCurInvMenuItem += 3; } else if (g_InputState.dwKeyPress & kKeyLeft) { gpGlobals->iCurInvMenuItem--; } else if (g_InputState.dwKeyPress & kKeyRight) { gpGlobals->iCurInvMenuItem++; } else if (g_InputState.dwKeyPress & kKeyPgUp) { gpGlobals->iCurInvMenuItem -= 3 * 7; } else if (g_InputState.dwKeyPress & kKeyPgDn) { gpGlobals->iCurInvMenuItem += 3 * 7; } else if (g_InputState.dwKeyPress & kKeyMenu) { return 0; } // // Make sure the current menu item index is in bound // if (gpGlobals->iCurInvMenuItem < 0) { gpGlobals->iCurInvMenuItem = 0; } else if (gpGlobals->iCurInvMenuItem >= g_iNumInventory) { gpGlobals->iCurInvMenuItem = g_iNumInventory - 1; } // // Redraw the box // PAL_CreateBox(PAL_XY(2, 0), 6, 17, 1, FALSE); // // Draw the texts in the current page // i = gpGlobals->iCurInvMenuItem / 3 * 3 - 3 * 4; if (i < 0) { i = 0; } for (j = 0; j < 7; j++) { for (k = 0; k < 3; k++) { wObject = gpGlobals->rgInventory[i].wItem; bColor = MENUITEM_COLOR; if (i >= MAX_INVENTORY || wObject == 0) { // // End of the list reached // j = 7; break; } if (i == gpGlobals->iCurInvMenuItem) { if (!(gpGlobals->g.rgObject[wObject].item.wFlags & g_wItemFlags) || (SHORT)gpGlobals->rgInventory[i].nAmount <= (SHORT)gpGlobals->rgInventory[i].nAmountInUse) { // // This item is not selectable // bColor = MENUITEM_COLOR_SELECTED_INACTIVE; } else { // // This item is selectable // if (gpGlobals->rgInventory[i].nAmount == 0) { bColor = MENUITEM_COLOR_EQUIPPEDITEM; } else { bColor = MENUITEM_COLOR_SELECTED; } } } else if (!(gpGlobals->g.rgObject[wObject].item.wFlags & g_wItemFlags) || (SHORT)gpGlobals->rgInventory[i].nAmount <= (SHORT)gpGlobals->rgInventory[i].nAmountInUse) { // // This item is not selectable // bColor = MENUITEM_COLOR_INACTIVE; } else if (gpGlobals->rgInventory[i].nAmount == 0) { bColor = MENUITEM_COLOR_EQUIPPEDITEM; } // // Draw the text // PAL_DrawText(PAL_GetWord(wObject), PAL_XY(15 + k * 100, 12 + j * 18), bColor, TRUE, FALSE); // // Draw the cursor on the current selected item // if (i == gpGlobals->iCurInvMenuItem) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_CURSOR), gpScreen, PAL_XY(40 + k * 100, 22 + j * 18)); } // // Draw the amount of this item // if ((SHORT)gpGlobals->rgInventory[i].nAmount - (SHORT)gpGlobals->rgInventory[i].nAmountInUse > 1) { PAL_DrawNumber(gpGlobals->rgInventory[i].nAmount - gpGlobals->rgInventory[i].nAmountInUse, 2, PAL_XY(96 + k * 100, 17 + j * 18), kNumColorCyan, kNumAlignRight); } i++; } } // // Draw the picture of current selected item // PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ITEMBOX), gpScreen, PAL_XY(5, 140)); wObject = gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].wItem; if (gpGlobals->g.rgObject[wObject].item.wBitmap != wPrevImageIndex) { if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wObject].item.wBitmap, gpGlobals->f.fpBALL) > 0) { wPrevImageIndex = gpGlobals->g.rgObject[wObject].item.wBitmap; } else { wPrevImageIndex = 0xFFFF; } } if (wPrevImageIndex != 0xFFFF) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(12, 148)); } // // Draw the description of the selected item // #ifndef PAL_WIN95 if (!g_fNoDesc && gpGlobals->lpObjectDesc != NULL) { char szDesc[512], *next; const char *d = PAL_GetObjectDesc(gpGlobals->lpObjectDesc, wObject); if (d != NULL) { k = 150; strcpy(szDesc, d); d = szDesc; while (TRUE) { next = strchr(d, '*'); if (next != NULL) { *next = '\0'; next++; } PAL_DrawText(d, PAL_XY(75, k), DESCTEXT_COLOR, TRUE, FALSE); k += 16; if (next == NULL) { break; } d = next; } } } #else if (!g_fNoDesc) { wScript = gpGlobals->g.rgObject[wObject].item.wScriptDesc; line = 0; while (wScript && gpGlobals->g.lprgScriptEntry[wScript].wOperation != 0) { if (gpGlobals->g.lprgScriptEntry[wScript].wOperation == 0xFFFF) { wScript = PAL_RunAutoScript(wScript, (1 << 15) | line); line++; } else { wScript = PAL_RunAutoScript(wScript, 0); } } } #endif if (g_InputState.dwKeyPress & kKeySearch) { if ((gpGlobals->g.rgObject[wObject].item.wFlags & g_wItemFlags) && (SHORT)gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].nAmount > (SHORT)gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].nAmountInUse) { if (gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].nAmount > 0) { j = (gpGlobals->iCurInvMenuItem < 3 * 4) ? (gpGlobals->iCurInvMenuItem / 3) : 4; k = gpGlobals->iCurInvMenuItem % 3; PAL_DrawText(PAL_GetWord(wObject), PAL_XY(15 + k * 100, 12 + j * 18), MENUITEM_COLOR_CONFIRMED, FALSE, FALSE); } return wObject; } } return 0xFFFF; }
WORD PAL_MagicSelectionMenuUpdate( VOID ) /*++ Purpose: Update the magic selection menu. Parameters: None. Return value: The selected magic. 0 if cancelled, 0xFFFF if not confirmed. --*/ { int i, j, k; BYTE bColor; // // Check for inputs // if (g_InputState.dwKeyPress & kKeyUp) { g_iCurrentItem -= 3; } else if (g_InputState.dwKeyPress & kKeyDown) { g_iCurrentItem += 3; } else if (g_InputState.dwKeyPress & kKeyLeft) { g_iCurrentItem--; } else if (g_InputState.dwKeyPress & kKeyRight) { g_iCurrentItem++; } else if (g_InputState.dwKeyPress & kKeyPgUp) { g_iCurrentItem -= 3 * 5; } else if (g_InputState.dwKeyPress & kKeyPgDn) { g_iCurrentItem += 3 * 5; } else if (g_InputState.dwKeyPress & kKeyMenu) { return 0; } // // Make sure the current menu item index is in bound // if (g_iCurrentItem < 0) { g_iCurrentItem = 0; } else if (g_iCurrentItem >= g_iNumMagic) { g_iCurrentItem = g_iNumMagic - 1; } // // Create the box. // PAL_CreateBox(PAL_XY(10, 42), 4, 16, 1, FALSE); if (gpGlobals->lpObjectDesc == NULL) { // // Draw the cash amount. // PAL_CreateSingleLineBox(PAL_XY(0, 0), 5, FALSE); PAL_DrawText(PAL_GetWord(CASH_LABEL), PAL_XY(10, 10), 0, FALSE, FALSE); PAL_DrawNumber(gpGlobals->dwCash, 6, PAL_XY(49, 14), kNumColorYellow, kNumAlignRight); // // Draw the MP of the selected magic. // PAL_CreateSingleLineBox(PAL_XY(215, 0), 5, FALSE); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(260, 14)); PAL_DrawNumber(rgMagicItem[g_iCurrentItem].wMP, 4, PAL_XY(230, 14), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(g_wPlayerMP, 4, PAL_XY(265, 14), kNumColorCyan, kNumAlignRight); } else { char szDesc[512], *next; const char *d = PAL_GetObjectDesc(gpGlobals->lpObjectDesc, rgMagicItem[g_iCurrentItem].wMagic); // // Draw the magic description. // if (d != NULL) { k = 3; strcpy(szDesc, d); d = szDesc; while (TRUE) { next = strchr(d, '*'); if (next != NULL) { *next = '\0'; next++; } PAL_DrawText(d, PAL_XY(100, k), DESCTEXT_COLOR, TRUE, FALSE); k += 16; if (next == NULL) { break; } d = next; } } // // Draw the MP of the selected magic. // PAL_CreateSingleLineBox(PAL_XY(0, 0), 5, FALSE); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(45, 14)); PAL_DrawNumber(rgMagicItem[g_iCurrentItem].wMP, 4, PAL_XY(15, 14), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(g_wPlayerMP, 4, PAL_XY(50, 14), kNumColorCyan, kNumAlignRight); } // // Draw the texts of the current page // i = g_iCurrentItem / 3 * 3 - 3 * 2; if (i < 0) { i = 0; } for (j = 0; j < 5; j++) { for (k = 0; k < 3; k++) { bColor = MENUITEM_COLOR; if (i >= g_iNumMagic) { // // End of the list reached // j = 5; break; } if (i == g_iCurrentItem) { if (rgMagicItem[i].fEnabled) { bColor = MENUITEM_COLOR_SELECTED; } else { bColor = MENUITEM_COLOR_SELECTED_INACTIVE; } } else if (!rgMagicItem[i].fEnabled) { bColor = MENUITEM_COLOR_INACTIVE; } // // Draw the text // PAL_DrawText(PAL_GetWord(rgMagicItem[i].wMagic), PAL_XY(35 + k * 87, 54 + j * 18), bColor, TRUE, FALSE); // // Draw the cursor on the current selected item // if (i == g_iCurrentItem) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_CURSOR), gpScreen, PAL_XY(60 + k * 87, 64 + j * 18)); } i++; } } if (g_InputState.dwKeyPress & kKeySearch) { if (rgMagicItem[g_iCurrentItem].fEnabled) { j = g_iCurrentItem % 3; k = (g_iCurrentItem < 3 * 2) ? (g_iCurrentItem / 3) : 2; j = 35 + j * 87; k = 54 + k * 18; PAL_DrawText(PAL_GetWord(rgMagicItem[g_iCurrentItem].wMagic), PAL_XY(j, k), MENUITEM_COLOR_CONFIRMED, FALSE, TRUE); return rgMagicItem[g_iCurrentItem].wMagic; } } return 0xFFFF; }
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_PlayerInfoBox( PAL_POS pos, WORD wPlayerRole, INT iTimeMeter, BYTE bTimeMeterColor, BOOL fUpdate ) /*++ Purpose: Show the player info box. Parameters: [IN] pos - the top-left corner position of the box. [IN] wPlayerRole - the player role ID to be shown. [IN] iTimeMeter - the value of time meter. 0 = empty, 100 = full. [IN] bTimeMeterColor - the color of time meter. [IN] fUpdate - whether to update the screen area or not. Return value: None. --*/ { SDL_Rect rect; BYTE bPoisonColor; int i, iPartyIndex; WORD wMaxLevel, w; const BYTE rgStatusPos[kStatusAll][2] = { {35, 19}, // confused {0, 0}, // slow {54, 1}, // sleep {55, 20}, // silence {0, 0}, // puppet {0, 0}, // bravery {0, 0}, // protect {0, 0}, // haste {0, 0}, // dualattack }; const WORD rgwStatusWord[kStatusAll] = { 0x1D, // confused 0x00, // slow 0x1C, // sleep 0x1A, // silence 0x00, // puppet 0x00, // bravery 0x00, // protect 0x00, // haste 0x00, // dualattack }; const BYTE rgbStatusColor[kStatusAll] = { 0x5F, // confused 0x00, // slow 0x0E, // sleep 0x3C, // silence 0x00, // puppet 0x00, // bravery 0x00, // protect 0x00, // haste 0x00, // dualattack }; // // Draw the box // PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_PLAYERINFOBOX), gpScreen, pos); // // Draw the player face // wMaxLevel = 0; bPoisonColor = 0xFF; for (iPartyIndex = 0; iPartyIndex <= gpGlobals->wMaxPartyMemberIndex; iPartyIndex++) { if (gpGlobals->rgParty[iPartyIndex].wPlayerRole == wPlayerRole) { break; } } if (iPartyIndex <= gpGlobals->wMaxPartyMemberIndex) { for (i = 0; i < MAX_POISONS; i++) { w = gpGlobals->rgPoisonStatus[i][iPartyIndex].wPoisonID; if (w != 0 && gpGlobals->g.rgObject[w].poison.wPoisonLevel <= 3) { if (gpGlobals->g.rgObject[w].poison.wPoisonLevel >= wMaxLevel) { wMaxLevel = gpGlobals->g.rgObject[w].poison.wPoisonLevel; bPoisonColor = (BYTE)(gpGlobals->g.rgObject[w].poison.wColor); } } } } if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0) { // // Always use the black/white color for dead players // and do not use the time meter // bPoisonColor = 0; iTimeMeter = 0; } if (bPoisonColor == 0xFF) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_PLAYERFACE_FIRST + wPlayerRole), gpScreen, PAL_XY(PAL_X(pos) - 2, PAL_Y(pos) - 4)); } else { PAL_RLEBlitMonoColor(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_PLAYERFACE_FIRST + wPlayerRole), gpScreen, PAL_XY(PAL_X(pos) - 2, PAL_Y(pos) - 4), bPoisonColor, 0); } #ifndef PAL_CLASSIC // // Draw a border for the Time Meter // rect.x = PAL_X(pos) + 31; rect.y = PAL_Y(pos) + 4; rect.w = 1; rect.h = 6; SDL_FillRect(gpScreen, &rect, 0xBD); rect.x += 39; SDL_FillRect(gpScreen, &rect, 0xBD); rect.x = PAL_X(pos) + 32; rect.y = PAL_Y(pos) + 3; rect.w = 38; rect.h = 1; SDL_FillRect(gpScreen, &rect, 0xBD); rect.y += 7; SDL_FillRect(gpScreen, &rect, 0xBD); // // Draw the Time meter bar // if (iTimeMeter >= 100) { rect.x = PAL_X(pos) + 33; rect.y = PAL_Y(pos) + 6; rect.w = 36; rect.h = 2; SDL_FillRect(gpScreen, &rect, 0x2C); } else if (iTimeMeter > 0) { rect.x = PAL_X(pos) + 33; rect.y = PAL_Y(pos) + 5; rect.w = iTimeMeter * 36 / 100; rect.h = 4; SDL_FillRect(gpScreen, &rect, bTimeMeterColor); } #endif // // Draw the HP and MP value // #ifdef PAL_CLASSIC PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(PAL_X(pos) + 49, PAL_Y(pos) + 6)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 47, PAL_Y(pos) + 8), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 26, PAL_Y(pos) + 5), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(PAL_X(pos) + 49, PAL_Y(pos) + 22)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 47, PAL_Y(pos) + 24), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 26, PAL_Y(pos) + 21), kNumColorCyan, kNumAlignRight); #else PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(PAL_X(pos) + 49, PAL_Y(pos) + 14)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 47, PAL_Y(pos) + 16), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 26, PAL_Y(pos) + 13), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(PAL_X(pos) + 49, PAL_Y(pos) + 24)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 47, PAL_Y(pos) + 26), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole], 4, PAL_XY(PAL_X(pos) + 26, PAL_Y(pos) + 23), kNumColorCyan, kNumAlignRight); #endif // // Draw Statuses // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { for (i = 0; i < kStatusAll; i++) { if (gpGlobals->rgPlayerStatus[wPlayerRole][i] > 0 && rgwStatusWord[i] != 0) { PAL_DrawText(PAL_GetWord(rgwStatusWord[i]), PAL_XY(PAL_X(pos) + rgStatusPos[i][0], PAL_Y(pos) + rgStatusPos[i][1]), rgbStatusColor[i], TRUE, FALSE); } } } // // Update the screen area if needed // if (fUpdate) { rect.x = PAL_X(pos) - 2; rect.y = PAL_Y(pos) - 4; rect.w = 77; rect.h = 39; VIDEO_UpdateScreen(&rect); } }
VOID PAL_EndingAnimation( VOID ) /*++ Purpose: Show the ending animation.//就是灵儿独自面对合体水魔兽的动画 Parameters: None. Return value: None. --*/ { LPBYTE buf; LPBYTE bufGirl; SDL_Surface *pUpper; SDL_Surface *pLower; SDL_Rect srcrect, dstrect; int yPosGirl = 180; int i; buf = (LPBYTE)UTIL_calloc(1, 64000); bufGirl = (LPBYTE)UTIL_calloc(1, 6000); pUpper = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); pLower = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(pUpper, gpScreen->format->palette); SDL_SetSurfacePalette(pLower, gpScreen->format->palette); #else SDL_SetPalette(pUpper, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); SDL_SetPalette(pLower, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif #ifdef PAL_WIN95 PAL_MKFDecompressChunk(buf, 64000, 69, gpGlobals->f.fpFBP); PAL_FBPBlitToSurface(buf, pUpper); PAL_MKFDecompressChunk(buf, 64000, 70, gpGlobals->f.fpFBP); PAL_FBPBlitToSurface(buf, pLower); #else PAL_MKFDecompressChunk(buf, 64000, 61, gpGlobals->f.fpFBP); PAL_FBPBlitToSurface(buf, pUpper); PAL_MKFDecompressChunk(buf, 64000, 62, gpGlobals->f.fpFBP); PAL_FBPBlitToSurface(buf, pLower); #endif PAL_MKFDecompressChunk(buf, 64000, 571, gpGlobals->f.fpMGO); PAL_MKFDecompressChunk(bufGirl, 6000, 572, gpGlobals->f.fpMGO); srcrect.x = 0; dstrect.x = 0; srcrect.w = 320; dstrect.w = 320; gpGlobals->wScreenWave = 2; for (i = 0; i < 400; i++) { // // Draw the background // srcrect.y = 0; srcrect.h = 200 - i / 2; dstrect.y = i / 2; dstrect.h = 200 - i / 2; SDL_BlitSurface(pLower, &srcrect, gpScreen, &dstrect); srcrect.y = 200 - i / 2; srcrect.h = i / 2; dstrect.y = 0; dstrect.h = i / 2; SDL_BlitSurface(pUpper, &srcrect, gpScreen, &dstrect); PAL_ApplyWave(gpScreen); // // Draw the beast // PAL_RLEBlitToSurface(PAL_SpriteGetFrame(buf, 0), gpScreen, PAL_XY(0, -400 + i)); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(buf, 1), gpScreen, PAL_XY(0, -200 + i)); #ifdef PAL_WIN95 PAL_RLEBlitToSurface(buf + 0x8444, gpScreen, PAL_XY(0, -200 + i)); #else PAL_RLEBlitToSurface(PAL_SpriteGetFrame(buf, 1), gpScreen, PAL_XY(0, -200 + i)); #endif // // Draw the girl // yPosGirl -= i & 1; if (yPosGirl < 80) { yPosGirl = 80; } PAL_RLEBlitToSurface(PAL_SpriteGetFrame(bufGirl, (SDL_GetTicks() / 50) % 4), gpScreen, PAL_XY(220, yPosGirl)); // // Update the screen // VIDEO_UpdateScreen(NULL); if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(pUpper, gpScreen->format->palette); SDL_SetSurfacePalette(pLower, gpScreen->format->palette); #else SDL_SetPalette(pUpper, SDL_LOGPAL | SDL_PHYSPAL, VIDEO_GetPalette(), 0, 256); SDL_SetPalette(pLower, SDL_LOGPAL | SDL_PHYSPAL, VIDEO_GetPalette(), 0, 256); #endif } UTIL_Delay(50); } gpGlobals->wScreenWave = 0; SDL_FreeSurface(pUpper); SDL_FreeSurface(pLower); free(buf); free(bufGirl); }
/*++ Generate the battle scene into the scene buffer. --*/ VOID PAL_BattleMakeScene(void) { int i; PAL_POS pos; LPBYTE pSrc, pDst; BYTE b; // // Draw the background // pSrc = g_Battle.lpBackground->pixels; pDst = g_Battle.lpSceneBuf->pixels; for (i = 0; i < g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h; i++) { b = (*pSrc & 0x0F); b += g_Battle.sBackgroundColorShift; if (b & 0x80) { b = 0; } else if (b & 0x70) { b = 0x0F; } *pDst = (b | (*pSrc & 0xF0)); ++pSrc; ++pDst; } PAL_ApplyWave(g_Battle.lpSceneBuf); // // Draw the enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { pos = g_Battle.rgEnemy[i].pos; if (g_Battle.rgEnemy[i].rgwStatus[kStatusConfused] > 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] == 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] == 0) { // // Enemy is confused // pos = PAL_XY(PAL_X(pos) + RandomLong(-1, 1), PAL_Y(pos)); } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame))); if (g_Battle.rgEnemy[i].wObjectID != 0) { if (g_Battle.rgEnemy[i].iColorShift) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgEnemy[i].iColorShift); } else { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } if (g_Battle.lpSummonSprite != NULL) { // // Draw the summoned god // pos = PAL_XY(PAL_X(g_Battle.posSummon) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame)) / 2, PAL_Y(g_Battle.posSummon) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame))); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame), g_Battle.lpSceneBuf, pos); } else { // // Draw the players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { pos = g_Battle.rgPlayer[i].pos; if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // continue; } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } // // Confused players should be drawn on top of normal players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // pos = PAL_XY(PAL_X(g_Battle.rgPlayer[i].pos), PAL_Y(g_Battle.rgPlayer[i].pos) + RandomLong(-1, 1)); pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } } }
VOID PAL_DrawNumber( UINT iNum, UINT nLength, PAL_POS pos, NUMCOLOR color, NUMALIGN align ) /*++ Purpose: Draw the specified number with the bitmaps in the UI sprite. Parameters: [IN] iNum - the number to be drawn. [IN] nLength - max. length of the number. [IN] pos - position on the screen. [IN] color - color of the number (yellow or blue). [IN] align - align mode of the number. Return value: None. --*/ { UINT nActualLength, i; int x, y; LPCBITMAPRLE rglpBitmap[10]; // // Get the bitmaps. Blue starts from 29, Cyan from 56, Yellow from 19. // x = (color == kNumColorBlue) ? 29 : ((color == kNumColorCyan) ? 56 : 19); for (i = 0; i < 10; i++) { rglpBitmap[i] = PAL_SpriteGetFrame(gpSpriteUI, (UINT)x + i); } i = iNum; nActualLength = 0; // // Calculate the actual length of the number. // while (i > 0) { i /= 10; nActualLength++; } if (nActualLength > nLength) { nActualLength = nLength; } else if (nActualLength == 0) { nActualLength = 1; } x = PAL_X(pos) - 6; y = PAL_Y(pos); switch (align) { case kNumAlignLeft: x += 6 * nActualLength; break; case kNumAlignMid: x += 3 * (nLength + nActualLength); break; case kNumAlignRight: x += 6 * nLength; break; } // // Draw the number. // while (nActualLength-- > 0) { PAL_RLEBlitToSurface(rglpBitmap[iNum % 10], gpScreen, PAL_XY(x, y)); x -= 6; iNum /= 10; } }
LPBOX PAL_CreateBox( PAL_POS pos, INT nRows, INT nColumns, INT iStyle, BOOL fSaveScreen ) /*++ Purpose: Create a box on the screen. Parameters: [IN] pos - position of the box. [IN] nRows - number of rows of the box. [IN] nColumns - number of columns of the box. [IN] iStyle - style of the box (0 or 1). [IN] fSaveScreen - whether save the used screen area or not. Return value: Pointer to a BOX structure. NULL if failed. If fSaveScreen is false, then always returns NULL. --*/ { int i, j, x, m, n; LPCBITMAPRLE rglpBorderBitmap[3][3]; LPBOX lpBox = NULL; SDL_Surface *save; SDL_Rect rect; // // Get the bitmaps // for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { rglpBorderBitmap[i][j] = PAL_SpriteGetFrame(gpSpriteUI, i * 3 + j + iStyle * 9); } } rect.x = PAL_X(pos); rect.y = PAL_Y(pos); rect.w = 0; rect.h = 0; // // Get the total width and total height of the box // for (i = 0; i < 3; i++) { if (i == 1) { rect.w += PAL_RLEGetWidth(rglpBorderBitmap[0][i]) * nColumns; rect.h += PAL_RLEGetHeight(rglpBorderBitmap[i][0]) * nRows; } else { rect.w += PAL_RLEGetWidth(rglpBorderBitmap[0][i]); rect.h += PAL_RLEGetHeight(rglpBorderBitmap[i][0]); } } if (fSaveScreen) { // // Save the used part of the screen // save = SDL_CreateRGBSurface(gpScreen->flags, rect.w, rect.h, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (save == NULL) { return NULL; } lpBox = (LPBOX)calloc(1, sizeof(BOX)); if (lpBox == NULL) { SDL_FreeSurface(save); return NULL; } SDL_BlitSurface(gpScreen, &rect, save, NULL); lpBox->lpSavedArea = save; lpBox->pos = pos; lpBox->wWidth = rect.w; lpBox->wHeight = rect.h; } // // Border takes 2 additional rows and columns... // nRows += 2; nColumns += 2; // // Draw the box // for (i = 0; i < nRows; i++) { x = rect.x; m = (i == 0) ? 0 : ((i == nRows - 1) ? 2 : 1); for (j = 0; j < nColumns; j++) { n = (j == 0) ? 0 : ((j == nColumns - 1) ? 2 : 1); PAL_RLEBlitToSurface(rglpBorderBitmap[m][n], gpScreen, PAL_XY(x, rect.y)); x += PAL_RLEGetWidth(rglpBorderBitmap[m][n]); } rect.y += PAL_RLEGetHeight(rglpBorderBitmap[m][0]); } return lpBox; }
static BOOL PAL_BattleDisplayStatChange( VOID ) /*++ Purpose: Display the HP and MP changes of all players and enemies. Parameters: None. Return value: TRUE if there are any number displayed, FALSE if not. --*/ { int i, x, y; SHORT sDamage; WORD wPlayerRole; BOOL f = FALSE; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } if (g_Battle.rgEnemy[i].wPrevHP != g_Battle.rgEnemy[i].e.wHealth) { // // Show the number of damage // sDamage = g_Battle.rgEnemy[i].e.wHealth - g_Battle.rgEnemy[i].wPrevHP; x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow); } f = TRUE; } } for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (g_Battle.rgPlayer[i].wPrevHP != gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole]) { sDamage = gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevHP; x = PAL_X(g_Battle.rgPlayer[i].pos); y = PAL_Y(g_Battle.rgPlayer[i].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)); if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow); } f = TRUE; } if (g_Battle.rgPlayer[i].wPrevMP != gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole]) { sDamage = gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevMP; x = PAL_X(g_Battle.rgPlayer[i].pos); y = PAL_Y(g_Battle.rgPlayer[i].pos) - 62; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)); if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorCyan); } f = TRUE; } } return f; }
LPBOX PAL_CreateSingleLineBox( PAL_POS pos, INT nLen, BOOL fSaveScreen ) /*++ Purpose: Create a single-line box on the screen. Parameters: [IN] pos - position of the box. [IN] nLen - length of the box. [IN] fSaveScreen - whether save the used screen area or not. Return value: Pointer to a BOX structure. NULL if failed. If fSaveScreen is false, then always returns NULL. --*/ { static const int iNumLeftSprite = 44; static const int iNumMidSprite = 45; static const int iNumRightSprite = 46; LPCBITMAPRLE lpBitmapLeft; LPCBITMAPRLE lpBitmapMid; LPCBITMAPRLE lpBitmapRight; SDL_Surface *save; SDL_Rect rect; LPBOX lpBox = NULL; int i; // // Get the bitmaps // lpBitmapLeft = PAL_SpriteGetFrame(gpSpriteUI, iNumLeftSprite); lpBitmapMid = PAL_SpriteGetFrame(gpSpriteUI, iNumMidSprite); lpBitmapRight = PAL_SpriteGetFrame(gpSpriteUI, iNumRightSprite); rect.x = PAL_X(pos); rect.y = PAL_Y(pos); // // Get the total width and total height of the box // rect.w = PAL_RLEGetWidth(lpBitmapLeft) + PAL_RLEGetWidth(lpBitmapRight); rect.w += PAL_RLEGetWidth(lpBitmapMid) * nLen; rect.h = PAL_RLEGetHeight(lpBitmapLeft); if (fSaveScreen) { // // Save the used part of the screen // save = SDL_CreateRGBSurface(gpScreen->flags, rect.w, rect.h, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (save == NULL) { return NULL; } lpBox = (LPBOX)calloc(1, sizeof(BOX)); if (lpBox == NULL) { SDL_FreeSurface(gpScreen); return NULL; } SDL_BlitSurface(gpScreen, &rect, save, NULL); lpBox->pos = pos; lpBox->lpSavedArea = save; lpBox->wHeight = (WORD)rect.w; lpBox->wWidth = (WORD)rect.h; } // // Draw the box // PAL_RLEBlitToSurface(lpBitmapLeft, gpScreen, pos); rect.x += PAL_RLEGetWidth(lpBitmapLeft); for (i = 0; i < nLen; i++) { PAL_RLEBlitToSurface(lpBitmapMid, gpScreen, PAL_XY(rect.x, rect.y)); rect.x += PAL_RLEGetWidth(lpBitmapMid); } PAL_RLEBlitToSurface(lpBitmapRight, gpScreen, PAL_XY(rect.x, rect.y)); return lpBox; }
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]--; } } }
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); } } }
VOID PAL_BattleUIUpdate( VOID ) /*++ Purpose: Update the status of battle UI. Parameters: None. Return value: None. --*/ { int i, j, x, y; WORD wPlayerRole, w; static int s_iFrame = 0; s_iFrame++; if (g_Battle.UI.fAutoAttack && !gpGlobals->fAutoBattle) { // // Draw the "auto attack" message if in the autoattack mode. // if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.fAutoAttack = FALSE; } else { PAL_DrawText(PAL_GetWord(BATTLEUI_LABEL_AUTO), PAL_XY(280, 10), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); } } if (gpGlobals->fAutoBattle) { PAL_BattlePlayerCheckReady(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom) { PAL_BattleUIPlayerReady(i); break; } } if (g_Battle.UI.state != kBattleUIWait) { w = PAL_BattleUIPickAutoMagic(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole, 9999); if (w == 0) { g_Battle.UI.wActionType = kBattleActionAttack; g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } else { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } PAL_BattleCommitAction(FALSE); } goto end; } if (g_InputState.dwKeyPress & kKeyAuto) { g_Battle.UI.fAutoAttack = !g_Battle.UI.fAutoAttack; g_Battle.UI.MenuState = kBattleMenuMain; } #ifdef PAL_CLASSIC if (g_Battle.Phase == kBattlePhasePerformAction) { goto end; } if (!g_Battle.UI.fAutoAttack) #endif { // // Draw the player info boxes. // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; w = F2int(g_Battle.rgPlayer[i].flTimeMeter); j = TIMEMETER_COLOR_DEFAULT; #ifndef PAL_CLASSIC if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusHaste] > 0) { j = TIMEMETER_COLOR_HASTE; } else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] > 0) { j = TIMEMETER_COLOR_SLOW; } #endif if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] != 0) { w = 0; } PAL_PlayerInfoBox(PAL_XY(91 + 77 * i, 165), wPlayerRole, w, j, FALSE); } } if (g_InputState.dwKeyPress & kKeyStatus) { PAL_PlayerStatus(); goto end; } if (g_Battle.UI.state != kBattleUIWait) { wPlayerRole = gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 && gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet]) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } PAL_BattleCommitAction(FALSE); goto end; // don't go further } // // Cancel any actions if player is dead or sleeping. // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] != 0) { g_Battle.UI.wActionType = kBattleActionPass; PAL_BattleCommitAction(FALSE); goto end; // don't go further } if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] != 0) { g_Battle.UI.wActionType = kBattleActionAttackMate; PAL_BattleCommitAction(FALSE); goto end; // don't go further } if (g_Battle.UI.fAutoAttack) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } PAL_BattleCommitAction(FALSE); goto end; // don't go further } // // Draw the arrow on the player's head. // i = SPRITENUM_BATTLE_ARROW_CURRENTPLAYER_RED; if (s_iFrame & 1) { i = SPRITENUM_BATTLE_ARROW_CURRENTPLAYER; } x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wCurPlayerIndex][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wCurPlayerIndex][1] - 74; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, i), gpScreen, PAL_XY(x, y)); } switch (g_Battle.UI.state) { case kBattleUIWait: if (!g_Battle.fEnemyCleared) { PAL_BattlePlayerCheckReady(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom) { PAL_BattleUIPlayerReady(i); break; } } } break; case kBattleUISelectMove: // // Draw the icons // { struct { int iSpriteNum; PAL_POS pos; BATTLEUIACTION action; } rgItems[] = { {SPRITENUM_BATTLEICON_ATTACK, PAL_XY(27, 140), kBattleUIActionAttack}, {SPRITENUM_BATTLEICON_MAGIC, PAL_XY(0, 155), kBattleUIActionMagic}, {SPRITENUM_BATTLEICON_COOPMAGIC, PAL_XY(54, 155), kBattleUIActionCoopMagic}, {SPRITENUM_BATTLEICON_MISCMENU, PAL_XY(27, 170), kBattleUIActionMisc} }; if (g_Battle.UI.MenuState == kBattleMenuMain) { if (g_InputState.dir == kDirNorth) { g_Battle.UI.wSelectedAction = 0; } else if (g_InputState.dir == kDirSouth) { g_Battle.UI.wSelectedAction = 3; } else if (g_InputState.dir == kDirWest) { if (PAL_BattleUIIsActionValid(kBattleUIActionMagic)) { g_Battle.UI.wSelectedAction = 1; } } else if (g_InputState.dir == kDirEast) { if (PAL_BattleUIIsActionValid(kBattleUIActionCoopMagic)) { g_Battle.UI.wSelectedAction = 2; } } } if (!PAL_BattleUIIsActionValid(rgItems[g_Battle.UI.wSelectedAction].action)) { g_Battle.UI.wSelectedAction = 0; } for (i = 0; i < 4; i++) { if (g_Battle.UI.wSelectedAction == i) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos); } else if (PAL_BattleUIIsActionValid(rgItems[i].action)) { PAL_RLEBlitMonoColor(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos, 0, -4); } else { PAL_RLEBlitMonoColor(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos, 0x10, -4); } } switch (g_Battle.UI.MenuState) { case kBattleMenuMain: if (g_InputState.dwKeyPress & kKeySearch) { switch (g_Battle.UI.wSelectedAction) { case 0: // // Attack // g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } break; case 1: // // Magic // g_Battle.UI.MenuState = kBattleMenuMagicSelect; PAL_MagicSelectionMenuInit(wPlayerRole, TRUE, 0); break; case 2: // // Cooperative magic // w = gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole; w = PAL_GetPlayerCooperativeMagic(w); g_Battle.UI.wActionType = kBattleActionCoopMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagUsableToEnemy) { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } } else { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetPlayerAll; } else { #ifdef PAL_CLASSIC g_Battle.UI.wSelectedIndex = 0; #else g_Battle.UI.wSelectedIndex = g_Battle.UI.wCurPlayerIndex; #endif g_Battle.UI.state = kBattleUISelectTargetPlayer; } } break; case 3: // // Misc menu // g_Battle.UI.MenuState = kBattleMenuMisc; g_iCurMiscMenuItem = 0; break; } } else if (g_InputState.dwKeyPress & kKeyDefend) { g_Battle.UI.wActionType = kBattleActionDefend; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyForce) { w = PAL_BattleUIPickAutoMagic(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole, 60); if (w == 0) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } else { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyFlee) { g_Battle.UI.wActionType = kBattleActionFlee; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyUseItem) { g_Battle.UI.MenuState = kBattleMenuUseItemSelect; PAL_ItemSelectMenuInit(kItemFlagUsable); } else if (g_InputState.dwKeyPress & kKeyThrowItem) { g_Battle.UI.MenuState = kBattleMenuThrowItemSelect; PAL_ItemSelectMenuInit(kItemFlagThrowable); } else if (g_InputState.dwKeyPress & kKeyRepeat) { PAL_BattleCommitAction(TRUE); } #ifdef PAL_CLASSIC else if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].state = kFighterWait; g_Battle.UI.state = kBattleUIWait; if (g_Battle.UI.wCurPlayerIndex > 0) { // // Revert to the previous player // do { g_Battle.rgPlayer[--g_Battle.UI.wCurPlayerIndex].state = kFighterWait; if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType == kBattleActionThrowItem) { for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID) { gpGlobals->rgInventory[i].nAmountInUse--; break; } } } else if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType == kBattleActionUseItem) { if (gpGlobals->g.rgObject[g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID].item.wFlags & kItemFlagConsuming) { for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID) { gpGlobals->rgInventory[i].nAmountInUse--; break; } } } } } while (g_Battle.UI.wCurPlayerIndex > 0 && (gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole] == 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusConfused] > 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusSleep] > 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusParalyzed] > 0)); } } #else else if (g_InputState.dwKeyPress & kKeyMenu) { FLOAT flMin = int2F(-1); j = -1; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].flTimeMeter >= 100) { g_Battle.rgPlayer[i].flTimeMeter += 100; // HACKHACK: Prevent the time meter from going below 100 if ((g_Battle.rgPlayer[i].flTimeMeter < flMin || flMin < 0) && i != (int)g_Battle.UI.wCurPlayerIndex && g_Battle.rgPlayer[i].state == kFighterWait) { flMin = g_Battle.rgPlayer[i].flTimeMeter; j = i; } } } if (j != -1) { g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].flTimeMeter = flMin - int2F(99); g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].state = kFighterWait; g_Battle.UI.state = kBattleUIWait; } } #endif break; case kBattleMenuMagicSelect: w = PAL_MagicSelectionMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; if (w != 0) { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagUsableToEnemy) { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } } else { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetPlayerAll; } else { #ifdef PAL_CLASSIC g_Battle.UI.wSelectedIndex = 0; #else g_Battle.UI.wSelectedIndex = g_Battle.UI.wCurPlayerIndex; #endif g_Battle.UI.state = kBattleUISelectTargetPlayer; } } } } break; case kBattleMenuUseItemSelect: PAL_BattleUIUseItem(); break; case kBattleMenuThrowItemSelect: PAL_BattleUIThrowItem(); break; case kBattleMenuMisc: w = PAL_BattleUIMiscMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; switch (w) { #ifdef PAL_CLASSIC case 2: // item #else case 1: // item #endif g_Battle.UI.MenuState = kBattleMenuMiscItemSubMenu; g_iCurSubMenuItem = 0; break; #ifdef PAL_CLASSIC case 3: // defend #else case 2: // defend #endif g_Battle.UI.wActionType = kBattleActionDefend; PAL_BattleCommitAction(FALSE); break; #ifdef PAL_CLASSIC case 1: // auto #else case 3: // auto #endif g_Battle.UI.fAutoAttack = TRUE; break; case 4: // flee g_Battle.UI.wActionType = kBattleActionFlee; PAL_BattleCommitAction(FALSE); break; case 5: // status PAL_PlayerStatus(); break; } } break; case kBattleMenuMiscItemSubMenu: w = PAL_BattleUIMiscItemSubMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; switch (w) { case 1: // use g_Battle.UI.MenuState = kBattleMenuUseItemSelect; PAL_ItemSelectMenuInit(kItemFlagUsable); break; case 2: // throw g_Battle.UI.MenuState = kBattleMenuThrowItemSelect; PAL_ItemSelectMenuInit(kItemFlagThrowable); break; } } break; } } break; case kBattleUISelectTargetEnemy: x = -1; y = 0; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID != 0) { x = i; y++; } } if (x == -1) { g_Battle.UI.state = kBattleUISelectMove; break; } if (g_Battle.UI.wActionType == kBattleActionCoopMagic) { if (!PAL_BattleUIIsActionValid(kBattleActionCoopMagic)) { g_Battle.UI.state = kBattleUISelectMove; break; } } #ifdef PAL_CLASSIC // // Don't bother selecting when only 1 enemy left // if (y == 1) { g_Battle.UI.wPrevEnemyTarget = (WORD)x; PAL_BattleCommitAction(FALSE); break; } #endif if (g_Battle.UI.wSelectedIndex > x) { g_Battle.UI.wSelectedIndex = x; } for (i = 0; i <= x; i++) { if (g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID != 0) { break; } g_Battle.UI.wSelectedIndex++; g_Battle.UI.wSelectedIndex %= x + 1; } // // Highlight the selected enemy // if (s_iFrame & 1) { i = g_Battle.UI.wSelectedIndex; x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos); x -= PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y -= PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)); PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), gpScreen, PAL_XY(x, y), 7); } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wPrevEnemyTarget = g_Battle.UI.wSelectedIndex; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyDown)) { if (g_Battle.UI.wSelectedIndex != 0) { g_Battle.UI.wSelectedIndex--; while (g_Battle.UI.wSelectedIndex != 0 && g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID == 0) { g_Battle.UI.wSelectedIndex--; } } } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyUp)) { if (g_Battle.UI.wSelectedIndex < x) { g_Battle.UI.wSelectedIndex++; while (g_Battle.UI.wSelectedIndex < x && g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID == 0) { g_Battle.UI.wSelectedIndex++; } } } break; case kBattleUISelectTargetPlayer: #ifdef PAL_CLASSIC // // Don't bother selecting when only 1 player is in the party // if (gpGlobals->wMaxPartyMemberIndex == 0) { g_Battle.UI.wSelectedIndex = 0; PAL_BattleCommitAction(FALSE); } #endif j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER; if (s_iFrame & 1) { j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER_RED; } // // Draw arrows on the selected player // x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wSelectedIndex][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wSelectedIndex][1] - 67; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, j), gpScreen, PAL_XY(x, y)); if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyDown)) { if (g_Battle.UI.wSelectedIndex != 0) { g_Battle.UI.wSelectedIndex--; } else { g_Battle.UI.wSelectedIndex = gpGlobals->wMaxPartyMemberIndex; } } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyUp)) { if (g_Battle.UI.wSelectedIndex < gpGlobals->wMaxPartyMemberIndex) { g_Battle.UI.wSelectedIndex++; } else { g_Battle.UI.wSelectedIndex = 0; } } break; case kBattleUISelectTargetEnemyAll: #ifdef PAL_CLASSIC // // Don't bother selecting // g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); #else if (g_Battle.UI.wActionType == kBattleActionCoopMagic) { if (!PAL_BattleUIIsActionValid(kBattleActionCoopMagic)) { g_Battle.UI.state = kBattleUISelectMove; break; } } if (s_iFrame & 1) { // // Highlight all enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos); x -= PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y -= PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)); PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), gpScreen, PAL_XY(x, y), 7); } } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); } #endif break; case kBattleUISelectTargetPlayerAll: #ifdef PAL_CLASSIC // // Don't bother selecting // g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); #else j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER; if (s_iFrame & 1) { j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER_RED; } for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.UI.wActionType == kBattleActionMagic) { w = gpGlobals->g.rgObject[g_Battle.UI.wObjectID].magic.wMagicNumber; if (gpGlobals->g.lprgMagic[w].wType == kMagicTypeTrance) { if (i != g_Battle.UI.wCurPlayerIndex) continue; } } // // Draw arrows on all players, despite of dead or not // x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][1] - 67; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, j), gpScreen, PAL_XY(x, y)); } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); } #endif break; } end: // // Show the text message if there is one. // #ifndef PAL_CLASSIC if (SDL_GetTicks() < g_Battle.UI.dwMsgShowTime) { // // The text should be shown in a small window at the center of the screen // PAL_POS pos; int len = strlen(g_Battle.UI.szMsg); // // Create the window box // pos = PAL_XY(160 - len * 4, 40); PAL_CreateSingleLineBox(pos, (len + 1) / 2, FALSE); // // Show the text on the screen // pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10); PAL_DrawText(g_Battle.UI.szMsg, pos, 0, FALSE, FALSE); } else if (g_Battle.UI.szNextMsg[0] != '\0') { strcpy(g_Battle.UI.szMsg, g_Battle.UI.szNextMsg); g_Battle.UI.dwMsgShowTime = SDL_GetTicks() + g_Battle.UI.wNextMsgDuration; g_Battle.UI.szNextMsg[0] = '\0'; } #endif // // Draw the numbers // for (i = 0; i < BATTLEUI_MAX_SHOWNUM; i++) { if (g_Battle.UI.rgShowNum[i].wNum > 0) { if ((SDL_GetTicks() - g_Battle.UI.rgShowNum[i].dwTime) / BATTLE_FRAME_TIME > 10) { g_Battle.UI.rgShowNum[i].wNum = 0; } else { PAL_DrawNumber(g_Battle.UI.rgShowNum[i].wNum, 5, PAL_XY(PAL_X(g_Battle.UI.rgShowNum[i].pos), PAL_Y(g_Battle.UI.rgShowNum[i].pos) - (SDL_GetTicks() - g_Battle.UI.rgShowNum[i].dwTime) / BATTLE_FRAME_TIME), g_Battle.UI.rgShowNum[i].color, kNumAlignRight); } } } PAL_ClearKeyState(); }
static VOID PAL_SceneDrawSprites( VOID ) /*++ Purpose: Draw all the sprites to scene. Parameters: None. Return value: None. --*/ { int i, x, y, vy; g_nSpriteToDraw = 0; // // Put all the sprites to be drawn into our array. // // // Players // for (i = 0; i <= (short)gpGlobals->wMaxPartyMemberIndex + gpGlobals->nFollower; i++) { LPCBITMAPRLE lpBitmap = PAL_SpriteGetFrame(PAL_GetPlayerSprite((BYTE)i), gpGlobals->rgParty[i].wFrame); if (lpBitmap == NULL) { continue; } // // Add it to our array // PAL_AddSpriteToDraw(lpBitmap, gpGlobals->rgParty[i].x - PAL_RLEGetWidth(lpBitmap) / 2, gpGlobals->rgParty[i].y + gpGlobals->wLayer + 10, gpGlobals->wLayer + 6); // // Calculate covering tiles on the map // PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]); } // // Event Objects (Monsters/NPCs/others) // for (i = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex; i < gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; i++) { LPCBITMAPRLE lpFrame; LPCSPRITE lpSprite; LPEVENTOBJECT lpEvtObj = &(gpGlobals->g.lprgEventObject[i]); int iFrame; if (lpEvtObj->sState == kObjStateHidden || lpEvtObj->sVanishTime > 0 || lpEvtObj->sState < 0) { continue; } // // Get the sprite // lpSprite = PAL_GetEventObjectSprite((WORD)i + 1); if (lpSprite == NULL) { continue; } iFrame = lpEvtObj->wCurrentFrameNum; if (lpEvtObj->nSpriteFrames == 3) { // // walking character // if (iFrame == 2) { iFrame = 0; } if (iFrame == 3) { iFrame = 2; } } lpFrame = PAL_SpriteGetFrame(lpSprite, lpEvtObj->wDirection * lpEvtObj->nSpriteFrames + iFrame); if (lpFrame == NULL) { continue; } // // Calculate the coordinate and check if outside the screen // x = (SHORT)lpEvtObj->x - PAL_X(gpGlobals->viewport); x -= PAL_RLEGetWidth(lpFrame) / 2; if (x >= 320 || x < -(int)PAL_RLEGetWidth(lpFrame)) { // // outside the screen; skip it // continue; } y = (SHORT)lpEvtObj->y - PAL_Y(gpGlobals->viewport); y += lpEvtObj->sLayer * 8 + 9; vy = y - PAL_RLEGetHeight(lpFrame) - lpEvtObj->sLayer * 8 + 2; if (vy >= 200 || vy < -(int)PAL_RLEGetHeight(lpFrame)) { // // outside the screen; skip it // continue; } // // Add it into the array // PAL_AddSpriteToDraw(lpFrame, x, y, lpEvtObj->sLayer * 8 + 2); // // Calculate covering map tiles // PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]); } // // All sprites are now in our array; sort them by their vertical positions. // for (x = 0; x < g_nSpriteToDraw - 1; x++) { SPRITE_TO_DRAW tmp; BOOL fSwap = FALSE; for (y = 0; y < g_nSpriteToDraw - 1 - x; y++) { if (PAL_Y(g_rgSpriteToDraw[y].pos) > PAL_Y(g_rgSpriteToDraw[y + 1].pos)) { fSwap = TRUE; tmp = g_rgSpriteToDraw[y]; g_rgSpriteToDraw[y] = g_rgSpriteToDraw[y + 1]; g_rgSpriteToDraw[y + 1] = tmp; } } if (!fSwap) { break; } } // // Draw all the sprites to the screen. // for (i = 0; i < g_nSpriteToDraw; i++) { SPRITE_TO_DRAW *p = &g_rgSpriteToDraw[i]; x = PAL_X(p->pos); y = PAL_Y(p->pos) - PAL_RLEGetHeight(p->lpSpriteFrame) - p->iLayer; PAL_RLEBlitToSurface(p->lpSpriteFrame, gpScreen, PAL_XY(x, y)); } }
VOID PAL_PlayerStatus( VOID ) /*++ Purpose: Show the player status. Parameters: None. Return value: None. --*/ { PAL_LARGE BYTE bufBackground[320 * 200]; PAL_LARGE BYTE bufImage[16384]; int iCurrent; int iPlayerRole; int i, y; WORD w; const int rgEquipPos[MAX_PLAYER_EQUIPMENTS][2] = { {190, 0}, {248, 40}, {252, 102}, {202, 134}, {142, 142}, {82, 126} }; PAL_MKFDecompressChunk(bufBackground, 320 * 200, STATUS_BACKGROUND_FBPNUM, gpGlobals->f.fpFBP); iCurrent = 0; while (iCurrent >= 0 && iCurrent <= gpGlobals->wMaxPartyMemberIndex) { iPlayerRole = gpGlobals->rgParty[iCurrent].wPlayerRole; // // Draw the background image // PAL_FBPBlitToSurface(bufBackground, gpScreen); // // Draw the text labels // PAL_DrawText(PAL_GetWord(STATUS_LABEL_EXP), PAL_XY(6, 6), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(6, 32), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP), PAL_XY(6, 54), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP), PAL_XY(6, 76), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER), PAL_XY(6, 98), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER), PAL_XY(6, 118), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE), PAL_XY(6, 138), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY), PAL_XY(6, 158), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE), PAL_XY(6, 178), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[iPlayerRole]), PAL_XY(110, 8), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); // // Draw the stats // PAL_DrawNumber(gpGlobals->Exp.rgPrimaryExp[iPlayerRole].wExp, 5, PAL_XY(58, 6), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.rgLevelUpExp[gpGlobals->g.PlayerRoles.rgwLevel[iPlayerRole]], 5, PAL_XY(58, 15), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwLevel[iPlayerRole], 2, PAL_XY(54, 35), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(65, 58)); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(65, 80)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[iPlayerRole], 4, PAL_XY(42, 56), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[iPlayerRole], 4, PAL_XY(63, 61), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[iPlayerRole], 4, PAL_XY(42, 78), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[iPlayerRole], 4, PAL_XY(63, 83), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerAttackStrength(iPlayerRole), 4, PAL_XY(42, 102), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(iPlayerRole), 4, PAL_XY(42, 122), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(iPlayerRole), 4, PAL_XY(42, 142), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(iPlayerRole), 4, PAL_XY(42, 162), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(iPlayerRole), 4, PAL_XY(42, 182), kNumColorYellow, kNumAlignRight); // // Draw the equipments // for (i = 0; i < MAX_PLAYER_EQUIPMENTS; i++) { w = gpGlobals->g.PlayerRoles.rgwEquipment[i][iPlayerRole]; if (w == 0) { continue; } // // Draw the image // if (PAL_MKFReadChunk(bufImage, 16384, gpGlobals->g.rgObject[w].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(rgEquipPos[i][0], rgEquipPos[i][1])); } // // Draw the text label // PAL_DrawText(PAL_GetWord(w), PAL_XY(rgEquipPos[i][0] + 5, rgEquipPos[i][1] + 38), STATUS_COLOR_EQUIPMENT, TRUE, FALSE); } // // Draw the image of player role // if (PAL_MKFReadChunk(bufImage, 16384, gpGlobals->g.PlayerRoles.rgwAvatar[iPlayerRole], gpGlobals->f.fpRGM) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(110, 30)); } // // Draw all poisons // y = 58; for (i = 0; i < MAX_POISONS; i++) { w = gpGlobals->rgPoisonStatus[i][iCurrent].wPoisonID; if (w != 0 && gpGlobals->g.rgObject[w].poison.wPoisonLevel <= 3) { PAL_DrawText(PAL_GetWord(w), PAL_XY(185, y), (BYTE)(gpGlobals->g.rgObject[w].poison.wColor + 10), TRUE, FALSE); y += 18; } } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Wait for input // PAL_ClearKeyState(); while (TRUE) { UTIL_Delay(1); if (g_InputState.dwKeyPress & kKeyMenu) { iCurrent = -1; break; } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyUp)) { iCurrent--; break; } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyDown | kKeySearch)) { iCurrent++; break; } } } }
VOID PAL_ScrollFBP( WORD wChunkNum, WORD wScrollSpeed, BOOL fScrollDown ) /*++ Purpose: Scroll up an FBP picture to the screen. Parameters: [IN] wChunkNum - number of chunk in fbp.mkf file. [IN] wScrollSpeed - scrolling speed of showing the picture. [IN] fScrollDown - TRUE if scroll down, FALSE if scroll up. Return value: None. --*/ { SDL_Surface *p; PAL_LARGE BYTE buf[320 * 200]; PAL_LARGE BYTE bufSprite[320 * 200]; int i, l; SDL_Rect rect, dstrect; if (PAL_MKFDecompressChunk(buf, 320 * 200, wChunkNum, gpGlobals->f.fpFBP) <= 0) { return; } if (g_wCurEffectSprite != 0) { PAL_MKFDecompressChunk(bufSprite, 320 * 200, g_wCurEffectSprite, gpGlobals->f.fpMGO); } p = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (p == NULL) { return; } #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(p, gpScreen->format->palette); #else SDL_SetPalette(p, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif VIDEO_BackupScreen(); PAL_FBPBlitToSurface(buf, p); if (wScrollSpeed == 0) { wScrollSpeed = 1; } rect.x = 0; rect.w = 320; dstrect.x = 0; dstrect.w = 320; for (l = 0; l < 220; l++) { i = l; if (i > 200) { i = 200; } if (fScrollDown) { rect.y = 0; dstrect.y = i; rect.h = 200 - i; dstrect.h = 200 - i; } else { rect.y = i; dstrect.y = 0; rect.h = 200 - i; dstrect.h = 200 - i; } SDL_BlitSurface(gpScreenBak, &rect, gpScreen, &dstrect); if (fScrollDown) { rect.y = 200 - i; dstrect.y = 0; rect.h = i; dstrect.h = i; } else { rect.y = 0; dstrect.y = 200 - i; rect.h = i; dstrect.h = i; } SDL_BlitSurface(p, &rect, gpScreen, &dstrect); PAL_ApplyWave(gpScreen); if (g_wCurEffectSprite != 0) { int f = SDL_GetTicks() / 150; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(bufSprite, f % PAL_SpriteGetNumFrames(bufSprite)), gpScreen, PAL_XY(0, 0)); } VIDEO_UpdateScreen(NULL); if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(p, gpScreen->format->palette); #else SDL_SetPalette(p, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif } UTIL_Delay(800 / wScrollSpeed); } SDL_BlitSurface(p, NULL, gpScreen, NULL); SDL_FreeSurface(p); VIDEO_UpdateScreen(NULL); }
WORD PAL_ItemUseMenu( WORD wItemToUse ) /*++ Purpose: Show the use item menu. Parameters: [IN] wItemToUse - the object ID of the item to use. Return value: The selected player to use the item onto. MENUITEM_VALUE_CANCELLED if user cancelled. --*/ { BYTE bColor, bSelectedColor; PAL_LARGE BYTE bufImage[2048]; DWORD dwColorChangeTime; static WORD wSelectedPlayer = 0; SDL_Rect rect = {110, 2, 200, 180}; int i; bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; dwColorChangeTime = 0; while (TRUE) { if (wSelectedPlayer > gpGlobals->wMaxPartyMemberIndex) { wSelectedPlayer = 0; } // // Draw the box // PAL_CreateBox(PAL_XY(110, 2), 7, 9, 0, FALSE); // // Draw the stats of the selected player // PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(200, 16), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP), PAL_XY(200, 34), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP), PAL_XY(200, 52), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER), PAL_XY(200, 70), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER), PAL_XY(200, 88), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE), PAL_XY(200, 106), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY), PAL_XY(200, 124), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE), PAL_XY(200, 142), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); i = gpGlobals->rgParty[wSelectedPlayer].wPlayerRole; PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwLevel[i], 4, PAL_XY(240, 20), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(263, 38)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[i], 4, PAL_XY(261, 40), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[i], 4, PAL_XY(240, 37), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(263, 56)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[i], 4, PAL_XY(261, 58), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[i], 4, PAL_XY(240, 55), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerAttackStrength(i), 4, PAL_XY(240, 74), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(i), 4, PAL_XY(240, 92), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(i), 4, PAL_XY(240, 110), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(i), 4, PAL_XY(240, 128), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(i), 4, PAL_XY(240, 146), kNumColorYellow, kNumAlignRight); // // Draw the names of the players in the party // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (i == wSelectedPlayer) { bColor = bSelectedColor; } else { bColor = MENUITEM_COLOR; } PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[i].wPlayerRole]), PAL_XY(125, 16 + 20 * i), bColor, TRUE, FALSE); } PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ITEMBOX), gpScreen, PAL_XY(120, 80)); i = PAL_GetItemAmount(wItemToUse); if (i > 0) { // // Draw the picture of the item // if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wItemToUse].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(127, 88)); } // // Draw the amount and label of the item // PAL_DrawText(PAL_GetWord(wItemToUse), PAL_XY(116, 143), STATUS_COLOR_EQUIPMENT, TRUE, FALSE); PAL_DrawNumber(i, 2, PAL_XY(170, 133), kNumColorCyan, kNumAlignRight); } // // Update the screen area // VIDEO_UpdateScreen(&rect); // // Wait for key // PAL_ClearKeyState(); while (TRUE) { // // See if we should change the highlight color // if (SDL_GetTicks() > dwColorChangeTime) { if ((WORD)bSelectedColor + 1 >= (WORD)MENUITEM_COLOR_SELECTED_FIRST + MENUITEM_COLOR_SELECTED_TOTALNUM) { bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; } else { bSelectedColor++; } dwColorChangeTime = SDL_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM); // // Redraw the selected item. // PAL_DrawText( PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[wSelectedPlayer].wPlayerRole]), PAL_XY(125, 16 + 20 * wSelectedPlayer), bSelectedColor, FALSE, TRUE); } PAL_ProcessEvent(); if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(1); } if (i <= 0) { return MENUITEM_VALUE_CANCELLED; } if (g_InputState.dwKeyPress & (kKeyUp | kKeyLeft)) { wSelectedPlayer--; } else if (g_InputState.dwKeyPress & (kKeyDown | kKeyRight)) { if (wSelectedPlayer < gpGlobals->wMaxPartyMemberIndex) { wSelectedPlayer++; } } else if (g_InputState.dwKeyPress & kKeyMenu) { break; } else if (g_InputState.dwKeyPress & kKeySearch) { return gpGlobals->rgParty[wSelectedPlayer].wPlayerRole; } } return MENUITEM_VALUE_CANCELLED; }
VOID PAL_ShowFBP( WORD wChunkNum, WORD wFade ) /*++ Purpose: Draw an FBP picture to the screen. Parameters: [IN] wChunkNum - number of chunk in fbp.mkf file. [IN] wFade - fading speed of showing the picture. Return value: None. --*/ { PAL_LARGE BYTE buf[320 * 200]; PAL_LARGE BYTE bufSprite[320 * 200]; const int rgIndex[6] = {0, 3, 1, 5, 2, 4}; SDL_Surface *p; int i, j, k; BYTE a, b; if (PAL_MKFDecompressChunk(buf, 320 * 200, wChunkNum, gpGlobals->f.fpFBP) <= 0) { memset(buf, 0, sizeof(buf)); } if (g_wCurEffectSprite != 0) { PAL_MKFDecompressChunk(bufSprite, 320 * 200, g_wCurEffectSprite, gpGlobals->f.fpMGO); } if (wFade) { wFade++; wFade *= 10; p = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(p, gpScreen->format->palette); #else SDL_SetPalette(p, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif PAL_FBPBlitToSurface(buf, p); VIDEO_BackupScreen(); for (i = 0; i < 16; i++) { for (j = 0; j < 6; j++) { // // Blend the pixels in the 2 buffers, and put the result into the // backup buffer // for (k = rgIndex[j]; k < gpScreen->pitch * gpScreen->h; k += 6) { a = ((LPBYTE)(p->pixels))[k]; b = ((LPBYTE)(gpScreenBak->pixels))[k]; if (i > 0) { if ((a & 0x0F) > (b & 0x0F)) { b++; } else if ((a & 0x0F) < (b & 0x0F)) { b--; } } ((LPBYTE)(gpScreenBak->pixels))[k] = ((a & 0xF0) | (b & 0x0F)); } SDL_BlitSurface(gpScreenBak, NULL, gpScreen, NULL); if (g_wCurEffectSprite != 0) { int f = SDL_GetTicks() / 150; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(bufSprite, f % PAL_SpriteGetNumFrames(bufSprite)), gpScreen, PAL_XY(0, 0)); } VIDEO_UpdateScreen(NULL); UTIL_Delay(wFade); } } SDL_FreeSurface(p); } // // HACKHACK: to make the ending show correctly // #ifdef PAL_WIN95 if (wChunkNum != 68) #else if (wChunkNum != 49) #endif { PAL_FBPBlitToSurface(buf, gpScreen); } VIDEO_UpdateScreen(NULL); }
static VOID PAL_BuyMenu_OnItemChange( WORD wCurrentItem ) /*++ Purpose: Callback function which is called when player selected another item in the buy menu. Parameters: [IN] wCurrentItem - current item on the menu, indicates the object ID of the currently selected item. Return value: None. --*/ { const SDL_Rect rect = {20, 8, 128, 175}; int i, n; PAL_LARGE BYTE bufImage[2048]; // // Draw the picture of current selected item // PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ITEMBOX), gpScreen, PAL_XY(35, 8)); if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wCurrentItem].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(42, 16)); } // // See how many of this item we have in the inventory // n = 0; for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == 0) { break; } else if (gpGlobals->rgInventory[i].wItem == wCurrentItem) { n = gpGlobals->rgInventory[i].nAmount; break; } } // // Draw the amount of this item in the inventory // PAL_CreateSingleLineBox(PAL_XY(20, 105), 5, FALSE); PAL_DrawText(PAL_GetWord(BUYMENU_LABEL_CURRENT), PAL_XY(30, 115), 0, FALSE, FALSE); PAL_DrawNumber(n, 6, PAL_XY(69, 119), kNumColorYellow, kNumAlignRight); // // Draw the cash amount // PAL_CreateSingleLineBox(PAL_XY(20, 145), 5, FALSE); PAL_DrawText(PAL_GetWord(CASH_LABEL), PAL_XY(30, 155), 0, FALSE, FALSE); PAL_DrawNumber(gpGlobals->dwCash, 6, PAL_XY(69, 159), kNumColorYellow, kNumAlignRight); VIDEO_UpdateScreen(&rect); }
/*++ Show the "you win" message and add the experience points for players. --*/ static VOID PAL_BattleWon(void) { const SDL_Rect rect = {65, 60, 200, 100}; const SDL_Rect rect1 = {80, 0, 180, 200}; int i, j, iTotalCount; DWORD dwExp; WORD w; BOOL fLevelUp; PLAYERROLES OrigPlayerRoles; // // Backup the initial player stats // OrigPlayerRoles = gpGlobals->g.PlayerRoles; if (g_Battle.iExpGained > 0) { // // Play the "battle win" music // PAL_PlayMUS(g_Battle.fIsBoss ? 2 : 3, FALSE, 0); // // Show the message about the total number of exp. and cash gained // PAL_CreateSingleLineBox(PAL_XY(83, 60), 8, FALSE); PAL_CreateSingleLineBox(PAL_XY(65, 105), 10, FALSE); PAL_DrawText(PAL_GetWord(BATTLEWIN_GETEXP_LABEL), PAL_XY(95, 70), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(BATTLEWIN_BEATENEMY_LABEL), PAL_XY(77, 115), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(BATTLEWIN_DOLLAR_LABEL), PAL_XY(197, 115), 0, FALSE, FALSE); PAL_DrawNumber(g_Battle.iExpGained, 5, PAL_XY(182, 74), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(g_Battle.iCashGained, 5, PAL_XY(162, 119), kNumColorYellow, kNumAlignMid); VIDEO_UpdateScreen(&rect); PAL_WaitForKey(g_Battle.fIsBoss ? 5500 : 3000); } // // Add the cash value // gpGlobals->dwCash += g_Battle.iCashGained; // // Add the experience points for each players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { fLevelUp = FALSE; w = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0) { continue; // don't care about dead players } dwExp = gpGlobals->Exp.rgPrimaryExp[w].wExp; dwExp += g_Battle.iExpGained; if (gpGlobals->g.PlayerRoles.rgwLevel[w] > MAX_LEVELS) { gpGlobals->g.PlayerRoles.rgwLevel[w] = MAX_LEVELS; } while (dwExp >= gpGlobals->g.rgLevelUpExp[gpGlobals->g.PlayerRoles.rgwLevel[w]]) { dwExp -= gpGlobals->g.rgLevelUpExp[gpGlobals->g.PlayerRoles.rgwLevel[w]]; if (gpGlobals->g.PlayerRoles.rgwLevel[w] < MAX_LEVELS) { fLevelUp = TRUE; PAL_PlayerLevelUp(w, 1); gpGlobals->g.PlayerRoles.rgwHP[w] = gpGlobals->g.PlayerRoles.rgwMaxHP[w]; gpGlobals->g.PlayerRoles.rgwMP[w] = gpGlobals->g.PlayerRoles.rgwMaxMP[w]; } } gpGlobals->Exp.rgPrimaryExp[w].wExp = (WORD)dwExp; if (fLevelUp) { // // Player has gained a level. Show the message // PAL_CreateSingleLineBox(PAL_XY(80, 0), 10, FALSE); PAL_CreateBox(PAL_XY(82, 32), 7, 8, 1, FALSE); PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(110, 10), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(110 + 16 * 3, 10), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(BATTLEWIN_LEVELUP_LABEL), PAL_XY(110 + 16 * 5, 10), 0, FALSE, FALSE); for (j = 0; j < 8; j++) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ARROW), gpScreen, PAL_XY(183, 48 + 18 * j)); } PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(100, 44), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP), PAL_XY(100, 62), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP), PAL_XY(100, 80), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER), PAL_XY(100, 98), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER), PAL_XY(100, 116), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE), PAL_XY(100, 134), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY), PAL_XY(100, 152), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE), PAL_XY(100, 170), BATTLEWIN_LEVELUP_LABEL_COLOR, TRUE, FALSE); // // Draw the original stats and stats after level up // PAL_DrawNumber(OrigPlayerRoles.rgwLevel[w], 4, PAL_XY(133, 47), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwLevel[w], 4, PAL_XY(195, 47), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwHP[w], 4, PAL_XY(133, 64), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwMaxHP[w], 4, PAL_XY(154, 68), kNumColorBlue, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(156, 66)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[w], 4, PAL_XY(195, 64), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[w], 4, PAL_XY(216, 68), kNumColorBlue, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(218, 66)); PAL_DrawNumber(OrigPlayerRoles.rgwMP[w], 4, PAL_XY(133, 82), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwMaxMP[w], 4, PAL_XY(154, 86), kNumColorBlue, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(156, 84)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[w], 4, PAL_XY(195, 82), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[w], 4, PAL_XY(216, 86), kNumColorBlue, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(218, 84)); PAL_DrawNumber(OrigPlayerRoles.rgwAttackStrength[w] + PAL_GetPlayerAttackStrength(w) - gpGlobals->g.PlayerRoles.rgwAttackStrength[w], 4, PAL_XY(133, 101), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerAttackStrength(w), 4, PAL_XY(195, 101), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwMagicStrength[w] + PAL_GetPlayerMagicStrength(w) - gpGlobals->g.PlayerRoles.rgwMagicStrength[w], 4, PAL_XY(133, 119), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(w), 4, PAL_XY(195, 119), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwDefense[w] + PAL_GetPlayerDefense(w) - gpGlobals->g.PlayerRoles.rgwDefense[w], 4, PAL_XY(133, 137), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(w), 4, PAL_XY(195, 137), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwDexterity[w] + PAL_GetPlayerDexterity(w) - gpGlobals->g.PlayerRoles.rgwDexterity[w], 4, PAL_XY(133, 155), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(w), 4, PAL_XY(195, 155), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(OrigPlayerRoles.rgwFleeRate[w] + PAL_GetPlayerFleeRate(w) - gpGlobals->g.PlayerRoles.rgwFleeRate[w], 4, PAL_XY(133, 173), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(w), 4, PAL_XY(195, 173), kNumColorYellow, kNumAlignRight); // // Update the screen and wait for key // VIDEO_UpdateScreen(&rect1); PAL_WaitForKey(3000); OrigPlayerRoles = gpGlobals->g.PlayerRoles; } // // Increasing of other hidden levels // iTotalCount = 0; iTotalCount += gpGlobals->Exp.rgAttackExp[w].wCount; iTotalCount += gpGlobals->Exp.rgDefenseExp[w].wCount; iTotalCount += gpGlobals->Exp.rgDexterityExp[w].wCount; iTotalCount += gpGlobals->Exp.rgFleeExp[w].wCount; iTotalCount += gpGlobals->Exp.rgHealthExp[w].wCount; iTotalCount += gpGlobals->Exp.rgMagicExp[w].wCount; iTotalCount += gpGlobals->Exp.rgMagicPowerExp[w].wCount; if (iTotalCount > 0) { #define CHECK_HIDDEN_EXP(expname, statname, label) \ { \ dwExp = g_Battle.iExpGained; \ dwExp *= gpGlobals->Exp.expname[w].wCount; \ dwExp /= iTotalCount; \ dwExp *= 2; \ \ dwExp += gpGlobals->Exp.expname[w].wExp; \ \ if (gpGlobals->Exp.expname[w].wLevel > MAX_LEVELS) \ { \ gpGlobals->Exp.expname[w].wLevel = MAX_LEVELS; \ } \ \ while (dwExp >= gpGlobals->g.rgLevelUpExp[gpGlobals->Exp.expname[w].wLevel]) \ { \ dwExp -= gpGlobals->g.rgLevelUpExp[gpGlobals->Exp.expname[w].wLevel]; \ gpGlobals->g.PlayerRoles.statname[w] += RandomLong(1, 2); \ if (gpGlobals->Exp.expname[w].wLevel < MAX_LEVELS) \ { \ gpGlobals->Exp.expname[w].wLevel++; \ } \ } \ \ gpGlobals->Exp.expname[w].wExp = (WORD)dwExp; \ \ if (gpGlobals->g.PlayerRoles.statname[w] != \ OrigPlayerRoles.statname[w]) \ { \ PAL_CreateSingleLineBox(PAL_XY(83, 60), 8, FALSE); \ PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(95, 70), \ 0, FALSE, FALSE); \ PAL_DrawText(PAL_GetWord(label), PAL_XY(143, 70), \ 0, FALSE, FALSE); \ PAL_DrawText(PAL_GetWord(BATTLEWIN_LEVELUP_LABEL), PAL_XY(175, 70), \ 0, FALSE, FALSE); \ PAL_DrawNumber(gpGlobals->g.PlayerRoles.statname[w] - \ OrigPlayerRoles.statname[w], \ 5, PAL_XY(188, 74), kNumColorYellow, kNumAlignRight); \ VIDEO_UpdateScreen(&rect); \ PAL_WaitForKey(3000); \ } \ } CHECK_HIDDEN_EXP(rgHealthExp, rgwMaxHP, STATUS_LABEL_HP); CHECK_HIDDEN_EXP(rgMagicExp, rgwMaxMP, STATUS_LABEL_MP); CHECK_HIDDEN_EXP(rgAttackExp, rgwAttackStrength, STATUS_LABEL_ATTACKPOWER); CHECK_HIDDEN_EXP(rgMagicPowerExp, rgwMagicStrength, STATUS_LABEL_MAGICPOWER); CHECK_HIDDEN_EXP(rgDefenseExp, rgwDefense, STATUS_LABEL_RESISTANCE); CHECK_HIDDEN_EXP(rgDexterityExp, rgwDexterity, STATUS_LABEL_DEXTERITY); CHECK_HIDDEN_EXP(rgFleeExp, rgwFleeRate, STATUS_LABEL_FLEERATE); #undef CHECK_HIDDEN_EXP } // // Learn all magics at the current level // j = 0; while (j < gpGlobals->g.nLevelUpMagic) { if (gpGlobals->g.lprgLevelUpMagic[j].m[w].wMagic == 0 || gpGlobals->g.lprgLevelUpMagic[j].m[w].wLevel > gpGlobals->g.PlayerRoles.rgwLevel[w]) { j++; continue; } if (PAL_AddMagic(w, gpGlobals->g.lprgLevelUpMagic[j].m[w].wMagic)) { PAL_CreateSingleLineBox(PAL_XY(65, 105), 10, FALSE); PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(75, 115), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(BATTLEWIN_ADDMAGIC_LABEL), PAL_XY(75 + 16 * 3, 115), 0, FALSE, FALSE); PAL_DrawText(PAL_GetWord(gpGlobals->g.lprgLevelUpMagic[j].m[w].wMagic), PAL_XY(75 + 16 * 5, 115), 0x1B, FALSE, FALSE); VIDEO_UpdateScreen(&rect); PAL_WaitForKey(3000); } j++; } } // // Run the post-battle scripts // for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnBattleEnd, i); } // // Recover automatically after each battle // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { w = gpGlobals->rgParty[i].wPlayerRole; #if 1//def PAL_CLASSIC gpGlobals->g.PlayerRoles.rgwHP[w] += (gpGlobals->g.PlayerRoles.rgwMaxHP[w] - gpGlobals->g.PlayerRoles.rgwHP[w]) / 2; gpGlobals->g.PlayerRoles.rgwMP[w] += (gpGlobals->g.PlayerRoles.rgwMaxMP[w] - gpGlobals->g.PlayerRoles.rgwMP[w]) / 2; #else if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0) { gpGlobals->g.PlayerRoles.rgwHP[w] = 1; } else if (g_Battle.iExpGained > 0) { FLOAT f = (gpGlobals->g.rgLevelUpExp[gpGlobals->g.PlayerRoles.rgwLevel[w]] / 5.0f) / g_Battle.iExpGained; if (f < 2) { f = 2; } gpGlobals->g.PlayerRoles.rgwHP[w] += (gpGlobals->g.PlayerRoles.rgwMaxHP[w] - gpGlobals->g.PlayerRoles.rgwHP[w]) / f; gpGlobals->g.PlayerRoles.rgwMP[w] += (gpGlobals->g.PlayerRoles.rgwMaxMP[w] - gpGlobals->g.PlayerRoles.rgwMP[w]) / f / 1.2; } #endif } }
VOID PAL_InGameMagicMenu( VOID ) /*++ Purpose: Show the magic menu. Parameters: None. Return value: None. --*/ { MENUITEM rgMenuItem[MAX_PLAYERS_IN_PARTY]; int i, y; static WORD w; WORD wMagic; const SDL_Rect rect = {35, 62, 95, 90}; // // Draw the player info boxes // y = 45; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { PAL_PlayerInfoBox(PAL_XY(y, 165), gpGlobals->rgParty[i].wPlayerRole, 100, TIMEMETER_COLOR_DEFAULT, TRUE); y += 78; } y = 75; // // Generate one menu items for each player in the party // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { assert(i <= MAX_PLAYERS_IN_PARTY); rgMenuItem[i].wValue = i; rgMenuItem[i].wNumWord = gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[i].wPlayerRole]; rgMenuItem[i].fEnabled = (gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0); rgMenuItem[i].pos = PAL_XY(48, y); y += 18; } // // Draw the box // PAL_CreateBox(PAL_XY(35, 62), gpGlobals->wMaxPartyMemberIndex, 2, 0, FALSE); VIDEO_UpdateScreen(&rect); w = PAL_ReadMenu(NULL, rgMenuItem, gpGlobals->wMaxPartyMemberIndex + 1, w, MENUITEM_COLOR); if (w == MENUITEM_VALUE_CANCELLED) { return; } wMagic = 0; while (TRUE) { wMagic = PAL_MagicSelectionMenu(gpGlobals->rgParty[w].wPlayerRole, FALSE, wMagic); if (wMagic == 0) { break; } if (gpGlobals->g.rgObject[wMagic].magic.wFlags & kMagicFlagApplyToAll) { gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse = PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse, 0); if (g_fScriptSuccess) { gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess = PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess, 0); gpGlobals->g.PlayerRoles.rgwMP[gpGlobals->rgParty[w].wPlayerRole] -= gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[wMagic].magic.wMagicNumber].wCostMP; } if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; } } else { // // Need to select which player to use the magic on. // WORD wPlayer = 0; SDL_Rect rect; while (wPlayer != MENUITEM_VALUE_CANCELLED) { // // Redraw the player info boxes first // y = 45; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { PAL_PlayerInfoBox(PAL_XY(y, 165), gpGlobals->rgParty[i].wPlayerRole, 100, TIMEMETER_COLOR_DEFAULT, TRUE); y += 78; } // // Draw the cursor on the selected item // rect.x = 70 + 78 * wPlayer; rect.y = 193; rect.w = 9; rect.h = 6; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_CURSOR), gpScreen, PAL_XY(rect.x, rect.y)); VIDEO_UpdateScreen(&rect); while (TRUE) { PAL_ClearKeyState(); PAL_ProcessEvent(); if (g_InputState.dwKeyPress & kKeyMenu) { wPlayer = MENUITEM_VALUE_CANCELLED; break; } else if (g_InputState.dwKeyPress & kKeySearch) { gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse = PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse, gpGlobals->rgParty[wPlayer].wPlayerRole); if (g_fScriptSuccess) { gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess = PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess, gpGlobals->rgParty[wPlayer].wPlayerRole); if (g_fScriptSuccess) { gpGlobals->g.PlayerRoles.rgwMP[gpGlobals->rgParty[w].wPlayerRole] -= gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[wMagic].magic.wMagicNumber].wCostMP; // // Check if we have run out of MP // if (gpGlobals->g.PlayerRoles.rgwMP[gpGlobals->rgParty[w].wPlayerRole] < gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[wMagic].magic.wMagicNumber].wCostMP) { // // Don't go further if run out of MP // wPlayer = MENUITEM_VALUE_CANCELLED; } } } break; } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyUp)) { if (wPlayer > 0) { wPlayer--; break; } } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyDown)) { if (wPlayer < gpGlobals->wMaxPartyMemberIndex) { wPlayer++; break; } } SDL_Delay(1); } } } // // Redraw the player info boxes // y = 45; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { PAL_PlayerInfoBox(PAL_XY(y, 165), gpGlobals->rgParty[i].wPlayerRole, 100, TIMEMETER_COLOR_DEFAULT, TRUE); y += 78; } } }
static VOID PAL_DialogWaitForKey( VOID ) /*++ Purpose: Wait for player to press a key after showing a dialog. Parameters: None. Return value: None. --*/ { PAL_LARGE SDL_Color palette[256]; SDL_Color *pCurrentPalette, t; int i; // // get the current palette // pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette); memcpy(palette, pCurrentPalette, sizeof(palette)); if (g_TextLib.bDialogPosition != kDialogCenterWindow && g_TextLib.bDialogPosition != kDialogCenter) { // // show the icon // LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon); if (p != NULL) { SDL_Rect rect; rect.x = PAL_X(g_TextLib.posIcon); rect.y = PAL_Y(g_TextLib.posIcon); rect.w = 16; rect.h = 16; PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon); VIDEO_UpdateScreen(&rect); } } PAL_ClearKeyState(); while (TRUE) { UTIL_Delay(100); if (g_TextLib.bDialogPosition != kDialogCenterWindow && g_TextLib.bDialogPosition != kDialogCenter) { // // palette shift // t = palette[0xF9]; for (i = 0xF9; i < 0xFE; i++) { palette[i] = palette[i + 1]; } palette[0xFE] = t; VIDEO_SetPalette(palette); } if (g_InputState.dwKeyPress != 0) { break; } } if (g_TextLib.bDialogPosition != kDialogCenterWindow && g_TextLib.bDialogPosition != kDialogCenter) { PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette); } PAL_ClearKeyState(); g_TextLib.fUserSkip = FALSE; }
VOID PAL_BattleMakeScene( VOID ) /*++ Purpose: Generate the battle scene into the scene buffer. Parameters: None. Return value: None. --*/ { int i; PAL_POS pos; LPBYTE pSrc, pDst; //BYTE b; // // Draw the background // pSrc = g_Battle.lpBackground->pixels; pDst = g_Battle.lpSceneBuf->pixels; // optimized by ZBY ZBY_TIMING_BEGIN(2); make_colorshift_table(g_Battle.sBackgroundColorShift); if (0) { //if (g_Battle.sBackgroundColorShift == 0) { memcpy(pDst, pSrc, g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h); } else { i = g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h; while (i--) { /*b = (*pSrc & 0x0F); b += g_Battle.sBackgroundColorShift; if (b & 0x80) { b = 0; } else if (b & 0x70) { b = 0x0F; } *pDst = (b | (*pSrc & 0xF0)); assert(*pDst == cs_table[*pSrc]); */ *pDst = cs_table[*pSrc]; ++pSrc; ++pDst; } } ZBY_TIMING_END(2, "PAL_BattleMakeScene"); PAL_ApplyWave(g_Battle.lpSceneBuf); // // Draw the enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { pos = g_Battle.rgEnemy[i].pos; if (g_Battle.rgEnemy[i].rgwStatus[kStatusConfused] > 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] == 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] == 0) { // // Enemy is confused // pos = PAL_XY(PAL_X(pos) + RandomLong(-1, 1), PAL_Y(pos)); } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame))); if (g_Battle.rgEnemy[i].wObjectID != 0) { if (g_Battle.rgEnemy[i].iColorShift) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgEnemy[i].iColorShift); } else { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } if (g_Battle.lpSummonSprite != NULL) { // // Draw the summoned god // pos = PAL_XY(PAL_X(g_Battle.posSummon) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame)) / 2, PAL_Y(g_Battle.posSummon) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame))); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame), g_Battle.lpSceneBuf, pos); } else { // // Draw the players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { pos = g_Battle.rgPlayer[i].pos; if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // continue; } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } // // Confused players should be drawn on top of normal players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // pos = PAL_XY(PAL_X(g_Battle.rgPlayer[i].pos), PAL_Y(g_Battle.rgPlayer[i].pos) + RandomLong(-1, 1)); pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } } }