static VOID PAL_BattleSpeedMenu( VOID ) /*++ Purpose: Show the Battle Speed selection box. Parameters: None. Return value: None. --*/ { LPBOX lpBox; WORD wReturnValue; const SDL_Rect rect = {131, 100, 165, 50}; MENUITEM rgMenuItem[5] = { { 1, BATTLESPEEDMENU_LABEL_1, TRUE, PAL_XY(145, 110) }, { 2, BATTLESPEEDMENU_LABEL_2, TRUE, PAL_XY(170, 110) }, { 3, BATTLESPEEDMENU_LABEL_3, TRUE, PAL_XY(195, 110) }, { 4, BATTLESPEEDMENU_LABEL_4, TRUE, PAL_XY(220, 110) }, { 5, BATTLESPEEDMENU_LABEL_5, TRUE, PAL_XY(245, 110) }, }; // // Create the boxes // lpBox = PAL_CreateSingleLineBox(PAL_XY(131, 100), 8, TRUE); VIDEO_UpdateScreen(&rect); // // Activate the menu // wReturnValue = PAL_ReadMenu(NULL, rgMenuItem, 5, gpGlobals->bBattleSpeed - 1, MENUITEM_COLOR); // // Delete the boxes // PAL_DeleteBox(lpBox); VIDEO_UpdateScreen(&rect); if (wReturnValue != MENUITEM_VALUE_CANCELLED) { gpGlobals->bBattleSpeed = wReturnValue; } }
VOID PAL_MakeScene( VOID ) /*++ Purpose: Draw the scene of the current frame to the screen. Both the map and the sprites are handled here. Parameters: None. Return value: None. --*/ { static SDL_Rect rect = {0, 0, 320, 200}; // // Step 1: Draw the complete map, for both of the layers. // rect.x = PAL_X(gpGlobals->viewport); rect.y = PAL_Y(gpGlobals->viewport); PAL_MapBlitToSurface(PAL_GetCurrentMap(), gpScreen, &rect, 0); PAL_MapBlitToSurface(PAL_GetCurrentMap(), gpScreen, &rect, 1); // // Step 2: Apply screen waving effects. // PAL_ApplyWave(gpScreen); // // Step 3: Draw all the sprites. // PAL_SceneDrawSprites(); // // Check if we need to fade in. // if (gpGlobals->fNeedToFadeIn) { VIDEO_UpdateScreen(NULL); PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; } }
static VOID PAL_InventoryMenu( VOID ) /*++ Purpose: Show the inventory menu. Parameters: None. Return value: None. --*/ { static WORD w = 0; const SDL_Rect rect = {30, 60, 75, 60}; MENUITEM rgMenuItem[2] = { // value label enabled pos { 1, INVMENU_LABEL_USE, TRUE, PAL_XY(43, 73) }, { 2, INVMENU_LABEL_EQUIP, TRUE, PAL_XY(43, 73 + 18) }, }; PAL_CreateBox(PAL_XY(30, 60), 1, 1, 0, FALSE); VIDEO_UpdateScreen(&rect); w = PAL_ReadMenu(NULL, rgMenuItem, 2, w - 1, MENUITEM_COLOR); switch (w) { case 1: PAL_GameUseItem(); break; case 2: PAL_GameEquipItem(); break; } }
/*++ 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; }
VOID PAL_DrawOpeningMenuBackground( VOID ) /*++ Purpose: Draw the background of the main menu. Parameters: None. Return value: None. --*/ { LPBYTE buf; buf = (LPBYTE)malloc(320 * 200); if (buf == NULL) { return; } // // Read the picture from fbp.mkf. // PAL_MKFDecompressChunk(buf, 320 * 200, MAINMENU_BACKGROUND_FBPNUM, gpGlobals->f.fpFBP); // // ...and blit it to the screen buffer. // PAL_FBPBlitToSurface(buf, gpScreen); VIDEO_UpdateScreen(NULL); free(buf); }
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); }
INT PAL_SaveSlotMenu( WORD wDefaultSlot ) /*++ Purpose: Show the load game menu. Parameters: [IN] wDefaultSlot - default save slot number (1-5). Return value: Which saved slot to load from (1-5). MENUITEM_VALUE_CANCELLED if cancelled. --*/ { LPBOX rgpBox[5]; int i; FILE *fp; WORD wItemSelected; WORD wSavedTimes; MENUITEM rgMenuItem[5]; const SDL_Rect rect = {195, 7, 120, 190}; // // Create the boxes and create the menu items // for (i = 0; i < 5; i++) { rgpBox[i] = PAL_CreateSingleLineBox(PAL_XY(195, 7 + 38 * i), 6, TRUE); rgMenuItem[i].wValue = i + 1; rgMenuItem[i].fEnabled = TRUE; rgMenuItem[i].wNumWord = LOADMENU_LABEL_SLOT_FIRST + i; rgMenuItem[i].pos = PAL_XY(210, 17 + 38 * i); } // // Draw the numbers of saved times // for (i = 1; i <= 5; i++) { fp = fopen(va("%s%d%s", PAL_SAVE_PREFIX, i, ".rpg"), "rb"); if (fp == NULL) { wSavedTimes = 0; } else { fread(&wSavedTimes, sizeof(WORD), 1, fp); wSavedTimes = SWAP16(wSavedTimes); fclose(fp); } // // Draw the number // PAL_DrawNumber((UINT)wSavedTimes, 4, PAL_XY(270, 38 * i - 17), kNumColorYellow, kNumAlignRight); } VIDEO_UpdateScreen(&rect); // // Activate the menu // wItemSelected = PAL_ReadMenu(NULL, rgMenuItem, 5, wDefaultSlot - 1, MENUITEM_COLOR); // // Delete the boxes // for (i = 0; i < 5; i++) { PAL_DeleteBox(rgpBox[i]); } VIDEO_UpdateScreen(&rect); return wItemSelected; }
WORD PAL_ItemSelectMenu( LPITEMCHANGED_CALLBACK lpfnMenuItemChanged, WORD wItemFlags ) /*++ Purpose: Show the item selection menu. Parameters: [IN] lpfnMenuItemChanged - Callback function which is called when user changed the current menu item. [IN] wItemFlags - flags for usable item. Return value: The object ID of the selected item. 0 if cancelled. --*/ { int iPrevIndex; WORD w; DWORD dwTime; PAL_ItemSelectMenuInit(wItemFlags); iPrevIndex = gpGlobals->iCurInvMenuItem; PAL_ClearKeyState(); if (lpfnMenuItemChanged != NULL) { g_fNoDesc = TRUE; (*lpfnMenuItemChanged)(gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].wItem); } dwTime = SDL_GetTicks(); while (TRUE) { if (lpfnMenuItemChanged == NULL) { PAL_MakeScene(); } w = PAL_ItemSelectMenuUpdate(); VIDEO_UpdateScreen(NULL); PAL_ClearKeyState(); PAL_ProcessEvent(); while (SDL_GetTicks() < dwTime) { PAL_ProcessEvent(); if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(5); } dwTime = SDL_GetTicks() + FRAME_TIME; if (w != 0xFFFF) { g_fNoDesc = FALSE; return w; } if (iPrevIndex != gpGlobals->iCurInvMenuItem) { if (gpGlobals->iCurInvMenuItem >= 0 && gpGlobals->iCurInvMenuItem < MAX_INVENTORY) { if (lpfnMenuItemChanged != NULL) { (*lpfnMenuItemChanged)(gpGlobals->rgInventory[gpGlobals->iCurInvMenuItem].wItem); } } iPrevIndex = gpGlobals->iCurInvMenuItem; } } assert(FALSE); return 0; // should not really reach here }
WORD PAL_MagicSelectionMenu( WORD wPlayerRole, BOOL fInBattle, WORD wDefaultMagic ) /*++ Purpose: Show the magic selection menu. Parameters: [IN] wPlayerRole - the player ID. [IN] fInBattle - TRUE if in battle, FALSE if not. [IN] wDefaultMagic - the default magic item. Return value: The selected magic. 0 if cancelled. --*/ { WORD w; int i; DWORD dwTime; PAL_MagicSelectionMenuInit(wPlayerRole, fInBattle, wDefaultMagic); PAL_ClearKeyState(); dwTime = SDL_GetTicks(); while (TRUE) { //PAL_MakeScene(); SDL_FillRect(gpScreen, NULL, SDL_MapRGB(gpScreen->format, 0,0,0)); w = 45; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { PAL_PlayerInfoBox(PAL_XY(w, 165), gpGlobals->rgParty[i].wPlayerRole, 100, TIMEMETER_COLOR_DEFAULT, FALSE); w += 78; } w = PAL_MagicSelectionMenuUpdate(); VIDEO_UpdateScreen(NULL); PAL_ClearKeyState(); if (w != 0xFFFF) { return w; } PAL_ProcessEvent(); while (SDL_GetTicks() < dwTime) { PAL_ProcessEvent(); if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(3); } dwTime = SDL_GetTicks() + FRAME_TIME; } return 0; // should not really reach here }
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_EquipItemMenu( WORD wItem ) /*++ Purpose: Show the menu which allow players to equip the specified item. Parameters: [IN] wItem - the object ID of the item. Return value: None. --*/ { PAL_LARGE BYTE bufBackground[320 * 200]; PAL_LARGE BYTE bufImage[2048]; WORD w; int iCurrentPlayer, i; BYTE bColor, bSelectedColor; DWORD dwColorChangeTime; gpGlobals->wLastUnequippedItem = wItem; PAL_MKFDecompressChunk(bufBackground, 320 * 200, EQUIPMENU_BACKGROUND_FBPNUM, gpGlobals->f.fpFBP); iCurrentPlayer = 0; bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; dwColorChangeTime = SDL_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM); while (TRUE) { wItem = gpGlobals->wLastUnequippedItem; // // Draw the background // PAL_FBPBlitToSurface(bufBackground, gpScreen); // // Draw the item picture // if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wItem].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(16, 16)); } // // Draw the current equipment of the selected player // w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; for (i = 0; i < MAX_PLAYER_EQUIPMENTS; i++) { if (gpGlobals->g.PlayerRoles.rgwEquipment[i][w] != 0) { PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwEquipment[i][w]), PAL_XY(130, 11 + i * 22), MENUITEM_COLOR, TRUE, FALSE); } } // // Draw the stats of the currently selected player // PAL_DrawNumber(PAL_GetPlayerAttackStrength(w), 4, PAL_XY(260, 14), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(w), 4, PAL_XY(260, 36), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(w), 4, PAL_XY(260, 58), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(w), 4, PAL_XY(260, 80), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(w), 4, PAL_XY(260, 102), kNumColorCyan, kNumAlignRight); // // Draw a box for player selection // PAL_CreateBox(PAL_XY(2, 95), gpGlobals->wMaxPartyMemberIndex, 2, 0, FALSE); // // Draw the label of players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { w = gpGlobals->rgParty[i].wPlayerRole; if (iCurrentPlayer == i) { if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { bColor = bSelectedColor; } else { bColor = MENUITEM_COLOR_SELECTED_INACTIVE; } } else { if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { bColor = MENUITEM_COLOR; } else { bColor = MENUITEM_COLOR_INACTIVE; } } PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(15, 108 + 18 * i), bColor, TRUE, FALSE); } // // Draw the text label and amount of the item // if (wItem != 0) { PAL_DrawText(PAL_GetWord(wItem), PAL_XY(5, 70), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); PAL_DrawNumber(PAL_GetItemAmount(wItem), 2, PAL_XY(65, 73), kNumColorCyan, kNumAlignRight); } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Accept input // PAL_ClearKeyState(); while (TRUE) { PAL_ProcessEvent(); // // 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 if needed. // w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(15, 108 + 18 * iCurrentPlayer), bSelectedColor, TRUE, TRUE); } } if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(1); } if (wItem == 0) { return; } if (g_InputState.dwKeyPress & (kKeyUp | kKeyLeft)) { iCurrentPlayer--; if (iCurrentPlayer < 0) { iCurrentPlayer = 0; } } else if (g_InputState.dwKeyPress & (kKeyDown | kKeyRight)) { iCurrentPlayer++; if (iCurrentPlayer > gpGlobals->wMaxPartyMemberIndex) { iCurrentPlayer = gpGlobals->wMaxPartyMemberIndex; } } else if (g_InputState.dwKeyPress & kKeyMenu) { return; } else if (g_InputState.dwKeyPress & kKeySearch) { w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { // // Run the equip script // gpGlobals->g.rgObject[wItem].item.wScriptOnEquip = PAL_RunTriggerScript(gpGlobals->g.rgObject[wItem].item.wScriptOnEquip, gpGlobals->rgParty[iCurrentPlayer].wPlayerRole); } } } }
/*++ Fade in the scene of battle. --*/ VOID PAL_BattleFadeScene(void) { int i, j, k; DWORD time; BYTE a, b; const int rgIndex[6] = {0, 3, 1, 5, 2, 4}; time = SDL_GetTicks(); for (i = 0; i < 12; i++) { for (j = 0; j < 6; j++) { PAL_ProcessEvent(); while (SDL_GetTicks() <= time) { PAL_ProcessEvent(); SDL_Delay(1); } time = SDL_GetTicks() + 16; // // 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)(g_Battle.lpSceneBuf->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)); } // // Draw the backup buffer to the screen // SDL_BlitSurface(gpScreenBak, NULL, gpScreen, NULL); PAL_BattleUIUpdate(); VIDEO_UpdateScreen(NULL); } } // // Draw the result buffer to the screen as the final step // SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); PAL_BattleUIUpdate(); VIDEO_UpdateScreen(NULL); }
/*++ 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 BOOL PAL_SystemMenu( VOID ) /*++ Purpose: Show the system menu. Parameters: None. Return value: TRUE if user made some operations in the menu, FALSE if user cancelled. --*/ { LPBOX lpMenuBox; WORD wReturnValue; int iSlot, i, iSavedTimes; FILE *fp; const SDL_Rect rect = {40, 60, 100, 135}; // // Create menu items // #ifdef PAL_CLASSIC MENUITEM rgSystemMenuItem[5] = { // value label enabled pos { 1, SYSMENU_LABEL_SAVE, TRUE, PAL_XY(53, 72) }, { 2, SYSMENU_LABEL_LOAD, TRUE, PAL_XY(53, 72 + 18) }, { 3, SYSMENU_LABEL_MUSIC, TRUE, PAL_XY(53, 72 + 36) }, { 4, SYSMENU_LABEL_SOUND, TRUE, PAL_XY(53, 72 + 54) }, { 5, SYSMENU_LABEL_QUIT, TRUE, PAL_XY(53, 72 + 72) }, }; #else MENUITEM rgSystemMenuItem[6] = { // value label enabled pos { 1, SYSMENU_LABEL_SAVE, TRUE, PAL_XY(53, 72) }, { 2, SYSMENU_LABEL_LOAD, TRUE, PAL_XY(53, 72 + 18) }, { 3, SYSMENU_LABEL_MUSIC, TRUE, PAL_XY(53, 72 + 36) }, { 4, SYSMENU_LABEL_SOUND, TRUE, PAL_XY(53, 72 + 54) }, { 5, SYSMENU_LABEL_BATTLEMODE, TRUE, PAL_XY(53, 72 + 72) }, { 6, SYSMENU_LABEL_QUIT, TRUE, PAL_XY(53, 72 + 90) }, }; #endif // // Create the menu box. // #ifdef PAL_CLASSIC lpMenuBox = PAL_CreateBox(PAL_XY(40, 60), 4, 3, 0, TRUE); #else lpMenuBox = PAL_CreateBox(PAL_XY(40, 60), 5, 3, 0, TRUE); #endif VIDEO_UpdateScreen(&rect); // // Perform the menu. // #ifdef PAL_CLASSIC wReturnValue = PAL_ReadMenu(PAL_SystemMenu_OnItemChange, rgSystemMenuItem, 5, gpGlobals->iCurSystemMenuItem, MENUITEM_COLOR); #else wReturnValue = PAL_ReadMenu(PAL_SystemMenu_OnItemChange, rgSystemMenuItem, 6, gpGlobals->iCurSystemMenuItem, MENUITEM_COLOR); #endif if (wReturnValue == MENUITEM_VALUE_CANCELLED) { // // User cancelled the menu // PAL_DeleteBox(lpMenuBox); VIDEO_UpdateScreen(&rect); return FALSE; } switch (wReturnValue) { case 1: // // Save game // iSlot = PAL_SaveSlotMenu(gpGlobals->bCurrentSaveSlot); if (iSlot != MENUITEM_VALUE_CANCELLED) { gpGlobals->bCurrentSaveSlot = (BYTE)iSlot; iSavedTimes = 0; for (i = 1; i <= 5; i++) { fp = fopen(va("%s%d%s", PAL_SAVE_PREFIX, i, ".rpg"), "rb"); if (fp != NULL) { WORD wSavedTimes; fread(&wSavedTimes, sizeof(WORD), 1, fp); fclose(fp); wSavedTimes = SWAP16(wSavedTimes); if ((int)wSavedTimes > iSavedTimes) { iSavedTimes = wSavedTimes; } } } PAL_SaveGame(va("%s%d%s", PAL_SAVE_PREFIX, iSlot, ".rpg"), iSavedTimes + 1); } break; case 2: // // Load game // iSlot = PAL_SaveSlotMenu(gpGlobals->bCurrentSaveSlot); if (iSlot != MENUITEM_VALUE_CANCELLED) { PAL_PlayMUS(0, FALSE, 1); PAL_FadeOut(1); PAL_InitGameData(iSlot); } break; case 3: // // Music // g_fNoMusic = !PAL_SwitchMenu(!g_fNoMusic); #ifdef PAL_HAS_NATIVEMIDI if (g_fUseMidi) { if (g_fNoMusic) { PAL_PlayMUS(0, FALSE, 0); } else { PAL_PlayMUS(gpGlobals->wNumMusic, TRUE, 0); } } #endif break; case 4: // // Sound // g_fNoSound = !PAL_SwitchMenu(!g_fNoSound); break; #ifndef PAL_CLASSIC case 5: // // Battle Mode // PAL_BattleSpeedMenu(); break; case 6: #else case 5: #endif // // Quit // if (PAL_ConfirmMenu()) { PAL_PlayMUS(0, FALSE, 2); PAL_FadeOut(2); PAL_Shutdown(); exit(0); } break; } PAL_DeleteBox(lpMenuBox); return TRUE; }
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); }
BOOL PAL_SwitchMenu( BOOL fEnabled ) /*++ Purpose: Show a "Enable/Disable" selection box. Parameters: [IN] fEnabled - whether the option is originally enabled or not. Return value: TRUE if user selected "Enable", FALSE if selected "Disable". --*/ { LPBOX rgpBox[2]; MENUITEM rgMenuItem[2]; int i; WORD wReturnValue; const SDL_Rect rect = {130, 100, 125, 50}; // // Create menu items // rgMenuItem[0].fEnabled = TRUE; rgMenuItem[0].pos = PAL_XY(145, 110); rgMenuItem[0].wValue = 0; rgMenuItem[0].wNumWord = SWITCHMENU_LABEL_DISABLE; rgMenuItem[1].fEnabled = TRUE; rgMenuItem[1].pos = PAL_XY(220, 110); rgMenuItem[1].wValue = 1; rgMenuItem[1].wNumWord = SWITCHMENU_LABEL_ENABLE; // // Create the boxes // for (i = 0; i < 2; i++) { rgpBox[i] = PAL_CreateSingleLineBox(PAL_XY(130 + 75 * i, 100), 2, TRUE); } VIDEO_UpdateScreen(&rect); // // Activate the menu // wReturnValue = PAL_ReadMenu(NULL, rgMenuItem, 2, fEnabled ? 1 : 0, MENUITEM_COLOR); // // Delete the boxes // for (i = 0; i < 2; i++) { PAL_DeleteBox(rgpBox[i]); } VIDEO_UpdateScreen(&rect); if (wReturnValue == MENUITEM_VALUE_CANCELLED) { return fEnabled; } return (wReturnValue == 0) ? FALSE : TRUE; }
BOOL PAL_ConfirmMenu( VOID ) /*++ Purpose: Show a "Yes or No?" confirm box. Parameters: None. Return value: TRUE if user selected Yes, FALSE if selected No. --*/ { LPBOX rgpBox[2]; MENUITEM rgMenuItem[2]; int i; WORD wReturnValue; const SDL_Rect rect = {130, 100, 125, 50}; // // Create menu items // rgMenuItem[0].fEnabled = TRUE; rgMenuItem[0].pos = PAL_XY(145, 110); rgMenuItem[0].wValue = 0; rgMenuItem[0].wNumWord = CONFIRMMENU_LABEL_NO; rgMenuItem[1].fEnabled = TRUE; rgMenuItem[1].pos = PAL_XY(220, 110); rgMenuItem[1].wValue = 1; rgMenuItem[1].wNumWord = CONFIRMMENU_LABEL_YES; // // Create the boxes // for (i = 0; i < 2; i++) { rgpBox[i] = PAL_CreateSingleLineBox(PAL_XY(130 + 75 * i, 100), 2, TRUE); } VIDEO_UpdateScreen(&rect); // // Activate the menu // wReturnValue = PAL_ReadMenu(NULL, rgMenuItem, 2, 0, MENUITEM_COLOR); // // Delete the boxes // for (i = 0; i < 2; i++) { PAL_DeleteBox(rgpBox[i]); } VIDEO_UpdateScreen(&rect); return (wReturnValue == MENUITEM_VALUE_CANCELLED || wReturnValue == 0) ? FALSE : TRUE; }
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); }
VOID PAL_DrawText( LPCSTR lpszText, PAL_POS pos, BYTE bColor, BOOL fShadow, BOOL fUpdate ) /*++ Purpose: Draw text on the screen. Parameters: [IN] lpszText - the text to be drawn. [IN] pos - Position of the text. [IN] bColor - Color of the text. [IN] fShadow - TRUE if the text is shadowed or not. [IN] fUpdate - TRUE if update the screen area. Return value: None. --*/ { SDL_Rect rect, urect; WORD wChar; rect.x = PAL_X(pos); rect.y = PAL_Y(pos); urect.x = rect.x; urect.y = rect.y; urect.h = 16; urect.w = 0; while (*lpszText) { // // Draw the character // if (*lpszText & 0x80) { // // BIG-5 Chinese Character // wChar = SWAP16(((LPBYTE)lpszText)[0] | (((LPBYTE)lpszText)[1] << 8)); if (fShadow) { PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0); PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x + 1, rect.y), 0); } PAL_DrawCharOnSurface(wChar, gpScreen, PAL_XY(rect.x, rect.y), bColor); lpszText += 2; rect.x += 16; urect.w += 16; } else { // // ASCII character // if (fShadow) { PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0); PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0); } PAL_DrawASCIICharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x, rect.y), bColor); lpszText++; rect.x += 8; urect.w += 8; } } // // Update the screen area // if (fUpdate && urect.w > 0) { VIDEO_UpdateScreen(&urect); } }
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_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; }
/*++ The main battle routine. Return value: The result of the battle. --*/ static BATTLERESULT PAL_BattleMain(void) { int i; DWORD dwTime; VIDEO_BackupScreen(); // // Generate the scene and draw the scene to the screen buffer // PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); // // Fade out the music and delay for a while // PAL_PlayMUS(0, FALSE, 1); UTIL_Delay(200); // // Switch the screen // VIDEO_SwitchScreen(5); // // Play the battle music // PAL_PlayMUS(gpGlobals->wNumBattleMusic, TRUE, 0); // // Fade in the screen when needed // if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; } // // Run the pre-battle scripts for each enemies // for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { g_Battle.rgEnemy[i].wScriptOnTurnStart = PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnTurnStart, i); if (g_Battle.BattleResult != kBattleResultPreBattle) { break; } } if (g_Battle.BattleResult == kBattleResultPreBattle) { g_Battle.BattleResult = kBattleResultOnGoing; } #ifndef PAL_CLASSIC PAL_UpdateTimeChargingUnit(); #endif dwTime = SDL_GetTicks(); PAL_ClearKeyState(); // // Run the main battle loop. // while (TRUE) { // // Break out if the battle ended. // if (g_Battle.BattleResult != kBattleResultOnGoing) { break; } // // 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; // // Run the main frame routine. // PAL_BattleStartFrame(); // // Update the screen. // VIDEO_UpdateScreen(NULL); } // // Return the battle result // return g_Battle.BattleResult; }
VOID PAL_BuyMenu( WORD wStoreNum ) /*++ Purpose: Show the buy item menu. Parameters: [IN] wStoreNum - number of the store to buy items from. Return value: None. --*/ { MENUITEM rgMenuItem[MAX_STORE_ITEM]; int i, y; WORD w; SDL_Rect rect = {125, 8, 190, 190}; // // create the menu items // y = 22; for (i = 0; i < MAX_STORE_ITEM; i++) { if (gpGlobals->g.lprgStore[wStoreNum].rgwItems[i] == 0) { break; } rgMenuItem[i].wValue = gpGlobals->g.lprgStore[wStoreNum].rgwItems[i]; rgMenuItem[i].wNumWord = gpGlobals->g.lprgStore[wStoreNum].rgwItems[i]; rgMenuItem[i].fEnabled = TRUE; rgMenuItem[i].pos = PAL_XY(150, y); y += 18; } // // Draw the box // PAL_CreateBox(PAL_XY(125, 8), 8, 8, 1, FALSE); // // Draw the number of prices // for (y = 0; y < i; y++) { w = gpGlobals->g.rgObject[rgMenuItem[y].wValue].item.wPrice; PAL_DrawNumber(w, 6, PAL_XY(235, 25 + y * 18), kNumColorCyan, kNumAlignRight); } VIDEO_UpdateScreen(&rect); w = 0; while (TRUE) { w = PAL_ReadMenu(PAL_BuyMenu_OnItemChange, rgMenuItem, i, w, MENUITEM_COLOR); if (w == MENUITEM_VALUE_CANCELLED) { break; } if (gpGlobals->g.rgObject[w].item.wPrice <= gpGlobals->dwCash) { if (PAL_ConfirmMenu()) { // // Player bought an item // gpGlobals->dwCash -= gpGlobals->g.rgObject[w].item.wPrice; PAL_AddItemToInventory(w, 1); } } // // Place the cursor to the current item on next loop // for (y = 0; y < i; y++) { if (w == rgMenuItem[y].wValue) { w = y; break; } } } }
VOID PAL_InGameMenu( VOID ) /*++ Purpose: Show the in-game main menu. Parameters: None. Return value: None. --*/ { LPBOX lpCashBox, lpMenuBox; WORD wReturnValue; const SDL_Rect rect = {0, 0, 150, 185}; // // Create menu items // MENUITEM rgMainMenuItem[4] = { // value label enabled pos { 1, GAMEMENU_LABEL_STATUS, TRUE, PAL_XY(16, 50) }, { 2, GAMEMENU_LABEL_MAGIC, TRUE, PAL_XY(16, 50 + 18) }, { 3, GAMEMENU_LABEL_INVENTORY, TRUE, PAL_XY(16, 50 + 36) }, { 4, GAMEMENU_LABEL_SYSTEM, TRUE, PAL_XY(16, 50 + 54) }, }; // // Display the cash amount. // lpCashBox = PAL_ShowCash(gpGlobals->dwCash); // // Create the menu box. // lpMenuBox = PAL_CreateBox(PAL_XY(3, 37), 3, 1, 0, TRUE); VIDEO_UpdateScreen(&rect); // // Process the menu // while (TRUE) { wReturnValue = PAL_ReadMenu(PAL_InGameMenu_OnItemChange, rgMainMenuItem, 4, gpGlobals->iCurMainMenuItem, MENUITEM_COLOR); if (wReturnValue == MENUITEM_VALUE_CANCELLED) { break; } switch (wReturnValue) { case 1: // // Status // PAL_PlayerStatus(); goto out; case 2: // // Magic // PAL_InGameMagicMenu(); goto out; case 3: // // Inventory // PAL_InventoryMenu(); goto out; case 4: // // System // if (PAL_SystemMenu()) { goto out; } break; } } out: // // Remove the boxes. // PAL_DeleteBox(lpCashBox); PAL_DeleteBox(lpMenuBox); VIDEO_UpdateScreen(&rect); }
VOID PAL_BattleFadeScene( VOID ) /*++ Purpose: Fade in the scene of battle. Parameters: None. Return value: None. --*/ { int i, j, k; DWORD time; BYTE a, b; const int rgIndex[6] = {0, 3, 1, 5, 2, 4}; UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattleFadeScene, "PAL_BattleFadeScene", __FILE__, "entry"); time = SDL_GetTicks(); for (i = 0; i < 12; i++) { for (j = 0; j < 6; j++) { PAL_ProcessEvent(); while (SDL_GetTicks() <= time) { PAL_ProcessEvent(); SDL_Delay(1); } time = SDL_GetTicks() + 16; // // 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)(g_Battle.lpSceneBuf->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)); } // // Draw the backup buffer to the screen // SDL_BlitSurface(gpScreenBak, NULL, gpScreen, NULL); PAL_BattleUIUpdate(); VIDEO_UpdateScreen(NULL); } } // // Draw the result buffer to the screen as the final step // SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); PAL_BattleUIUpdate(); VIDEO_UpdateScreen(NULL); UTIL_WriteLog(LOG_DEBUG, "[0x%08x][%s][%s] - %s", (long)PAL_BattleFadeScene, "PAL_BattleFadeScene", __FILE__, "end"); }
VOID PAL_StartDialog( BYTE bDialogLocation, BYTE bFontColor, INT iNumCharFace, BOOL fPlayingRNG ) /*++ Purpose: Start a new dialog. Parameters: [IN] bDialogLocation - the location of the text on the screen. [IN] bFontColor - the font color of the text. [IN] iNumCharFace - number of the character face in RGM.MKF. [IN] fPlayingRNG - whether we are playing a RNG video or not. Return value: None. --*/ { PAL_LARGE BYTE buf[16384]; SDL_Rect rect; if (gpGlobals->fInBattle && !g_fUpdatedInBattle) { // // Update the screen in battle, or the graphics may seem messed up // VIDEO_UpdateScreen(NULL); g_fUpdatedInBattle = TRUE; } g_TextLib.bIcon = 0; g_TextLib.posIcon = 0; g_TextLib.nCurrentDialogLine = 0; g_TextLib.posDialogTitle = PAL_XY(12, 8); g_TextLib.fUserSkip = FALSE; if (bFontColor != 0) { g_TextLib.bCurrentFontColor = bFontColor; } if (fPlayingRNG && iNumCharFace) { VIDEO_BackupScreen(); g_TextLib.fPlayingRNG = TRUE; } switch (bDialogLocation) { case kDialogUpper: if (iNumCharFace > 0) { // // Display the character face at the upper part of the screen // if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0) { rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf); rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf); rect.x = 48 - rect.w / 2; rect.y = 55 - rect.h / 2; if (rect.x < 0) { rect.x = 0; } if (rect.y < 0) { rect.y = 0; } PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y)); if (rect.x < 0) { rect.x = 0; } if (rect.y < 0) { rect.y = 0; } VIDEO_UpdateScreen(&rect); } } g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8); g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26); break; case kDialogCenter: g_TextLib.posDialogText = PAL_XY(80, 40); break; case kDialogLower: if (iNumCharFace > 0) { // // Display the character face at the lower part of the screen // if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0) { rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2; rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2; PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y)); VIDEO_UpdateScreen(NULL); } } g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108); g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126); break; case kDialogCenterWindow: g_TextLib.posDialogText = PAL_XY(160, 40); break; } g_TextLib.bDialogPosition = bDialogLocation; }
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_ShowDialogText( LPCSTR lpszText ) /*++ Purpose: Show one line of the dialog text. Parameters: [IN] lpszText - the text to be shown. Return value: None. --*/ { SDL_Rect rect; int x, y, len = strlen(lpszText); PAL_ClearKeyState(); g_TextLib.bIcon = 0; if (gpGlobals->fInBattle && !g_fUpdatedInBattle) { // // Update the screen in battle, or the graphics may seem messed up // VIDEO_UpdateScreen(NULL); g_fUpdatedInBattle = TRUE; } if (g_TextLib.nCurrentDialogLine > 3) { // // The rest dialogs should be shown in the next page. // PAL_DialogWaitForKey(); g_TextLib.nCurrentDialogLine = 0; VIDEO_RestoreScreen(); VIDEO_UpdateScreen(NULL); } x = PAL_X(g_TextLib.posDialogText); y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18; if (g_TextLib.bDialogPosition == kDialogCenterWindow) { // // The text should be shown in a small window at the center of the screen // #ifndef PAL_CLASSIC if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing) { PAL_BattleUIShowText(lpszText, 1400); } else #endif { PAL_POS pos; LPBOX lpBox; // // Create the window box // pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText)); lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE); rect.x = PAL_X(pos); rect.y = PAL_Y(pos); rect.w = 320 - rect.x * 2 + 32; rect.h = 64; // // Show the text on the screen // pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10); PAL_DrawText(lpszText, pos, 0, FALSE, FALSE); VIDEO_UpdateScreen(&rect); PAL_DialogWaitForKey(); // // Delete the box // PAL_DeleteBox(lpBox); VIDEO_UpdateScreen(&rect); PAL_EndDialog(); } } else { if (g_TextLib.nCurrentDialogLine == 0 && g_TextLib.bDialogPosition != kDialogCenter && (BYTE)lpszText[len - 1] == 0x47 && (BYTE)lpszText[len - 2] == 0xA1) { // // name of character // PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE); } else { // // normal texts // char text[3]; if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0) { // // Save the screen before we show the first line of dialog // VIDEO_BackupScreen(); } while (lpszText != NULL && *lpszText != '\0') { switch (*lpszText) { case '-': // // Set the font color to Cyan // if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN) { g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; } else { g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN; } lpszText++; break; case '\'': // // Set the font color to Red // if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED) { g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; } else { g_TextLib.bCurrentFontColor = FONT_COLOR_RED; } lpszText++; break; case '\"': // // Set the font color to Yellow // if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW) { g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; } else { g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW; } lpszText++; break; case '$': // // Set the delay time of text-displaying // g_TextLib.iDelayTime = atoi(lpszText + 1) * 10 / 7; lpszText += 3; break; case '~': // // Delay for a period and quit // UTIL_Delay(atoi(lpszText + 1) * 80 / 7); g_TextLib.nCurrentDialogLine = 0; g_TextLib.fUserSkip = FALSE; return; // don't go further case ')': // // Set the waiting icon // g_TextLib.bIcon = 1; lpszText++; break; case '(': // // Set the waiting icon // g_TextLib.bIcon = 2; lpszText++; break; case '\\': lpszText++; default: if (*lpszText & 0x80) { text[0] = lpszText[0]; text[1] = lpszText[1]; text[2] = '\0'; lpszText += 2; } else { text[0] = *lpszText; text[1] = '\0'; lpszText++; } PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE); x += ((text[0] & 0x80) ? 16 : 8); if (!g_TextLib.fUserSkip) { PAL_ClearKeyState(); UTIL_Delay(g_TextLib.iDelayTime * 8); if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu)) { // // User pressed a key to skip the dialog // g_TextLib.fUserSkip = TRUE; } } } } g_TextLib.posIcon = PAL_XY(x, y); g_TextLib.nCurrentDialogLine++; } } }
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; } } } }