view Party.cpp @ 149:2b0c652cc165

12.02.13
author Ritor1
date Tue, 12 Feb 2013 10:17:11 +0600
parents 541f3df0aa55
children cca78efb377e
line wrap: on
line source

#include <assert.h>

#include "Party.h"
#include "MapInfo.h"
#include "Time.h"
#include "AudioPlayer.h"
#include "IconFrameTable.h"
#include "Mouse.h"
#include "PlayerFrameTable.h"
#include "TurnEngine.h"
#include "stru279.h"
#include "Viewport.h"
#include "Actor.h"
#include "GUIWindow.h"

#include "mm7_data.h"







Party *pParty; // idb

struct ActionQueue *pPartyActionQueue = new ActionQueue;




//----- (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
  Player *v2; // esi@1
  signed int v3; // ebx@1
  Player *v4; // ecx@2
  signed int v5; // eax@3
  bool result; // eax@7

  uMaxPerception = 0;
  v2 = this->pPlayers;
  v3 = 4;
  do
  {
    if ( v2->CanAct() )
    {
      v5 = v2->GetPerception();
      if ( v5 > uMaxPerception )
        uMaxPerception = v5;
    }
    ++v2;
    --v3;
  }
  while ( v3 );
  if ( uLevelMapStatsID && (signed int)uLevelMapStatsID < 77 )
    result = uMaxPerception >= 2 * pMapStats->pInfos[uLevelMapStatsID]._per;
  else
    result = 0;
  return result;
}

//----- (004936E1) --------------------------------------------------------
void Party::SetHoldingItem(ItemGen *pItem)
{
  Party *v2; // esi@1

  v2 = this;
  sub_421B2C_PlaceInInventory_or_DropPickedItem();
  memcpy(&v2->pPickedItem, pItem, sizeof(v2->pPickedItem));
  pMouse->SetCursorBitmapFromItemID(v2->pPickedItem.uItemID);
}

//----- (0049370F) --------------------------------------------------------
int Party::GetNextActiveCharacter()
{
  Party *v1; // esi@1
  int v2; // eax@4
  signed int v4; // ecx@6
  Player *v5; // edx@6
  Player *v6; // eax@7
  Player *v7; // ecx@23
  signed int v8; // esi@23
  signed int v9; // edx@23
  Player **v10; // edi@23
  Player *v11; // eax@24
  int v12; // [sp+Ch] [bp-4h]@1

  v1 = this;
  v12 = 0;
  if ( pParty->bTurnBasedModeOn == 1 )
  {
    if ( pTurnEngine->field_4 != 2 || (pTurnEngine->pQueue[0].uPackedID & 7) != 4 )
      return 0;
    v2 = pTurnEngine->pQueue[0].uPackedID >> 3;
    return v2 + 1;
  }
  v4 = 0;
  v5 = v1->pPlayers;//[0].uTimeToRecovery;
  while ( 1 )
  {
    v6 = ::pPlayers[v4 + 1];
    if ( v6->pConditions[2]
      || v6->pConditions[12]
      || v6->pConditions[13]
      || v6->pConditions[14]
      || v6->pConditions[15]
      || v6->pConditions[16]
	  || v5->uTimeToRecovery )
    {
      byte_AE3368[v4] = 1;
    }
    else if ( !byte_AE3368[v4] )
      break;
    ++v4;
    ++v5;
    if ( v4 >= 4 )
      break;
  }
  if(v4<4)
  {
	  v12 = v4;
	  byte_AE3368[v4] = 1;
  }
  if ( (unsigned __int8)(byte_AE3369 & byte_AE336A & byte_AE336B) & byte_AE3368[0] )
    memset(byte_AE3368, 0, 4u);
  v2 = v12;
  if ( v12 )
    return v2 + 1;
  v7 = v1->pPlayers;//[0].uSpeedBonus;
  v8 = 0;
  v9 = 1;
  v10 = &::pPlayers[1];
  while ( 2 )
  {
    v11 = *v10;
    if ( !(*v10)->pConditions[2]
      && !v11->pConditions[12]
      && !v11->pConditions[13]
      && !v11->pConditions[14]
      && !v11->pConditions[15]
      && !v11->pConditions[16]
	  && !v7->uTimeToRecovery )
    {
      if ( v12 )
      {
		if ( v7->uSpeedBonus > v8 )
        {
          v8 = v7->uSpeedBonus;
          v12 = v9;
        }
      }
      else
      {
        v8 = *(short *)v7;
        v12 = v9;
      }
    }
    ++v10;
    ++v9;
    ++v7;
    if ( v9 - 1 < 4 )
      continue;
    return v12;
  }
}


