/*++ 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_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; }
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)); } }
static VOID PAL_CalcCoverTiles( SPRITE_TO_DRAW *lpSpriteToDraw ) /*++ Purpose: Calculate all the tiles which may cover the specified sprite. Add the tiles into our list as well. Parameters: [IN] lpSpriteToDraw - pointer to SPRITE_TO_DRAW struct. Return value: None. --*/ { int x, y, i, l, iTileHeight; LPCBITMAPRLE lpTile; const int sx = PAL_X(gpGlobals->viewport) + PAL_X(lpSpriteToDraw->pos); const int sy = PAL_Y(gpGlobals->viewport) + PAL_Y(lpSpriteToDraw->pos); const int sh = ((sx % 32) ? 1 : 0); const int width = PAL_RLEGetWidth(lpSpriteToDraw->lpSpriteFrame); const int height = PAL_RLEGetHeight(lpSpriteToDraw->lpSpriteFrame); int dx = 0; int dy = 0; int dh = 0; // // Loop through all the tiles in the area of the sprite. // for (y = (sy - height - 15) / 16; y <= sy / 16; y++) { for (x = (sx - width / 2) / 32; x <= (sx + width / 2) / 32; x++) { for (i = ((x == (sx - width / 2) / 32) ? 0 : 3); i < 5; i++) { // // Scan tiles in the following form (* = to scan): // // . . . * * * . . . // . . . * * . . . . // switch (i) { case 0: dx = x; dy = y; dh = sh; break; case 1: dx = x - 1; break; case 2: dx = (sh ? x : (x - 1)); dy = (sh ? (y + 1) : y); dh = 1 - sh; break; case 3: dx = x + 1; dy = y; dh = sh; break; case 4: dx = (sh ? (x + 1) : x); dy = (sh ? (y + 1) : y); dh = 1 - sh; break; } for (l = 0; l < 2; l++) { lpTile = PAL_MapGetTileBitmap(dx, dy, dh, l, PAL_GetCurrentMap()); iTileHeight = (signed char)PAL_MapGetTileHeight(dx, dy, dh, l, PAL_GetCurrentMap()); // // Check if this tile may cover the sprites // if (lpTile != NULL && iTileHeight > 0 && (dy + iTileHeight) * 16 + dh * 8 >= sy) { // // This tile may cover the sprite // PAL_AddSpriteToDraw(lpTile, dx * 32 + dh * 16 - 16 - PAL_X(gpGlobals->viewport), dy * 16 + dh * 8 + 7 + l + iTileHeight * 8 - PAL_Y(gpGlobals->viewport), iTileHeight * 8 + l); } } } } } }
LPBOX PAL_CreateSingleLineBox( PAL_POS pos, INT nLen, BOOL fSaveScreen ) /*++ Purpose: Create a single-line box on the screen. Parameters: [IN] pos - position of the box. [IN] nLen - length of the box. [IN] fSaveScreen - whether save the used screen area or not. Return value: Pointer to a BOX structure. NULL if failed. If fSaveScreen is false, then always returns NULL. --*/ { static const int iNumLeftSprite = 44; static const int iNumMidSprite = 45; static const int iNumRightSprite = 46; LPCBITMAPRLE lpBitmapLeft; LPCBITMAPRLE lpBitmapMid; LPCBITMAPRLE lpBitmapRight; SDL_Surface *save; SDL_Rect rect; LPBOX lpBox = NULL; int i; // // Get the bitmaps // lpBitmapLeft = PAL_SpriteGetFrame(gpSpriteUI, iNumLeftSprite); lpBitmapMid = PAL_SpriteGetFrame(gpSpriteUI, iNumMidSprite); lpBitmapRight = PAL_SpriteGetFrame(gpSpriteUI, iNumRightSprite); rect.x = PAL_X(pos); rect.y = PAL_Y(pos); // // Get the total width and total height of the box // rect.w = PAL_RLEGetWidth(lpBitmapLeft) + PAL_RLEGetWidth(lpBitmapRight); rect.w += PAL_RLEGetWidth(lpBitmapMid) * nLen; rect.h = PAL_RLEGetHeight(lpBitmapLeft); if (fSaveScreen) { // // Save the used part of the screen // save = SDL_CreateRGBSurface(gpScreen->flags, rect.w, rect.h, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (save == NULL) { return NULL; } lpBox = (LPBOX)calloc(1, sizeof(BOX)); if (lpBox == NULL) { SDL_FreeSurface(gpScreen); return NULL; } SDL_BlitSurface(gpScreen, &rect, save, NULL); lpBox->pos = pos; lpBox->lpSavedArea = save; lpBox->wHeight = (WORD)rect.w; lpBox->wWidth = (WORD)rect.h; } // // Draw the box // PAL_RLEBlitToSurface(lpBitmapLeft, gpScreen, pos); rect.x += PAL_RLEGetWidth(lpBitmapLeft); for (i = 0; i < nLen; i++) { PAL_RLEBlitToSurface(lpBitmapMid, gpScreen, PAL_XY(rect.x, rect.y)); rect.x += PAL_RLEGetWidth(lpBitmapMid); } PAL_RLEBlitToSurface(lpBitmapRight, gpScreen, PAL_XY(rect.x, rect.y)); return lpBox; }
LPBOX PAL_CreateBox( PAL_POS pos, INT nRows, INT nColumns, INT iStyle, BOOL fSaveScreen ) /*++ Purpose: Create a box on the screen. Parameters: [IN] pos - position of the box. [IN] nRows - number of rows of the box. [IN] nColumns - number of columns of the box. [IN] iStyle - style of the box (0 or 1). [IN] fSaveScreen - whether save the used screen area or not. Return value: Pointer to a BOX structure. NULL if failed. If fSaveScreen is false, then always returns NULL. --*/ { int i, j, x, m, n; LPCBITMAPRLE rglpBorderBitmap[3][3]; LPBOX lpBox = NULL; SDL_Surface *save; SDL_Rect rect; // // Get the bitmaps // for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { rglpBorderBitmap[i][j] = PAL_SpriteGetFrame(gpSpriteUI, i * 3 + j + iStyle * 9); } } rect.x = PAL_X(pos); rect.y = PAL_Y(pos); rect.w = 0; rect.h = 0; // // Get the total width and total height of the box // for (i = 0; i < 3; i++) { if (i == 1) { rect.w += PAL_RLEGetWidth(rglpBorderBitmap[0][i]) * nColumns; rect.h += PAL_RLEGetHeight(rglpBorderBitmap[i][0]) * nRows; } else { rect.w += PAL_RLEGetWidth(rglpBorderBitmap[0][i]); rect.h += PAL_RLEGetHeight(rglpBorderBitmap[i][0]); } } if (fSaveScreen) { // // Save the used part of the screen // save = SDL_CreateRGBSurface(gpScreen->flags, rect.w, rect.h, 8, gpScreen->format->Rmask, gpScreen->format->Gmask, gpScreen->format->Bmask, gpScreen->format->Amask); if (save == NULL) { return NULL; } lpBox = (LPBOX)calloc(1, sizeof(BOX)); if (lpBox == NULL) { SDL_FreeSurface(save); return NULL; } SDL_BlitSurface(gpScreen, &rect, save, NULL); lpBox->lpSavedArea = save; lpBox->pos = pos; lpBox->wWidth = rect.w; lpBox->wHeight = rect.h; } // // Border takes 2 additional rows and columns... // nRows += 2; nColumns += 2; // // Draw the box // for (i = 0; i < nRows; i++) { x = rect.x; m = (i == 0) ? 0 : ((i == nRows - 1) ? 2 : 1); for (j = 0; j < nColumns; j++) { n = (j == 0) ? 0 : ((j == nColumns - 1) ? 2 : 1); PAL_RLEBlitToSurface(rglpBorderBitmap[m][n], gpScreen, PAL_XY(x, rect.y)); x += PAL_RLEGetWidth(rglpBorderBitmap[m][n]); } rect.y += PAL_RLEGetHeight(rglpBorderBitmap[m][0]); } return lpBox; }
static BOOL PAL_BattleDisplayStatChange( VOID ) /*++ Purpose: Display the HP and MP changes of all players and enemies. Parameters: None. Return value: TRUE if there are any number displayed, FALSE if not. --*/ { int i, x, y; SHORT sDamage; WORD wPlayerRole; BOOL f = FALSE; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } if (g_Battle.rgEnemy[i].wPrevHP != g_Battle.rgEnemy[i].e.wHealth) { // // Show the number of damage // sDamage = g_Battle.rgEnemy[i].e.wHealth - g_Battle.rgEnemy[i].wPrevHP; x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow); } f = TRUE; } } for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; if (g_Battle.rgPlayer[i].wPrevHP != gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole]) { sDamage = gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevHP; x = PAL_X(g_Battle.rgPlayer[i].pos); y = PAL_Y(g_Battle.rgPlayer[i].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)); if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow); } f = TRUE; } if (g_Battle.rgPlayer[i].wPrevMP != gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole]) { sDamage = gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevMP; x = PAL_X(g_Battle.rgPlayer[i].pos); y = PAL_Y(g_Battle.rgPlayer[i].pos) - 62; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)); if (y < 10) { y = 10; } if (sDamage < 0) { PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue); } else { PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorCyan); } f = TRUE; } } return f; }
VOID PAL_BattlePlayerPerformAction( WORD wPlayerIndex ) /*++ Purpose: Perform the selected action for a player. Parameters: [IN] wPlayerIndex - the index of the player. Return value: None. --*/ { // TODO SHORT sDamage; WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole; SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget; int x, y; int i, t; WORD str, def, res, wObject; BOOL fCritical, fPoisoned; PAL_BattlePlayerValidateAction(wPlayerIndex); PAL_BattleBackupStat(); switch (g_Battle.rgPlayer[wPlayerIndex].action.ActionType) { case kBattleActionAttack: if (sTarget != -1) { // // Attack one enemy // if (g_Battle.rgEnemy[sTarget].wObjectID == 0) { sTarget = PAL_BattleSelectAutoTarget(); g_Battle.rgPlayer[wPlayerIndex].action.sTarget = sTarget; } for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[sTarget].e.wDefense; def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[sTarget].e.wAttackResistance; fCritical = FALSE; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (RandomLong(0, 5) == 0) { // // Critical Hit // sDamage *= 3; fCritical = TRUE; } if (wPlayerRole == 0 && RandomLong(0, 11) == 0) { // // Bonus hit for Li Xiaoyao // sDamage *= 2; fCritical = TRUE; } if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[sTarget].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[sTarget].e.wHealth = 0; } if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[sTarget].pos); y = PAL_Y(g_Battle.rgEnemy[sTarget].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); } } else { // // Attack all enemies // for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++) { int division = 1; const int index[MAX_ENEMIES_IN_TEAM] = {2, 1, 0, 4, 3}; fCritical = (RandomLong(0, 5) == 0); if (t == 0) { g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7; PAL_BattleDelay(4, 0); } PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical); for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++) { if (g_Battle.rgEnemy[index[i]].wObjectID == 0 || index[i] > g_Battle.wMaxEnemyIndex) { continue; } str = PAL_GetPlayerAttackStrength(wPlayerRole); def = g_Battle.rgEnemy[index[i]].e.wDefense; def += (g_Battle.rgEnemy[index[i]].e.wLevel + 6) * 4; res = g_Battle.rgEnemy[index[i]].e.wAttackResistance; sDamage = PAL_CalcPhysicalAttackDamage(str, def, res); if (fCritical) { // // Critical Hit // sDamage *= 3; } sDamage /= division; if (sDamage <= 0) { sDamage = 1; } if (g_Battle.rgEnemy[index[i]].e.wHealth > (WORD)sDamage) { g_Battle.rgEnemy[index[i]].e.wHealth -= sDamage; } else { g_Battle.rgEnemy[index[i]].e.wHealth = 0; } // // Show the number of damage // x = PAL_X(g_Battle.rgEnemy[index[i]].pos); y = PAL_Y(g_Battle.rgEnemy[index[i]].pos) - 70; x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; y += PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[index[i]].lpSprite, g_Battle.rgEnemy[index[i]].wCurrentFrame)) / 2; if (y < 10) { y = 10; } PAL_BattleUIShowNum((WORD)sDamage, PAL_XY(x, y), kNumColorBlue); division++; if (division > 3) { division = 3; } } } } PAL_BattleUpdateFighters(); PAL_BattleMakeScene(); PAL_BattleDelay(5, 0); break; case kBattleActionAttackMate: break; case kBattleActionCoopMagic: break; case kBattleActionDefend: g_Battle.rgPlayer[wPlayerIndex].fDefending = TRUE; break; case kBattleActionFlee: break; case kBattleActionMagic: break; case kBattleActionThrowItem: break; case kBattleActionUseItem: wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID; PAL_BattleShowPlayerUseItemAnim(wPlayerIndex, wObject, sTarget); // // Run the script // gpGlobals->g.rgObject[wObject].item.wScriptOnUse = PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].item.wScriptOnUse, (sTarget == -1) ? 0xFFFF : gpGlobals->rgParty[sTarget].wPlayerRole); // // Remove the item if the item is consuming and the script succeeded // if ((gpGlobals->g.rgObject[wObject].item.wFlags & kItemFlagConsuming) && g_fScriptSuccess) { PAL_AddItemToInventory(wObject, -1); } PAL_BattleUpdateFighters(); PAL_BattleDisplayStatChange(); PAL_BattleDelay(8, 0); break; case kBattleActionPass: break; } PAL_BattlePostActionCheck(FALSE); // // Check for poisons // fPoisoned = FALSE; PAL_BattleBackupStat(); for (i = 0; i < MAX_POISONS; i++) { wObject = gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonID; if (wObject != 0) { fPoisoned = TRUE; gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript = PAL_RunTriggerScript(gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript, wPlayerRole); } } if (fPoisoned) { PAL_BattleDelay(3, 0); PAL_BattleUpdateFighters(); if (PAL_BattleDisplayStatChange()) { PAL_BattleDelay(12, 0); } } // // Update statuses // for (i = 0; i < kStatusAll; i++) { if (gpGlobals->rgPlayerStatus[wPlayerRole][i] > 0) { gpGlobals->rgPlayerStatus[wPlayerRole][i]--; } } }
static VOID PAL_BattleShowPlayerAttackAnim( WORD wPlayerIndex, BOOL fCritical ) /*++ Purpose: Show the physical attack effect for player. Parameters: [IN] wPlayerIndex - the index of the player. [IN] fCritical - TRUE if this is a critical hit. Return value: None. --*/ { WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole; SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget; int index, i, j; int enemy_x = 0, enemy_y = 0, enemy_h = 0, x, y, dist = 0; int w, h; DWORD dwTime; if (sTarget != -1) { enemy_x = PAL_X(g_Battle.rgEnemy[sTarget].pos); enemy_y = PAL_Y(g_Battle.rgEnemy[sTarget].pos); enemy_x += PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)) / 2; enemy_h = PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame)); enemy_y += enemy_h; if (sTarget >= 3) { dist = (sTarget - wPlayerIndex) * 8; } } else { enemy_x = 150; enemy_y = 100; } index = gpGlobals->g.rgwBattleEffectIndex[gpGlobals->g.PlayerRoles.rgwSpriteNumInBattle[wPlayerRole]][1]; index *= 3; // // Play the attack voice // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0) { if (!fCritical) { SOUND_Play(gpGlobals->g.PlayerRoles.rgwAttackSound[wPlayerRole]); } else { SOUND_Play(gpGlobals->g.PlayerRoles.rgwCriticalSound[wPlayerRole]); } } // // Show the animation // x = enemy_x - dist + 64; y = enemy_y + dist + 20; g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 8; w = PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[wPlayerIndex].lpSprite, 8)); h = PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[wPlayerIndex].lpSprite, 8)); g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x - w / 2, y - h); PAL_BattleDelay(2, 0); x -= 10; y -= 2; g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x - w / 2, y - h); PAL_BattleDelay(1, 0); g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9; x -= 16; y -= 4; SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]); x = enemy_x; y = enemy_y - enemy_h / 3 + 10; dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME; for (i = 0; i < 3; i++) { LPCBITMAPRLE b = PAL_SpriteGetFrame(g_Battle.lpEffectSprite, index++); // // Clear the input state of previous frame. // PAL_ClearKeyState(); // // 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; // // Update the gesture of enemies. // for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { if (g_Battle.rgEnemy[j].wObjectID == 0) { continue; } if (--g_Battle.rgEnemy[j].e.wIdleAnimSpeed == 0) { g_Battle.rgEnemy[j].wCurrentFrame++; g_Battle.rgEnemy[j].e.wIdleAnimSpeed = gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[j].wObjectID].enemy.wEnemyID].wIdleAnimSpeed; } if (g_Battle.rgEnemy[j].wCurrentFrame >= g_Battle.rgEnemy[j].e.wIdleFrames) { g_Battle.rgEnemy[j].wCurrentFrame = 0; } } PAL_BattleMakeScene(); SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL); PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b))); x -= 16; y += 16; PAL_BattleUIUpdate(); if (i == 0) { if (sTarget == -1) { for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { g_Battle.rgEnemy[j].iColorShift = 6; } } else { g_Battle.rgEnemy[sTarget].iColorShift = 6; } // // Flash the screen if it's a critical hit // if (fCritical) { SDL_FillRect(gpScreen, NULL, 15); } } VIDEO_UpdateScreen(NULL); if (i == 1) { g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) + 2, PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) + 1); } } dist = 8; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { g_Battle.rgEnemy[i].iColorShift = 0; } if (sTarget == -1) { for (i = 0; i < 3; i++) { for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++) { x = PAL_X(g_Battle.rgEnemy[j].pos); y = PAL_Y(g_Battle.rgEnemy[j].pos); x -= dist; y -= dist / 2; g_Battle.rgEnemy[j].pos = PAL_XY(x, y); } PAL_BattleDelay(1, 0); dist /= -2; } } else { x = PAL_X(g_Battle.rgEnemy[sTarget].pos); y = PAL_Y(g_Battle.rgEnemy[sTarget].pos); for (i = 0; i < 3; i++) { x -= dist; dist /= -2; y += dist; g_Battle.rgEnemy[sTarget].pos = PAL_XY(x, y); PAL_BattleDelay(1, 0); } } }
VOID PAL_BattleUIUpdate( VOID ) /*++ Purpose: Update the status of battle UI. Parameters: None. Return value: None. --*/ { int i, j, x, y; WORD wPlayerRole, w; static int s_iFrame = 0; s_iFrame++; if (g_Battle.UI.fAutoAttack && !gpGlobals->fAutoBattle) { // // Draw the "auto attack" message if in the autoattack mode. // if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.fAutoAttack = FALSE; } else { PAL_DrawText(PAL_GetWord(BATTLEUI_LABEL_AUTO), PAL_XY(280, 10), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); } } if (gpGlobals->fAutoBattle) { PAL_BattlePlayerCheckReady(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom) { PAL_BattleUIPlayerReady(i); break; } } if (g_Battle.UI.state != kBattleUIWait) { w = PAL_BattleUIPickAutoMagic(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole, 9999); if (w == 0) { g_Battle.UI.wActionType = kBattleActionAttack; g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } else { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } PAL_BattleCommitAction(FALSE); } goto end; } if (g_InputState.dwKeyPress & kKeyAuto) { g_Battle.UI.fAutoAttack = !g_Battle.UI.fAutoAttack; g_Battle.UI.MenuState = kBattleMenuMain; } #ifdef PAL_CLASSIC if (g_Battle.Phase == kBattlePhasePerformAction) { goto end; } if (!g_Battle.UI.fAutoAttack) #endif { // // Draw the player info boxes. // for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { wPlayerRole = gpGlobals->rgParty[i].wPlayerRole; w = F2int(g_Battle.rgPlayer[i].flTimeMeter); j = TIMEMETER_COLOR_DEFAULT; #ifndef PAL_CLASSIC if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusHaste] > 0) { j = TIMEMETER_COLOR_HASTE; } else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] > 0) { j = TIMEMETER_COLOR_SLOW; } #endif if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] != 0) { w = 0; } PAL_PlayerInfoBox(PAL_XY(91 + 77 * i, 165), wPlayerRole, w, j, FALSE); } } if (g_InputState.dwKeyPress & kKeyStatus) { PAL_PlayerStatus(); goto end; } if (g_Battle.UI.state != kBattleUIWait) { wPlayerRole = gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole; if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 && gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet]) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } PAL_BattleCommitAction(FALSE); goto end; // don't go further } // // Cancel any actions if player is dead or sleeping. // if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] != 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] != 0) { g_Battle.UI.wActionType = kBattleActionPass; PAL_BattleCommitAction(FALSE); goto end; // don't go further } if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] != 0) { g_Battle.UI.wActionType = kBattleActionAttackMate; PAL_BattleCommitAction(FALSE); goto end; // don't go further } if (g_Battle.UI.fAutoAttack) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } PAL_BattleCommitAction(FALSE); goto end; // don't go further } // // Draw the arrow on the player's head. // i = SPRITENUM_BATTLE_ARROW_CURRENTPLAYER_RED; if (s_iFrame & 1) { i = SPRITENUM_BATTLE_ARROW_CURRENTPLAYER; } x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wCurPlayerIndex][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wCurPlayerIndex][1] - 74; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, i), gpScreen, PAL_XY(x, y)); } switch (g_Battle.UI.state) { case kBattleUIWait: if (!g_Battle.fEnemyCleared) { PAL_BattlePlayerCheckReady(); for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].state == kFighterCom) { PAL_BattleUIPlayerReady(i); break; } } } break; case kBattleUISelectMove: // // Draw the icons // { struct { int iSpriteNum; PAL_POS pos; BATTLEUIACTION action; } rgItems[] = { {SPRITENUM_BATTLEICON_ATTACK, PAL_XY(27, 140), kBattleUIActionAttack}, {SPRITENUM_BATTLEICON_MAGIC, PAL_XY(0, 155), kBattleUIActionMagic}, {SPRITENUM_BATTLEICON_COOPMAGIC, PAL_XY(54, 155), kBattleUIActionCoopMagic}, {SPRITENUM_BATTLEICON_MISCMENU, PAL_XY(27, 170), kBattleUIActionMisc} }; if (g_Battle.UI.MenuState == kBattleMenuMain) { if (g_InputState.dir == kDirNorth) { g_Battle.UI.wSelectedAction = 0; } else if (g_InputState.dir == kDirSouth) { g_Battle.UI.wSelectedAction = 3; } else if (g_InputState.dir == kDirWest) { if (PAL_BattleUIIsActionValid(kBattleUIActionMagic)) { g_Battle.UI.wSelectedAction = 1; } } else if (g_InputState.dir == kDirEast) { if (PAL_BattleUIIsActionValid(kBattleUIActionCoopMagic)) { g_Battle.UI.wSelectedAction = 2; } } } if (!PAL_BattleUIIsActionValid(rgItems[g_Battle.UI.wSelectedAction].action)) { g_Battle.UI.wSelectedAction = 0; } for (i = 0; i < 4; i++) { if (g_Battle.UI.wSelectedAction == i) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos); } else if (PAL_BattleUIIsActionValid(rgItems[i].action)) { PAL_RLEBlitMonoColor(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos, 0, -4); } else { PAL_RLEBlitMonoColor(PAL_SpriteGetFrame(gpSpriteUI, rgItems[i].iSpriteNum), gpScreen, rgItems[i].pos, 0x10, -4); } } switch (g_Battle.UI.MenuState) { case kBattleMenuMain: if (g_InputState.dwKeyPress & kKeySearch) { switch (g_Battle.UI.wSelectedAction) { case 0: // // Attack // g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } break; case 1: // // Magic // g_Battle.UI.MenuState = kBattleMenuMagicSelect; PAL_MagicSelectionMenuInit(wPlayerRole, TRUE, 0); break; case 2: // // Cooperative magic // w = gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole; w = PAL_GetPlayerCooperativeMagic(w); g_Battle.UI.wActionType = kBattleActionCoopMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagUsableToEnemy) { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } } else { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetPlayerAll; } else { #ifdef PAL_CLASSIC g_Battle.UI.wSelectedIndex = 0; #else g_Battle.UI.wSelectedIndex = g_Battle.UI.wCurPlayerIndex; #endif g_Battle.UI.state = kBattleUISelectTargetPlayer; } } break; case 3: // // Misc menu // g_Battle.UI.MenuState = kBattleMenuMisc; g_iCurMiscMenuItem = 0; break; } } else if (g_InputState.dwKeyPress & kKeyDefend) { g_Battle.UI.wActionType = kBattleActionDefend; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyForce) { w = PAL_BattleUIPickAutoMagic(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole, 60); if (w == 0) { g_Battle.UI.wActionType = kBattleActionAttack; if (PAL_PlayerCanAttackAll(gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole)) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } else { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.wSelectedIndex = -1; } else { g_Battle.UI.wSelectedIndex = PAL_BattleSelectAutoTarget(); } } PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyFlee) { g_Battle.UI.wActionType = kBattleActionFlee; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & kKeyUseItem) { g_Battle.UI.MenuState = kBattleMenuUseItemSelect; PAL_ItemSelectMenuInit(kItemFlagUsable); } else if (g_InputState.dwKeyPress & kKeyThrowItem) { g_Battle.UI.MenuState = kBattleMenuThrowItemSelect; PAL_ItemSelectMenuInit(kItemFlagThrowable); } else if (g_InputState.dwKeyPress & kKeyRepeat) { PAL_BattleCommitAction(TRUE); } #ifdef PAL_CLASSIC else if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].state = kFighterWait; g_Battle.UI.state = kBattleUIWait; if (g_Battle.UI.wCurPlayerIndex > 0) { // // Revert to the previous player // do { g_Battle.rgPlayer[--g_Battle.UI.wCurPlayerIndex].state = kFighterWait; if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType == kBattleActionThrowItem) { for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID) { gpGlobals->rgInventory[i].nAmountInUse--; break; } } } else if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType == kBattleActionUseItem) { if (gpGlobals->g.rgObject[g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID].item.wFlags & kItemFlagConsuming) { for (i = 0; i < MAX_INVENTORY; i++) { if (gpGlobals->rgInventory[i].wItem == g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID) { gpGlobals->rgInventory[i].nAmountInUse--; break; } } } } } while (g_Battle.UI.wCurPlayerIndex > 0 && (gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole] == 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusConfused] > 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusSleep] > 0 || gpGlobals->rgPlayerStatus[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole][kStatusParalyzed] > 0)); } } #else else if (g_InputState.dwKeyPress & kKeyMenu) { FLOAT flMin = int2F(-1); j = -1; for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.rgPlayer[i].flTimeMeter >= 100) { g_Battle.rgPlayer[i].flTimeMeter += 100; // HACKHACK: Prevent the time meter from going below 100 if ((g_Battle.rgPlayer[i].flTimeMeter < flMin || flMin < 0) && i != (int)g_Battle.UI.wCurPlayerIndex && g_Battle.rgPlayer[i].state == kFighterWait) { flMin = g_Battle.rgPlayer[i].flTimeMeter; j = i; } } } if (j != -1) { g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].flTimeMeter = flMin - int2F(99); g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].state = kFighterWait; g_Battle.UI.state = kBattleUIWait; } } #endif break; case kBattleMenuMagicSelect: w = PAL_MagicSelectionMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; if (w != 0) { g_Battle.UI.wActionType = kBattleActionMagic; g_Battle.UI.wObjectID = w; if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagUsableToEnemy) { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetEnemyAll; } else { g_Battle.UI.wSelectedIndex = g_Battle.UI.wPrevEnemyTarget; g_Battle.UI.state = kBattleUISelectTargetEnemy; } } else { if (gpGlobals->g.rgObject[w].magic.wFlags & kMagicFlagApplyToAll) { g_Battle.UI.state = kBattleUISelectTargetPlayerAll; } else { #ifdef PAL_CLASSIC g_Battle.UI.wSelectedIndex = 0; #else g_Battle.UI.wSelectedIndex = g_Battle.UI.wCurPlayerIndex; #endif g_Battle.UI.state = kBattleUISelectTargetPlayer; } } } } break; case kBattleMenuUseItemSelect: PAL_BattleUIUseItem(); break; case kBattleMenuThrowItemSelect: PAL_BattleUIThrowItem(); break; case kBattleMenuMisc: w = PAL_BattleUIMiscMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; switch (w) { #ifdef PAL_CLASSIC case 2: // item #else case 1: // item #endif g_Battle.UI.MenuState = kBattleMenuMiscItemSubMenu; g_iCurSubMenuItem = 0; break; #ifdef PAL_CLASSIC case 3: // defend #else case 2: // defend #endif g_Battle.UI.wActionType = kBattleActionDefend; PAL_BattleCommitAction(FALSE); break; #ifdef PAL_CLASSIC case 1: // auto #else case 3: // auto #endif g_Battle.UI.fAutoAttack = TRUE; break; case 4: // flee g_Battle.UI.wActionType = kBattleActionFlee; PAL_BattleCommitAction(FALSE); break; case 5: // status PAL_PlayerStatus(); break; } } break; case kBattleMenuMiscItemSubMenu: w = PAL_BattleUIMiscItemSubMenuUpdate(); if (w != 0xFFFF) { g_Battle.UI.MenuState = kBattleMenuMain; switch (w) { case 1: // use g_Battle.UI.MenuState = kBattleMenuUseItemSelect; PAL_ItemSelectMenuInit(kItemFlagUsable); break; case 2: // throw g_Battle.UI.MenuState = kBattleMenuThrowItemSelect; PAL_ItemSelectMenuInit(kItemFlagThrowable); break; } } break; } } break; case kBattleUISelectTargetEnemy: x = -1; y = 0; for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++) { if (g_Battle.rgEnemy[i].wObjectID != 0) { x = i; y++; } } if (x == -1) { g_Battle.UI.state = kBattleUISelectMove; break; } if (g_Battle.UI.wActionType == kBattleActionCoopMagic) { if (!PAL_BattleUIIsActionValid(kBattleActionCoopMagic)) { g_Battle.UI.state = kBattleUISelectMove; break; } } #ifdef PAL_CLASSIC // // Don't bother selecting when only 1 enemy left // if (y == 1) { g_Battle.UI.wPrevEnemyTarget = (WORD)x; PAL_BattleCommitAction(FALSE); break; } #endif if (g_Battle.UI.wSelectedIndex > x) { g_Battle.UI.wSelectedIndex = x; } for (i = 0; i <= x; i++) { if (g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID != 0) { break; } g_Battle.UI.wSelectedIndex++; g_Battle.UI.wSelectedIndex %= x + 1; } // // Highlight the selected enemy // if (s_iFrame & 1) { i = g_Battle.UI.wSelectedIndex; x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos); x -= PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y -= PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)); PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), gpScreen, PAL_XY(x, y), 7); } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wPrevEnemyTarget = g_Battle.UI.wSelectedIndex; PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyDown)) { if (g_Battle.UI.wSelectedIndex != 0) { g_Battle.UI.wSelectedIndex--; while (g_Battle.UI.wSelectedIndex != 0 && g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID == 0) { g_Battle.UI.wSelectedIndex--; } } } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyUp)) { if (g_Battle.UI.wSelectedIndex < x) { g_Battle.UI.wSelectedIndex++; while (g_Battle.UI.wSelectedIndex < x && g_Battle.rgEnemy[g_Battle.UI.wSelectedIndex].wObjectID == 0) { g_Battle.UI.wSelectedIndex++; } } } break; case kBattleUISelectTargetPlayer: #ifdef PAL_CLASSIC // // Don't bother selecting when only 1 player is in the party // if (gpGlobals->wMaxPartyMemberIndex == 0) { g_Battle.UI.wSelectedIndex = 0; PAL_BattleCommitAction(FALSE); } #endif j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER; if (s_iFrame & 1) { j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER_RED; } // // Draw arrows on the selected player // x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wSelectedIndex][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][g_Battle.UI.wSelectedIndex][1] - 67; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, j), gpScreen, PAL_XY(x, y)); if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { PAL_BattleCommitAction(FALSE); } else if (g_InputState.dwKeyPress & (kKeyLeft | kKeyDown)) { if (g_Battle.UI.wSelectedIndex != 0) { g_Battle.UI.wSelectedIndex--; } else { g_Battle.UI.wSelectedIndex = gpGlobals->wMaxPartyMemberIndex; } } else if (g_InputState.dwKeyPress & (kKeyRight | kKeyUp)) { if (g_Battle.UI.wSelectedIndex < gpGlobals->wMaxPartyMemberIndex) { g_Battle.UI.wSelectedIndex++; } else { g_Battle.UI.wSelectedIndex = 0; } } break; case kBattleUISelectTargetEnemyAll: #ifdef PAL_CLASSIC // // Don't bother selecting // g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); #else if (g_Battle.UI.wActionType == kBattleActionCoopMagic) { if (!PAL_BattleUIIsActionValid(kBattleActionCoopMagic)) { g_Battle.UI.state = kBattleUISelectMove; break; } } if (s_iFrame & 1) { // // Highlight all enemies // for (i = g_Battle.wMaxEnemyIndex; i >= 0; i--) { if (g_Battle.rgEnemy[i].wObjectID == 0) { continue; } x = PAL_X(g_Battle.rgEnemy[i].pos); y = PAL_Y(g_Battle.rgEnemy[i].pos); x -= PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2; y -= PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)); PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), gpScreen, PAL_XY(x, y), 7); } } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); } #endif break; case kBattleUISelectTargetPlayerAll: #ifdef PAL_CLASSIC // // Don't bother selecting // g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); #else j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER; if (s_iFrame & 1) { j = SPRITENUM_BATTLE_ARROW_SELECTEDPLAYER_RED; } for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++) { if (g_Battle.UI.wActionType == kBattleActionMagic) { w = gpGlobals->g.rgObject[g_Battle.UI.wObjectID].magic.wMagicNumber; if (gpGlobals->g.lprgMagic[w].wType == kMagicTypeTrance) { if (i != g_Battle.UI.wCurPlayerIndex) continue; } } // // Draw arrows on all players, despite of dead or not // x = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][0] - 8; y = g_rgPlayerPos[gpGlobals->wMaxPartyMemberIndex][i][1] - 67; PAL_RLEBlitToSurface(PAL_SpriteGetFrame(gpSpriteUI, j), gpScreen, PAL_XY(x, y)); } if (g_InputState.dwKeyPress & kKeyMenu) { g_Battle.UI.state = kBattleUISelectMove; } else if (g_InputState.dwKeyPress & kKeySearch) { g_Battle.UI.wSelectedIndex = (WORD)-1; PAL_BattleCommitAction(FALSE); } #endif break; } end: // // Show the text message if there is one. // #ifndef PAL_CLASSIC if (SDL_GetTicks() < g_Battle.UI.dwMsgShowTime) { // // The text should be shown in a small window at the center of the screen // PAL_POS pos; int len = strlen(g_Battle.UI.szMsg); // // Create the window box // pos = PAL_XY(160 - len * 4, 40); PAL_CreateSingleLineBox(pos, (len + 1) / 2, FALSE); // // Show the text on the screen // pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10); PAL_DrawText(g_Battle.UI.szMsg, pos, 0, FALSE, FALSE); } else if (g_Battle.UI.szNextMsg[0] != '\0') { strcpy(g_Battle.UI.szMsg, g_Battle.UI.szNextMsg); g_Battle.UI.dwMsgShowTime = SDL_GetTicks() + g_Battle.UI.wNextMsgDuration; g_Battle.UI.szNextMsg[0] = '\0'; } #endif // // Draw the numbers // for (i = 0; i < BATTLEUI_MAX_SHOWNUM; i++) { if (g_Battle.UI.rgShowNum[i].wNum > 0) { if ((SDL_GetTicks() - g_Battle.UI.rgShowNum[i].dwTime) / BATTLE_FRAME_TIME > 10) { g_Battle.UI.rgShowNum[i].wNum = 0; } else { PAL_DrawNumber(g_Battle.UI.rgShowNum[i].wNum, 5, PAL_XY(PAL_X(g_Battle.UI.rgShowNum[i].pos), PAL_Y(g_Battle.UI.rgShowNum[i].pos) - (SDL_GetTicks() - g_Battle.UI.rgShowNum[i].dwTime) / BATTLE_FRAME_TIME), g_Battle.UI.rgShowNum[i].color, kNumAlignRight); } } } PAL_ClearKeyState(); }
VOID PAL_BattleMakeScene( VOID ) /*++ Purpose: Generate the battle scene into the scene buffer. Parameters: None. Return value: None. --*/ { int i; PAL_POS pos; LPBYTE pSrc, pDst; //BYTE b; // // Draw the background // pSrc = g_Battle.lpBackground->pixels; pDst = g_Battle.lpSceneBuf->pixels; // optimized by ZBY ZBY_TIMING_BEGIN(2); make_colorshift_table(g_Battle.sBackgroundColorShift); if (0) { //if (g_Battle.sBackgroundColorShift == 0) { memcpy(pDst, pSrc, g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h); } else { i = g_Battle.lpSceneBuf->pitch * g_Battle.lpSceneBuf->h; while (i--) { /*b = (*pSrc & 0x0F); b += g_Battle.sBackgroundColorShift; if (b & 0x80) { b = 0; } else if (b & 0x70) { b = 0x0F; } *pDst = (b | (*pSrc & 0xF0)); assert(*pDst == cs_table[*pSrc]); */ *pDst = cs_table[*pSrc]; ++pSrc; ++pDst; } } ZBY_TIMING_END(2, "PAL_BattleMakeScene"); 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); } } } } }