Mercurial > mm7
view Engine/Party.cpp @ 2541:a902abdfc7f2
1. Renamed class Game to class Engine.
2. Separated game logic as state of FSM from game logic as engine.
3. Found out that many UI screen initializers were optimized away, intially
they all returned newly created window as separate object like it is done
in CharacterUI_Initialize.
author | a.parshin |
---|---|
date | Sun, 10 May 2015 01:29:11 +0200 |
parents | 1bcadc6dd203 |
children | bacf9809126a |
line wrap: on
line source
#define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #define _CRT_SECURE_NO_WARNINGS #include "Engine/Engine.h" #include "Party.h" #include "Timer.h" #include "Media/Audio/AudioPlayer.h" #include "Engine/Tables/IconFrameTable.h" #include "IO/Mouse.h" #include "Engine/Tables/PlayerFrameTable.h" #include "Engine/TurnEngine/TurnEngine.h" #include "Engine/Graphics/Viewport.h" #include "Engine/Objects/Actor.h" #include "GUI/GUIWindow.h" #include "texts.h" #include "Engine/Graphics/Outdoor.h" #include "LOD.h" #include "Engine/Objects/SpriteObject.h" #include "Engine/Objects/ObjectList.h" Party *pParty = nullptr; struct ActionQueue *pPartyActionQueue = new ActionQueue; std::array<bool, 4> playerAlreadyPicked; // byte_AE3368_ char PickedPlayer2_unused; // byte_AE3369_ char PickedPlayer3_unused; // byte_AE336A_ char PickedPlayer4_unused; // byte_AE336B_ //----- (0044A56A) -------------------------------------------------------- void Party::CountHirelings() { field_70A = 0; for (unsigned int i = 0; i < pNPCStats->uNumNewNPCs; ++i) { NPCData* npc = &pNPCStats->pNewNPCData[i]; if (npc->Hired() && (!pHirelings[0].pName || strcmp(npc->pName, pHirelings[0].pName))) { if (!pHirelings[1].pName || strcmp(npc->pName, pHirelings[1].pName)) ++field_70A; } } } // inlined //----- (mm6c::004858D0) -------------------------------------------------- void Party::Zero() { uFlags2 = 0; uNumGoldInBank = 0; uCurrentYear = 0; uCurrentMonth = 0; uCurrentMonthWeek = 0; uDaysPlayed = 0; uCurrentHour = 0; uCurrentMinute = 0; uCurrentTimeSecond = 0; field_6FC = 0; days_played_without_rest = 0; vPosition.x = 0; vPosition.y = 0; vPosition.z = 0; uFallStartY = 0; sRotationY = 0; sRotationX = 0; uFallSpeed = 0; field_28 = 0; uDefaultPartyHeight = 192; field_14_radius = 37; y_rotation_granularity = 25; y_rotation_speed = 90; uWalkSpeed = 384; walk_sound_timer = 0; field_24 = 5; field_6FC = 0; field_708 = 15; field_0 = 25; uNumDeaths = 0; uNumPrisonTerms = 0; uNumBountiesCollected = 0; monster_for_hunting_killed.fill(0); monster_id_for_hunting.fill(0); memset(_quest_bits, 0, sizeof(_quest_bits)); pArcomageWins.fill(0); uNumArenaPageWins = 0; uNumArenaSquireWins = 0; uNumArenaKnightWins = 0; uNumArenaLordWins = 0; } //inlined //----- (mm6c::0045BE90) -------------------------------------------------- void ActionQueue::Reset() { uNumActions = 0; } //----- (004760C1) -------------------------------------------------------- void ActionQueue::Add(PartyAction action) { if (uNumActions < 30) pActions[uNumActions++] = action; } //----- (00497FC5) -------------------------------------------------------- bool Party::_497FC5_check_party_perception_against_level() { int uMaxPerception; // edi@1 signed int v5; // eax@3 bool result; // eax@7 uMaxPerception = 0; for (int i = 0; i < 4; i++) { if ( this->pPlayers[i].CanAct() ) { v5 = this->pPlayers[i].GetPerception(); if ( v5 > uMaxPerception ) uMaxPerception = v5; } } if ( uLevelMapStatsID && (signed int)uLevelMapStatsID < 77 ) result = uMaxPerception >= 2 * pMapStats->pInfos[uLevelMapStatsID]._per; else result = 0; return result; } //----- (004936E1) -------------------------------------------------------- void Party::SetHoldingItem(ItemGen *pItem) { sub_421B2C_PlaceInInventory_or_DropPickedItem(); memcpy(&pPickedItem, pItem, sizeof(pPickedItem)); pMouse->SetCursorBitmapFromItemID(pPickedItem.uItemID); } //----- (0049370F) -------------------------------------------------------- int Party::GetNextActiveCharacter() { int v2; // eax@4 signed int v8; // esi@23 int v12; // [sp+Ch] [bp-4h]@1 v12 = 0; if ( pParty->bTurnBasedModeOn == 1 ) { if ( pTurnEngine->turn_stage != TE_ATTACK || PID_TYPE(pTurnEngine->pQueue[0].uPackedID) != OBJECT_Player) return 0; v2 = PID_ID(pTurnEngine->pQueue[0].uPackedID); return v2 + 1; } if ( playerAlreadyPicked[0] && playerAlreadyPicked[1] && playerAlreadyPicked[2] && playerAlreadyPicked[3] ) playerAlreadyPicked.fill(false); for (int i = 0; i < 4; i++) { if ( !this->pPlayers[i].CanAct() || this->pPlayers[i].uTimeToRecovery > 0) playerAlreadyPicked[i] = true; else if ( !playerAlreadyPicked[i] ) { playerAlreadyPicked[i] = true; if (i > 0) //TODO check if this condition really should be here. it is equal to the original source but still seems kind of weird return i + 1; break; } } for (int i = 0; i < 4; i++) { if ( this->pPlayers[i].CanAct() && this->pPlayers[i].uTimeToRecovery == 0 ) { if ( v12 == 0 || this->pPlayers[i].uSpeedBonus > v8 ) { v8 = this->pPlayers[i].uSpeedBonus; v12 = i + 1; } } } return v12; } //----- (00493244) -------------------------------------------------------- bool Party::HasItem(unsigned int uItemID) { for (int player = 0; player < 4; player++) { for (int itemPos = 0; itemPos < 138; itemPos++) { if (pParty->pPlayers[player].pOwnItems[itemPos].uItemID == uItemID) return true; } } return false; } //----- (00492AD5) -------------------------------------------------------- void Party::SetFood(unsigned int uNumFood) { pUIAnim_Food->uAnimTime = 0; pParty->uNumFoodRations = uNumFood; pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[pUIAnim_Food->uIconID].uAnimLength; } //----- (00492B03) -------------------------------------------------------- void Party::TakeFood(unsigned int uNumFood) { if (pParty->uNumFoodRations <= uNumFood) pParty->uNumFoodRations = 0; else pParty->uNumFoodRations -= uNumFood; pUIAnim_Food->uAnimTime = 0; pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[pUIAnim_Food->uIconID].uAnimLength; } //----- (00492B42) -------------------------------------------------------- void Party::GiveFood(unsigned int _this) { pParty->uNumFoodRations += _this; pUIAnim_Food->uAnimTime = 0; pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[pUIAnim_Food->uIconID].uAnimLength; } //----- (00492B70) -------------------------------------------------------- void Party::SetGold(unsigned int uNumGold) { pParty->uNumGold = uNumGold; pUIAnim_Gold->uAnimTime = 0; pUIAnim_Gold->uAnimLength = 8 * pIconsFrameTable->pIcons[pUIAnim_Gold->uIconID].uAnimLength; pAudioPlayer->PlaySound(SOUND_gold01, 0, 0, -1, 0, 0, 0, 0); } //----- (00492BB6) -------------------------------------------------------- void Party::TakeGold(unsigned int uNumGold) { if ( uNumGold <= pParty->uNumGold ) pParty->uNumGold -= uNumGold; else pParty->uNumGold = 0; pUIAnim_Gold->uAnimTime = 0; pUIAnim_Gold->uAnimLength = 8 * pIconsFrameTable->pIcons[pUIAnim_Gold->uIconID].uAnimLength; pAudioPlayer->PlaySound(SOUND_gold01, 0, 0, -1, 0, 0, 0, 0); } //----- (0049135E) -------------------------------------------------------- unsigned int Party::GetPartyFame() { unsigned __int64 total_exp = 0; for (uint i = 0; i < 4; ++i) total_exp += pPlayers[i].uExperience; return (unsigned int)(min(total_exp / 1000, UINT_MAX)); //min wasn't present, but could be incorrect without it } //----- (0049137D) -------------------------------------------------------- void Party::CreateDefaultParty(char bGiveItems) { Player *pCharacter; // esi@3 int uSkillIdx; // eax@11 unsigned int v16; // [sp-4h] [bp-44h]@26 signed int uNumPlayers; // [sp+18h] [bp-28h]@1 ItemGen Dst; // [sp+1Ch] [bp-24h]@10 pHireling1Name[0] = 0; pHireling2Name[0] = 0; this->hirelingScrollPosition = 0; memset(&pHirelings, 0, sizeof(pHirelings)); strcpy(this->pPlayers[0].pName, pGlobalTXT_LocalizationStrings[509]); //Zoltan this->pPlayers[0].uPrevFace = 17; this->pPlayers[0].uCurrentFace = 17; this->pPlayers[0].uPrevVoiceID = 17; this->pPlayers[0].uVoiceID = 17; this->pPlayers[0].uMight = 30; this->pPlayers[0].uIntelligence = 5; this->pPlayers[0].uWillpower = 5; this->pPlayers[0].uEndurance = 13; this->pPlayers[0].uAccuracy = 13; this->pPlayers[0].uSpeed = 14; this->pPlayers[0].uLuck = 7; this->pPlayers[0].pActiveSkills[PLAYER_SKILL_LEATHER] = 1; // leather this->pPlayers[0].pActiveSkills[PLAYER_SKILL_ARMSMASTER] = 1; // armsmaster this->pPlayers[0].pActiveSkills[PLAYER_SKILL_BOW] = 1; // bow this->pPlayers[0].pActiveSkills[PLAYER_SKILL_SWORD] = 1; // sword this->pPlayers[1].uPrevFace = 3; this->pPlayers[1].uCurrentFace = 3; this->pPlayers[1].uPrevVoiceID = 3; this->pPlayers[1].uVoiceID = 3; strcpy(this->pPlayers[1].pName, pGlobalTXT_LocalizationStrings[506]); //Roderic this->pPlayers[1].uMight = 13; this->pPlayers[1].uIntelligence = 9; this->pPlayers[1].uWillpower = 9; this->pPlayers[1].uEndurance = 13; this->pPlayers[1].uAccuracy = 13; this->pPlayers[1].uSpeed = 13; this->pPlayers[1].uLuck = 13; this->pPlayers[1].pActiveSkills[PLAYER_SKILL_LEATHER] = 1; // leather this->pPlayers[1].pActiveSkills[PLAYER_SKILL_STEALING] = 1; // stealing this->pPlayers[1].pActiveSkills[PLAYER_SKILL_DAGGER] = 1; // dagger this->pPlayers[1].pActiveSkills[PLAYER_SKILL_TRAP_DISARM] = 1; // disarm trap this->pPlayers[2].uPrevFace = 14; this->pPlayers[2].uCurrentFace = 14; this->pPlayers[2].uPrevVoiceID = 14; this->pPlayers[2].uVoiceID = 14; strcpy(this->pPlayers[2].pName, pGlobalTXT_LocalizationStrings[508]); // Serena this->pPlayers[2].uMight = 12; this->pPlayers[2].uIntelligence = 9; this->pPlayers[2].uWillpower = 20; this->pPlayers[2].uEndurance = 22; this->pPlayers[2].uAccuracy = 7; this->pPlayers[2].uSpeed = 13; this->pPlayers[2].uLuck = 7; this->pPlayers[2].pActiveSkills[PLAYER_SKILL_ALCHEMY] = 1; // alchemy this->pPlayers[2].pActiveSkills[PLAYER_SKILL_LEATHER] = 1; // leather this->pPlayers[2].pActiveSkills[PLAYER_SKILL_BODY] = 1; // body this->pPlayers[2].pActiveSkills[PLAYER_SKILL_MACE] = 1; // mace strcpy(this->pPlayers[3].pName, pGlobalTXT_LocalizationStrings[507]); // Alexis this->pPlayers[3].uPrevFace = 10; this->pPlayers[3].uCurrentFace = 10; this->pPlayers[3].uEndurance = 13; this->pPlayers[3].uAccuracy = 13; this->pPlayers[3].uSpeed = 13; this->pPlayers[3].uPrevVoiceID = 10; this->pPlayers[3].uVoiceID = 10; this->pPlayers[3].uMight = 5; this->pPlayers[3].uIntelligence = 30; this->pPlayers[3].uWillpower = 9; this->pPlayers[3].uLuck = 7; this->pPlayers[3].pActiveSkills[PLAYER_SKILL_LEATHER] = 1; // leather this->pPlayers[3].pActiveSkills[PLAYER_SKILL_AIR] = 1; // air this->pPlayers[3].pActiveSkills[PLAYER_SKILL_FIRE] = 1; // fire this->pPlayers[3].pActiveSkills[PLAYER_SKILL_STAFF] = 1; // staff for (uNumPlayers = 0; uNumPlayers < 4; uNumPlayers++) { pCharacter = &pParty->pPlayers[uNumPlayers]; if (pCharacter->classType == PLAYER_CLASS_KNIGHT) pCharacter->sResMagicBase = 10; //player[i].pResMagicBase pCharacter->lastOpenedSpellbookPage = 0; for (int i = 0; i < 9; i++)//for Magic Book { if (pPlayers[uNumPlayers].pActiveSkills[12+i]) { pCharacter->lastOpenedSpellbookPage = i; break; } } pCharacter->uExpressionTimePassed = 0; Dst.Reset(); if ( bGiveItems ) { pItemsTable->GenerateItem(2, 40, &Dst); //ring pCharacter->AddItem2(-1, &Dst); for (uSkillIdx = 0; uSkillIdx < 36; uSkillIdx++) { if ( pCharacter->pActiveSkills[uSkillIdx] ) { switch ( uSkillIdx ) { case PLAYER_SKILL_STAFF: pCharacter->WearItem(ITEM_STAFF_1); break; case PLAYER_SKILL_SWORD: pCharacter->WearItem(ITEM_LONGSWORD_1); break; case PLAYER_SKILL_DAGGER: pCharacter->WearItem(ITEM_DAGGER_1); break; case PLAYER_SKILL_AXE: pCharacter->WearItem(ITEM_AXE_1); break; case PLAYER_SKILL_SPEAR: pCharacter->WearItem(ITEM_SPEAR_1); break; case PLAYER_SKILL_BOW: pCharacter->WearItem(ITEM_CROSSBOW_1); break; case PLAYER_SKILL_MACE: pCharacter->WearItem(ITEM_MACE_1); break; case PLAYER_SKILL_SHIELD: pCharacter->WearItem(ITEM_BUCKLER_1); break; case PLAYER_SKILL_LEATHER: pCharacter->WearItem(ITEM_LEATHER_1); break; case PLAYER_SKILL_CHAIN: pCharacter->WearItem(ITEM_CHAINMAIL_1); break; case PLAYER_SKILL_PLATE: pCharacter->WearItem(ITEM_PLATE_1); break; case PLAYER_SKILL_FIRE: pCharacter->AddItem(-1, ITEM_SPELLBOOK_FIRE_STRIKE); break; case PLAYER_SKILL_AIR: pCharacter->AddItem(-1, ITEM_SPELLBOOK_AIR_FEATHER_FALL); break; case PLAYER_SKILL_WATER: pCharacter->AddItem(-1, ITEM_SPELLBOOK_WATER_POISON_SPRAY); break; case PLAYER_SKILL_EARTH: pCharacter->AddItem(-1, ITEM_SPELLBOOK_EARTH_SLOW); break; case PLAYER_SKILL_SPIRIT: pCharacter->AddItem(-1, ITEM_SPELLBOOK_SPIRIT_BLESS); break; case PLAYER_SKILL_MIND: pCharacter->AddItem(-1, ITEM_SPELLBOOK_MIND_MIND_BLAST); break; case PLAYER_SKILL_BODY: pCharacter->AddItem(-1, ITEM_SPELLBOOK_BODY_FIRST_AID); break; case PLAYER_SKILL_ITEM_ID: case PLAYER_SKILL_REPAIR: case PLAYER_SKILL_MEDITATION: case PLAYER_SKILL_PERCEPTION: case PLAYER_SKILL_DIPLOMACY: case PLAYER_SKILL_TRAP_DISARM: case PLAYER_SKILL_LEARNING: pCharacter->AddItem(-1, ITEM_POTION_BOTTLE); v16 = 5 * (rand() % 3 + 40); // simple reagent pCharacter->AddItem(-1, v16); break; case PLAYER_SKILL_DODGE: pCharacter->AddItem(-1, ITEM_BOOTS_1); break; case PLAYER_SKILL_UNARMED: pCharacter->AddItem(-1, ITEM_GAUNTLETS_1); break; default: break; } } } for (int i = 0; i < 138; i++) { if ( pCharacter->pInventoryItemList[i].uItemID != 0) pCharacter->pInventoryItemList[i].SetIdentified(); } } pCharacter->sHealth = pCharacter->GetMaxHealth(); pCharacter->sMana = pCharacter->GetMaxMana(); } } //----- (004917CE) -------------------------------------------------------- int Party::Reset() { Zero(); field_708 = 15; sEyelevel = 160; uNumGold = 200; uNumFoodRations = 7; alignment = PartyAlignment_Neutral; SetUserInterface(alignment, true); uTimePlayed = 0x21C00u; uLastRegenerationTime = 0x21C00; bTurnBasedModeOn = false; uActiveCharacter = 1; ::pPlayers.ZerothIndex() = &pPlayers[0]; for (uint i = 0; i < 4; ++i) ::pPlayers[i + 1] = &pPlayers[i]; pPlayers[0].Reset(PLAYER_CLASS_KNIGHT); pPlayers[1].Reset(PLAYER_CLASS_THEIF); pPlayers[2].Reset(PLAYER_CLASS_CLERIC); pPlayers[3].Reset(PLAYER_CLASS_SORCERER); pPlayers[0].uCurrentFace = 17; pPlayers[0].uPrevVoiceID = 17; pPlayers[0].uVoiceID = 17; pPlayers[0].SetInitialStats(); pPlayers[0].uSex = pPlayers[0].GetSexByVoice(); pPlayers[0].RandomizeName(); strcpy(pPlayers[0].pName, pGlobalTXT_LocalizationStrings[509]); pPlayers[1].uCurrentFace = 3; pPlayers[1].uPrevVoiceID = 3; pPlayers[1].uVoiceID = 3; pPlayers[1].SetInitialStats(); pPlayers[1].uSex = pPlayers[1].GetSexByVoice(); pPlayers[1].RandomizeName(); strcpy(pPlayers[1].pName, pGlobalTXT_LocalizationStrings[506]); pPlayers[2].uCurrentFace = 14; pPlayers[2].uPrevVoiceID = 14; pPlayers[2].uVoiceID = 14; pPlayers[2].SetInitialStats(); pPlayers[2].uSex = pPlayers[3].GetSexByVoice(); pPlayers[2].RandomizeName(); strcpy(pPlayers[2].pName, pGlobalTXT_LocalizationStrings[508]); pPlayers[3].uCurrentFace = 10; pPlayers[3].uPrevVoiceID = 10; pPlayers[3].uVoiceID = 10; pPlayers[3].SetInitialStats(); pPlayers[3].uSex = pPlayers[3].GetSexByVoice(); pPlayers[3].RandomizeName(); strcpy(pPlayers[3].pName, pGlobalTXT_LocalizationStrings[507]); for (uint i = 0; i < 4; ++i) { pPlayers[i].uTimeToRecovery = 0; for (uint j = 0; j < 20; ++j) pPlayers[i].pConditions[j] = 0; for (uint j = 0; j < 24; ++j) pPlayers[i].pPlayerBuffs[j].Reset(); pPlayers[i].expression = CHARACTER_EXPRESSION_1; pPlayers[i].uExpressionTimePassed = 0; pPlayers[i].uExpressionTimeLength = rand() % 256 + 128; } for (uint i = 1; i < 20; ++i) pPartyBuffs[i].Reset(); pWindowList_at_506F50_minus1_indexing_buttons____and_an_int_[0] = 100; // default character ui - stats uFlags = 0; memset(_autonote_bits, 0, sizeof(_autonote_bits)); memset(_quest_bits, 0, sizeof(_quest_bits)); pIsArtifactFound.fill(0); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_RED_POTION_ACTIVE, 1); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_SEASHELL_ACTIVE, 1); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_LONGBOW_ACTIVE, 1); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_PLATE_ACTIVE, 1); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_LUTE_ACTIVE, 1); _449B7E_toggle_bit(_quest_bits, PARTY_QUEST_EMERALD_HAT_ACTIVE, 1); PartyTimes._shop_ban_times.fill(0); memcpy(pNPCStats->pNewNPCData, pNPCStats->pNPCData, 0x94BCu); memcpy(pNPCStats->pGroups_copy, pNPCStats->pGroups, 0x66u); pNPCStats->pNewNPCData[3].uFlags |= 128;//|= 0x80u; Lady Margaret _494035_timed_effects__water_walking_damage__etc(); pEventTimer->Pause(); return 0; } //----- (0043AD34) -------------------------------------------------------- void Party::Yell() { Actor *v0; // esi@5 int v1; // edi@9 int v2; // ebx@9 int v3; // eax@9 if ( (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime > 0 ) pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset(); if ( pParty->bTurnBasedModeOn != 1 ) { for (unsigned int i = 0; i < uNumActors; i++) { v0 = &pActors[i]; if ( v0->Actor::CanAct() && v0->pMonsterInfo.uHostilityType != MonsterInfo::Hostility_Long && v0->pMonsterInfo.uMovementType != MONSTER_MOVEMENT_TYPE_STAIONARY ) { v1 = abs(v0->vPosition.x - pParty->vPosition.x); v2 = abs(v0->vPosition.y - pParty->vPosition.y); v3 = abs(v0->vPosition.z - pParty->vPosition.z); if (int_get_vector_length(v1, v2, v3) < 512) Actor::AI_Flee(i, 4, 0, 0); } } } } //----- (00491BF9) -------------------------------------------------------- void Party::ResetPosMiscAndSpellBuffs() { this->vPosition.y = 0; this->vPosition.z = 0; this->vPosition.x = 0; this->uFallStartY = 0; this->sRotationY = 0; this->sRotationX = 0; this->uFallSpeed = 0; this->field_28 = 0; this->uDefaultPartyHeight = 120; this->field_14_radius = 37; this->y_rotation_granularity = 25; this->uWalkSpeed = 384; this->y_rotation_speed = 90; this->field_24 = 5; this->field_6FC = 0; this->field_708 = 15; this->field_0 = 25; for (int playerId = 0; playerId < 4; playerId++) { for (int buffId = 0; buffId < 24; buffId++) { this->pPlayers[playerId].pPlayerBuffs[buffId].Reset(); } } for (int buffId = 0; buffId < 20; buffId++) { this->pPartyBuffs[buffId].Reset(); } } //----- (004909F4) -------------------------------------------------------- void Party::UpdatePlayersAndHirelingsEmotions() { int v4; // edx@27 for (int i = 0; i < 4; ++i) { Player* player = &pPlayers[i]; player->uExpressionTimePassed += (unsigned short)pMiscTimer->uTimeElapsed; uint condition = player->GetMajorConditionIdx(); if (condition == Condition_Good || condition == Condition_Zombie) { if (player->uExpressionTimePassed < player->uExpressionTimeLength) continue; player->uExpressionTimePassed = 0; if (player->expression != 1 || rand() % 5) { player->expression = CHARACTER_EXPRESSION_1; player->uExpressionTimeLength = rand() % 256 + 32; } else { v4 = rand() % 100; if (v4 < 25) player->expression = CHARACTER_EXPRESSION_13; else if (v4 < 31) player->expression = CHARACTER_EXPRESSION_14; else if (v4 < 37) player->expression = CHARACTER_EXPRESSION_15; else if (v4 < 43) player->expression = CHARACTER_EXPRESSION_16; else if (v4 < 46) player->expression = CHARACTER_EXPRESSION_17; else if (v4 < 52) player->expression = CHARACTER_EXPRESSION_18; else if (v4 < 58) player->expression = CHARACTER_EXPRESSION_19; else if (v4 < 64) player->expression = CHARACTER_EXPRESSION_20; else if (v4 < 70) player->expression = CHARACTER_EXPRESSION_54; else if (v4 < 76) player->expression = CHARACTER_EXPRESSION_55; else if (v4 < 82) player->expression = CHARACTER_EXPRESSION_56; else if (v4 < 88) player->expression = CHARACTER_EXPRESSION_57; else if (v4 < 94) player->expression = CHARACTER_EXPRESSION_29; else player->expression = CHARACTER_EXPRESSION_30; } for (unsigned int j = 0; j < pPlayerFrameTable->uNumFrames; ++j) { PlayerFrame* frame = &pPlayerFrameTable->pFrames[j]; if (frame->expression == player->expression) { player->uExpressionTimeLength = 8 * frame->uAnimLength; break; } } } else if (player->expression != CHARACTER_EXPRESSION_DMGRECVD_MINOR && player->expression != CHARACTER_EXPRESSION_DMGRECVD_MODERATE && player->expression != CHARACTER_EXPRESSION_DMGRECVD_MAJOR || player->uExpressionTimePassed >= player->uExpressionTimeLength) { player->uExpressionTimeLength = 0; player->uExpressionTimePassed = 0; switch (condition) { case Condition_Dead: player->expression = CHARACTER_EXPRESSION_DEAD; break; case Condition_Pertified: player->expression = CHARACTER_EXPRESSION_PERTIFIED; break; case Condition_Eradicated: player->expression = CHARACTER_EXPRESSION_ERADICATED; break; case Condition_Cursed: player->expression = CHARACTER_EXPRESSION_CURSED; break; case Condition_Weak: player->expression = CHARACTER_EXPRESSION_WEAK; break; case Condition_Sleep: player->expression = CHARACTER_EXPRESSION_SLEEP; break; case Condition_Fear: player->expression = CHARACTER_EXPRESSION_FEAR; break; case Condition_Drunk: player->expression = CHARACTER_EXPRESSION_DRUNK; break; case Condition_Insane: player->expression = CHARACTER_EXPRESSION_INSANE; break; case Condition_Poison_Weak: case Condition_Poison_Medium: case Condition_Poison_Severe: player->expression = CHARACTER_EXPRESSION_POISONED; break; case Condition_Disease_Weak: case Condition_Disease_Medium: case Condition_Disease_Severe: player->expression = CHARACTER_EXPRESSION_DISEASED; break; case Condition_Paralyzed: player->expression = CHARACTER_EXPRESSION_PARALYZED; break; case Condition_Unconcious: player->expression = CHARACTER_EXPRESSION_UNCONCIOUS; break; default: Error("Invalid condition: %u", condition); } } } for (int i = 0; i < 2; ++i) { NPCData* hireling = &pParty->pHirelings[i]; if (!hireling->evt_C) continue; hireling->evt_B += pMiscTimer->uTimeElapsed; if (hireling->evt_B >= hireling->evt_C) { hireling->evt_A = 0; hireling->evt_B = 0; hireling->evt_C = 0; Assert(sizeof(NPCData) == 0x4C); memset(hireling, 0, sizeof(*hireling)); pParty->hirelingScrollPosition = 0; pParty->CountHirelings(); viewparams->bRedrawGameUI = true; } } } //----- (00490D02) -------------------------------------------------------- void Party::RestAndHeal() { Player *pPlayer; // esi@4 bool have_vessels_soul; // [sp+10h] [bp-8h]@10 for ( uint i = 0; i < 20; ++i ) pParty->pPartyBuffs[i].Reset(); for ( int pPlayerID = 0; pPlayerID < 4; ++pPlayerID ) { pPlayer = &pParty->pPlayers[pPlayerID]; for ( uint i = 0; i < 20; ++i ) pPlayer->pPlayerBuffs[i].Reset(); pPlayer->Zero(); if ( pPlayer->pConditions[Condition_Dead] || pPlayer->pConditions[Condition_Pertified] || pPlayer->pConditions[Condition_Eradicated] )//Dead/Petrified/Eradicated continue; pPlayer->pConditions[Condition_Unconcious] = 0;//Unconcious pPlayer->pConditions[Condition_Drunk] = 0;//Drunk pPlayer->pConditions[Condition_Fear] = 0;//Fear pPlayer->pConditions[Condition_Sleep] = 0;//Sleep pPlayer->pConditions[Condition_Weak] = 0;//Weak pPlayer->uTimeToRecovery = 0; pPlayer->sHealth = pPlayer->GetMaxHealth(); pPlayer->sMana = pPlayer->GetMaxMana(); if ( pPlayer->classType == PLAYER_CLASS_LICH ) { have_vessels_soul = false; for ( uint i = 0; i < 126; i++ ) { if ( pPlayer->pInventoryItemList[i].uItemID == ITEM_LICH_JAR_FULL && pPlayer->pInventoryItemList[i].uHolderPlayer == pPlayerID + 1 ) have_vessels_soul = true; } if ( !have_vessels_soul ) { pPlayer->sHealth = pPlayer->GetMaxHealth() / 2; pPlayer->sMana = pPlayer->GetMaxMana() / 2; } } if (pPlayer->pConditions[Condition_Zombie]) { pPlayer->sMana = 0; pPlayer->sHealth /= 2; } else if ( pPlayer->pConditions[Condition_Poison_Severe] || pPlayer->pConditions[Condition_Disease_Severe] ) { pPlayer->sHealth /= 4; pPlayer->sMana /= 4; } else if ( pPlayer->pConditions[Condition_Poison_Medium] || pPlayer->pConditions[Condition_Disease_Medium] ) { pPlayer->sHealth /= 3; pPlayer->sMana /= 3; } else if ( pPlayer->pConditions[Condition_Poison_Weak] || pPlayer->pConditions[Condition_Disease_Weak] ) { pPlayer->sHealth /= 2; pPlayer->sMana /= 2; } if ( pPlayer->pConditions[Condition_Insane] ) pPlayer->sMana = 0; UpdatePlayersAndHirelingsEmotions(); } pParty->days_played_without_rest = 0; } //----- (004938D1) -------------------------------------------------------- void __fastcall Rest(unsigned int uHoursToSleep) { signed __int64 v2; // st7@3 if ( uHoursToSleep > 240 ) Actor::InitializeActors(); v2 = (signed __int64)((7680 * uHoursToSleep) * 0.033333335); pParty->uTimePlayed += v2; for (int i = 1; i <= 4; i++) { pPlayers[i]->Recover((int)v2); } _494035_timed_effects__water_walking_damage__etc(); } //----- (004B1BDB) -------------------------------------------------------- void RestAndHeal(__int64 uNumMinutes) { signed __int64 v1; // ST2C_8@1 signed __int64 v2; // qax@1 unsigned __int64 v4; // qax@1 unsigned int v5; // ebx@1 pParty->pHirelings[0].bHasUsedTheAbility = 0; pParty->pHirelings[1].bHasUsedTheAbility = 0; pParty->uTimePlayed += (signed __int64)((double)(7680 * uNumMinutes) * 0.033333335); v1 = (signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375); v2 = v1 / 60 / 60; v4 = (unsigned int)v2 / 0x18; v5 = (unsigned int)(v4 / 7) >> 2; pParty->uCurrentTimeSecond = v1 % 60; pParty->uCurrentMinute = v1 / 60 % 60; pParty->uCurrentHour = v2 % 24; pParty->uCurrentMonthWeek = v4 / 7 & 3; pParty->uDaysPlayed = (unsigned int)v4 % 0x1C; pParty->uCurrentMonth = v5 % 0xC; pParty->uCurrentYear = v5 / 0xC + game_starting_year; pParty->RestAndHeal(); for (int i = 0; i < 4; i++) { pParty->pPlayers[i].uTimeToRecovery = 0; pParty->pPlayers[i].uNumDivineInterventionCastsThisDay = 0; pParty->pPlayers[i].uNumArmageddonCasts = 0; pParty->pPlayers[i].uNumFireSpikeCasts = 0; pParty->pPlayers[i].field_1B3B = 0; } pParty->UpdatePlayersAndHirelingsEmotions(); } //----- (0041F5BE) -------------------------------------------------------- void Party::Sleep6Hours() { if ( _506F18_num_minutes_to_sleep < 6 ) { if ( _506F18_num_minutes_to_sleep ) { Rest(_506F18_num_minutes_to_sleep); _506F18_num_minutes_to_sleep = 0; OutdoorLocation::LoadActualSkyFrame(); } if ( dword_506F14 == 2 ) { pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Escape, 0, 0); } } else { Rest(6u); _506F18_num_minutes_to_sleep -= 6; OutdoorLocation::LoadActualSkyFrame(); } viewparams->bRedrawGameUI = 1; } bool TestPartyQuestBit( PARTY_QUEST_BITS bit ) { return _449B57_test_bit(pParty->_quest_bits, bit); } //----- (0047752B) -------------------------------------------------------- int Party::GetPartyReputation() { DDM_DLV_Header *v0; // ebx@1 signed int v1; // esi@3 v0 = &pOutdoor->ddm; if ( uCurrentlyLoadedLevelType != LEVEL_Outdoor ) v0 = &pIndoor->dlv; v1 = 0; if ( CheckHiredNPCSpeciality(Pirate) ) v1 += 5; if ( CheckHiredNPCSpeciality(Burglar) ) v1 += 5; if ( CheckHiredNPCSpeciality(Gypsy) ) v1 += 5; if ( CheckHiredNPCSpeciality(Duper) ) v1 += 5; if ( CheckHiredNPCSpeciality(FallenWizard) ) v1 += 5; return v1 + v0->uReputation; } //----- (004269A2) -------------------------------------------------------- void Party::GivePartyExp(unsigned int pEXPNum) { signed int pActivePlayerCount; // ecx@1 int pLearningPercent; // eax@13 if ( pEXPNum > 0) { pActivePlayerCount = 0; for ( uint i = 0; i < 4; ++i ) { if ( !pParty->pPlayers[i].pConditions[Condition_Unconcious] && !pParty->pPlayers[i].pConditions[Condition_Dead] && !pParty->pPlayers[i].pConditions[Condition_Pertified] && !pParty->pPlayers[i].pConditions[Condition_Eradicated] ) pActivePlayerCount ++; } if ( pActivePlayerCount ) { pEXPNum = pEXPNum / pActivePlayerCount; for ( uint i = 0; i < 4; ++i ) { if ( !pParty->pPlayers[i].pConditions[Condition_Unconcious] && !pParty->pPlayers[i].pConditions[Condition_Dead] && !pParty->pPlayers[i].pConditions[Condition_Pertified] && !pParty->pPlayers[i].pConditions[Condition_Eradicated] ) { pLearningPercent = pParty->pPlayers[i].GetLearningPercent(); pEXPNum = pEXPNum + pEXPNum * pLearningPercent / 100; pParty->pPlayers[i].uExperience += pEXPNum; if ( pParty->pPlayers[i].uExperience > 4000000000i64 ) { pParty->pPlayers[i].uExperience = 0; } } } } } } //----- (00420C05) -------------------------------------------------------- void Party::PartyFindsGold(unsigned int uNumGold, int _1_dont_share_with_followers___2_the_same_but_without_a_message__else_normal) { int hirelingSalaries; // ebp@1 unsigned int goldToGain; // esi@1 NPCData *v12; // ecx@21 unsigned int v13; // ecx@23 signed int hirelingCount; // [sp+Ch] [bp-4h]@6 hirelingSalaries = 0; goldToGain = uNumGold; if ( _1_dont_share_with_followers___2_the_same_but_without_a_message__else_normal == 2 ) pTmpBuf2[0] = 0; else if ( _1_dont_share_with_followers___2_the_same_but_without_a_message__else_normal == 1 ) { sprintf(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[467], uNumGold);// You found %lu gold! } else { hirelingCount = 0; for (int i = 0; i < 2; i++) { if (this->pHirelings[i].pName) { hirelingCount++; pTmpBuf[hirelingCount] = i; } } for (uint i = 0; i < pNPCStats->uNumNewNPCs; i++) { if ( pNPCStats->pNewNPCData[i].uFlags & 0x80 && (!this->pHirelings[0].pName || strcmp(pNPCStats->pNewNPCData[i].pName, this->pHirelings[0].pName)) && (!this->pHirelings[1].pName || strcmp(pNPCStats->pNewNPCData[i].pName, this->pHirelings[1].pName)) ) { hirelingCount++; pTmpBuf[hirelingCount] = i + 2; } } for (int i = 0; i < hirelingCount; i++) { uchar thisBufId = (uchar)pTmpBuf[i]; if (thisBufId < 2) v12 = &this->pHirelings[thisBufId]; else v12 = &pNPCStats->pNPCData[thisBufId + 499]; v13 = v12->uProfession; if ( v13 ) hirelingSalaries += pNPCStats->pProfessions[v13].uHirePrice;//*(&pNPCStats->field_13A58 + 5 * v13); } if ( CheckHiredNPCSpeciality(Factor) ) goldToGain += (signed int)(10 * goldToGain) / 100; if ( CheckHiredNPCSpeciality(Banker) ) goldToGain += (signed int)(20 * goldToGain) / 100; if ( CheckHiredNPCSpeciality(Pirate) ) goldToGain += (signed int)(10 * goldToGain) / 100; if ( hirelingSalaries ) { hirelingSalaries = (signed int)(goldToGain * hirelingSalaries / 100) / 100; if ( hirelingSalaries < 1 ) hirelingSalaries = 1; sprintf(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[466], goldToGain, hirelingSalaries);// You found %lu gold (followers take %lu)! } else { sprintf(pTmpBuf2.data(), pGlobalTXT_LocalizationStrings[467], goldToGain);// You found %lu gold! } } this->uNumGold += goldToGain - hirelingSalaries; pUIAnim_Gold->uAnimTime = 0; pUIAnim_Gold->uAnimLength = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Gold->uIconID].uAnimLength; if ( pTmpBuf2[0] ) ShowStatusBarString(pTmpBuf2.data(), 2u); pAudioPlayer->PlaySound(SOUND_gold01, 0, 0, -1, 0, 0, 0, 0); } //----- (00421B2C) -------------------------------------------------------- void Party::sub_421B2C_PlaceInInventory_or_DropPickedItem() { unsigned int v0; // eax@2 Texture *v1; // ebx@2 int v2; // eax@3 int v4; // eax@6 unsigned __int16 v5; // dx@11 signed int v6; // eax@11 __int16 v8; // ax@16 SpriteObject a1; // [sp+4h] [bp-78h]@11 int v11; // [sp+74h] [bp-8h]@2 int v12; // [sp+78h] [bp-4h]@5 if ( !pParty->pPickedItem.uItemID ) return; v0 = pIcons_LOD->LoadTexture( pParty->pPickedItem.GetIconName(), TEXTURE_16BIT_PALETTE); v1 = pIcons_LOD->GetTexture(v0); v11 = areWeLoadingTexture; if ( uActiveCharacter && (v2 = ::pPlayers[uActiveCharacter]->AddItem(-1, pParty->pPickedItem.uItemID)) != 0 ) { memcpy(&::pPlayers[uActiveCharacter]->pInventoryItemList[v2-1], &pParty->pPickedItem, 0x24u); pMouse->RemoveHoldingItem(); } else { for (v12 = 0; v12 < 4; v12++) { v4 = pParty->pPlayers[v12].AddItem(-1, pParty->pPickedItem.uItemID); if ( v4 ) { memcpy(&pParty->pPlayers[v12].pInventoryItemList[v4 - 1], &pParty->pPickedItem, sizeof(ItemGen)); pMouse->RemoveHoldingItem(); break; } } if ( v12 == 4 ) { v5 = pItemsTable->pItems[pParty->pPickedItem.uItemID].uSpriteID; v6 = 0; a1.uType = pItemsTable->pItems[pParty->pPickedItem.uItemID].uSpriteID; for ( uint i = 0; i < pObjectList->uNumObjects; i++ ) { if ( v5 == pObjectList->pObjects[i].uObjectID ) { v6 = i; break; } } a1.spell_caster_pid = OBJECT_Player; a1.uObjectDescID = v6; a1.vPosition.y = pParty->vPosition.y; a1.vPosition.x = pParty->vPosition.x; a1.vPosition.z = pParty->sEyelevel + pParty->vPosition.z; a1.uSoundID = 0; a1.uFacing = 0; a1.uAttributes = 8; v8 = pIndoor->GetSector( pParty->vPosition.x, pParty->vPosition.y, pParty->sEyelevel + pParty->vPosition.z); a1.uSpriteFrameID = 0; a1.uSectorID = v8; memcpy(&a1.stru_24, &pParty->pPickedItem, sizeof(a1.stru_24)); a1.Create(pParty->sRotationY, 184, 200, 0); pMouse->RemoveHoldingItem(); } } if ( !v11 ) { v1->Release(); pIcons_LOD->SyncLoadedFilesCount(); } return; } //----- (0048C6F6) -------------------------------------------------------- bool Party::AddItemToParty(ItemGen *pItem) { unsigned int v2; // eax@1 char *v5; // eax@8 Texture *v7; // ebx@10 signed int v8; // esi@10 Player *v9; // edi@11 int v10; // eax@11 int v21; // [sp+24h] [bp-4h]@10 v2 = pItem->uItemID; if ( !pItemsTable->pItems[v2].uItemID_Rep_St ) pItem->SetIdentified(); v5 = pItemsTable->pItems[v2].pIconName; if ( v5 ) { v7 = pIcons_LOD->LoadTexturePtr(v5, TEXTURE_16BIT_PALETTE); v21 = areWeLoadingTexture; v8 = 0; uint current_player = uActiveCharacter; for (int i = 0; i < 4; i++) { current_player = current_player + i; if ( current_player > 4 ) current_player = current_player - 4; v9 = ::pPlayers[current_player]; v10 = v9->AddItem(-1, pItem->uItemID); if ( v10 ) { memcpy(&v9->pInventoryItemList[v10-1], pItem, 0x24u); pItem->Reset(); pAudioPlayer->PlaySound(SOUND_gold01, 0, 0, -1, 0, 0, 0, 0); v9->PlaySound(SPEECH_60, 0); if ( !v21 ) { v7->Release(); pIcons_LOD->SyncLoadedFilesCount(); } return true; } } if ( !v21 ) { v7->Release(); pIcons_LOD->SyncLoadedFilesCount(); } return false; } else { MessageBoxW(nullptr, L"Invalid picture_name detected ::addItem()", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Party.cpp:795", 0); return false; } } // 506128: using guessed type int areWeLoadingTexture; bool Party::IsPartyEvil() { return _449B57_test_bit(_quest_bits, 100); } bool Party::IsPartyGood() { return _449B57_test_bit(_quest_bits, 99); } //----- (0046A89E) -------------------------------------------------------- int Party::_46A89E_immolation_effect(int* affected, int affectedArrSize, int effectRange) { int v5; // ebx@3 int v17; // [sp+Ch] [bp-10h]@3 int v18; // [sp+10h] [bp-Ch]@3 int affectedCount; // [sp+18h] [bp-4h]@1 affectedCount = 0; for ( size_t i = 0; i < uNumActors; ++i ) { v5 = abs(pActors[i].vPosition.x - this->vPosition.x); v17 = abs(pActors[i].vPosition.y - this->vPosition.y); v18 = abs(pActors[i].vPosition.z - this->vPosition.z); if ( int_get_vector_length(v5, v17, v18) <= effectRange ) { if ( pActors[i].uAIState != Dead && pActors[i].uAIState != Dying && pActors[i].uAIState != Removed && pActors[i].uAIState != Disabled && pActors[i].uAIState != Summoned ) { affected[affectedCount] = i; affectedCount++; if ( affectedCount >= affectedArrSize ) break; } } } return affectedCount; } //----- (00444D80) -------------------------------------------------------- int GetTravelTime() { signed int new_travel_time; // esi@1 new_travel_time = uDefaultTravelTime_ByFoot; if ( CheckHiredNPCSpeciality(Guide) ) --new_travel_time; if ( CheckHiredNPCSpeciality(Tracker) ) new_travel_time -= 2; if ( CheckHiredNPCSpeciality(Pathfinder) ) new_travel_time -= 3; if ( CheckHiredNPCSpeciality(Explorer) ) --new_travel_time; if ( new_travel_time < 1 ) new_travel_time = 1; return new_travel_time; } // 6BD07C: using guessed type int uDefaultTravelTime_ByFoot; //----- (00449B57) -------------------------------------------------------- bool _449B57_test_bit(unsigned __int8 *a1, __int16 a2) { return (a1[(a2 - 1) >> 3] & (0x80 >> (a2 - 1) % 8)) != 0; } //----- (00449B7E) -------------------------------------------------------- void _449B7E_toggle_bit(unsigned char *pArray, __int16 a2, unsigned __int16 bToggle) { signed int v3; // esi@1 unsigned char set_bit; // edx@1 v3 = a2 - 1; set_bit = 0x80 >> v3 % 8; if (bToggle) pArray[v3 / 8] |= set_bit; else pArray[v3 / 8] &= ~set_bit; } //----- (004760D5) -------------------------------------------------------- PartyAction ActionQueue::Next() { if (!uNumActions) return PARTY_INVALID; PartyAction result = pActions[0]; for (unsigned int i = 0; i < uNumActions - 1; ++i) pActions[i] = pActions[i + 1]; --uNumActions; return result; }