/*++ Read global game data from data files. --*/ static VOID PAL_ReadGlobalGameData(void) { const GAMEDATA *p = &gpGlobals->g; unsigned int i; LOAD_DATA(p->lprgScriptEntry, p->nScriptEntry * sizeof(SCRIPTENTRY), 4, gpGlobals->f.fpSSS); LOAD_DATA(p->lprgStore, p->nStore * sizeof(STORE), 0, gpGlobals->f.fpDATA); LOAD_DATA(p->lprgEnemy, p->nEnemy * sizeof(ENEMY), 1, gpGlobals->f.fpDATA); LOAD_DATA(p->lprgEnemyTeam, p->nEnemyTeam * sizeof(ENEMYTEAM), 2, gpGlobals->f.fpDATA); LOAD_DATA(p->lprgMagic, p->nMagic * sizeof(MAGIC), 4, gpGlobals->f.fpDATA); LOAD_DATA(p->lprgBattleField, p->nBattleField * sizeof(BATTLEFIELD), 5, gpGlobals->f.fpDATA); LOAD_DATA(p->lprgLevelUpMagic, p->nLevelUpMagic * sizeof(LEVELUPMAGIC_ALL), 6, gpGlobals->f.fpDATA); LOAD_DATA(p->rgwBattleEffectIndex, sizeof(p->rgwBattleEffectIndex), 11, gpGlobals->f.fpDATA); PAL_MKFReadChunk((LPBYTE)&(p->EnemyPos), sizeof(p->EnemyPos), 13, gpGlobals->f.fpDATA); DO_BYTESWAP(&(p->EnemyPos), sizeof(p->EnemyPos)); PAL_MKFReadChunk((LPBYTE)(p->rgLevelUpExp), sizeof(p->rgLevelUpExp), 14, gpGlobals->f.fpDATA); DO_BYTESWAP(p->rgLevelUpExp, sizeof(p->rgLevelUpExp)); }
/*++ 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; }
INT PAL_MKFDecompressChunk( LPBYTE lpBuffer, UINT uiBufferSize, UINT uiChunkNum, FILE *fp ) /*++ Purpose: Decompress a compressed chunk from an MKF archive into lpBuffer. Parameters: [OUT] lpBuffer - pointer to the destination buffer. [IN] uiBufferSize - size of the destination buffer. [IN] uiChunkNum - the number of the chunk in the MKF archive to read. [IN] fp - pointer to the fopen'ed MKF file. Return value: Integer value which indicates the size of the chunk. -1 if there are error in parameters, or buffer size is not enough. -3 if cannot allocate memory for decompression. --*/ { LPBYTE buf; int len; len = PAL_MKFGetChunkSize(uiChunkNum, fp); if (len <= 0) { return len; } buf = (LPBYTE)malloc(len); if (buf == NULL) { return -3; } PAL_MKFReadChunk(buf, len, uiChunkNum, fp); len = Decompress(buf, lpBuffer, uiBufferSize); free(buf); return len; }
INT PAL_InitUI( VOID ) /*++ Purpose: Initialze the UI subsystem. Parameters: None. Return value: 0 = success, -1 = fail. --*/ { int iSize; // // Load the UI sprite. // iSize = PAL_MKFGetChunkSize(CHUNKNUM_SPRITEUI, gpGlobals->f.fpDATA); if (iSize < 0) { return -1; } gpSpriteUI = (LPSPRITE)calloc(1, iSize); if (gpSpriteUI == NULL) { return -1; } PAL_MKFReadChunk(gpSpriteUI, iSize, CHUNKNUM_SPRITEUI, gpGlobals->f.fpDATA); return 0; }
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_StartDialog( BYTE bDialogLocation, BYTE bFontColor, INT iNumCharFace, BOOL fPlayingRNG ) /*++ Purpose: Start a new dialog. Parameters: [IN] bDialogLocation - the location of the text on the screen. [IN] bFontColor - the font color of the text. [IN] iNumCharFace - number of the character face in RGM.MKF. [IN] fPlayingRNG - whether we are playing a RNG video or not. Return value: None. --*/ { PAL_LARGE BYTE buf[16384]; SDL_Rect rect; if (gpGlobals->fInBattle && !g_fUpdatedInBattle) { // // Update the screen in battle, or the graphics may seem messed up // VIDEO_UpdateScreen(NULL); g_fUpdatedInBattle = TRUE; } g_TextLib.bIcon = 0; g_TextLib.posIcon = 0; g_TextLib.nCurrentDialogLine = 0; g_TextLib.posDialogTitle = PAL_XY(12, 8); g_TextLib.fUserSkip = FALSE; if (bFontColor != 0) { g_TextLib.bCurrentFontColor = bFontColor; } if (fPlayingRNG && iNumCharFace) { VIDEO_BackupScreen(); g_TextLib.fPlayingRNG = TRUE; } switch (bDialogLocation) { case kDialogUpper: if (iNumCharFace > 0) { // // Display the character face at the upper part of the screen // if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0) { rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf); rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf); rect.x = 48 - rect.w / 2; rect.y = 55 - rect.h / 2; if (rect.x < 0) { rect.x = 0; } if (rect.y < 0) { rect.y = 0; } PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y)); if (rect.x < 0) { rect.x = 0; } if (rect.y < 0) { rect.y = 0; } VIDEO_UpdateScreen(&rect); } } g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8); g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26); break; case kDialogCenter: g_TextLib.posDialogText = PAL_XY(80, 40); break; case kDialogLower: if (iNumCharFace > 0) { // // Display the character face at the lower part of the screen // if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0) { rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2; rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2; PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y)); VIDEO_UpdateScreen(NULL); } } g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108); g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126); break; case kDialogCenterWindow: g_TextLib.posDialogText = PAL_XY(160, 40); break; } g_TextLib.bDialogPosition = bDialogLocation; }
VOID MIDI_Play( INT iNumRIX, BOOL fLoop ) /*++ Purpose: Start playing the specified music in MIDI format. Parameters: [IN] iNumRIX - number of the music. 0 to stop playing current music. [IN] fLoop - Whether the music should be looped or not. Return value: None. --*/ { FILE *fp; unsigned char *buf; int size; SDL_RWops *rw; #ifdef PAL_WIN95 char filename[1024]; #endif if (g_pMid != NULL && iNumRIX == iMidCurrent && native_midi_active()) { return; } SOUND_PlayCDA(-1); native_midi_freesong(g_pMid); g_pMid = NULL; iMidCurrent = -1; if (g_fNoMusic || iNumRIX <= 0) { return; } #ifdef PAL_WIN95 sprintf(filename, "%s/musics/%.3d.mid", PAL_PREFIX, iNumRIX); g_pMid = native_midi_loadsong(filename); if (g_pMid != NULL) { native_midi_start(g_pMid); iMidCurrent = iNumRIX; fMidLoop = fLoop; } #else fp = UTIL_OpenFile("midi.mkf"); if (fp == NULL) { return; } if (iNumRIX > PAL_MKFGetChunkCount(fp)) { fclose(fp); return; } size = PAL_MKFGetChunkSize(iNumRIX, fp); if (size <= 0) { fclose(fp); return; } buf = (unsigned char *)UTIL_malloc(size); PAL_MKFReadChunk((LPBYTE)buf, size, iNumRIX, fp); fclose(fp); rw = SDL_RWFromConstMem((const void *)buf, size); g_pMid = native_midi_loadsong_RW(rw); if (g_pMid != NULL) { native_midi_start(g_pMid); iMidCurrent = iNumRIX; fMidLoop = fLoop; } SDL_RWclose(rw); free(buf); #endif }
/*++ Start a battle. Parameters: [IN] wEnemyTeam - the number of the enemy team. [IN] fIsBoss - TRUE for boss fight (not allowed to flee). Return value: The result of the battle. --*/ BATTLERESULT PAL_StartBattle(WORD wEnemyTeam, BOOL fIsBoss) { int i; WORD w, wPrevWaveLevel; SHORT sPrevWaveProgression; // // Set the screen waving effects // wPrevWaveLevel = gpGlobals->wScreenWave; sPrevWaveProgression = gpGlobals->sWaveProgression; gpGlobals->sWaveProgression = 0; gpGlobals->wScreenWave = gpGlobals->g.lprgBattleField[gpGlobals->wNumBattleField].wScreenWave; // // Make sure everyone in the party is alive, also clear all hidden // EXP count records // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { w = gpGlobals->rgParty[i].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0) { gpGlobals->g.PlayerRoles.rgwHP[w] = 1; gpGlobals->rgPlayerStatus[w][kStatusPuppet] = 0; } gpGlobals->Exp.rgHealthExp[w].wCount = 0; gpGlobals->Exp.rgMagicExp[w].wCount = 0; gpGlobals->Exp.rgAttackExp[w].wCount = 0; gpGlobals->Exp.rgMagicPowerExp[w].wCount = 0; gpGlobals->Exp.rgDefenseExp[w].wCount = 0; gpGlobals->Exp.rgDexterityExp[w].wCount = 0; gpGlobals->Exp.rgFleeExp[w].wCount = 0; } // // Clear all item-using records // for (i = 0; i < MAX_INVENTORY; i++) { gpGlobals->rgInventory[i].nAmountInUse = 0; } // // Store all enemies // for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { memset(&(g_Battle.rgEnemy[i]), 0, sizeof(BATTLEENEMY)); w = gpGlobals->g.lprgEnemyTeam[wEnemyTeam].rgwEnemy[i]; if (w == 0xFFFF) { break; } if (w != 0) { g_Battle.rgEnemy[i].e = gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[w].enemy.wEnemyID]; g_Battle.rgEnemy[i].wObjectID = w; g_Battle.rgEnemy[i].state = kFighterWait; g_Battle.rgEnemy[i].wScriptOnTurnStart = gpGlobals->g.rgObject[w].enemy.wScriptOnTurnStart; g_Battle.rgEnemy[i].wScriptOnBattleEnd = gpGlobals->g.rgObject[w].enemy.wScriptOnBattleEnd; g_Battle.rgEnemy[i].wScriptOnReady = gpGlobals->g.rgObject[w].enemy.wScriptOnReady; g_Battle.rgEnemy[i].iColorShift = 0; g_Battle.rgEnemy[i].dwMaxHealth = g_Battle.rgEnemy[i].e.wHealth; #ifndef PAL_CLASSIC g_Battle.rgEnemy[i].flTimeMeter = 50; // // HACK: Otherwise the black thief lady will be too hard to beat // if (g_Battle.rgEnemy[i].e.wDexterity == 164) { g_Battle.rgEnemy[i].e.wDexterity /= ((gpGlobals->wMaxPartyMemberIndex == 0) ? 6 : 3); } // // HACK: Heal up automatically for final boss // if (g_Battle.rgEnemy[i].e.wHealth == 32760) { for (w = 0; w < MAX_PLAYER_ROLES; w++) { gpGlobals->g.PlayerRoles.rgwHP[w] = gpGlobals->g.PlayerRoles.rgwMaxHP[w]; gpGlobals->g.PlayerRoles.rgwMP[w] = gpGlobals->g.PlayerRoles.rgwMaxMP[w]; } } // // Yet another HACKs // if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -32) { g_Battle.rgEnemy[i].e.wDexterity = 0; // for Grandma Knife } else if (g_Battle.rgEnemy[i].e.wDexterity == 20) { // // for Fox Demon // if (gpGlobals->g.PlayerRoles.rgwLevel[0] < 15) { g_Battle.rgEnemy[i].e.wDexterity = 8; } else if (gpGlobals->g.PlayerRoles.rgwLevel[4] > 28 || gpGlobals->Exp.rgPrimaryExp[4].wExp > 0) { g_Battle.rgEnemy[i].e.wDexterity = 60; } } else if (g_Battle.rgEnemy[i].e.wExp == 250 && g_Battle.rgEnemy[i].e.wCash == 1100) { g_Battle.rgEnemy[i].e.wDexterity += 12; // for Snake Demon } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -60) { g_Battle.rgEnemy[i].e.wDexterity = 15; // for Spider } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -30) { g_Battle.rgEnemy[i].e.wDexterity = (WORD)-10; // for Stone Head } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -16) { g_Battle.rgEnemy[i].e.wDexterity = 0; // for Zombie } else if ((SHORT)g_Battle.rgEnemy[i].e.wDexterity == -20) { g_Battle.rgEnemy[i].e.wDexterity = -8; // for Flower Demon } else if (g_Battle.rgEnemy[i].e.wLevel < 20 && gpGlobals->wNumScene >= 0xD8 && gpGlobals->wNumScene <= 0xE2) { // // for low-level monsters in the Cave of Trial // g_Battle.rgEnemy[i].e.wLevel += 15; g_Battle.rgEnemy[i].e.wDexterity += 25; } else if (gpGlobals->wNumScene == 0x90) { g_Battle.rgEnemy[i].e.wDexterity += 25; // for Tower Dragons } else if (g_Battle.rgEnemy[i].e.wLevel == 2 && g_Battle.rgEnemy[i].e.wCash == 48) { g_Battle.rgEnemy[i].e.wDexterity += 8; // for Miao Fists } else if (g_Battle.rgEnemy[i].e.wLevel == 4 && g_Battle.rgEnemy[i].e.wCash == 240) { g_Battle.rgEnemy[i].e.wDexterity += 18; // for Fat Miao } else if (g_Battle.rgEnemy[i].e.wLevel == 16 && g_Battle.rgEnemy[i].e.wMagicRate == 4 && g_Battle.rgEnemy[i].e.wAttackEquivItemRate == 4) { g_Battle.rgEnemy[i].e.wDexterity += 50; // for Black Spider } #endif } } g_Battle.wMaxEnemyIndex = i - 1; // // Store all players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { g_Battle.rgPlayer[i].flTimeMeter = 15.0f; #ifndef PAL_CLASSIC g_Battle.rgPlayer[i].flTimeSpeedModifier = 2.0f; g_Battle.rgPlayer[i].sTurnOrder = -1; #endif g_Battle.rgPlayer[i].wHidingTime = 0; g_Battle.rgPlayer[i].state = kFighterWait; g_Battle.rgPlayer[i].action.sTarget = -1; g_Battle.rgPlayer[i].fDefending = FALSE; g_Battle.rgPlayer[i].wCurrentFrame = 0; g_Battle.rgPlayer[i].iColorShift = FALSE; } // // Load sprites and background // PAL_LoadBattleSprites(); PAL_LoadBattleBackground(); // // Create the surface for scene buffer // g_Battle.lpSceneBuf = SDL_CreateRGBSurface(gpScreen->flags & ~SDL_HWSURFACE, 320, 200, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (g_Battle.lpSceneBuf == NULL) { TerminateOnError("PAL_StartBattle(): creating surface for scene buffer failed!"); } #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetSurfacePalette(g_Battle.lpSceneBuf, gpScreen->format->palette); #else SDL_SetPalette(g_Battle.lpSceneBuf, SDL_PHYSPAL | SDL_LOGPAL, VIDEO_GetPalette(), 0, 256); #endif PAL_UpdateEquipments(); g_Battle.iExpGained = 0; g_Battle.iCashGained = 0; g_Battle.fIsBoss = fIsBoss; g_Battle.fEnemyCleared = FALSE; g_Battle.fEnemyMoving = FALSE; g_Battle.iHidingTime = 0; g_Battle.wMovingPlayerIndex = 0; g_Battle.UI.szMsg[0] = '\0'; g_Battle.UI.szNextMsg[0] = '\0'; g_Battle.UI.dwMsgShowTime = 0; g_Battle.UI.state = kBattleUIWait; g_Battle.UI.fAutoAttack = FALSE; g_Battle.UI.wSelectedIndex = 0; g_Battle.UI.wPrevEnemyTarget = 0; memset(g_Battle.UI.rgShowNum, 0, sizeof(g_Battle.UI.rgShowNum)); g_Battle.lpSummonSprite = NULL; g_Battle.sBackgroundColorShift = 0; gpGlobals->fInBattle = TRUE; g_Battle.BattleResult = kBattleResultPreBattle; PAL_BattleUpdateFighters(); // // Load the battle effect sprite. // i = PAL_MKFGetChunkSize(10, gpGlobals->f.fpDATA); g_Battle.lpEffectSprite = UTIL_malloc(i); PAL_MKFReadChunk(g_Battle.lpEffectSprite, i, 10, gpGlobals->f.fpDATA); #ifdef PAL_CLASSIC g_Battle.Phase = kBattlePhaseSelectAction; g_Battle.fRepeat = FALSE; g_Battle.fForce = FALSE; g_Battle.fFlee = FALSE; #endif #ifdef PAL_ALLOW_KEYREPEAT SDL_EnableKeyRepeat(120, 75); #endif // // Run the main battle routine. // i = PAL_BattleMain(); #ifdef PAL_ALLOW_KEYREPEAT SDL_EnableKeyRepeat(0, 0); PAL_ClearKeyState(); g_InputState.prevdir = kDirUnknown; #endif if (i == kBattleResultWon) { // // Player won the battle. Add the Experience points. // PAL_BattleWon(); } // // Clear all item-using records // for (w = 0; w < MAX_INVENTORY; w++) { gpGlobals->rgInventory[w].nAmountInUse = 0; } // // Clear all player status, poisons and temporary effects // PAL_ClearAllPlayerStatus(); for (w = 0; w < MAX_PLAYER_ROLES; w++) { PAL_CurePoisonByLevel(w, 3); PAL_RemoveEquipmentEffect(w, kBodyPartExtra); } // // Free all the battle sprites // PAL_FreeBattleSprites(); free(g_Battle.lpEffectSprite); // // Free the surfaces for the background picture and scene buffer // SDL_FreeSurface(g_Battle.lpBackground); SDL_FreeSurface(g_Battle.lpSceneBuf); g_Battle.lpBackground = NULL; g_Battle.lpSceneBuf = NULL; gpGlobals->fInBattle = FALSE; PAL_PlayMUS(gpGlobals->wNumMusic, TRUE, 1); // // Restore the screen waving effects // gpGlobals->sWaveProgression = sPrevWaveProgression; gpGlobals->wScreenWave = wPrevWaveLevel; return i; }
VOID MIDI_Play( INT iNumRIX, BOOL fLoop ) /*++ Purpose: Start playing the specified music in MIDI format. Parameters: [IN] iNumRIX - number of the music. 0 to stop playing current music. [IN] fLoop - Whether the music should be looped or not. Return value: None. --*/ { FILE *fp; unsigned char *buf; int size; SDL_RWops *rw; #ifdef TIMIDITY if (g_pMid != NULL && iNumRIX == iMidCurrent && Timidity_Active()) #else if (g_pMid != NULL && iNumRIX == iMidCurrent && native_midi_active()) #endif { return; } SOUND_PlayCDA(-1); #ifdef TIMIDITY Timidity_FreeSong(g_pMid); #else native_midi_freesong(g_pMid); #endif g_pMid = NULL; iMidCurrent = -1; if (g_fNoMusic || iNumRIX <= 0) { return; } fp = fopen(PAL_PREFIX "midi.mkf", "rb"); if (fp == NULL) { return; } if (iNumRIX > PAL_MKFGetChunkCount(fp)) { fclose(fp); return; } size = PAL_MKFGetChunkSize(iNumRIX, fp); if (size <= 0) { fclose(fp); return; } buf = (unsigned char *)UTIL_malloc(size); PAL_MKFReadChunk((LPBYTE)buf, size, iNumRIX, fp); fclose(fp); rw = SDL_RWFromConstMem((const void *)buf, size); #ifdef TIMIDITY g_pMid = Timidity_LoadSong_RW(rw); #else g_pMid = native_midi_loadsong_RW(rw); #endif if (g_pMid != NULL) { #ifdef TIMIDITY Timidity_Start(g_pMid); #else native_midi_start(g_pMid); #endif iMidCurrent = iNumRIX; fMidLoop = fLoop; } SDL_RWclose(rw); free(buf); }
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; }
VOID PAL_EquipItemMenu( WORD wItem ) /*++ Purpose: Show the menu which allow players to equip the specified item. Parameters: [IN] wItem - the object ID of the item. Return value: None. --*/ { PAL_LARGE BYTE bufBackground[320 * 200]; PAL_LARGE BYTE bufImage[2048]; WORD w; int iCurrentPlayer, i; BYTE bColor, bSelectedColor; DWORD dwColorChangeTime; gpGlobals->wLastUnequippedItem = wItem; PAL_MKFDecompressChunk(bufBackground, 320 * 200, EQUIPMENU_BACKGROUND_FBPNUM, gpGlobals->f.fpFBP); iCurrentPlayer = 0; bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; dwColorChangeTime = SDL_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM); while (TRUE) { wItem = gpGlobals->wLastUnequippedItem; // // Draw the background // PAL_FBPBlitToSurface(bufBackground, gpScreen); // // Draw the item picture // if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wItem].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(16, 16)); } // // Draw the current equipment of the selected player // w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; for (i = 0; i < MAX_PLAYER_EQUIPMENTS; i++) { if (gpGlobals->g.PlayerRoles.rgwEquipment[i][w] != 0) { PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwEquipment[i][w]), PAL_XY(130, 11 + i * 22), MENUITEM_COLOR, TRUE, FALSE); } } // // Draw the stats of the currently selected player // PAL_DrawNumber(PAL_GetPlayerAttackStrength(w), 4, PAL_XY(260, 14), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(w), 4, PAL_XY(260, 36), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(w), 4, PAL_XY(260, 58), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(w), 4, PAL_XY(260, 80), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(w), 4, PAL_XY(260, 102), kNumColorCyan, kNumAlignRight); // // Draw a box for player selection // PAL_CreateBox(PAL_XY(2, 95), gpGlobals->wMaxPartyMemberIndex, 2, 0, FALSE); // // Draw the label of players // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { w = gpGlobals->rgParty[i].wPlayerRole; if (iCurrentPlayer == i) { if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { bColor = bSelectedColor; } else { bColor = MENUITEM_COLOR_SELECTED_INACTIVE; } } else { if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { bColor = MENUITEM_COLOR; } else { bColor = MENUITEM_COLOR_INACTIVE; } } PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(15, 108 + 18 * i), bColor, TRUE, FALSE); } // // Draw the text label and amount of the item // if (wItem != 0) { PAL_DrawText(PAL_GetWord(wItem), PAL_XY(5, 70), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); PAL_DrawNumber(PAL_GetItemAmount(wItem), 2, PAL_XY(65, 73), kNumColorCyan, kNumAlignRight); } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Accept input // PAL_ClearKeyState(); while (TRUE) { PAL_ProcessEvent(); // // See if we should change the highlight color // if (SDL_GetTicks() > dwColorChangeTime) { if ((WORD)bSelectedColor + 1 >= (WORD)MENUITEM_COLOR_SELECTED_FIRST + MENUITEM_COLOR_SELECTED_TOTALNUM) { bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; } else { bSelectedColor++; } dwColorChangeTime = SDL_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM); // // Redraw the selected item if needed. // w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[w]), PAL_XY(15, 108 + 18 * iCurrentPlayer), bSelectedColor, TRUE, TRUE); } } if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(1); } if (wItem == 0) { return; } if (g_InputState.dwKeyPress & (kKeyUp | kKeyLeft)) { iCurrentPlayer--; if (iCurrentPlayer < 0) { iCurrentPlayer = 0; } } else if (g_InputState.dwKeyPress & (kKeyDown | kKeyRight)) { iCurrentPlayer++; if (iCurrentPlayer > gpGlobals->wMaxPartyMemberIndex) { iCurrentPlayer = gpGlobals->wMaxPartyMemberIndex; } } else if (g_InputState.dwKeyPress & kKeyMenu) { return; } else if (g_InputState.dwKeyPress & kKeySearch) { w = gpGlobals->rgParty[iCurrentPlayer].wPlayerRole; if (gpGlobals->g.rgObject[wItem].item.wFlags & (kItemFlagEquipableByPlayerRole_First << w)) { // // Run the equip script // gpGlobals->g.rgObject[wItem].item.wScriptOnEquip = PAL_RunTriggerScript(gpGlobals->g.rgObject[wItem].item.wScriptOnEquip, gpGlobals->rgParty[iCurrentPlayer].wPlayerRole); } } } }
static VOID PAL_BuyMenu_OnItemChange( WORD wCurrentItem ) /*++ Purpose: Callback function which is called when player selected another item in the buy menu. Parameters: [IN] wCurrentItem - current item on the menu, indicates the object ID of the currently selected item. Return value: None. --*/ { const SDL_Rect rect = {20, 8, 128, 175}; int i, n; PAL_LARGE BYTE bufImage[2048]; // // Draw the picture of current selected item // PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ITEMBOX), gpScreen, PAL_XY(35, 8)); if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wCurrentItem].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(42, 16)); } // // See how many of this item we have in the inventory // n = 0; for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == 0) { break; } else if (gpGlobals->rgInventory[i].wItem == wCurrentItem) { n = gpGlobals->rgInventory[i].nAmount; break; } } // // Draw the amount of this item in the inventory // PAL_CreateSingleLineBox(PAL_XY(20, 105), 5, FALSE); PAL_DrawText(PAL_GetWord(BUYMENU_LABEL_CURRENT), PAL_XY(30, 115), 0, FALSE, FALSE); PAL_DrawNumber(n, 6, PAL_XY(69, 119), kNumColorYellow, kNumAlignRight); // // Draw the cash amount // PAL_CreateSingleLineBox(PAL_XY(20, 145), 5, FALSE); PAL_DrawText(PAL_GetWord(CASH_LABEL), PAL_XY(30, 155), 0, FALSE, FALSE); PAL_DrawNumber(gpGlobals->dwCash, 6, PAL_XY(69, 159), kNumColorYellow, kNumAlignRight); VIDEO_UpdateScreen(&rect); }
WORD PAL_ItemUseMenu( WORD wItemToUse ) /*++ Purpose: Show the use item menu. Parameters: [IN] wItemToUse - the object ID of the item to use. Return value: The selected player to use the item onto. MENUITEM_VALUE_CANCELLED if user cancelled. --*/ { BYTE bColor, bSelectedColor; PAL_LARGE BYTE bufImage[2048]; DWORD dwColorChangeTime; static WORD wSelectedPlayer = 0; SDL_Rect rect = {110, 2, 200, 180}; int i; bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; dwColorChangeTime = 0; while (TRUE) { if (wSelectedPlayer > gpGlobals->wMaxPartyMemberIndex) { wSelectedPlayer = 0; } // // Draw the box // PAL_CreateBox(PAL_XY(110, 2), 7, 9, 0, FALSE); // // Draw the stats of the selected player // PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(200, 16), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP), PAL_XY(200, 34), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP), PAL_XY(200, 52), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER), PAL_XY(200, 70), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER), PAL_XY(200, 88), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE), PAL_XY(200, 106), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY), PAL_XY(200, 124), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE), PAL_XY(200, 142), ITEMUSEMENU_COLOR_STATLABEL, TRUE, FALSE); i = gpGlobals->rgParty[wSelectedPlayer].wPlayerRole; PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwLevel[i], 4, PAL_XY(240, 20), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(263, 38)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[i], 4, PAL_XY(261, 40), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[i], 4, PAL_XY(240, 37), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(263, 56)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[i], 4, PAL_XY(261, 58), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[i], 4, PAL_XY(240, 55), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerAttackStrength(i), 4, PAL_XY(240, 74), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(i), 4, PAL_XY(240, 92), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(i), 4, PAL_XY(240, 110), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(i), 4, PAL_XY(240, 128), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(i), 4, PAL_XY(240, 146), kNumColorYellow, kNumAlignRight); // // Draw the names of the players in the party // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (i == wSelectedPlayer) { bColor = bSelectedColor; } else { bColor = MENUITEM_COLOR; } PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[i].wPlayerRole]), PAL_XY(125, 16 + 20 * i), bColor, TRUE, FALSE); } PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_ITEMBOX), gpScreen, PAL_XY(120, 80)); i = PAL_GetItemAmount(wItemToUse); if (i > 0) { // // Draw the picture of the item // if (PAL_MKFReadChunk(bufImage, 2048, gpGlobals->g.rgObject[wItemToUse].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(127, 88)); } // // Draw the amount and label of the item // PAL_DrawText(PAL_GetWord(wItemToUse), PAL_XY(116, 143), STATUS_COLOR_EQUIPMENT, TRUE, FALSE); PAL_DrawNumber(i, 2, PAL_XY(170, 133), kNumColorCyan, kNumAlignRight); } // // Update the screen area // VIDEO_UpdateScreen(&rect); // // Wait for key // PAL_ClearKeyState(); while (TRUE) { // // See if we should change the highlight color // if (SDL_GetTicks() > dwColorChangeTime) { if ((WORD)bSelectedColor + 1 >= (WORD)MENUITEM_COLOR_SELECTED_FIRST + MENUITEM_COLOR_SELECTED_TOTALNUM) { bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST; } else { bSelectedColor++; } dwColorChangeTime = SDL_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM); // // Redraw the selected item. // PAL_DrawText( PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[gpGlobals->rgParty[wSelectedPlayer].wPlayerRole]), PAL_XY(125, 16 + 20 * wSelectedPlayer), bSelectedColor, FALSE, TRUE); } PAL_ProcessEvent(); if (g_InputState.dwKeyPress != 0) { break; } SDL_Delay(1); } if (i <= 0) { return MENUITEM_VALUE_CANCELLED; } if (g_InputState.dwKeyPress & (kKeyUp | kKeyLeft)) { wSelectedPlayer--; } else if (g_InputState.dwKeyPress & (kKeyDown | kKeyRight)) { if (wSelectedPlayer < gpGlobals->wMaxPartyMemberIndex) { wSelectedPlayer++; } } else if (g_InputState.dwKeyPress & kKeyMenu) { break; } else if (g_InputState.dwKeyPress & kKeySearch) { return gpGlobals->rgParty[wSelectedPlayer].wPlayerRole; } } return MENUITEM_VALUE_CANCELLED; }
VOID PAL_PlayerStatus( VOID ) /*++ Purpose: Show the player status. Parameters: None. Return value: None. --*/ { PAL_LARGE BYTE bufBackground[320 * 200]; PAL_LARGE BYTE bufImage[16384]; int iCurrent; int iPlayerRole; int i, y; WORD w; const int rgEquipPos[MAX_PLAYER_EQUIPMENTS][2] = { {190, 0}, {248, 40}, {252, 102}, {202, 134}, {142, 142}, {82, 126} }; PAL_MKFDecompressChunk(bufBackground, 320 * 200, STATUS_BACKGROUND_FBPNUM, gpGlobals->f.fpFBP); iCurrent = 0; while (iCurrent >= 0 && iCurrent <= gpGlobals->wMaxPartyMemberIndex) { iPlayerRole = gpGlobals->rgParty[iCurrent].wPlayerRole; // // Draw the background image // PAL_FBPBlitToSurface(bufBackground, gpScreen); // // Draw the text labels // PAL_DrawText(PAL_GetWord(STATUS_LABEL_EXP), PAL_XY(6, 6), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL), PAL_XY(6, 32), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP), PAL_XY(6, 54), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP), PAL_XY(6, 76), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER), PAL_XY(6, 98), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER), PAL_XY(6, 118), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE), PAL_XY(6, 138), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY), PAL_XY(6, 158), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE), PAL_XY(6, 178), MENUITEM_COLOR, TRUE, FALSE); PAL_DrawText(PAL_GetWord(gpGlobals->g.PlayerRoles.rgwName[iPlayerRole]), PAL_XY(110, 8), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); // // Draw the stats // PAL_DrawNumber(gpGlobals->Exp.rgPrimaryExp[iPlayerRole].wExp, 5, PAL_XY(58, 6), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.rgLevelUpExp[gpGlobals->g.PlayerRoles.rgwLevel[iPlayerRole]], 5, PAL_XY(58, 15), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwLevel[iPlayerRole], 2, PAL_XY(54, 35), kNumColorYellow, kNumAlignRight); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(65, 58)); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, PAL_XY(65, 80)); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwHP[iPlayerRole], 4, PAL_XY(42, 56), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxHP[iPlayerRole], 4, PAL_XY(63, 61), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMP[iPlayerRole], 4, PAL_XY(42, 78), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(gpGlobals->g.PlayerRoles.rgwMaxMP[iPlayerRole], 4, PAL_XY(63, 83), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerAttackStrength(iPlayerRole), 4, PAL_XY(42, 102), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(iPlayerRole), 4, PAL_XY(42, 122), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(iPlayerRole), 4, PAL_XY(42, 142), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(iPlayerRole), 4, PAL_XY(42, 162), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(iPlayerRole), 4, PAL_XY(42, 182), kNumColorYellow, kNumAlignRight); // // Draw the equipments // for (i = 0; i < MAX_PLAYER_EQUIPMENTS; i++) { w = gpGlobals->g.PlayerRoles.rgwEquipment[i][iPlayerRole]; if (w == 0) { continue; } // // Draw the image // if (PAL_MKFReadChunk(bufImage, 16384, gpGlobals->g.rgObject[w].item.wBitmap, gpGlobals->f.fpBALL) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(rgEquipPos[i][0], rgEquipPos[i][1])); } // // Draw the text label // PAL_DrawText(PAL_GetWord(w), PAL_XY(rgEquipPos[i][0] + 5, rgEquipPos[i][1] + 38), STATUS_COLOR_EQUIPMENT, TRUE, FALSE); } // // Draw the image of player role // if (PAL_MKFReadChunk(bufImage, 16384, gpGlobals->g.PlayerRoles.rgwAvatar[iPlayerRole], gpGlobals->f.fpRGM) > 0) { PAL_RLEBlitToSurface(bufImage, gpScreen, PAL_XY(110, 30)); } // // Draw all poisons // y = 58; for (i = 0; i < MAX_POISONS; i++) { w = gpGlobals->rgPoisonStatus[i][iCurrent].wPoisonID; if (w != 0 && gpGlobals->g.rgObject[w].poison.wPoisonLevel <= 3) { PAL_DrawText(PAL_GetWord(w), PAL_XY(185, y), (BYTE)(gpGlobals->g.rgObject[w].poison.wColor + 10), TRUE, FALSE); y += 18; } } // // Update the screen // VIDEO_UpdateScreen(NULL); // // Wait for input // PAL_ClearKeyState(); while (TRUE) { UTIL_Delay(1); if (g_InputState.dwKeyPress & kKeyMenu) { iCurrent = -1; break; } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyUp)) { iCurrent--; break; } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyDown | kKeySearch)) { iCurrent++; break; } } } }
SDL_Color * PAL_GetPalette( INT iPaletteNum, BOOL fNight ) /*++ Purpose: Get the specified palette in pat.mkf file. Parameters: [IN] iPaletteNum - number of the palette. [IN] fNight - whether use the night palette or not. Return value: Pointer to the palette. NULL if failed. --*/ { static SDL_Color palette[256]; PAL_LARGE BYTE buf[1536]; INT i; FILE *fp; fp = UTIL_OpenRequiredFile("pat.mkf"); // // Read the palette data from the pat.mkf file // i = PAL_MKFReadChunk(buf, 1536, iPaletteNum, fp); fclose(fp); if (i < 0) { // // Read failed // return NULL; } else if (i <= 256 * 3) { // // There is no night colors in the palette // fNight = FALSE; } for (i = 0; i < 256; i++) { palette[i].r = buf[(fNight ? 256 * 3 : 0) + i * 3] << 2; palette[i].g = buf[(fNight ? 256 * 3 : 0) + i * 3 + 1] << 2; palette[i].b = buf[(fNight ? 256 * 3 : 0) + i * 3 + 2] << 2; #if 0 palette[i].r += (255 - palette[i].r) / 5; palette[i].g += (255 - palette[i].g) / 5; palette[i].b += (255 - palette[i].b) / 5; #endif } return palette; }