VOID PAL_EndDialog( VOID ) /*++ Purpose: Ends a dialog. Parameters: None. Return value: None. --*/ { PAL_ClearDialog(TRUE); // // Set some default parameters, as there are some parts of script // which doesn't have a "start dialog" instruction before showing the dialog. // g_TextLib.posDialogTitle = PAL_XY(12, 8); g_TextLib.posDialogText = PAL_XY(44, 26); g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; g_TextLib.bDialogPosition = kDialogUpper; g_TextLib.fUserSkip = FALSE; g_TextLib.fPlayingRNG = FALSE; }
VOID PAL_ClearDialog( BOOL fWaitForKey ) /*++ Purpose: Clear the state of the dialog. Parameters: [IN] fWaitForKey - whether wait for any key or not. Return value: None. --*/ { if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey) { PAL_DialogWaitForKey(); } g_TextLib.nCurrentDialogLine = 0; if (g_TextLib.bDialogPosition == kDialogCenter) { g_TextLib.posDialogTitle = PAL_XY(12, 8); g_TextLib.posDialogText = PAL_XY(44, 26); g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; g_TextLib.bDialogPosition = kDialogUpper; } }
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; } }
/*++ Load the default game data. --*/ static VOID PAL_LoadDefaultGame(void) { const GAMEDATA *p = &gpGlobals->g; UINT32 i; // // Load the default data from the game data files. // LOAD_DATA(p->lprgEventObject, p->nEventObject * sizeof(EVENTOBJECT), 0, gpGlobals->f.fpSSS); PAL_MKFReadChunk((LPBYTE)(p->rgScene), sizeof(p->rgScene), 1, gpGlobals->f.fpSSS); DO_BYTESWAP(p->rgScene, sizeof(p->rgScene)); PAL_MKFReadChunk((LPBYTE)(p->rgObject), sizeof(p->rgObject), 2, gpGlobals->f.fpSSS); DO_BYTESWAP(p->rgObject, sizeof(p->rgObject)); PAL_MKFReadChunk((LPBYTE)(&(p->PlayerRoles)), sizeof(PLAYERROLES), 3, gpGlobals->f.fpDATA); DO_BYTESWAP(&(p->PlayerRoles), sizeof(PLAYERROLES)); // // Set some other default data. // gpGlobals->dwCash = 0; gpGlobals->wNumMusic = 0; gpGlobals->wNumPalette = 0; gpGlobals->wNumScene = 1; gpGlobals->wCollectValue = 0; gpGlobals->fNightPalette = FALSE; gpGlobals->wMaxPartyMemberIndex = 0; gpGlobals->viewport = PAL_XY(0, 0); gpGlobals->wLayer = 0; gpGlobals->wChaseRange = 1; #ifndef PAL_CLASSIC gpGlobals->bBattleSpeed = 2; #endif memset(gpGlobals->rgInventory, 0, sizeof(gpGlobals->rgInventory)); memset(gpGlobals->rgPoisonStatus, 0, sizeof(gpGlobals->rgPoisonStatus)); memset(gpGlobals->rgParty, 0, sizeof(gpGlobals->rgParty)); memset(gpGlobals->rgTrail, 0, sizeof(gpGlobals->rgTrail)); memset(&(gpGlobals->Exp), 0, sizeof(gpGlobals->Exp)); for (i = 0; i < MAX_PLAYER_ROLES; i++) { gpGlobals->Exp.rgPrimaryExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgHealthExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgMagicExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgAttackExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgMagicPowerExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgDefenseExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgDexterityExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; gpGlobals->Exp.rgFleeExp[i].wLevel = p->PlayerRoles.rgwLevel[i]; } gpGlobals->fEnteringScene = TRUE; }
LPBOX PAL_ShowCash( DWORD dwCash ) /*++ Purpose: Show the cash amount at the top left corner of the screen. Parameters: [IN] dwCash - amount of cash. Return value: pointer to the saved screen part. --*/ { LPBOX lpBox; // // Create the box. // lpBox = PAL_CreateSingleLineBox(PAL_XY(0, 0), 5, TRUE); if (lpBox == NULL) { return NULL; } // // Draw the text label. // PAL_DrawText(PAL_GetWord(CASH_LABEL), PAL_XY(10, 10), 0, FALSE, FALSE); // // Draw the cash amount. // PAL_DrawNumber(dwCash, 6, PAL_XY(49, 14), kNumColorYellow, kNumAlignRight); return lpBox; }
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; } }
/*++ 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_BattleUIShowNum( WORD wNum, PAL_POS pos, NUMCOLOR color ) /*++ Purpose: Show a number on battle screen (indicates HP/MP change). Parameters: [IN] wNum - number to be shown. [IN] pos - position of the number on the screen. [IN] color - color of the number. Return value: None. --*/ { int i; for (i = 0; i < BATTLEUI_MAX_SHOWNUM; i++) { if (g_Battle.UI.rgShowNum[i].wNum == 0) { g_Battle.UI.rgShowNum[i].wNum = wNum; g_Battle.UI.rgShowNum[i].pos = PAL_XY(PAL_X(pos) - 15, PAL_Y(pos)); g_Battle.UI.rgShowNum[i].color = color; g_Battle.UI.rgShowNum[i].dwTime = SDL_GetTicks(); break; } } }
static VOID PAL_AddSpriteToDraw( LPCBITMAPRLE lpSpriteFrame, int x, int y, int iLayer ) /*++ Purpose: Add a sprite to our list of drawing. Parameters: [IN] lpSpriteFrame - the bitmap of the sprite frame. [IN] x - the X coordinate on the screen. [IN] y - the Y coordinate on the screen. [IN] iLayer - the layer of the sprite. Return value: None. --*/ { assert(g_nSpriteToDraw < MAX_SPRITE_TO_DRAW); g_rgSpriteToDraw[g_nSpriteToDraw].lpSpriteFrame = lpSpriteFrame; g_rgSpriteToDraw[g_nSpriteToDraw].pos = PAL_XY(x, y); g_rgSpriteToDraw[g_nSpriteToDraw].iLayer = iLayer; g_nSpriteToDraw++; }
static VOID PAL_SellMenu_OnItemChange( WORD wCurrentItem ) /*++ Purpose: Callback function which is called when player selected another item in the sell item menu. Parameters: [IN] wCurrentItem - current item on the menu, indicates the object ID of the currently selected item. Return value: None. --*/ { // // Draw the cash amount // PAL_CreateSingleLineBox(PAL_XY(100, 150), 5, FALSE); PAL_DrawText(PAL_GetWord(CASH_LABEL), PAL_XY(110, 160), 0, FALSE, FALSE); PAL_DrawNumber(gpGlobals->dwCash, 6, PAL_XY(149, 164), kNumColorYellow, kNumAlignRight); // // Draw the price // PAL_CreateSingleLineBox(PAL_XY(220, 150), 5, FALSE); if (gpGlobals->g.rgObject[wCurrentItem].item.wFlags & kItemFlagSellable) { PAL_DrawText(PAL_GetWord(SELLMENU_LABEL_PRICE), PAL_XY(230, 160), 0, FALSE, FALSE); PAL_DrawNumber(gpGlobals->g.rgObject[wCurrentItem].item.wPrice / 2, 6, PAL_XY(269, 164), kNumColorYellow, kNumAlignRight); } }
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); } }
/*++ Player flee the battle. --*/ VOID PAL_BattlePlayerEscape(void) { int i, j; WORD wPlayerRole; SOUND_Play(45); PAL_BattleUpdateFighters(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { g_Battle.rgPlayer[i].wCurrentFrame = 0; } } for (i = 0; i < 16; i++) { for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++) { wPlayerRole = gpGlobals->rgParty[j].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { // // TODO: This is still not the same as the original game // switch (j) { case 0: if (gpGlobals->wMaxPartyMemberIndex > 0) { g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 6); break; } case 1: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 4, PAL_Y(g_Battle.rgPlayer[j].pos) + 4); break; case 2: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 6, PAL_Y(g_Battle.rgPlayer[j].pos) + 3); break; // @@@ - extra 4th role: case 3: g_Battle.rgPlayer[j].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[j].pos) + 6, PAL_Y(g_Battle.rgPlayer[j].pos) + 3); break; default: assert(FALSE); // Not possible break; } } } PAL_BattleDelay(1, 0, FALSE); } // // Remove all players from the screen // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { g_Battle.rgPlayer[i].pos = PAL_XY(9999, 9999); } PAL_BattleDelay(1, 0, FALSE); g_Battle.BattleResult = kBattleResultFleed; }
/*++ 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 } }
/*++ Load all the loaded sprites. --*/ VOID PAL_LoadBattleSprites(void) { int i, l, x, y, s; FILE *fp; PAL_FreeBattleSprites(); fp = UTIL_OpenRequiredFile("abc.mkf"); // // Load battle sprites for players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { s = PAL_GetPlayerBattleSprite(gpGlobals->rgParty[i].wPlayerRole); l = PAL_MKFGetDecompressedSize(s, gpGlobals->f.fpF); if (l <= 0) { continue; } g_Battle.rgPlayer[i].lpSprite = UTIL_calloc(l, 1); PAL_MKFDecompressChunk(g_Battle.rgPlayer[i].lpSprite, l, s, gpGlobals->f.fpF); // // Set the default position for this player // x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][0]; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][1]; g_Battle.rgPlayer[i].posOriginal = PAL_XY(x, y); g_Battle.rgPlayer[i].pos = PAL_XY(x, y); } // // Load battle sprites for enemies // for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } l = PAL_MKFGetDecompressedSize( gpGlobals->g.rgObject[g_Battle.rgEnemy[i].wObjectID].enemy.wEnemyID, fp); if (l <= 0) { continue; } g_Battle.rgEnemy[i].lpSprite = UTIL_calloc(l, 1); PAL_MKFDecompressChunk(g_Battle.rgEnemy[i].lpSprite, l, gpGlobals->g.rgObject[g_Battle.rgEnemy[i].wObjectID].enemy.wEnemyID, fp); // // Set the default position for this enemy // x = gpGlobals->g.EnemyPos.pos[i][g_Battle.wMaxEnemyIndex].x; y = gpGlobals->g.EnemyPos.pos[i][g_Battle.wMaxEnemyIndex].y; y += g_Battle.rgEnemy[i].e.wYPosOffset; g_Battle.rgEnemy[i].posOriginal = PAL_XY(x, y); g_Battle.rgEnemy[i].pos = PAL_XY(x, y); } fclose(fp); }
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; }
INT PAL_InitText( VOID ) /*++ Purpose: Initialize the in-game texts. Parameters: None. Return value: 0 = success. -1 = memory allocation error. --*/ { FILE *fpMsg, *fpWord; int i; // // Open the message and word data files. // fpMsg = UTIL_OpenRequiredFile("m.msg"); fpWord = UTIL_OpenRequiredFile("word.dat"); // // See how many words we have // fseek(fpWord, 0, SEEK_END); i = ftell(fpWord); // // Each word has 10 bytes // g_TextLib.nWords = (i + (WORD_LENGTH - 1)) / WORD_LENGTH; // // Read the words // g_TextLib.lpWordBuf = (LPBYTE)malloc(i); if (g_TextLib.lpWordBuf == NULL) { fclose(fpWord); fclose(fpMsg); return -1; } fseek(fpWord, 0, SEEK_SET); fread(g_TextLib.lpWordBuf, i, 1, fpWord); // // Close the words file // fclose(fpWord); // // Read the message offsets. The message offsets are in SSS.MKF #3 // i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD); g_TextLib.nMsgs = i - 1; g_TextLib.lpMsgOffset = (LPDWORD)malloc(i * sizeof(DWORD)); if (g_TextLib.lpMsgOffset == NULL) { free(g_TextLib.lpWordBuf); fclose(fpMsg); return -1; } PAL_MKFReadChunk((LPBYTE)(g_TextLib.lpMsgOffset), i * sizeof(DWORD), 3, gpGlobals->f.fpSSS); // // Read the messages. // fseek(fpMsg, 0, SEEK_END); i = ftell(fpMsg); g_TextLib.lpMsgBuf = (LPBYTE)malloc(i); if (g_TextLib.lpMsgBuf == NULL) { free(g_TextLib.lpMsgOffset); free(g_TextLib.lpWordBuf); fclose(fpMsg); return -1; } fseek(fpMsg, 0, SEEK_SET); fread(g_TextLib.lpMsgBuf, 1, i, fpMsg); fclose(fpMsg); g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT; g_TextLib.bIcon = 0; g_TextLib.posIcon = 0; g_TextLib.nCurrentDialogLine = 0; g_TextLib.iDelayTime = 3; g_TextLib.posDialogTitle = PAL_XY(12, 8); g_TextLib.posDialogText = PAL_XY(44, 26); g_TextLib.bDialogPosition = kDialogUpper; g_TextLib.fUserSkip = FALSE; PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA); return 0; }
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); }
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"); }
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_UpdateParty( VOID ) /*++ Purpose: Update the location and walking gesture of all the party members. Parameters: None. Return value: None. --*/ { int xSource, ySource, xTarget, yTarget, xOffset, yOffset, i; // // Has user pressed one of the arrow keys? // if (g_InputState.dir != kDirUnknown) { xOffset = ((g_InputState.dir == kDirWest || g_InputState.dir == kDirSouth) ? -16 : 16); yOffset = ((g_InputState.dir == kDirWest || g_InputState.dir == kDirNorth) ? -8 : 8); xSource = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset); ySource = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset); xTarget = xSource + xOffset; yTarget = ySource + yOffset; gpGlobals->wPartyDirection = g_InputState.dir; // // Check for obstacles on the destination location // if (!PAL_CheckObstacle(PAL_XY(xTarget, yTarget), TRUE, 0)) { // // Player will actually be moved. Store trail. // for (i = 3; i >= 0; i--) { gpGlobals->rgTrail[i + 1] = gpGlobals->rgTrail[i]; } gpGlobals->rgTrail[0].wDirection = g_InputState.dir; gpGlobals->rgTrail[0].x = xSource; gpGlobals->rgTrail[0].y = ySource; // // Move the viewport // gpGlobals->viewport = PAL_XY(PAL_X(gpGlobals->viewport) + xOffset, PAL_Y(gpGlobals->viewport) + yOffset); // // Update gestures // PAL_UpdatePartyGestures(TRUE); return; // don't go further } } PAL_UpdatePartyGestures(FALSE); }
VOID PAL_UpdatePartyGestures( BOOL fWalking ) /*++ Purpose: Update the gestures of all the party members. Parameters: [IN] fWalking - whether the party is walking or not. Return value: None. --*/ { static int s_iThisStepFrame = 0; int iStepFrameFollower = 0, iStepFrameLeader = 0; int i; if (fWalking) { // // Update the gesture for party leader // s_iThisStepFrame = (s_iThisStepFrame + 1) % 4; if (s_iThisStepFrame & 1) { iStepFrameLeader = (s_iThisStepFrame + 1) / 2; iStepFrameFollower = 3 - iStepFrameLeader; } else { iStepFrameLeader = 0; iStepFrameFollower = 0; } gpGlobals->rgParty[0].x = PAL_X(gpGlobals->partyoffset); gpGlobals->rgParty[0].y = PAL_Y(gpGlobals->partyoffset); if (gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[0].wPlayerRole] == 4) { gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * 4 + s_iThisStepFrame; } else { gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * 3 + iStepFrameLeader; } // // Update the gestures and positions for other party members // for (i = 1; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++) { gpGlobals->rgParty[i].x = gpGlobals->rgTrail[1].x - PAL_X(gpGlobals->viewport); gpGlobals->rgParty[i].y = gpGlobals->rgTrail[1].y - PAL_Y(gpGlobals->viewport); if (i == 2) { gpGlobals->rgParty[i].x += (gpGlobals->rgTrail[1].wDirection == kDirEast || gpGlobals->rgTrail[1].wDirection == kDirWest) ? -16 : 16; gpGlobals->rgParty[i].y += 8; } else { gpGlobals->rgParty[i].x += ((gpGlobals->rgTrail[1].wDirection == kDirWest || gpGlobals->rgTrail[1].wDirection == kDirSouth) ? 16 : -16); gpGlobals->rgParty[i].y += ((gpGlobals->rgTrail[1].wDirection == kDirWest || gpGlobals->rgTrail[1].wDirection == kDirNorth) ? 8 : -8); } // // Adjust the position if there is obstacle // if (PAL_CheckObstacle(PAL_XY(gpGlobals->rgParty[i].x + PAL_X(gpGlobals->viewport), gpGlobals->rgParty[i].y + PAL_Y(gpGlobals->viewport)), TRUE, 0)) { gpGlobals->rgParty[i].x = gpGlobals->rgTrail[1].x - PAL_X(gpGlobals->viewport); gpGlobals->rgParty[i].y = gpGlobals->rgTrail[1].y - PAL_Y(gpGlobals->viewport); } // // Update gesture for this party member // if (gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[i].wPlayerRole] == 4) { gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * 4 + s_iThisStepFrame; } else { gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * 3 + iStepFrameLeader; } } if (gpGlobals->nFollower > 0) { // // Update the position and gesture for the follower // gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].x = gpGlobals->rgTrail[3].x - PAL_X(gpGlobals->viewport); gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].y = gpGlobals->rgTrail[3].y - PAL_Y(gpGlobals->viewport); gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wFrame = gpGlobals->rgTrail[3].wDirection * 3 + iStepFrameFollower; } } else { // // Player is not moved. Use the "standing" gesture instead of "walking" one. // i = gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[0].wPlayerRole]; if (i == 0) { i = 3; } gpGlobals->rgParty[0].wFrame = gpGlobals->wPartyDirection * i; for (i = 1; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++) { int f = gpGlobals->g.PlayerRoles.rgwWalkFrames[gpGlobals->rgParty[i].wPlayerRole]; if (f == 0) { f = 3; } gpGlobals->rgParty[i].wFrame = gpGlobals->rgTrail[2].wDirection * f; } if (gpGlobals->nFollower > 0) { gpGlobals->rgParty[gpGlobals->wMaxPartyMemberIndex + 1].wFrame = gpGlobals->rgTrail[3].wDirection * 3; } s_iThisStepFrame &= 2; s_iThisStepFrame ^= 2; } }
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_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; }
INT PAL_LoadSavedGame( LPCSTR szFileName ) /*++ Purpose: Load a saved game. Parameters: [IN] szFileName - file name of saved game. Return value: 0 if success, -1 if failed. --*/ { FILE *fp; static SAVEDGAME s; UINT32 i; // // Try to open the specified file // fp = fopen(szFileName, "rb"); if (fp == NULL) { return -1; } // // Read all data from the file and close. // fread(&s, sizeof(SAVEDGAME), 1, fp); fclose(fp); // // Adjust endianness // DO_BYTESWAP(&s, sizeof(SAVEDGAME)); // // Cash amount is in DWORD, so do a wordswap in Big-Endian. // #if SDL_BYTEORDER == SDL_BIG_ENDIAN s.dwCash = ((s.dwCash >> 16) | (s.dwCash << 16)); #endif // // Get all the data from the saved game struct. // gpGlobals->viewport = PAL_XY(s.wViewportX, s.wViewportY); gpGlobals->wMaxPartyMemberIndex = s.nPartyMember; gpGlobals->wNumScene = s.wNumScene; gpGlobals->fNightPalette = (s.wPaletteOffset != 0); gpGlobals->wPartyDirection = s.wPartyDirection; gpGlobals->wNumMusic = s.wNumMusic; gpGlobals->wNumBattleMusic = s.wNumBattleMusic; gpGlobals->wNumBattleField = s.wNumBattleField; gpGlobals->wScreenWave = s.wScreenWave; gpGlobals->sWaveProgression = 0; gpGlobals->wCollectValue = s.wCollectValue; gpGlobals->wLayer = s.wLayer; gpGlobals->wChaseRange = s.wChaseRange; gpGlobals->wChasespeedChangeCycles = s.wChasespeedChangeCycles; gpGlobals->nFollower = s.nFollower; gpGlobals->dwCash = s.dwCash; #ifndef PAL_CLASSIC gpGlobals->bBattleSpeed = s.wBattleSpeed; if (gpGlobals->bBattleSpeed > 5 || gpGlobals->bBattleSpeed == 0) { gpGlobals->bBattleSpeed = 2; } #endif memcpy(gpGlobals->rgParty, s.rgParty, sizeof(gpGlobals->rgParty)); memcpy(gpGlobals->rgTrail, s.rgTrail, sizeof(gpGlobals->rgTrail)); gpGlobals->Exp = s.Exp; gpGlobals->g.PlayerRoles = s.PlayerRoles; memset(gpGlobals->rgPoisonStatus, 0, sizeof(gpGlobals->rgPoisonStatus)); memcpy(gpGlobals->rgInventory, s.rgInventory, sizeof(gpGlobals->rgInventory)); memcpy(gpGlobals->g.rgScene, s.rgScene, sizeof(gpGlobals->g.rgScene)); memcpy(gpGlobals->g.rgObject, s.rgObject, sizeof(gpGlobals->g.rgObject)); memcpy(gpGlobals->g.lprgEventObject, s.rgEventObject, sizeof(EVENTOBJECT) * gpGlobals->g.nEventObject); gpGlobals->fEnteringScene = FALSE; PAL_CompressInventory(); // // Success // return 0; }
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++; } } }
/*++ 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_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_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 }
VOID PAL_LoadResources( VOID ) /*++ Purpose: Load the game resources if needed. Parameters: None. Return value: None. --*/ { int i, index, l, n; WORD wPlayerID, wSpriteNum; if (gpResources == NULL || gpResources->bLoadFlags == 0) { return; } // // Load scene // if (gpResources->bLoadFlags & kLoadScene) { FILE *fpMAP, *fpGOP; fpMAP = UTIL_OpenRequiredFile("map.mkf"); fpGOP = UTIL_OpenRequiredFile("gop.mkf"); if (gpGlobals->fEnteringScene) { gpGlobals->wScreenWave = 0; gpGlobals->sWaveProgression = 0; } // // Free previous loaded scene (sprites and map) // PAL_FreeEventObjectSprites(); PAL_FreeMap(gpResources->lpMap); // // Load map // i = gpGlobals->wNumScene - 1; gpResources->lpMap = PAL_LoadMap(gpGlobals->g.rgScene[i].wMapNum, fpMAP, fpGOP); if (gpResources->lpMap == NULL) { fclose(fpMAP); fclose(fpGOP); TerminateOnError("PAL_LoadResources(): Fail to load map #%d (scene #%d) !", gpGlobals->g.rgScene[i].wMapNum, gpGlobals->wNumScene); } // // Load sprites // index = gpGlobals->g.rgScene[i].wEventObjectIndex; gpResources->nEventObject = gpGlobals->g.rgScene[i + 1].wEventObjectIndex; gpResources->nEventObject -= index; if (gpResources->nEventObject > 0) { gpResources->lppEventObjectSprites = (LPSPRITE *)UTIL_calloc(gpResources->nEventObject, sizeof(LPSPRITE)); } for (i = 0; i < gpResources->nEventObject; i++, index++) { n = gpGlobals->g.lprgEventObject[index].wSpriteNum; if (n == 0) { // // this event object has no sprite // gpResources->lppEventObjectSprites[i] = NULL; continue; } l = PAL_MKFGetDecompressedSize(n, gpGlobals->f.fpMGO); gpResources->lppEventObjectSprites[i] = (LPSPRITE)UTIL_malloc(l); if (PAL_MKFDecompressChunk(gpResources->lppEventObjectSprites[i], l, n, gpGlobals->f.fpMGO) > 0) { gpGlobals->g.lprgEventObject[index].nSpriteFramesAuto = PAL_SpriteGetNumFrames(gpResources->lppEventObjectSprites[i]); } } gpGlobals->partyoffset = PAL_XY(160, 112); fclose(fpGOP); fclose(fpMAP); } // // Load player sprites // if (gpResources->bLoadFlags & kLoadPlayerSprite) { // // Free previous loaded player sprites // PAL_FreePlayerSprites(); for (i = 0; i <= (short)gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerID = gpGlobals->rgParty[i].wPlayerRole; assert(wPlayerID < MAX_PLAYER_ROLES); // // Load player sprite // wSpriteNum = gpGlobals->g.PlayerRoles.rgwSpriteNum[wPlayerID]; l = PAL_MKFGetDecompressedSize(wSpriteNum, gpGlobals->f.fpMGO); gpResources->rglpPlayerSprite[i] = (LPSPRITE)UTIL_malloc(l); PAL_MKFDecompressChunk(gpResources->rglpPlayerSprite[i], l, wSpriteNum, gpGlobals->f.fpMGO); } if (gpGlobals->nFollower > 0) { // // Load the follower sprite // wSpriteNum = gpGlobals->rgParty[i].wPlayerRole; l = PAL_MKFGetDecompressedSize(wSpriteNum, gpGlobals->f.fpMGO); gpResources->rglpPlayerSprite[i] = (LPSPRITE)UTIL_malloc(l); PAL_MKFDecompressChunk(gpResources->rglpPlayerSprite[i], l, wSpriteNum, gpGlobals->f.fpMGO); } } // // Clear all of the load flags // gpResources->bLoadFlags = 0; }
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); }