//----- (00493244) --------------------------------------------------------
bool Party::HasItem(unsigned int uItemID)
{
  Player *v2; // edx@1
  signed int v3; // ecx@2
  ItemGen *v4; // eax@2

  v2 = pParty->pPlayers;//[0].pInventoryItems;
  while ( v2 <= &pParty->pPlayers[3] )
  {
    v3 = 0;
	v4 = v2->pInventoryItems;
    do
    {
      if ( v4->uItemID == uItemID )
        return 1;
      ++v3;
      ++v4;
    }
    while ( v3 < 138 );
    ++v2;
  }
  return 0;
}


//----- (00492AD5) --------------------------------------------------------
__int16 Party::SetFood(unsigned int uNumFood)
{
  __int16 result; // ax@1

  pUIAnim_Food->uAnimTime = 0;
  pParty->uNumFoodRations = uNumFood;
  result = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Food->uIconID].uAnimLength;
  pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Food->uIconID].uAnimLength;
  return result;
}

//----- (00492B03) --------------------------------------------------------
void Party::TakeFood(unsigned int uNumFood)
{
  if ( ((pParty->uNumFoodRations - uNumFood) & 0x80000000u) == 0 )
    pParty->uNumFoodRations -= uNumFood;
  else
    pParty->uNumFoodRations = 0;
  pUIAnim_Food->uAnimTime = 0;
  pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Food->uIconID].uAnimLength;
}

//----- (00492B42) --------------------------------------------------------
__int16 Party::GiveFood(unsigned int _this)
{
  __int16 result; // ax@1

  pParty->uNumFoodRations += _this;
  pUIAnim_Food->uAnimTime = 0;
  result = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Food->uIconID].uAnimLength;
  pUIAnim_Food->uAnimLength = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Food->uIconID].uAnimLength;
  return result;
}

