/* 在屏幕上创建一个新的字母 */ void create_new_letter(void) { if (head == NULL) { head = fly_new(); /* 当前没有任何字母,创建新链表 */ } else { fly_t now = fly_new(); fly_insert(NULL, head, now); /* 插入到链表的头部 */ head = now; } /* 字母、初始位置、掉落速度均为随机设定 */ head->x = 0; head->y = rand() % (SCR_WIDTH / 8 - 2) * 8 + 8; head->v = F_div_F(int2F(rand() % 1000), int2F(2000)) + f2F(0.5); head->text = rand() % 26; release_key(head->text); /* 清除过往的按键 */ }
FLOAT sqrt(FLOAT x) { FLOAT dt, t = int2F(2); do { dt = F_div_int((F_div_F(x, t) - t), 2); t += dt; } while(Fabs(dt) > f2F(1e-4)); return t; }
FLOAT f(FLOAT x) { return F_div_F(int2F(1),int2F(1) + F_mul_int(F_mul_F(x,x),25)); /* f(x) = 1/(1+25x^2) */ /* FLOAT a = int2F(1); FLOAT b = F_mul_F(x,x); FLOAT c = F_mul_int(b ,25); FLOAT d = int2F(1) + c;*/ // nemu_assert(x == f2F(0.8)); // nemu_assert(b < f2F(0)); /* a ++ ; a -- ; b ++ ; b -- ; c ++ ; c -- ; d ++ ; d -- ; return F_div_F(a,d);*/ }
FLOAT pow(FLOAT x, FLOAT y) { /* we only compute x^0.333 */ FLOAT t2, dt, t = int2F(2); do { t2 = F_mul_F(t, t); dt = (F_div_F(x, t2) - t) / 3; t += dt; } while(Fabs(dt) > f2F(1e-4)); return t; }
/* 更新按键 */ bool update_keypress(void) { fly_t it, target = NULL; FLOAT min = -int2F(100); cli(); /* 寻找相应键已被按下、最底部且未被击中的字符 */ for (it = head; it != NULL; it = it->_next) { assert(it->text >= 0 && it->text < 26); if (it->v > 0 && it->x > min && query_key(it->text)) { min = it->x; target = it; } } /* 如果找到则更新相应数据 */ if (target != NULL) { release_key(target->text); target->v = -int2F(3); /* 速度改为向上 */ return true; } sti(); return false; }
/* 逻辑时钟前进1单位 */ void update_letter_pos(void) { fly_t it; for (it = head; it != NULL; ) { fly_t next = it->_next; it->x += it->v; /* 根据速度更新位置 */ if (it->x < 0 || it->x + f2F(7.9) > int2F(SCR_HEIGHT)) { if (it->x < 0) hit ++; /* 从上部飞出屏幕 */ else miss ++; /* 从下部飞出屏幕 */ fly_remove(it); fly_free(it); if (it == head) head = next; /* 更新链表 */ } it = next; } }
int main(){ /* for(c=-(0x8000);c<0x8000;++c){ nemu_assert(c==(F2int(int2F(c)))); } set_bp(); f = 2.0; unsigned int u = *(unsigned int *)&f; nemu_assert(u>0); set_bp(); */ a = f2F(20000.0); nemu_assert((int2F(20000)-a)<5); set_bp(); b = F2int(a); nemu_assert(2==b); HIT_GOOD_TRAP; return 0; }
FLOAT f(FLOAT x) { /* f(x) = 1/(1+25x^2) */ return F_div_F(int2F(1), int2F(1) + F_mul_int(F_mul_F(x, x), 25)); }
BATTLERESULT PAL_StartBattle( WORD wEnemyTeam, BOOL fIsBoss ) /*++ Purpose: 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. --*/ { 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; #ifndef PAL_CLASSIC g_Battle.rgEnemy[i].flTimeMeter = int2F(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 = int2F(15); #ifndef PAL_CLASSIC g_Battle.rgPlayer[i].flTimeSpeedModifier = int2F(2); 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 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(); }