VOID PAL_SceneFade( INT iPaletteNum, BOOL fNight, INT iStep ) /*++ Purpose: Fade in or fade out the screen. Update the scene during the process. Parameters: [IN] iPaletteNum - number of the palette. [IN] fNight - whether use the night palette or not. [IN] iStep - positive to fade in, nagative to fade out. Return value: None. --*/ { SDL_Color *palette, newpalette[256]; int i, j; DWORD time; palette = PAL_GetPalette(iPaletteNum, fNight); if (palette == NULL) { return; } if (iStep == 0) { iStep = 1; } gpGlobals->fNeedToFadeIn = FALSE; if (iStep > 0) { for (i = 0; i < 64; i += iStep) { time = SDL_GetTicks() + 100; // // Generate the scene // PAL_ClearKeyState(); g_InputState.dir = kDirUnknown; g_InputState.prevdir = kDirUnknown; PAL_GameUpdate(FALSE); PAL_MakeScene(); VIDEO_UpdateScreen(NULL); // // Calculate the current palette... // for (j = 0; j < 256; j++) { newpalette[j].r = (palette[j].r * i) >> 6; newpalette[j].g = (palette[j].g * i) >> 6; newpalette[j].b = (palette[j].b * i) >> 6; } VIDEO_SetPalette(newpalette); PAL_ProcessEvent(); while (!SDL_TICKS_PASSED(SDL_GetTicks(), time)) { PAL_ProcessEvent(); SDL_Delay(5); } } } else { for (i = 63; i >= 0; i += iStep)
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(); 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(5); } dwTime = SDL_GetTicks() + FRAME_TIME; } return 0; // should not really reach here }
VOID PAL_StartFrame( VOID ) /*++ Purpose: Starts a video frame. Called once per video frame. Parameters: None. Return value: None. --*/ { // // Run the game logic of one frame // PAL_GameUpdate(TRUE); if (gpGlobals->fEnteringScene) { return; } // // Update the positions and gestures of party members // PAL_UpdateParty(); // // Update the scene // PAL_MakeScene(); VIDEO_UpdateScreen(NULL); if (g_InputState.dwKeyPress & kKeyMenu) { // // Show the in-game menu // PAL_InGameMenu(); } else if (g_InputState.dwKeyPress & kKeyUseItem) { // // Show the use item menu // PAL_GameUseItem(); } else if (g_InputState.dwKeyPress & kKeyThrowItem) { // // Show the equipment menu // PAL_GameEquipItem(); } else if (g_InputState.dwKeyPress & kKeyForce) { // // Show the magic menu // PAL_InGameMagicMenu(); } else if (g_InputState.dwKeyPress & kKeyStatus) { // // Show the player status // PAL_PlayerStatus(); } else if (g_InputState.dwKeyPress & kKeySearch) { // // Process search events // PAL_Search(); } else if (g_InputState.dwKeyPress & kKeyFlee) { // // Quit Game // if (PAL_ConfirmMenu()) { PAL_PlayMUS(0, FALSE, 2); PAL_FadeOut(2); PAL_Shutdown(); exit(0); } } if (--gpGlobals->wChasespeedChangeCycles == 0) { gpGlobals->wChaseRange = 1; } }
VOID PAL_Search( VOID ) /*++ Purpose: Process searching trigger events. Parameters: None. Return value: None. --*/ { int x, y, xOffset, yOffset, dx, dy, dh, ex, ey, eh, i, k, l; LPEVENTOBJECT p; PAL_POS rgPos[13]; // // Get the party location // x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset); y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset); if (gpGlobals->wPartyDirection == kDirNorth || gpGlobals->wPartyDirection == kDirEast) { xOffset = 16; } else { xOffset = -16; } if (gpGlobals->wPartyDirection == kDirEast || gpGlobals->wPartyDirection == kDirSouth) { yOffset = 8; } else { yOffset = -8; } rgPos[0] = PAL_XY(x, y); for (i = 0; i < 4; i++) { rgPos[i * 3 + 1] = PAL_XY(x + xOffset, y + yOffset); rgPos[i * 3 + 2] = PAL_XY(x, y + yOffset * 2); rgPos[i * 3 + 3] = PAL_XY(x + xOffset, y); x += xOffset; y += yOffset; } for (i = 0; i < 13; i++) { // // Convert to map location // dh = ((PAL_X(rgPos[i]) % 32) ? 1 : 0); dx = PAL_X(rgPos[i]) / 32; dy = PAL_Y(rgPos[i]) / 16; // // Loop through all event objects // for (k = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex; k < gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; k++) { p = &(gpGlobals->g.lprgEventObject[k]); ex = p->x / 32; ey = p->y / 16; eh = ((p->x % 32) ? 1 : 0); if (p->sState <= 0 || p->wTriggerMode >= kTriggerTouchNear || p->wTriggerMode * 6 - 4 < i || dx != ex || dy != ey || dh != eh) { continue; } // // Adjust direction/gesture for party members and the event object // if (p->nSpriteFrames * 4 > p->wCurrentFrameNum) { p->wCurrentFrameNum = 0; // use standing gesture p->wDirection = (gpGlobals->wPartyDirection + 2) % 4; // face the party for (l = 0; l <= gpGlobals->wMaxPartyMemberIndex; l++) { // // All party members should face the event object // gpGlobals->rgParty[l].wFrame = gpGlobals->wPartyDirection * 3; } // // Redraw everything // PAL_MakeScene(); VIDEO_UpdateScreen(NULL); } // // Execute the script // p->wTriggerScript = PAL_RunTriggerScript(p->wTriggerScript, k + 1); // // Clear inputs and delay for a short time // UTIL_Delay(50); PAL_ClearKeyState(); return; // don't go further } } }
VOID PAL_GameUpdate( BOOL fTrigger ) /*++ Purpose: The main game logic routine. Update the status of everything. Parameters: [IN] fTrigger - whether to process trigger events or not. Return value: None. --*/ { WORD wEventObjectID, wDir; int i; LPEVENTOBJECT p; // // Check for trigger events // if (fTrigger) { // // Check if we are entering a new scene // if (gpGlobals->fEnteringScene) { // // Run the script for entering the scene // gpGlobals->fEnteringScene = FALSE; i = gpGlobals->wNumScene - 1; gpGlobals->g.rgScene[i].wScriptOnEnter = PAL_RunTriggerScript(gpGlobals->g.rgScene[i].wScriptOnEnter, 0xFFFF); if (gpGlobals->fEnteringScene || gpGlobals->fGameStart) { // // Don't go further as we're switching to another scene // return; } PAL_ClearKeyState(); PAL_MakeScene(); } // // Update the vanish time for all event objects // for (wEventObjectID = 0; wEventObjectID < gpGlobals->g.nEventObject; wEventObjectID++) { p = &gpGlobals->g.lprgEventObject[wEventObjectID]; if (p->sVanishTime != 0) { p->sVanishTime += ((p->sVanishTime < 0) ? 1 : -1); } } // // Loop through all event objects in the current scene // for (wEventObjectID = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex + 1; wEventObjectID <= gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; wEventObjectID++) { p = &gpGlobals->g.lprgEventObject[wEventObjectID - 1]; if (p->sVanishTime != 0) { continue; } if (p->sState < 0) { if (p->x < PAL_X(gpGlobals->viewport) || p->x > PAL_X(gpGlobals->viewport) + 320 || p->y < PAL_Y(gpGlobals->viewport) || p->y > PAL_Y(gpGlobals->viewport) + 320) { p->sState = abs(p->sState); p->wCurrentFrameNum = 0; } } else if (p->sState > 0 && p->wTriggerMode >= kTriggerTouchNear) { // // This event object can be triggered without manually exploring // if (abs(PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset) - p->x) + abs(PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset) - p->y) * 2 < (p->wTriggerMode - kTriggerTouchNear) * 32 + 16) { // // Player is in the trigger zone. // if (p->nSpriteFrames) { // // The sprite has multiple frames. Try to adjust the direction. // int xOffset, yOffset; p->wCurrentFrameNum = 0; xOffset = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset) - p->x; yOffset = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset) - p->y; if (xOffset > 0) { p->wDirection = ((yOffset > 0) ? kDirEast : kDirNorth); } else { p->wDirection = ((yOffset > 0) ? kDirSouth : kDirWest); } // // Redraw the scene // PAL_UpdatePartyGestures(FALSE); PAL_MakeScene(); VIDEO_UpdateScreen(NULL); } // // Execute the script. // p->wTriggerScript = PAL_RunTriggerScript(p->wTriggerScript, wEventObjectID); PAL_ClearKeyState(); if (gpGlobals->fEnteringScene || gpGlobals->fGameStart) { // // Don't go further on scene switching // return; } } } } } // // Run autoscript for each event objects // for (wEventObjectID = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex + 1; wEventObjectID <= gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; wEventObjectID++) { p = &gpGlobals->g.lprgEventObject[wEventObjectID - 1]; if (p->sState > 0 && p->sVanishTime == 0) { WORD wScriptEntry = p->wAutoScript; if (wScriptEntry != 0) { p->wAutoScript = PAL_RunAutoScript(wScriptEntry, wEventObjectID); if (gpGlobals->fEnteringScene || gpGlobals->fGameStart) { // // Don't go further on scene switching // return; } } } // // Check if the player is in the way // if (fTrigger && p->sState >= kObjStateBlocker && p->wSpriteNum != 0 && abs(p->x - PAL_X(gpGlobals->viewport) - PAL_X(gpGlobals->partyoffset)) + abs(p->y - PAL_Y(gpGlobals->viewport) - PAL_Y(gpGlobals->partyoffset)) * 2 <= 12) { // // Player is in the way, try to move a step // wDir = (p->wDirection + 1) % 4; for (i = 0; i < 4; i++) { int x, y; PAL_POS pos; x = PAL_X(gpGlobals->viewport) + PAL_X(gpGlobals->partyoffset); y = PAL_Y(gpGlobals->viewport) + PAL_Y(gpGlobals->partyoffset); x += ((wDir == kDirWest || wDir == kDirSouth) ? -16 : 16); y += ((wDir == kDirWest || wDir == kDirNorth) ? -8 : 8); pos = PAL_XY(x, y); if (!PAL_CheckObstacle(pos, TRUE, 0)) { // // move here // gpGlobals->viewport = PAL_XY( PAL_X(pos) - PAL_X(gpGlobals->partyoffset), PAL_Y(pos) - PAL_Y(gpGlobals->partyoffset)); break; } wDir = (wDir + 1) % 4; } } } gpGlobals->dwFrameNum++; }
VOID PAL_StartFrame( VOID ) /*++ Purpose: Starts a video frame. Called once per video frame. Parameters: None. Return value: None. --*/ { // // Run the game logic of one frame // LoginInfo("PAL_StartFrame\n" ); PAL_GameUpdate(TRUE); if (gpGlobals->fEnteringScene) { return; } // // Update the positions and gestures of party members // PAL_UpdateParty(); // // Update the scene // PAL_MakeScene(); VIDEO_UpdateScreen(NULL); if (g_InputState.dwKeyPress & kKeyMenu) { // // Show the in-game menu // PAL_InGameMenu(); } else if (g_InputState.dwKeyPress & kKeyUseItem) { // // Show the use item menu // PAL_GameUseItem(); } else if (g_InputState.dwKeyPress & kKeyStatus) { // // Show the player status // PAL_PlayerStatus(); } else if (g_InputState.dwKeyPress & kKeySearch) { // // Process search events // PAL_Search(); } if (--gpGlobals->wChasespeedChangeCycles == 0) { gpGlobals->wChaseRange = 1; } }