//----- (00492B70) --------------------------------------------------------
void Party::SetGold(unsigned int uNumGold)
{
  pParty->uNumGold = uNumGold;
  pUIAnim_Gold->uAnimTime = 0;
  pUIAnim_Gold->uAnimLength = 8 * pIconsFrameTable->pIcons[(signed __int16)pUIAnim_Gold->uIconID].uAnimLength;
  pAudioPlayer->PlaySound(SOUND_GoldReceived, 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[(signed __int16)pUIAnim_Gold->uIconID].uAnimLength;
  pAudioPlayer->PlaySound(SOUND_GoldReceived, 0, 0, -1, 0, 0, 0, 0);
}

//----- (0049135E) --------------------------------------------------------
unsigned int Party::GetPartyFame()
{
  signed int v1; // eax@1
  Player *v2; // ecx@1
  signed int v3; // edx@1

  v1 = 0;
  v2 = this->pPlayers;//[0].uExperience;
  v3 = 4;                                       // (E exp) / 1000
  do
  {
	v1 += (int)v2->uExperience; // needs review
    ++v2;
    --v3;
  }
  while ( v3 );
  return v1 / 1000;
}

//----- (0049137D) --------------------------------------------------------
void Party::CreateDefaultParty(char bGiveItems)
{
  Party *pParty; // esi@1
  signed __int16 v3; // ax@1
  //int pResMagicBase; // ecx@1
  Player *pCharacter; // esi@3
  signed int uSpellBookPageCount; // edx@5
  int pMagicSkills; // eax@5
  int uSkillIdx; // eax@11
  //unsigned __int8 v9; // zf@37
  //char v10; // sf@37
  //unsigned __int8 v11; // of@37
  char *pAttributes; // eax@38
  signed int v13; // ecx@38
  int uMaxSP; // eax@42
  unsigned int v15; // [sp-4h] [bp-44h]@14
  unsigned int v16; // [sp-4h] [bp-44h]@26
  int v17; // [sp+10h] [bp-30h]@1
  int v18; // [sp+14h] [bp-2Ch]@11
  signed int uNumPlayers; // [sp+18h] [bp-28h]@1
  ItemGen Dst; // [sp+1Ch] [bp-24h]@10


  pParty = this;

  pHireling1Name[0] = 0;
  pHireling2Name[0] = 0;
  pParty->field_709 = 0;
  memset(pHirelings, 0, 2 * sizeof(*pHirelings));

  strcpy(this->pPlayers[0].pName, pGlobalTXT_LocalizationStrings[509]); //Zoltan
  pParty->pPlayers[0].field_1928 = 17;
  pParty->pPlayers[0].uFace = 17;
  pParty->pPlayers[0].field_1924 = 17;
  pParty->pPlayers[0].uVoiceID = 17;
  pParty->pPlayers[0].uMight = 30;
  pParty->pPlayers[0].uIntelligence = 5;
  pParty->pPlayers[0].uWillpower = 5;
  pParty->pPlayers[0].uEndurance = 13;
  pParty->pPlayers[0].uAccuracy = 13;
  pParty->pPlayers[0].uSpeed = 14;
  pParty->pPlayers[0].uLuck = 7;
  pParty->pPlayers[0].pActiveSkills[PLAYER_SKILL_LEATHER] = 1;         // leather
  pParty->pPlayers[0].pActiveSkills[PLAYER_SKILL_ARMSMASTER] = 1;        // armsmaster
  pParty->pPlayers[0].pActiveSkills[PLAYER_SKILL_BOW] = 1;         // bow
  pParty->pPlayers[0].pActiveSkills[PLAYER_SKILL_SWORD] = 1;         // sword
  pParty->pPlayers[1].field_1928 = 3;
  pParty->pPlayers[1].uFace = 3;
  pParty->pPlayers[1].field_1924 = 3;
  pParty->pPlayers[1].uVoiceID = 3;
  strcpy(pParty->pPlayers[1].pName, pGlobalTXT_LocalizationStrings[506]); //Roderic
  pParty->pPlayers[1].uMight = 13;
  pParty->pPlayers[1].uIntelligence = 9;
  pParty->pPlayers[1].uWillpower = 9;
  pParty->pPlayers[1].uEndurance = 13;
  pParty->pPlayers[1].uAccuracy = 13;
  pParty->pPlayers[1].uSpeed = 13;
  pParty->pPlayers[1].uLuck = 13;
  pParty->pPlayers[1].pActiveSkills[PLAYER_SKILL_LEATHER] = 1;         // leather
  pParty->pPlayers[1].pActiveSkills[PLAYER_SKILL_STEALING] = 1;        // stealing
  pParty->pPlayers[1].pActiveSkills[PLAYER_SKILL_DAGGER] = 1;         // dagger
  pParty->pPlayers[1].pActiveSkills[PLAYER_SKILL_TRAP_DISARM] = 1;        // disarm trap
  pParty->pPlayers[2].field_1928 = 14;
  pParty->pPlayers[2].uFace = 14;
  pParty->pPlayers[2].field_1924 = 14;
  pParty->pPlayers[2].uVoiceID = 14;
  strcpy(pParty->pPlayers[2].pName, pGlobalTXT_LocalizationStrings[508]); // Serena
  pParty->pPlayers[2].uMight = 12;
  pParty->pPlayers[2].uIntelligence = 9;
  pParty->pPlayers[2].uWillpower = 20;
  pParty->pPlayers[2].uEndurance = 22;
  pParty->pPlayers[2].uAccuracy = 7;
  pParty->pPlayers[2].uSpeed = 13;
  pParty->pPlayers[2].uLuck = 7;
  pParty->pPlayers[2].pActiveSkills[PLAYER_SKILL_ALCHEMY] = 1;        // alchemy
  pParty->pPlayers[2].pActiveSkills[PLAYER_SKILL_LEATHER] = 1;         // leather
  pParty->pPlayers[2].pActiveSkills[PLAYER_SKILL_BODY] = 1;        // body
  pParty->pPlayers[2].pActiveSkills[PLAYER_SKILL_MACE] = 1;         // mace
  strcpy(pParty->pPlayers[3].pName, pGlobalTXT_LocalizationStrings[507]); // Alexis
  v3 = 10;
  pParty->pPlayers[3].field_1928 = 10;
  pParty->pPlayers[3].uFace = 10;
  //pResMagicBase = (int)&pParty->pPlayers[0].sResMagicBase;
  pParty->pPlayers[3].uEndurance = 13;
  pParty->pPlayers[3].uAccuracy = 13;
  pParty->pPlayers[3].uSpeed = 13;
  pParty->pPlayers[3].field_1924 = 10;
  pParty->pPlayers[3].uVoiceID = 10;
  pParty->pPlayers[3].uMight = 5;
  pParty->pPlayers[3].uIntelligence = 30;
  pParty->pPlayers[3].uWillpower = 9;
  pParty->pPlayers[3].uLuck = 7;
  pParty->pPlayers[3].pActiveSkills[PLAYER_SKILL_LEATHER] = 1;         // leather
  pParty->pPlayers[3].pActiveSkills[PLAYER_SKILL_AIR] = 1;        // air
  pParty->pPlayers[3].pActiveSkills[PLAYER_SKILL_FIRE] = 1;        // fire
  pParty->pPlayers[3].pActiveSkills[PLAYER_SKILL_STAFF] = 1;         // staff
  //uNumPlayers = 4;
  //while ( 1 )
  for (uNumPlayers = 0; uNumPlayers < 4; uNumPlayers++)
  {
    pCharacter = &pParty->pPlayers[uNumPlayers];
    if (pCharacter->classType == PLAYER_CLASS_KNIGHT)
      pCharacter->sResMagicBase = v3; //player[i].pResMagicBase
    uSpellBookPageCount = 0;
    //pMagicSkills = pPlayers[uNumPlayers].pActiveSkills[12];// Skills
    //while ( !*(short *)pMagicSkills )         //player[i].skillFire
	for (int i = 0; i < 9; i++)//for Magic Book
    {
      //++uSpellBookPageCount;
      //pMagicSkills++;
      //if ( uSpellBookPageCount >= 9 )
        //goto LABEL_10;
	    if (pPlayers[uNumPlayers].pActiveSkills[12+i])
			++uSpellBookPageCount;
    }
    pCharacter->pNumSpellBookPage = uSpellBookPageCount;
//LABEL_10:
    pCharacter->uExpressionTimePassed = 0;
    Dst.Reset();
    if ( bGiveItems )
    {
      pItemsTable->GenerateItem(2, 40, &Dst);
      pCharacter->AddItem2(-1, &Dst);
      //uSkillIdx = 0;
      //v18 = 0;
      //do
	  for (uSkillIdx = 0; uSkillIdx < 36; uSkillIdx++)
      {
        if ( pCharacter->pActiveSkills[uSkillIdx] )
        {
          switch ( uSkillIdx )
          {
            case PLAYER_SKILL_STAFF:
              v15 = ITEM_STAFF_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_SWORD:
              v15 = ITEM_LONGSWORD_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_DAGGER:
              v15 = ITEM_DAGGER_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_AXE:
              v15 = ITEM_AXE_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_SPEAR:
              v15 = ITEM_SPEAR_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_BOW:
              v15 = ITEM_CROSSBOW_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_MACE:
              v15 = ITEM_MACE_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_SHIELD:
              v15 = ITEM_BUCKLER_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_LEATHER:
              v15 = ITEM_LEATHER_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_CHAIN:
              v15 = ITEM_CHAINMAIL_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_PLATE:
              v15 = ITEM_PLATE_1;
              pCharacter->WearItem(v15);
              break;
            case PLAYER_SKILL_FIRE:
              v16 = ITEM_SPELLBOOK_FIRE_STRIKE;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_AIR:
              v16 = ITEM_SPELLBOOK_AIR_FEATHER_FALL;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_WATER:
              v16 = ITEM_SPELLBOOK_WATER_POISON_SPRAY;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_EARTH:
              v16 = ITEM_SPELLBOOK_EARTH_SLOW;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_SPIRIT:
              v16 = ITEM_SPELLBOOK_SPIRIT_BLESS;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_MIND:
              v16 = ITEM_SPELLBOOK_MIND_MIND_BLAST;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_BODY:
              v16 = ITEM_SPELLBOOK_BODY_FIRST_AID;
              pCharacter->AddItem(-1, v16);
              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:
              v16 = ITEM_BOOTS_1;
              pCharacter->AddItem(-1, v16);
              break;
            case PLAYER_SKILL_UNARMED:
              v16 = ITEM_GAUNTLETS_1;
              pCharacter->AddItem(-1, v16);
              break;
            default:
              break;
          }
        }
        //uSkillIdx = v18 + 1;
        //v11 = uSkillIdx > 36;
        //v9 = v18 == 35;
        //v10 = uSkillIdx - 35 < 0;
      }
      //while (uSkillIdx < 36);
      pAttributes = (char *)&pCharacter->pInventoryItems[0].uAttributes;
      //v13 = 138;
      for (v13 = 138; v13 > 0; --v13)
      {
        if ( *((int *)pAttributes - 5) )
          *(int *)pAttributes |= 1;
        pAttributes += 36;
        //--v13;
      }
      //while ( v13 );
    }
    pCharacter->sHealth = pCharacter->GetMaxHealth();
    pCharacter->sMana = pCharacter->GetMaxMana();
    //pCharacter++;
    //uNumPlayers--;
    //if (!uNumPlayers)
      //break;
    //pResMagicBase = (int)pCharacter;
    v3 = 10;
  }
}

//----- (004917CE) --------------------------------------------------------
int Party::Reset()
{
  //Party *v1; // esi@1
  //unsigned __int64 *pTimePlayed; // edi@1
  //bool v3; // edx@1
  //Player **v4; // eax@1
  //Player *v5; // ecx@1
  PLAYER_SEX pSex; // cl@3
  PLAYER_SEX v7; // al@6
  PLAYER_SEX v8; // al@9
  PLAYER_SEX v9; // cl@12
  //Player *v12; // edx@17
  //signed int v13; // edi@18
  SpellBuff *v14; // ebx@21
  signed int v15; // edi@21

  field_708 = 15;
  sEyelevel = 160;
  uFlags2 = 0;
  uNumGold = 200;
  uNumGoldInBank = 0;
  uNumFoodRations = 7;
  uAlignment = 1;

  SetUserInterface(uAlignment, true);

  uTimePlayed = 0x21C00u;
  uLastRegenerationTime = 0x21C00;

  bTurnBasedModeOn = false;

  uActiveCharacter = 1;
  ::pPlayers[0] = pPlayers;
  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].uFace = 17;
  pPlayers[0].field_1924 = 17;
  pPlayers[0].uVoiceID = 17;
  pPlayers[0].SetInitialStats();
 
  switch ( pPlayers[0].uVoiceID )
  {
    case 0:
    case 1:
    case 2:
    case 3:
    case 8:
    case 9:
    case 12:
    case 13:
    case 16:
    case 17:
    case 20:
    case 23:
    default:
      pSex = SEX_MALE;
      break;
    case 4:
    case 5:
    case 6:
    case 7:
    case 10:
    case 11:
    case 14:
    case 15:
    case 18:
    case 19:
    case 21:
    case 24:
      pSex = SEX_FEMALE;
      break;
  }
  pPlayers[0].uSex = pSex;
  pPlayers[0].RandomizeName();
  strcpy(pPlayers[0].pName, pGlobalTXT_LocalizationStrings[509]);


  pPlayers[1].uFace = 3;
  pPlayers[1].field_1924 = 3;
  pPlayers[1].uVoiceID = 3;
  pPlayers[1].SetInitialStats();
  v7 = SEX_MALE;
  switch (pPlayers[1].uVoiceID)
  {
    case 0:
    case 1:
    case 2:
    case 3:
    case 8:
    case 9:
    case 0xCu:
    case 0xDu:
    case 0x10u:
    case 0x11u:
    case 0x14u:
    case 0x17u:
      v7 = SEX_MALE;
      break;
    case 4:
    case 5:
    case 6:
    case 7:
    case 0xAu:
    case 0xBu:
    case 0xEu:
    case 0xFu:
    case 0x12u:
    case 0x13u:
    case 0x15u:
    case 0x18u:
      v7 = SEX_FEMALE;
      break;
    default:
      break;
  }
  pPlayers[1].uSex = v7;
  pPlayers[1].RandomizeName();
  strcpy(pPlayers[1].pName, pGlobalTXT_LocalizationStrings[506]);
  pPlayers[2].uFace = 14;
  pPlayers[2].field_1924 = 14;
  pPlayers[2].uVoiceID = 14;
  pPlayers[2].SetInitialStats();
  v8 = SEX_MALE;
  switch (pPlayers[2].uVoiceID)
  {
    case 0:
    case 1:
    case 2:
    case 3:
    case 8:
    case 9:
    case 0xCu:
    case 0xDu:
    case 0x10u:
    case 0x11u:
    case 0x14u:
    case 0x17u:
      v8 = SEX_MALE;
      break;
    case 4:
    case 5:
    case 6:
    case 7:
    case 0xAu:
    case 0xBu:
    case 0xEu:
    case 0xFu:
    case 0x12u:
    case 0x13u:
    case 0x15u:
    case 0x18u:
      v8 = SEX_FEMALE;
      break;
    default:
      break;
  }
  pPlayers[2].uSex = v8;
  pPlayers[2].RandomizeName();
  strcpy(pPlayers[2].pName, pGlobalTXT_LocalizationStrings[508]);
  pPlayers[3].uFace = 10;
  pPlayers[3].field_1924 = 10;
  pPlayers[3].uVoiceID = 10;
  pPlayers[3].SetInitialStats();
  v9 = SEX_MALE;
  switch (pPlayers[3].uVoiceID)
  {
    case 0u:
    case 1u:
    case 2u:
    case 3u:
    case 8u:
    case 9u:
    case 0xCu:
    case 0xDu:
    case 0x10u:
    case 0x11u:
    case 0x14u:
    case 0x17u:
      v9 = SEX_MALE;
      break;
    case 4u:
    case 5u:
    case 6u:
    case 7u:
    case 0xAu:
    case 0xBu:
    case 0xEu:
    case 0xFu:
    case 0x12u:
    case 0x13u:
    case 0x15u:
    case 0x18u:
      v9 = SEX_FEMALE;
      break;
    default:
      break;
  }
  pPlayers[3].uSex = v9;
  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;
  uFlags = 0;

  memset(_award_bits, 0, 64);
  _449B7E_toggle_bit(_award_bits, 1, 1);
  _449B7E_toggle_bit(_award_bits, 2, 1);
  _449B7E_toggle_bit(_award_bits, 3, 1);
  _449B7E_toggle_bit(_award_bits, 4, 1);
  _449B7E_toggle_bit(_award_bits, 5, 1);
  _449B7E_toggle_bit(_award_bits, 6, 1);


  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
  unsigned int v4; // [sp+8h] [bp-4h]@4

  if ( (signed __int64)pParty->pPartyBuffs[11].uExpireTime > 0 )
    pParty->pPartyBuffs[11].Reset();
  if ( pParty->bTurnBasedModeOn != 1 )
  {
    v4 = 0;
    if ( (signed int)uNumActors > 0 )
    {
      v0 = pActors;//[0].pMonsterInfo.uMovementType;
      do
      {
		if ( v0->Actor::CanAct() && v0->pMonsterInfo.uHostilityType != 4 && v0->pMonsterInfo.uMovementType != 5 )
        {
		  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 ( (double)sub_4621DA(v1, v2, v3) < 512.0 )
            Actor::_402968(v4, 4, 0, 0);
        }
        ++v4;
        ++v0;
      }
      while ( (signed int)v4 < (signed int)uNumActors );
    }
  }
}

