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; } }
/*++ 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_EndingScreen( VOID ) { RIX_Play(0x1a, TRUE, 0); PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 110, 150, 7); PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 151, 999, 9); PAL_FadeOut(2); RIX_Play(0x19, TRUE, 0); PAL_ShowFBP(75, 0); PAL_FadeIn(5, FALSE, 1); PAL_ScrollFBP(74, 0xf, TRUE); PAL_FadeOut(1); SDL_FillRect(gpScreen, NULL, 0); gpGlobals->wNumPalette = 4; gpGlobals->fNeedToFadeIn = TRUE; PAL_EndingAnimation(); RIX_Play(0, FALSE, 2); PAL_ColorFade(7, 15, FALSE); if (!SOUND_PlayCDA(2)) { RIX_Play(0x11, TRUE, 0); } SDL_FillRect(gpScreen, NULL, 0); PAL_SetPalette(0, FALSE); PAL_RNGPlay(0xb, 0, 999, 7); PAL_FadeOut(2); SDL_FillRect(gpScreen, NULL, 0); gpGlobals->wNumPalette = 8; gpGlobals->fNeedToFadeIn = TRUE; PAL_RNGPlay(10, 0, 999, 6); PAL_EndingSetEffectSprite(0); PAL_ShowFBP(77, 10); VIDEO_BackupScreen(); PAL_EndingSetEffectSprite(0x27b); PAL_ShowFBP(76, 7); PAL_SetPalette(5, FALSE); PAL_ShowFBP(73, 7); PAL_ScrollFBP(72, 0xf, TRUE); PAL_ShowFBP(71, 7); PAL_ShowFBP(68, 7); PAL_EndingSetEffectSprite(0); PAL_ShowFBP(68, 6); PAL_WaitForKey(0); RIX_Play(0, FALSE, 1); UTIL_Delay(500); if (!SOUND_PlayCDA(13)) { RIX_Play(9, TRUE, 0); } PAL_ScrollFBP(67, 0xf, TRUE); PAL_ScrollFBP(66, 0xf, TRUE); PAL_ScrollFBP(65, 0xf, TRUE); PAL_ScrollFBP(64, 0xf, TRUE); PAL_ScrollFBP(63, 0xf, TRUE); PAL_ScrollFBP(62, 0xf, TRUE); PAL_ScrollFBP(61, 0xf, TRUE); PAL_ScrollFBP(60, 0xf, TRUE); PAL_ScrollFBP(59, 0xf, TRUE); RIX_Play(0, FALSE, 6); PAL_FadeOut(3); }
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_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); }
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; } } }
INT PAL_OpeningMenu( VOID ) /*++ Purpose: Show the opening menu. Parameters: None. Return value: Which saved slot to load from (1-5). 0 to start a new game. --*/ { WORD wItemSelected; WORD wDefaultItem = 0; MENUITEM rgMainMenuItem[2] = { // value label enabled position { 0, MAINMENU_LABEL_NEWGAME, TRUE, PAL_XY(125, 95) }, { 1, MAINMENU_LABEL_LOADGAME, TRUE, PAL_XY(125, 112) } }; // // Play the background music // PAL_PlayMUS(RIX_NUM_OPENINGMENU, TRUE, 1); // // Draw the background // PAL_DrawOpeningMenuBackground(); PAL_FadeIn(0, FALSE, 1); while (TRUE) { // // Activate the menu // wItemSelected = PAL_ReadMenu(NULL, rgMainMenuItem, 2, wDefaultItem, MENUITEM_COLOR); if (wItemSelected == 0 || wItemSelected == MENUITEM_VALUE_CANCELLED) { // // Start a new game // wItemSelected = 0; break; } else { // // Load game // wItemSelected = PAL_SaveSlotMenu(1); if (wItemSelected != MENUITEM_VALUE_CANCELLED) { break; } wDefaultItem = 1; } } // // Fade out the screen and the music // PAL_PlayMUS(0, FALSE, 1); PAL_FadeOut(1); return (INT)wItemSelected; }
VOID PAL_RNGPlay( INT iNumRNG, INT iStartFrame, INT iEndFrame, INT iSpeed ) /*++ Purpose: Play a RNG movie. Parameters: [IN] iNumRNG - number of the RNG movie. [IN] iStartFrame - start frame number. [IN] iEndFrame - end frame number. [IN] iSpeed - speed of playing. Return value: None. --*/ { UINT iTime; int iDelay = 800 / (iSpeed == 0 ? 16 : iSpeed); FILE *fp; fp = UTIL_OpenRequiredFile("rng.mkf"); for (; iStartFrame <= iEndFrame; iStartFrame++) { iTime = SDL_GetTicks() + iDelay; if (PAL_RNGBlitToSurface(iNumRNG, iStartFrame, gpScreen, fp) == -1) { // // Failed to get the frame, don't go further // fclose(fp); return; } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Fade in the screen if needed // if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; } // // Delay for a while // PAL_ProcessEvent(); while (SDL_GetTicks() <= iTime) { PAL_ProcessEvent(); SDL_Delay(1); } } fclose(fp); }
VOID PAL_RNGPlay( INT iNumRNG, INT iStartFrame, INT iEndFrame, INT iSpeed ) /*++ Purpose: Play a RNG movie. Parameters: [IN] iNumRNG - number of the RNG movie. [IN] iStartFrame - start frame number. [IN] iEndFrame - end frame number. [IN] iSpeed - speed of playing. Return value: None. --*/ { int iDelay = 800 / (iSpeed == 0 ? 16 : iSpeed); uint8_t *rng = (uint8_t *)malloc(65000); uint8_t *buf = (uint8_t *)malloc(65000); FILE *fp = UTIL_OpenRequiredFile("rng.mkf"); for (; rng && buf && iStartFrame <= iEndFrame; iStartFrame++) { uint32_t iTime = SDL_GetTicks() + iDelay; // // Read, decompress and render the frame // if (PAL_RNGReadFrame(buf, 65000, iNumRNG, iStartFrame, fp) < 0 || PAL_RNGBlitToSurface(rng, Decompress(buf, rng, 65000), gpScreen) == -1) { // // Failed to get the frame, don't go further // break; } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Fade in the screen if needed // if (gpGlobals->fNeedToFadeIn) { PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1); gpGlobals->fNeedToFadeIn = FALSE; } // // Delay for a while // PAL_DelayUntil(iTime); } fclose(fp); free(rng); free(buf); }