//----- (00491BF9) --------------------------------------------------------
void Party::ResetPosMiscAndSpellBuffs()
{
  Party *v1; // esi@1
  Player *v2; // edi@1
  SpellBuff *v3; // ebx@2
  SpellBuff *v4; // esi@5
  signed int v5; // edi@5
  signed int v6; // [sp+8h] [bp-8h]@1
  signed int v7; // [sp+Ch] [bp-4h]@2

  v1 = this;
  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 = 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;
  v2 = this->pPlayers;//[0].pPlayerBuffs;
  v6 = 4;
  do
  {
    v3 = v2->pPlayerBuffs;
    v7 = 24;
    do
    {
      v3->Reset();
      ++v3;
      --v7;
    }
    while ( v7 );
    ++v2;
    --v6;
  }
  while ( v6 );
  v4 = v1->pPartyBuffs;
  v5 = 20;
  do
  {
    v4->Reset();
    ++v4;
    --v5;
  }
  while ( v5 );
}

//----- (004909F4) --------------------------------------------------------
void Party::UpdatePlayersAndHirelingsEmotions()
{
  //Player *v1; // esi@2
  //unsigned int v2; // eax@3
  //__int16 v3; // cx@5
  int v4; // edx@27
  //signed int v5; // eax@52
  //PlayerFrame *v6; // edx@53
  //NPCData *v7; // esi@60
  //signed int v8; // ebp@61
  //int v9; // ebx@62
  //unsigned int v10; // edi@62
  //signed int v11; // [sp+0h] [bp-4h]@2

  if (dword_A75070 == stru_51076C.field_8)
    return;

  dword_A75070 = stru_51076C.field_8;
  //v1 = this->pPlayers;//(char *)&this->pPlayers[0].uExpressionID;
  for (int i = 0; i < 4; ++i)
  {
    auto player = pPlayers + i;
    player->uExpressionTimePassed += (unsigned short)pMiscTimer->uTimeElapsed;


    auto condition = player->GetMajorConditionIdx();
    if (condition == Player::Condition_Good || condition == Player::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 (int j = 0; j < pPlayerFrameTable->uNumFrames; ++j)
      {
        auto frame = pPlayerFrameTable->pFrames + j;
        if (frame->expression == player->expression)
        {
          player->uExpressionTimeLength = 8 * pPlayerFrameTable->pFrames[j].uAnimLength;
          break;
        }
      }
    }
    else if (player->expression != 34 &&
             player->expression != 35 &&
             player->expression != 36 ||
             player->uExpressionTimePassed >= player->uExpressionTimeLength)
    {
      player->uExpressionTimeLength = 0;
      player->uExpressionTimePassed = 0;

      switch (condition)
      {
        case Player::Condition_Dead:        player->expression = CHARACTER_EXPRESSION_DEAD;      break;
        case Player::Condition_Pertified:   player->expression = CHARACTER_EXPRESSION_PERTIFIED; break;
        case Player::Condition_Eradicated:  player->expression = CHARACTER_EXPRESSION_ERADICATED; break;
        case Player::Condition_Cursed:      player->expression = CHARACTER_EXPRESSION_CURSED; break;
        case Player::Condition_Weak:        player->expression = CHARACTER_EXPRESSION_WEAK; break;
        case Player::Condition_Sleep:       player->expression = CHARACTER_EXPRESSION_SLEEP; break;
        case Player::Condition_Fear:        player->expression = CHARACTER_EXPRESSION_FEAR; break;
        case Player::Condition_Drunk:       player->expression = CHARACTER_EXPRESSION_DRUNK; break;
        case Player::Condition_Insane:      player->expression = CHARACTER_EXPRESSION_INSANE; break;
        case Player::Condition_Poison1:
        case Player::Condition_Poison2:
        case Player::Condition_Poison3:     player->expression = CHARACTER_EXPRESSION_POISONED; break;
        case Player::Condition_Disease1:
        case Player::Condition_Disease2:
        case Player::Condition_Disease3:    player->expression = CHARACTER_EXPRESSION_DISEASED; break;
        case Player::Condition_Paralyzed:   player->expression = CHARACTER_EXPRESSION_PARALYZED; break;
        case Player::Condition_Unconcious:  player->expression = CHARACTER_EXPRESSION_UNCONCIOUS; break;
        default:
          assert(false);
      }
    }
  }


  for (int i = 0; i < 2; ++i)
  {
    auto hireling = pParty->pHirelings + i;
    if (!hireling->_anim_end_time)
      continue;

    hireling->_anim_current_time += pMiscTimer->uTimeElapsed;
    if (hireling->_anim_current_time >= hireling->_anim_end_time)
    {
      hireling->bDrawSomeAnim = false;
      hireling->_anim_current_time = 0;
      hireling->_anim_end_time = 0;

      assert(sizeof(NPCData) == 0x4C);
      memset(hireling, 0, sizeof(*hireling));

      pParty->field_709 = 0;
      sub_44A56A();
      viewparams->bRedrawGameUI = 1;
    }
  }
}

//----- (00490D02) --------------------------------------------------------
void Party::RestAndHeal()
{
  SpellBuff *v1; // esi@1
  Player *v2; // esi@4
  signed int v3; // ebx@4
  SpellBuff *v4; // edi@4
  int v5; // eax@9
  char v6; // zf@9
  ItemGen *v7; // eax@10
  signed int v8; // ecx@10
  int v9; // eax@18
  int v10; // eax@25
  signed int v11; // ecx@26
  signed int v12; // [sp-4h] [bp-1Ch]@26
  Party *v13; // [sp+Ch] [bp-Ch]@1
  signed int v14; // [sp+10h] [bp-8h]@10
  signed int v15; // [sp+14h] [bp-4h]@3

  v13 = this;
  v1 = pParty->pPartyBuffs;
  do
  {
    v1->Reset();
    ++v1;
  }
  while ( (signed int)v1 < (signed int)pParty->pPlayers );
  v15 = 0;
  do
  {
    v2 = &pParty->pPlayers[v15];
    v3 = 20;
    v4 = v2->pPlayerBuffs;
    do
    {
      v4->Reset();
      ++v4;
      --v3;
    }
    while ( v3 );
    v2->Zero();
    if ( v2->pConditions[14] || v2->pConditions[15] || v2->pConditions[16] )
      goto LABEL_33;
    LODWORD(v2->pConditions[13]) = 0;
    HIDWORD(v2->pConditions[13]) = 0;
    LODWORD(v2->pConditions[4]) = 0;
    HIDWORD(v2->pConditions[4]) = 0;
    LODWORD(v2->pConditions[2]) = 0;
    HIDWORD(v2->pConditions[2]) = 0;
    LODWORD(v2->pConditions[3]) = 0;
    HIDWORD(v2->pConditions[3]) = 0;
    LODWORD(v2->pConditions[1]) = 0;
    HIDWORD(v2->pConditions[1]) = 0;
    v2->uTimeToRecovery = 0;
    v2->sHealth = v2->GetMaxHealth();
    v5 = v2->GetMaxMana();
    v6 = v2->classType == PLAYER_CLASS_LICH;
    v2->sMana = v5;
    if ( v6 )
    {
      v14 = 0;
      v7 = v2->pInventoryItems;//[0].field_1A;
      v8 = 138;
      do
      {
		if ( v7->uItemID == 601 && (unsigned __int8)v7->field_1A== v15 + 1 )
          v14 = 1;
        ++v7;
        --v8;
      }
      while ( v8 );
      if ( !v14 )
      {
        v2->sHealth = v2->GetMaxHealth() / 2;
        v2->sMana = v2->GetMaxMana() / 2;
      }
    }
    if ( !v2->pConditions[17] )
    {
      if ( v2->pConditions[10] || v2->pConditions[11] )
      {
        v11 = 4;
        v12 = 4;
      }
      else
      {
        if ( !v2->pConditions[8] && !v2->pConditions[9] )
        {
          if ( !v2->pConditions[6] && !v2->pConditions[7] )
            goto LABEL_30;
          v2->sHealth /= 2;
          v10 = v2->sMana / 2;
          goto LABEL_29;
        }
        v11 = 3;
        v12 = 3;
      }
      v2->sHealth /= v11;
      v10 = v2->sMana / v12;
LABEL_29:
      v2->sMana = v10;
      goto LABEL_30;
    }
    v9 = v2->sHealth;
    v2->sMana = 0;
    v2->sHealth = v9 / 2;
LABEL_30:
    if ( v2->pConditions[5] )
      v2->sMana = 0;
    UpdatePlayersAndHirelingsEmotions();
LABEL_33:
    ++v15;
  }
  while ( v15 < 4 );
  pParty->field_764 = 0;
}