World of Might and Magic  0.2.0
Open reimplementation of Might and Magic 6 7 8 game engine
Actor.cpp
См. документацию.
1 #include "Engine/Objects/Actor.h"
2 
3 #include "Engine/Engine.h"
4 #include "Engine/Localization.h"
6 #include "Engine/Time.h"
7 
8 #include "GUI/GUIWindow.h"
9 #include "GUI/UI/UIGame.h"
10 #include "GUI/UI/UIStatusBar.h"
11 
13 
14 #include "../Graphics/DecalBuilder.h"
15 #include "../Graphics/Level/Decoration.h"
16 #include "../Graphics/Outdoor.h"
17 #include "../Graphics/Overlays.h"
18 #include "../Graphics/PaletteManager.h"
19 #include "../Graphics/Sprites.h"
20 #include "../Graphics/Viewport.h"
21 #include "../Graphics/Vis.h"
22 #include "../LOD.h"
23 #include "../OurMath.h"
24 #include "../Party.h"
25 #include "../Spells/CastSpellInfo.h"
26 #include "../Tables/FactionTable.h"
27 #include "../TurnEngine/TurnEngine.h"
28 #include "../stru298.h"
29 #include "ObjectList.h"
30 #include "SpriteObject.h"
31 
33 
34 // should be injected into Actor but struct size cant be changed
37 
38 std::array<Actor, 500> pActors;
39 size_t uNumActors;
40 
42 
43 std::array<uint, 5> _4DF380_hostilityRanges = {0, 1024, 2560, 5120, 10240};
44 
45 //----- (0042FB5C) --------------------------------------------------------
46 // True if monster should play attack animation when casting this spell.
47 bool ShouldMonsterPlayAttackAnim(signed int spell_id) {
48  switch (spell_id) {
49  case SPELL_FIRE_HASTE:
50  case SPELL_AIR_SHIELD:
52  case SPELL_SPIRIT_BLESS:
53  case SPELL_SPIRIT_FATE:
61  return false;
62  }
63  return true;
64 }
65 
66 //----- (0041AF52) --------------------------------------------------------
68  // bar length
69  unsigned int bar_length;
70  if (actor->pMonsterInfo.uHP <= 25)
71  bar_length = 25;
72  else if (actor->pMonsterInfo.uHP < 200)
73  bar_length = actor->pMonsterInfo.uHP;
74  else
75  bar_length = 200;
76 
77  // bar colour
78  Image *bar_image = game_ui_monster_hp_green;
79  if (actor->sCurrentHP <= (0.34 * actor->pMonsterInfo.uHP))
80  bar_image = game_ui_monster_hp_red;
81  else if (actor->sCurrentHP <= (0.67 * actor->pMonsterInfo.uHP))
82  bar_image = game_ui_monster_hp_yellow;
83 
84  // how much of bar is filled
85  unsigned int bar_filled_length = bar_length;
86  if (actor->sCurrentHP < (int)actor->pMonsterInfo.uHP)
87  bar_filled_length = (bar_length * actor->sCurrentHP) / actor->pMonsterInfo.uHP;
88 
89  // centralise for clipping and draw
90  unsigned int uX = window->uFrameX + (signed int)(window->uFrameWidth - bar_length) / 2;
91 
92  render->SetUIClipRect(uX, window->uFrameY + 32, uX + bar_length, window->uFrameY + 52);
93  render->DrawTextureAlphaNew(uX / 640.0f, (window->uFrameY + 32) / 480.0f,
95 
96  render->SetUIClipRect(uX, window->uFrameY + 32, uX + bar_filled_length,
97  window->uFrameY + 52);
98  render->DrawTextureAlphaNew(uX / 640.0f, (window->uFrameY + 34) / 480.0f,
99  bar_image);
100 
101  // draw hp bar ends
102  render->ResetUIClipRect();
103  render->DrawTextureAlphaNew((uX - 5) / 640.0f,
104  (window->uFrameY + 32) / 480.0f,
106  render->DrawTextureAlphaNew((uX + bar_length) / 640.0f,
107  (window->uFrameY + 32) / 480.0f,
109 }
110 
111 //----- (00448A40) --------------------------------------------------------
112 void Actor::ToggleFlag(signed int uActorID, unsigned int uFlag, int bToggle) {
113  if (uActorID >= 0 && uActorID <= (signed int)(uNumActors - 1)) {
114  if (bToggle) {
115  pActors[uActorID].uAttributes |= uFlag;
116  } else {
117  if (uFlag == 0x10000) {
118  if (pActors[uActorID].uAIState == Disabled)
119  pActors[uActorID].uAIState = Standing;
120  }
121  pActors[uActorID].uAttributes &= ~uFlag;
122  }
123  }
124 }
125 
126 //----- (00448518) --------------------------------------------------------
127 void sub_448518_npc_set_item(int npc, unsigned int item, int a3) {
128  for (uint i = 0; i < uNumActors; i++) {
129  if (pActors[uNumActors].sNPC_ID == npc) Actor::GiveItem(i, item, a3);
130  }
131 }
132 
133 //----- (004485A7) --------------------------------------------------------
134 void Actor::GiveItem(signed int uActorID, unsigned int uItemID,
135  unsigned int bGive) {
136  if ((uActorID >= 0) &&
137  (signed int)uActorID <= (signed int)(uNumActors - 1)) {
138  if (bGive) {
139  if (pActors[uActorID].uCarriedItemID == ITEM_NULL)
140  pActors[uActorID].uCarriedItemID = uItemID;
141  else if (pActors[uActorID].ActorHasItems[0].uItemID == ITEM_NULL)
142  pActors[uActorID].ActorHasItems[0].uItemID = uItemID;
143  else if (pActors[uActorID].ActorHasItems[1].uItemID == ITEM_NULL)
144  pActors[uActorID].ActorHasItems[1].uItemID = uItemID;
145  } else {
146  if (pActors[uActorID].uCarriedItemID == uItemID)
147  pActors[uActorID].uCarriedItemID = ITEM_NULL;
148  else if (pActors[uActorID].ActorHasItems[0].uItemID == uItemID)
149  pActors[uActorID].ActorHasItems[0].Reset();
150  else if (pActors[uActorID].ActorHasItems[1].uItemID == uItemID)
151  pActors[uActorID].ActorHasItems[1].Reset();
152  }
153  }
154 }
155 
156 //----- (0040894B) --------------------------------------------------------
158  bool stoned = this->pActorBuffs[ACTOR_BUFF_STONED].Active();
159  bool paralyzed = this->pActorBuffs[ACTOR_BUFF_PARALYZED].Active();
160  return !(stoned || paralyzed || this->uAIState == Dying ||
161  this->uAIState == Dead || this->uAIState == Removed ||
162  this->uAIState == Summoned || this->uAIState == Disabled);
163 }
164 
165 //----- (004089C7) --------------------------------------------------------
167  bool stoned = this->pActorBuffs[ACTOR_BUFF_STONED].Active();
168  return (stoned || (uAIState == Dying) || (uAIState == Dead) ||
169  (uAIState == Removed) || (uAIState == Summoned) ||
170  (uAIState == Disabled));
171 }
172 
173 //----- (004086E9) --------------------------------------------------------
175  int v2; // edi@1
176 
177  v2 = 0;
178  if (!this->ActorHasItems[3].uItemID) {
179  if (this->pMonsterInfo.uTreasureDiceRolls) {
180  for (int i = 0; i < this->pMonsterInfo.uTreasureDiceRolls; i++)
181  v2 += rand() % this->pMonsterInfo.uTreasureDiceSides + 1;
182  if (v2) {
185  (ITEM_ENCHANTMENT)v2; // actual gold amount
186  }
187  }
188  }
189  if (rand() % 100 < this->pMonsterInfo.uTreasureDropChance) {
190  if (this->pMonsterInfo.uTreasureLevel)
192  this->pMonsterInfo.uTreasureType,
193  &this->ActorHasItems[2]);
194  }
195  this->uAttributes |= ACTOR_HAS_ITEM;
196 }
197 
198 //----- (00404AC7) --------------------------------------------------------
199 void Actor::AI_SpellAttack(unsigned int uActorID, AIDirection *pDir,
200  int uSpellID, int a4, unsigned int uSkillLevel) {
201  Actor *actorPtr; // esi@1
202  unsigned int realPoints; // edi@1
203  unsigned int masteryLevel; // eax@1
204  int v8; // edi@16
205  signed int v10; // ecx@22
206  int v19; // edi@34
207  int v20; // eax@35
208  signed int v23; // eax@41
209  int v28; // st6@50
210  int v30; // esi@50
211  int v31; // ST3C_4@51
212  unsigned int v32; // edi@51
213  signed int v36; // eax@67
214  int v39; // ecx@75
215  int v42; // ecx@91
216  int v44; // ecx@100
217  int v48; // ecx@110
218  int v51; // ecx@130
219  int v54; // ecx@138
220  int v59; // edi@146
221  int v61; // edi@146
222  signed int v63; // edi@146
223  int v68; // edi@168
224  signed int v70; // ecx@172
225  int v79; // edx@185
226  int v80; // eax@185
227  signed int v91; // eax@200
228  int v94; // ecx@208
229  int v96; // ecx@217
230  int pitch; // [sp+2Ch] [bp-A4h]@51
231  int v114; // [sp+48h] [bp-88h]@41
232  SpriteObject a1; // [sp+4Ch] [bp-84h]@1
233  int v116; // [sp+BCh] [bp-14h]@49
234  int v118; // [sp+C4h] [bp-Ch]@29
235  int v119; // [sp+C8h] [bp-8h]@48
236  int v120; // [sp+CCh] [bp-4h]@1
237  int spellnuma; // [sp+D8h] [bp+8h]@29
238  int spellnumb; // [sp+D8h] [bp+8h]@48
239  int spellnumc; // [sp+D8h] [bp+8h]@50
240  int spellnume; // [sp+D8h] [bp+8h]@179
241  int a1a; // [sp+E0h] [bp+10h]@34
242  int a1c; // [sp+E0h] [bp+10h]@184
243 
244  GameTime spell_length = GameTime(0);
245 
246  actorPtr = &pActors[uActorID];
247  realPoints = uSkillLevel & 0x3F;
248  masteryLevel = SkillToMastery(uSkillLevel);
249 
250  switch (uSpellID) {
252  case SPELL_FIRE_FIREBALL:
257  case SPELL_EARTH_BLADES:
261  case SPELL_BODY_HARM:
265  a1.uType = spell_sprite_mapping[uSpellID].uSpriteType;
266  a1.uObjectDescID = GetObjDescId(uSpellID);
267  a1.containing_item.Reset();
268  a1.spell_id = uSpellID;
269  a1.spell_level = uSkillLevel;
270  a1.vPosition.x = actorPtr->vPosition.x;
271  a1.spell_skill = 0;
272  a1.vPosition.y = actorPtr->vPosition.y;
273  a1.vPosition.z = actorPtr->vPosition.z +
274  ((signed int)actorPtr->uActorHeight >> 1);
275  a1.uFacing = (short)pDir->uYawAngle;
276  a1.uSoundID = 0;
277  a1.uAttributes = 0;
278  a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y,
279  a1.vPosition.z);
280  a1.uSpriteFrameID = 0;
281  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
282  a1.spell_target_pid = 0;
283  if ((double)pDir->uDistance < 307.2)
285  else if (pDir->uDistance < 1024)
287  else if (pDir->uDistance < 2560)
289  else
291 
292  a1.field_61 = 2;
293  v91 = a1.Create(
294  pDir->uYawAngle, pDir->uPitchAngle,
296  if (v91 != -1) {
297  pAudioPlayer->PlaySpellSound(uSpellID, PID(OBJECT_Item, v91));
298  return;
299  }
300  return;
301  break;
302 
303  case SPELL_FIRE_HASTE:
304  if (masteryLevel == 1 || masteryLevel == 2)
305  v39 = 60 * (realPoints + 60);
306  else if (masteryLevel == 3)
307  v39 = 2 * 60 * (realPoints + 20);
308  else if (masteryLevel == 4)
309  v39 = 3 * 60 * (realPoints + 15);
310  else
311  v39 = 0;
312 
313  spell_length = GameTime::FromMinutes(v39 / 60);
314 
315  actorPtr->pActorBuffs[ACTOR_BUFF_HASTE].Apply((pParty->GetPlayingTime() + spell_length),
316  masteryLevel, 0, 0, 0);
319  PID(OBJECT_Actor, uActorID), 0, -1, 0,
320  0);
321  return;
322 
325  v114 = pParty->vPosition.z + 2500;
326  v23 = 8;
327  if (masteryLevel == 2)
328  v23 = 10;
329  else if (masteryLevel == 3)
330  v23 = 12;
331  else if (masteryLevel == 4)
332  v23 = 14;
333  spellnumb = 0;
334  v28 = 0;
335  for (int i = 0; i < v23; i++) {
336  v30 = rand() % 1000;
337  spellnumc = v30 - 2500;
338  v120 = v28 * v28;
339  v119 = spellnumb * spellnumb;
340  if (sqrt((float)(spellnumc * spellnumc + v119 + v120)) <= 1.0) {
341  v32 = 0;
342  pitch = 0;
343  } else {
344  v31 = (signed __int64)sqrt((float)(v119 + v120));
345  v32 = stru_5C6E00->Atan2(spellnumb, (int)v28);
346  pitch = stru_5C6E00->Atan2(v31, (int)spellnumc);
347  }
348  a1.containing_item.Reset();
349  a1.uType = spell_sprite_mapping[uSpellID].uSpriteType;
350  a1.uObjectDescID = GetObjDescId(uSpellID);
351  a1.spell_level = uSkillLevel;
352  a1.vPosition.x = pParty->vPosition.x;
353  a1.vPosition.y = pParty->vPosition.y;
354  a1.vPosition.z = v30 + v114;
356  a1.spell_skill = 0;
357  a1.uAttributes = 0;
358  a1.uSectorID = 0;
359  a1.uSpriteFrameID = 0;
360  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
361  a1.spell_target_pid = 0;
363  stru_50C198._427546(v30 + 2500);
364  a1.uFacing = v32;
365  a1.uSoundID = 0;
366  if (pDir->uDistance < 307.2)
368  else if (pDir->uDistance < 1024)
370  else if (pDir->uDistance < 2560)
372  else
374  a1.field_61 = 2;
375  v36 = a1.Create(
376  v32, pitch,
377  pObjectList->pObjects[(signed __int16)a1.uObjectDescID]
378  .uSpeed,
379  0);
380  if (v36 != -1) {
381  pAudioPlayer->PlaySpellSound(9, PID(OBJECT_Item, v36));
382  }
383  spellnumb = rand() % 1024 - 512;
384  v28 = rand() % 1024 - 512;
385  }
386  return;
387  break;
388 
389  case SPELL_AIR_SPARKS:
390  if (masteryLevel == 2)
391  v10 = 5;
392  else if (masteryLevel == 3)
393  v10 = 7;
394  else if (masteryLevel == 4)
395  v10 = 9;
396  else
397  v10 = 3;
398  spellnuma = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360;
399  a1.uType = spell_sprite_mapping[uSpellID].uSpriteType;
400  v118 = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360 /
401  (v10 - 1);
402  a1.uObjectDescID = GetObjDescId(uSpellID);
403 
404  a1.containing_item.Reset();
406  a1.spell_level = uSkillLevel;
407  a1.vPosition.x = actorPtr->vPosition.x;
408  a1.spell_skill = 0;
409  a1.vPosition.y = actorPtr->vPosition.y;
410  a1.vPosition.z = actorPtr->vPosition.z +
411  ((signed int)actorPtr->uActorHeight >> 1);
412  a1.uFacing = pDir->uYawAngle;
413  a1.uSoundID = 0;
414  a1.uAttributes = 0;
415  a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y,
416  a1.vPosition.z);
417  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
418  a1.uSpriteFrameID = 0;
419  a1.spell_target_pid = 0;
421  v19 = spellnuma / -2;
422  a1a = spellnuma / 2;
423  if (spellnuma / -2 > spellnuma / 2) {
424  v20 = spellnuma / 2;
425  } else {
426  do {
427  a1.uFacing = v19 + (short)pDir->uYawAngle;
428  v20 = a1.Create(
429  (int16_t)a1.uFacing, pDir->uPitchAngle,
431  .uSpeed,
432  0);
433  v19 += v118;
434  } while (v19 <= a1a);
435  }
436  if (v20 != -1) {
437  pAudioPlayer->PlaySpellSound(15, PID(OBJECT_Item, v20));
438  return;
439  }
440  return;
441  break;
442 
443  case SPELL_AIR_SHIELD:
444  if (masteryLevel == 1 || masteryLevel == 2)
445  v8 = 5 * 60 * realPoints + 3840;
446  else if (masteryLevel == 3)
447  v8 = 15 * 60 * realPoints + 3840;
448  else if (masteryLevel == 4)
449  v8 = 60 * 60 * (realPoints + 64);
450  else
451  v8 = 0;
452  spell_length = GameTime::FromMinutes(v8 / 60);
454  (pParty->GetPlayingTime() + spell_length),
455  masteryLevel, 0, 0, 0);
456  return;
457 
459  if (masteryLevel == 1 || masteryLevel == 2)
460  v44 = 5 * 60 * realPoints + 3840;
461  else if (masteryLevel == 3)
462  v44 = 15 * 60 * realPoints + 3840;
463  else if (masteryLevel == 4)
464  v44 = 60 * 60 * (realPoints + 64);
465  else
466  v44 = 0;
467  spell_length = GameTime::FromMinutes(v44 / 60);
469  (pParty->GetPlayingTime() + spell_length),
470  masteryLevel, realPoints + 5, 0, 0);
473  PID(OBJECT_Actor, uActorID), 0, -1, 0, 0);
474  return;
475 
476  case SPELL_SPIRIT_BLESS:
477  if (masteryLevel == 1 || masteryLevel == 2)
478  v42 = 5 * 60 * realPoints + 3840;
479  else if (masteryLevel == 3)
480  v42 = 15 * 60 * realPoints + 3840;
481  else if (masteryLevel == 4)
482  v42 = 20 * 60 * realPoints + 3840;
483  else
484  v42 = 0;
485  spell_length = GameTime::FromMinutes(v42 / 60);
487  (pParty->GetPlayingTime() + spell_length),
488  masteryLevel, realPoints + 5, 0, 0);
489 
492  PID(OBJECT_Actor, uActorID), 0, -1, 0,
493  0);
494  return;
495 
496  case SPELL_SPIRIT_FATE:
497  if (masteryLevel == 1 || masteryLevel == 2)
498  v48 = 2 * realPoints + 40;
499  else if (masteryLevel == 3)
500  v48 = 3 * realPoints + 60;
501  else if (masteryLevel == 4)
502  v48 = 2 * (3 * realPoints + 60);
503  else
504  v48 = 0;
505  spell_length = GameTime::FromMinutes(5);
506  actorPtr->pActorBuffs[ACTOR_BUFF_FATE].Apply(
507  (pParty->GetPlayingTime() + spell_length),
508  masteryLevel, v48, 0, 0);
511  PID(OBJECT_Actor, uActorID), 0, -1, 0,
512  0);
513  return;
514 
516  if (masteryLevel == 1 || masteryLevel == 2)
517  v54 = 5 * 60 * realPoints + 3840;
518  else if (masteryLevel == 3)
519  v54 = 15 * 60 * realPoints + 3840;
520  else if (masteryLevel == 4)
521  v54 = 20 * 60 * realPoints + 3840;
522  else
523  v54 = 0;
524  spell_length = GameTime::FromMinutes(v54 / 60);
526  (pParty->GetPlayingTime() + spell_length),
527  masteryLevel, realPoints + 5, 0, 0);
530  PID(OBJECT_Actor, uActorID), 0, -1, 0,
531  0);
532  return;
533 
535  if ((signed int)masteryLevel <= 0 || (signed int)masteryLevel > 4)
536  v51 = 0;
537  else
538  v51 = 60 * 60 * realPoints;
539  spell_length = GameTime::FromMinutes(v51 / 60);
541  (pParty->GetPlayingTime() + spell_length),
542  masteryLevel, realPoints, 0, 0);
545  PID(OBJECT_Actor, uActorID), 0, -1, 0,
546  0);
547  return;
548 
550  actorPtr->sCurrentHP += 5 * realPoints + 10;
551  if (actorPtr->sCurrentHP >= (signed int)actorPtr->pMonsterInfo.uHP)
552  actorPtr->sCurrentHP = (short)actorPtr->pMonsterInfo.uHP;
555  PID(OBJECT_Actor, uActorID), 0, -1, 0,
556  0);
557  return;
558 
560  for (int i = 0; i < 20; i++) pParty->pPartyBuffs[i].Reset();
561  for (int i = 1; i <= 4; i++) {
562  v59 = pPlayers[i]->GetParameterBonus(
563  pPlayers[i]->GetActualWillpower());
564  v61 = (pPlayers[i]->GetParameterBonus(
565  pPlayers[i]->GetActualIntelligence()) +
566  v59) /
567  2;
568  v63 = v61 +
569  pPlayers[i]->GetParameterBonus(
570  pPlayers[i]->GetActualLuck()) +
571  30;
572  if (rand() % v63 < 30) {
573  for (uint k = 0; k < pPlayers[i]->pPlayerBuffs.size(); k++)
574  pPlayers[i]->pPlayerBuffs[k].Reset();
575  pOtherOverlayList->_4418B1(11210, i + 99, 0, 65536);
576  }
577  }
578  pAudioPlayer->PlaySpellSound(80, PID(OBJECT_Actor, uActorID));
579  return;
580 
582  if (masteryLevel == 1 || masteryLevel == 2) {
583  v96 = 5 * 60 * realPoints + 128 * 30;
584  } else if (masteryLevel == 3) {
585  HEXRAYS_LOWORD(realPoints) = 3 * realPoints;
586  v96 = 15 * 60 * (uSkillLevel & 0x3F) + 128 * 30;
587  } else if (masteryLevel == 4) {
588  v96 = 20 * 60 * realPoints + 128 * 30;
589  HEXRAYS_LOWORD(realPoints) = 4 * realPoints;
590  } else {
591  HEXRAYS_LOWORD(realPoints) = uSkillLevel;
592  v96 = 0;
593  }
594  spell_length = GameTime::FromMinutes(v96 / 60);
596  (pParty->GetPlayingTime() + spell_length),
597  masteryLevel, realPoints, 0, 0);
600  PID(OBJECT_Actor, uActorID), 0, -1, 0,
601  0);
602  return;
603 
605  if (masteryLevel == 1 || masteryLevel == 2)
606  v94 = 5 * 60 * realPoints + 30 * 128;
607  else if (masteryLevel == 3)
608  v94 = 15 * 60 * realPoints + 30 * 128;
609  else if (masteryLevel == 4)
610  v94 = 20 * 60 * realPoints + 30 * 128;
611  else
612  v94 = 0;
613  spell_length = GameTime::FromMinutes(v94 / 60);
615  (pParty->GetPlayingTime() + spell_length),
616  masteryLevel, realPoints + 5, 0, 0);
619  PID(OBJECT_Actor, uActorID), 0, -1, 0,
620  0);
621  return;
622 
624  if (masteryLevel == 2)
625  v70 = 5;
626  else if (masteryLevel == 3)
627  v70 = 7;
628  else if (masteryLevel == 4)
629  v70 = 9;
630  else
631  v70 = 3;
632 
633  spellnume = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360;
634  a1.uType = spell_sprite_mapping[uSpellID].uSpriteType;
635  v116 = (signed int)(60 * stru_5C6E00->uIntegerDoublePi) / 360 /
636  (v70 - 1);
637  a1.uObjectDescID = GetObjDescId(uSpellID);
638  a1.containing_item.Reset();
639  a1.spell_id = uSpellID;
640  a1.spell_level = uSkillLevel;
641  a1.vPosition.x = actorPtr->vPosition.x;
642  a1.spell_skill = 0;
643  a1.vPosition.y = actorPtr->vPosition.y;
644  a1.vPosition.z = actorPtr->vPosition.z +
645  ((signed int)actorPtr->uActorHeight >> 1);
646  a1.uFacing = pDir->uYawAngle;
647  a1.uSoundID = 0;
648  a1.uAttributes = 0;
649  a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y,
650  a1.vPosition.z);
651  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
652  a1.uSpriteFrameID = 0;
653  a1.spell_target_pid = 0;
655  a1c = spellnume / -2;
656  if (spellnume / -2 > spellnume / 2) {
657  v80 = spellnume / -2;
658  } else {
659  do {
660  v79 = pDir->uYawAngle;
661  a1.uFacing = a1c + (short)pDir->uYawAngle;
662  v80 = a1.Create(
663  v79, pDir->uPitchAngle,
665  .uSpeed,
666  0);
667  a1c += v116;
668  } while (a1c <= spellnume / 2);
669  }
670  if (v80 != -1) {
671  pAudioPlayer->PlaySpellSound(93, PID(OBJECT_Item, v80));
672  return;
673  }
674  return;
675 
677  if (masteryLevel == 0)
678  v68 = 0;
679  else if (masteryLevel == 1 || (masteryLevel == 2) ||
680  (masteryLevel == 3))
681  v68 = 5 * 30 * realPoints + 30 * 128;
682  else
683  v68 = 15 * 30 * realPoints + 30 * 128;
684  spell_length = GameTime::FromMinutes(v68 / 60);
686  (pParty->GetPlayingTime() + spell_length),
687  masteryLevel, 0, 0, 0);
690  PID(OBJECT_Actor, uActorID), 0, -1, 0,
691  0);
692  return;
693  }
694 }
695 
696 unsigned short Actor::GetObjDescId(int spellId) {
697  return pObjectList->ObjectIDByItemID(spell_sprite_mapping[spellId].uSpriteType); // crash here
698 }
699 
701  unsigned int v2 = a1->uAlly;
702  if (!a1->uAlly) v2 = (a1->pMonsterInfo.uID - 1) / 3 + 1;
703 
704  unsigned int v3 = a2->uAlly;
705  if (!a2->uAlly) v3 = (a2->pMonsterInfo.uID - 1) / 3 + 1;
706 
707  if (v2 >= 39 && v2 <= 44 && v3 >= 39 && v3 <= 44 ||
708  v2 >= 45 && v2 <= 50 && v3 >= 45 && v3 <= 50 ||
709  v2 >= 51 && v2 <= 62 && v3 >= 51 && v3 <= 62 ||
710  v2 >= 78 && v2 <= 83 && v3 >= 78 && v3 <= 83 || v2 == v3)
711  return true;
712  else
713  return false;
714 }
715 
716 //----- (0043AC45) --------------------------------------------------------
717 void Actor::AggroSurroundingPeasants(unsigned int uActorID, int a2) {
718  int v4; // ebx@8
719  int v5; // ST1C_4@8
720  int v6; // eax@8
721 
722  int x = 0;
723  x |= 0x80000;
724  int y = 0;
725  y |= 0x80000;
726  Actor *victim = &pActors[uActorID];
727  if (a2 == 1) victim->uAttributes |= ACTOR_AGGRESSOR;
728 
729  for (uint i = 0; i < uNumActors; ++i) {
730  Actor *actor = &pActors[i];
731  if (!actor->CanAct() || i == uActorID) continue;
732 
733  if (Actor::ArePeasantsOfSameFaction(victim, actor)) {
734  v4 = abs(actor->vPosition.x - victim->vPosition.x);
735  v5 = abs(actor->vPosition.y - victim->vPosition.y);
736  v6 = abs(actor->vPosition.z - victim->vPosition.z);
737  if (int_get_vector_length(v4, v5, v6) < 4096) {
740  if (a2 == 1) actor->uAttributes |= ACTOR_AGGRESSOR;
741  }
742  }
743  }
744 }
745 
746 //----- (00404874) --------------------------------------------------------
747 void Actor::AI_RangedAttack(unsigned int uActorID, struct AIDirection *pDir,
748  int type, char a4) {
749  char specAb; // al@1
750  int v13; // edx@28
751 
752  SpriteObject a1; // [sp+Ch] [bp-74h]@1
753 
754  switch (type) {
755  case 1:
757  break;
758  case 2:
760  break;
761  case 3:
763  break;
764  case 4:
766  break;
767  case 5:
769  break;
770  case 6:
772  break;
773  case 7:
775  break;
776  case 8:
778  break;
779  case 9:
781  break;
782  case 10:
784  break;
785  case 11:
787  break;
788  case 13:
790  break;
791  default:
792  return;
793  }
794  bool found = false;
796  if (a1.uObjectDescID == 0) {
797  Error("Item not found");
798  return;
799  }
800  a1.containing_item.Reset();
801  a1.spell_id = 0;
802  a1.vPosition.x = pActors[uActorID].vPosition.x;
803  a1.vPosition.y = pActors[uActorID].vPosition.y;
804  a1.vPosition.z = pActors[uActorID].vPosition.z + (pActors[uActorID].uActorHeight * 0.75);
805  a1.spell_level = 0;
806  a1.spell_skill = 0;
807  a1.uFacing = pDir->uYawAngle;
808  a1.uSoundID = 0;
809  a1.uAttributes = 0;
810  a1.uSectorID =
811  pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z);
812  a1.uSpriteFrameID = 0;
813  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
814  a1.spell_target_pid = 0;
815  if (pDir->uDistance < 307.2)
817  else if (pDir->uDistance < 1024)
819  else if (pDir->uDistance < 2560)
821  else
823 
824  a1.field_61 = a4;
825  a1.Create(pDir->uYawAngle, pDir->uPitchAngle,
826  pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed,
827  0);
828  if (pActors[uActorID].pMonsterInfo.uSpecialAbilityType == 1) {
829  specAb = pActors[uActorID].pMonsterInfo.uSpecialAbilityDamageDiceBonus;
830  if (specAb == 2) {
831  a1.vPosition.z += 40;
832  v13 = pDir->uYawAngle;
833  } else {
834  if (specAb != 3) return;
835  a1.Create(
836  pDir->uYawAngle + 30, // TODO(_) find out why the YawAngle change
837  pDir->uPitchAngle,
838  pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed,
839  0);
840  v13 = pDir->uYawAngle - 30;
841  }
842  a1.Create(
843  v13, pDir->uPitchAngle,
844  pObjectList->pObjects[(signed __int16)a1.uObjectDescID].uSpeed, 0);
845  }
846  return;
847 }
848 
849 //----- (00404736) --------------------------------------------------------
850 void Actor::Explode(unsigned int uActorID) { // death explosion for some actors eg gogs
851  SpriteObject a1;
854  a1.containing_item.Reset();
855  a1.spell_id = 0;
856  a1.spell_level = 0;
857  a1.spell_skill = 0;
858  a1.vPosition.x = pActors[uActorID].vPosition.x;
859  a1.vPosition.y = pActors[uActorID].vPosition.y;
860  a1.vPosition.z = pActors[uActorID].vPosition.z + (pActors[uActorID].uActorHeight * 0.75);
861  a1.uFacing = 0;
862  a1.uSoundID = 0;
863  a1.uAttributes = 0;
864  a1.uSectorID = pIndoor->GetSector(a1.vPosition.x, a1.vPosition.y, a1.vPosition.z);
865  a1.uSpriteFrameID = 0;
866  a1.spell_caster_pid = PID(OBJECT_Actor, uActorID);
867  a1.spell_target_pid = 0;
869  a1.field_61 = 4;
870  a1.Create(0, 0, 0, 0);
871  return;
872 }
873 
874 //----- (004040E9) --------------------------------------------------------
875 // // Get direction vector from object1 to object2,
876 // // distance from object1 to object2 and Euler angles of the direction vector
877 // //
878 // //
879 // // object1 & object2 format : objectType | (objectID << 3)
880 // // objectType == 2 - SpriteObject
881 // // objectType == 3 - Actor
882 // // objectType == 4 - Party
883 // // objectType == 5 - Decoration
884 // //
885 // // originally this function had following prototype:
886 // // struct DirectionInfo GetDirectionInfo(signed int object1, signed int
887 // object2, signed int a4)
888 // // but compiler converts functions returning structures by value in the such
889 // way
890 void Actor::GetDirectionInfo(unsigned int uObj1ID, unsigned int uObj2ID,
891  struct AIDirection *pOut, int a4) {
892  signed int v4; // eax@1
893  signed int v5; // ecx@1
894  int v18; // edx@15
895  float v31; // st7@45
896  float v32; // st6@45
897  float v33; // st7@45
898  Vec3_int_ v37; // [sp-10h] [bp-5Ch]@15
899  AIDirection v41; // [sp+14h] [bp-38h]@46
900  float outy2 = 0; // [sp+38h] [bp-14h]@33
901  float outx2 = 0; // [sp+3Ch] [bp-10h]@33
902  int outz = 0; // [sp+40h] [bp-Ch]@6
903  int outy = 0; // [sp+44h] [bp-8h]@6
904  int outx = 0; // [sp+48h] [bp-4h]@6
905  float a4a; // [sp+58h] [bp+Ch]@45
906 
907  v4 = PID_ID(uObj1ID);
908  // v6 = uObj2ID;
909  v5 = PID_ID(uObj2ID);
910  switch (PID_TYPE(uObj1ID)) {
911  case OBJECT_Item: {
912  outx = pSpriteObjects[v4].vPosition.x;
913  outy = pSpriteObjects[v4].vPosition.y;
914  outz = pSpriteObjects[v4].vPosition.z;
915  break;
916  }
917  case OBJECT_Actor: {
918  outx = pActors[v4].vPosition.x;
919  outy = pActors[v4].vPosition.y;
920  outz = pActors[v4].vPosition.z + (pActors[v4].uActorHeight * 0.75);
921  break;
922  }
923  case OBJECT_Player: {
924  if (!v4) {
925  outx = pParty->vPosition.x;
926  outy = pParty->vPosition.y;
927  outz =
928  pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3;
929  break;
930  }
931  if (v4 == 4) {
933  v37.z =
934  pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3;
935  v37.x = pParty->vPosition.x;
936  v37.y = pParty->vPosition.y;
937  Vec3_int_::Rotate(24, v18, 0, v37, &outx, &outy, &outz);
938  break;
939  }
940  if (v4 == 3) {
942  v37.z =
943  pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3;
944  v37.x = pParty->vPosition.x;
945  v37.y = pParty->vPosition.y;
946  Vec3_int_::Rotate(8, v18, 0, v37, &outx, &outy, &outz);
947  break;
948  }
949  if (v4 == 2) {
950  v37.z =
951  pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3;
953  v37.x = pParty->vPosition.x;
954  v37.y = pParty->vPosition.y;
955  Vec3_int_::Rotate(8, v18, 0, v37, &outx, &outy, &outz);
956  break;
957  }
958  if (v4 == 1) {
959  v37.z =
960  pParty->vPosition.z + (signed int)pParty->uPartyHeight / 3;
962  v37.x = pParty->vPosition.x;
963  v37.y = pParty->vPosition.y;
964  Vec3_int_::Rotate(24, v18, 0, v37, &outx, &outy, &outz);
965  break;
966  }
967  }
968  case OBJECT_Decoration: {
969  outx = pLevelDecorations[v4].vPosition.x;
970  outy = pLevelDecorations[v4].vPosition.y;
971  outz = pLevelDecorations[v4].vPosition.z;
972  break;
973  }
974  default: {
975  outz = 0;
976  outy = 0;
977  outx = 0;
978  break;
979  }
980  case OBJECT_BModel: {
982  outx = (pIndoor->pFaces[v4].pBounding.x1 +
983  pIndoor->pFaces[v4].pBounding.x2) >>
984  1;
985  outy = (pIndoor->pFaces[v4].pBounding.y1 +
986  pIndoor->pFaces[v4].pBounding.y2) >>
987  1;
988  outz = (pIndoor->pFaces[v4].pBounding.z1 +
989  pIndoor->pFaces[v4].pBounding.z2) >>
990  1;
991  }
992  break;
993  }
994  }
995 
996  switch (PID_TYPE(uObj2ID)) {
997  case OBJECT_Item: {
998  outx2 = (float)pSpriteObjects[v5].vPosition.x;
999  outy2 = (float)pSpriteObjects[v5].vPosition.y;
1000  a4 = pSpriteObjects[v5].vPosition.z;
1001  break;
1002  }
1003  case OBJECT_Actor: {
1004  outx2 = (float)pActors[v5].vPosition.x;
1005  outy2 = (float)pActors[v5].vPosition.y;
1006  a4 = pActors[v5].vPosition.z + (pActors[v5].uActorHeight * 0.75);
1007  break;
1008  }
1009  case OBJECT_Player: {
1010  outx2 = (float)pParty->vPosition.x;
1011  outy2 = (float)pParty->vPosition.y;
1012  if (!a4) a4 = pParty->sEyelevel;
1013  a4 = pParty->vPosition.z + a4;
1014  break;
1015  }
1016  case OBJECT_Decoration: {
1017  outx2 = (float)pLevelDecorations[v5].vPosition.x;
1018  outy2 = (float)pLevelDecorations[v5].vPosition.y;
1019  a4 = pLevelDecorations[v5].vPosition.z;
1020  break;
1021  }
1022  default: {
1023  outx2 = 0.0;
1024  outy2 = 0.0;
1025  a4 = 0;
1026  break;
1027  }
1028  case OBJECT_BModel: {
1030  outx2 = (float)((pIndoor->pFaces[v5].pBounding.x1 +
1031  pIndoor->pFaces[v5].pBounding.x2) >>
1032  1);
1033  outy2 = (float)((pIndoor->pFaces[v5].pBounding.y1 +
1034  pIndoor->pFaces[v5].pBounding.y2) >>
1035  1);
1036  a4 = (pIndoor->pFaces[v5].pBounding.z1 +
1037  pIndoor->pFaces[v5].pBounding.z2) >>
1038  1;
1039  }
1040  break;
1041  }
1042  }
1043 
1044  v31 = (float)outx2 - (float)outx;
1045  v32 = (float)outy2 - (float)outy;
1046  a4a = (float)a4 - (float)outz;
1047  outx2 = v32 * v32;
1048  outy2 = v31 * v31;
1049  v33 = sqrt(a4a * a4a + outy2 + outx2);
1050  if (v33 <= 1.0) {
1051  pOut->vDirection.x = 65536;
1052  pOut->vDirection.y = 0;
1053  pOut->vDirection.z = 0;
1054  pOut->uDistance = 1;
1055  pOut->uDistanceXZ = 1;
1056  pOut->uYawAngle = 0;
1057  pOut->uPitchAngle = 0;
1058  } else {
1059  pOut->vDirection.x = (int32_t)(1.0 / v33 * v31 * 65536.0);
1060  pOut->vDirection.y = (int32_t)(1.0 / v33 * v32 * 65536.0);
1061  pOut->vDirection.z = (int32_t)(1.0 / v33 * a4a * 65536.0);
1062  pOut->uDistance = (uint)v33;
1063  pOut->uDistanceXZ = (uint)sqrt(outy2 + outx2);
1064  pOut->uYawAngle =
1065  stru_5C6E00->Atan2((signed __int64)v31, (signed __int64)v32);
1066  pOut->uPitchAngle =
1067  stru_5C6E00->Atan2(pOut->uDistanceXZ, (signed __int64)a4a);
1068  }
1069 }
1070 
1071 //----- (00404030) --------------------------------------------------------
1072 void Actor::AI_FaceObject(unsigned int uActorID, unsigned int uObjID, int UNUSED,
1073  AIDirection *Dir_In) {
1074  AIDirection *Dir_Out;
1075  AIDirection Dir_Ret;
1076 
1077  if (rand() % 100 >= 5) {
1078  if (!Dir_In) {
1079  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), uObjID, &Dir_Ret, 0);
1080  Dir_Out = &Dir_Ret;
1081  } else {
1082  Dir_Out = Dir_In;
1083  }
1084 
1085  pActors[uActorID].uYawAngle = Dir_Out->uYawAngle;
1086  pActors[uActorID].uCurrentActionTime = 0;
1087  pActors[uActorID].vVelocity.z = 0;
1088  pActors[uActorID].vVelocity.y = 0;
1089  pActors[uActorID].vVelocity.x = 0;
1090  pActors[uActorID].uPitchAngle = Dir_Out->uPitchAngle;
1091  pActors[uActorID].uCurrentActionLength = 256;
1092  pActors[uActorID].uAIState = Interacting;
1093  pActors[uActorID].UpdateAnimation();
1094  } else {
1095  Actor::AI_Bored(uActorID, uObjID, Dir_In);
1096  }
1097 }
1098 
1099 //----- (00403F58) --------------------------------------------------------
1100 void Actor::AI_StandOrBored(unsigned int uActorID, signed int uObjID,
1101  int uActionLength, AIDirection *a4) {
1102  if (rand() % 2) // 0 or 1
1103  AI_Bored(uActorID, uObjID, a4);
1104  else
1105  AI_Stand(uActorID, uObjID, uActionLength, a4);
1106 }
1107 
1108 //----- (00403EB6) --------------------------------------------------------
1109 void Actor::AI_Stand(unsigned int uActorID, unsigned int object_to_face_pid,
1110  unsigned int uActionLength, AIDirection *a4) {
1111  assert(uActorID < uNumActors);
1112  // Actor* actor = &pActors[uActorID];
1113 
1114  AIDirection a3;
1115  if (!a4) {
1116  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), object_to_face_pid,
1117  &a3, 0);
1118  a4 = &a3;
1119  }
1120 
1121  pActors[uActorID].uAIState = Standing;
1122  if (!uActionLength)
1123  pActors[uActorID].uCurrentActionLength =
1124  rand() % 256 + 256; // от 256 до 256 + 256
1125  else
1126  pActors[uActorID].uCurrentActionLength = uActionLength;
1127  pActors[uActorID].uCurrentActionTime = 0;
1128  pActors[uActorID].uYawAngle = a4->uYawAngle;
1129  pActors[uActorID].uPitchAngle = a4->uPitchAngle;
1130  pActors[uActorID].vVelocity.z = 0;
1131  pActors[uActorID].vVelocity.y = 0;
1132  pActors[uActorID].vVelocity.x = 0;
1133  pActors[uActorID].UpdateAnimation();
1134 }
1135 
1136 //----- (00403E61) --------------------------------------------------------
1137 void Actor::StandAwhile(unsigned int uActorID) {
1138  pActors[uActorID].uCurrentActionLength = rand() % 128 + 128;
1139  pActors[uActorID].uCurrentActionTime = 0;
1140  pActors[uActorID].uAIState = Standing;
1141  pActors[uActorID].vVelocity.z = 0;
1142  pActors[uActorID].vVelocity.y = 0;
1143  pActors[uActorID].vVelocity.x = 0;
1144  pActors[uActorID].UpdateAnimation();
1145 }
1146 
1147 //----- (00403C6C) --------------------------------------------------------
1148 void Actor::AI_MeleeAttack(unsigned int uActorID, signed int sTargetPid,
1149  struct AIDirection *arg0) {
1150  int16_t v6; // esi@6
1151  int16_t v7; // edi@6
1152  signed int v8; // eax@7
1153  Vec3_int_ v10; // ST04_12@9
1154  AIDirection *v12; // eax@11
1155  AIDirection a3; // [sp+Ch] [bp-48h]@12
1156  AIDirection v20; // [sp+28h] [bp-2Ch]@12
1157  int v23; // [sp+4Ch] [bp-8h]@6
1158  unsigned int v25; // [sp+5Ch] [bp+8h]@13
1159 
1160  assert(uActorID < uNumActors);
1161 
1162  if (pActors[uActorID].pMonsterInfo.uMovementType ==
1164  pActors[uActorID].pMonsterInfo.uAIType == 1) {
1165  Actor::AI_Stand(uActorID, sTargetPid, 0, arg0);
1166  return;
1167  }
1168 
1169  if (PID_TYPE(sTargetPid) == OBJECT_Actor) {
1170  v8 = PID_ID(sTargetPid);
1171  v6 = pActors[v8].vPosition.x;
1172  v7 = pActors[v8].vPosition.y;
1173  v23 = (int)(pActors[v8].uActorHeight * 0.75 + pActors[v8].vPosition.z);
1174  } else if (PID_TYPE(sTargetPid) == OBJECT_Player) {
1175  v6 = pParty->vPosition.x;
1176  v7 = pParty->vPosition.y;
1177  v23 = pParty->vPosition.z + pParty->sEyelevel;
1178  } else {
1179  Error("Should not get here");
1180  return;
1181  }
1182 
1183  v10.x = pActors[uActorID].vPosition.x;
1184  v10.y = pActors[uActorID].vPosition.y;
1185  v10.z = (int32_t)(pActors[uActorID].uActorHeight * 0.75 +
1186  pActors[uActorID].vPosition.z);
1187 
1188  if (sub_407A1C((int)v6, (int)v7, v23, v10)) {
1189  if (arg0 != nullptr) {
1190  v12 = arg0;
1191  } else {
1192  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), sTargetPid,
1193  &a3, 0);
1194  v12 = &a3;
1195  }
1196  pActors[uActorID].uYawAngle = (short)v12->uYawAngle;
1197  pActors[uActorID].uCurrentActionLength =
1199  ->pSpriteSFrames[pActors[uActorID].pSpriteIDs[ANIM_AtkMelee]]
1200  .uAnimLength *
1201  8;
1202  pActors[uActorID].uCurrentActionTime = 0;
1203  pActors[uActorID].uAIState = AttackingMelee;
1204  Actor::PlaySound(uActorID, 0);
1205  v25 = pMonsterStats->pInfos[pActors[uActorID].pMonsterInfo.uID]
1206  .uRecoveryTime;
1207  if (pActors[uActorID].pActorBuffs[ACTOR_BUFF_SLOWED].Active()) v25 *= 2;
1208  if (!pParty->bTurnBasedModeOn) {
1209  pActors[uActorID].pMonsterInfo.uRecoveryTime = (int)(flt_6BE3A8_debug_recmod2 * v25 * 2.133333333333333);
1210  } else {
1211  pActors[uActorID].pMonsterInfo.uRecoveryTime = v25;
1212  }
1213  pActors[uActorID].vVelocity.z = 0;
1214  pActors[uActorID].vVelocity.y = 0;
1215  pActors[uActorID].vVelocity.x = 0;
1216  pActors[uActorID].UpdateAnimation();
1217  } else {
1218  Actor::AI_Pursue1(uActorID, sTargetPid, rand() % 2, 64, arg0);
1219  }
1220 }
1221 
1222 //----- (00438CF3) --------------------------------------------------------
1223 void Actor::ApplyFineForKillingPeasant(unsigned int uActorID) {
1224  if (uLevelMapStatsID == 0 || !pActors[uActorID].IsPeasant()) return;
1225 
1226  if ((uLevelMapStatsID == 6 || uLevelMapStatsID == 7) &&
1227  pParty->IsPartyEvil()) // celeste and bracada
1228  return;
1229 
1230  if ((uLevelMapStatsID == 5 || uLevelMapStatsID == 8) &&
1231  pParty->IsPartyGood()) // the pit and deyja
1232  return;
1233 
1235  pActors[uActorID].pMonsterInfo.uLevel +
1237  if (pParty->uFine < 0) pParty->uFine = 0;
1238  if (pParty->uFine > 4000000) pParty->uFine = 4000000;
1239 
1241  if (pOutdoor->ddm.uReputation < 10000) pOutdoor->ddm.uReputation++;
1242  } else if (uCurrentlyLoadedLevelType == LEVEL_Indoor) {
1243  if (pIndoor->dlv.uReputation < 10000) pIndoor->dlv.uReputation++;
1244  } else {
1245  assert(false);
1246  }
1247 
1248  if (pParty->uFine) {
1249  for (int i = 1; i <= 4; i++) {
1250  if (!_449B57_test_bit(pPlayers[i]->_achieved_awards_bits, PLAYER_GUILD_BITS__FINED))
1251  _449B7E_toggle_bit(pPlayers[i]->_achieved_awards_bits, PLAYER_GUILD_BITS__FINED, 1u);
1252  }
1253  }
1254 }
1255 
1256 //----- (0043AE80) --------------------------------------------------------
1257 void Actor::AddBloodsplatOnDamageOverlay(unsigned int uActorID, int a2,
1258  signed int a3) {
1259  unsigned int v4; // esi@1
1260 
1261  v4 = PID(OBJECT_Actor, uActorID);
1262  switch (a2) {
1263  case 1:
1264  if (a3)
1265  pOtherOverlayList->_4418B6(904, v4, 0,
1266  (int)(sub_43AE12(a3) * 65536.0), 0);
1267  return;
1268  case 2:
1269  if (a3)
1270  pOtherOverlayList->_4418B6(905, v4, 0,
1271  (int)(sub_43AE12(a3) * 65536.0), 0);
1272  return;
1273  case 3:
1274  if (a3)
1275  pOtherOverlayList->_4418B6(906, v4, 0,
1276  (int)(sub_43AE12(a3) * 65536.0), 0);
1277  return;
1278  case 4:
1279  if (a3)
1280  pOtherOverlayList->_4418B6(907, v4, 0,
1281  (int)(sub_43AE12(a3) * 65536.0), 0);
1282  return;
1283  case 5:
1284  pOtherOverlayList->_4418B6(901, v4, 0, PID(OBJECT_Actor, uActorID),
1285  0);
1286  return;
1287  case 6:
1288  pOtherOverlayList->_4418B6(902, v4, 0, PID(OBJECT_Actor, uActorID),
1289  0);
1290  return;
1291  case 7:
1292  pOtherOverlayList->_4418B6(903, v4, 0, PID(OBJECT_Actor, uActorID),
1293  0);
1294  return;
1295  case 8:
1296  pOtherOverlayList->_4418B6(900, v4, 0, PID(OBJECT_Actor, uActorID),
1297  0);
1298  return;
1299  case 9:
1300  pOtherOverlayList->_4418B6(909, v4, 0, PID(OBJECT_Actor, uActorID),
1301  0);
1302  return;
1303  case 10:
1304  pOtherOverlayList->_4418B6(908, v4, 0, PID(OBJECT_Actor, uActorID),
1305  0);
1306  return;
1307  default:
1308  return;
1309  }
1310  return;
1311 }
1312 
1313 //----- (0043B3E0) --------------------------------------------------------
1314 int Actor::_43B3E0_CalcDamage(signed int dmgSource) {
1315  int v2; // ebp@1
1316  int v3; // eax@9
1317  int v4; // edi@9
1318  int v5; // esi@9
1319  unsigned __int16 v8; // si@21
1320  int v9; // edi@21
1321  int v10; // eax@23
1322  int v11; // [sp+10h] [bp-4h]@1
1323 
1324  v2 = 0;
1325  v11 = 0;
1326 
1327  switch (dmgSource) {
1328  case 0:
1329  if (this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Active())
1331  if (this->pActorBuffs[ACTOR_BUFF_HEROISM].Active() &&
1332  this->pActorBuffs[ACTOR_BUFF_HEROISM].uPower > v2)
1334  if (this->pActorBuffs[ACTOR_BUFF_PAIN_HAMMERHANDS].Active())
1338  v5 = this->pMonsterInfo.uAttack1DamageBonus;
1339  break;
1340  case 1:
1343  v5 = this->pMonsterInfo.uAttack2DamageBonus;
1344  break;
1345  case 2:
1347  v9 = this->pMonsterInfo.uSpell1ID;
1348  v10 = SkillToMastery(v8);
1349  return _43AFE3_calc_spell_damage(v9, v8 & 0x3F, v10, 0);
1350  break;
1351  case 3:
1353  v9 = this->pMonsterInfo.uSpell2ID;
1354  v10 = SkillToMastery(v8);
1355  return _43AFE3_calc_spell_damage(v9, v8 & 0x3F, v10, 0);
1356  break;
1357  case 4:
1361  default:
1362  return 0;
1363  }
1364  for (int i = 0; i < v3; i++) v11 += rand() % v4 + 1;
1365  return v11 + v5 + v2;
1366 }
1367 
1368 //----- (00438B9B) --------------------------------------------------------
1370  unsigned int InHostile_Id; // eax@1
1371 
1372  InHostile_Id = this->uAlly;
1373  if (!this->uAlly) InHostile_Id = (this->pMonsterInfo.uID - 1) / 3 + 1;
1374  return (signed int)InHostile_Id >= 39 &&
1375  (signed int)InHostile_Id <= 44 // Dwarfs peasants
1376  || (signed int)InHostile_Id >= 45 &&
1377  (signed int)InHostile_Id <= 50 // Elves peasants
1378  || (signed int)InHostile_Id >= 51 &&
1379  (signed int)InHostile_Id <= 62 // Humans peasants
1380  || (signed int)InHostile_Id >= 78 &&
1381  (signed int)InHostile_Id <= 83; // Goblins peasants
1382 }
1383 
1384 //----- (0042EBEE) --------------------------------------------------------
1385 void Actor::StealFrom(unsigned int uActorID) {
1386  Player *pPlayer; // edi@1
1387  int v4; // ebx@2
1388  unsigned int v5; // eax@2
1389  DDM_DLV_Header *v6; // esi@4
1390  int v8; // [sp+8h] [bp-4h]@6
1391 
1392  pPlayer = &pParty->pPlayers[uActiveCharacter - 1];
1393  if (pPlayer->CanAct()) {
1395  v4 = 0;
1397  if (v5) v4 = pMapStats->pInfos[v5]._steal_perm;
1398  v6 = &pOutdoor->ddm;
1400  pPlayer->StealFromActor(uActorID, v4, v6->uReputation++);
1401  v8 = pPlayer->GetAttackRecoveryTime(0);
1402  if (v8 < 30) v8 = 30;
1403  if (!pParty->bTurnBasedModeOn)
1404  pPlayer->SetRecoveryTime(
1405  (int)(flt_6BE3A4_debug_recmod1 * v8 * 2.133333333333333));
1407  }
1408  return;
1409 }
1410 
1411 //----- (00403A60) --------------------------------------------------------
1412 void Actor::AI_SpellAttack2(unsigned int uActorID, signed int edx0,
1413  AIDirection *pDir) {
1414  Actor *v3; // ebx@1
1415  int16_t v4; // esi@3
1416  int16_t v5; // edi@3
1417  signed int v6; // eax@4
1418  Vec3_int_ v7; // ST04_12@6
1419  AIDirection *v9; // eax@8
1420  __int16 v13; // ax@10
1421  AIDirection a3; // [sp+Ch] [bp-48h]@9
1422  AIDirection v18; // [sp+28h] [bp-2Ch]@9
1423  int v19; // [sp+44h] [bp-10h]@6
1424  signed int a2; // [sp+48h] [bp-Ch]@1
1425  int v21; // [sp+4Ch] [bp-8h]@3
1426  unsigned int pDira; // [sp+5Ch] [bp+8h]@10
1427 
1428  v3 = &pActors[uActorID];
1429  a2 = edx0;
1430  if (PID_TYPE(edx0) == OBJECT_Actor) {
1431  v6 = PID_ID(edx0);
1432  v4 = pActors[v6].vPosition.x;
1433  v5 = pActors[v6].vPosition.y;
1434  v21 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z);
1435  } else if (PID_TYPE(edx0) == OBJECT_Player) {
1436  v4 = pParty->vPosition.x;
1437  v5 = pParty->vPosition.y;
1438  v21 = pParty->vPosition.z + pParty->sEyelevel;
1439  } else {
1440  Error("Should not get here");
1441  return;
1442  }
1443  v19 = v3->uActorHeight;
1444  v7.z = v3->vPosition.z + (v19 * 0.75);
1445  v7.y = v3->vPosition.y;
1446  v7.x = v3->vPosition.x;
1447  if (sub_407A1C(v4, v5, v21, v7)) {
1448  if (pDir == nullptr) {
1449  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), a2, &a3, 0);
1450  v9 = &a3;
1451  } else {
1452  v9 = pDir;
1453  }
1454  v3->uYawAngle = (short)v9->uYawAngle;
1455  v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]]
1456  .uAnimLength;
1457  v3->uCurrentActionLength = 8 * v13;
1458  v3->uCurrentActionTime = 0;
1459  v3->uAIState = AttackingRanged4;
1460  Actor::PlaySound(uActorID, 0);
1461  pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime;
1462  if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].Active()) pDira *= 2;
1463  if (pParty->bTurnBasedModeOn) {
1464  v3->pMonsterInfo.uRecoveryTime = pDira;
1465  } else {
1466  v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength + (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333);
1467  }
1468  v3->vVelocity.z = 0;
1469  v3->vVelocity.y = 0;
1470  v3->vVelocity.x = 0;
1471  if (ShouldMonsterPlayAttackAnim(v3->pMonsterInfo.uSpell2ID)) {
1472  v3->uCurrentActionLength = 64;
1473  v3->uCurrentActionTime = 0;
1474  v3->uAIState = Fidgeting;
1475  v3->UpdateAnimation();
1476  v3->uAIState = AttackingRanged4;
1477  } else {
1478  v3->UpdateAnimation();
1479  }
1480  } else {
1481  Actor::AI_Pursue1(uActorID, a2, uActorID, 64, pDir);
1482  }
1483 }
1484 
1485 //----- (00403854) --------------------------------------------------------
1486 void Actor::AI_SpellAttack1(unsigned int uActorID, signed int sTargetPid,
1487  AIDirection *pDir) {
1488  Actor *v3; // ebx@1
1489  int16_t v4; // esi@3
1490  int16_t v5; // edi@3
1491  signed int v6; // eax@4
1492  Vec3_int_ v7; // ST04_12@6
1493  AIDirection *v9; // eax@8
1494  __int16 v13; // ax@10
1495  signed int v16; // ecx@17
1496  AIDirection a3; // [sp+Ch] [bp-48h]@9
1497  AIDirection v18; // [sp+28h] [bp-2Ch]@9
1498  int v19; // [sp+44h] [bp-10h]@6
1499  int v21; // [sp+4Ch] [bp-8h]@3
1500  unsigned int pDira; // [sp+5Ch] [bp+8h]@10
1501 
1502  v3 = &pActors[uActorID];
1503  if (PID_TYPE(sTargetPid) == OBJECT_Actor) {
1504  v6 = PID_ID(sTargetPid);
1505  v4 = pActors[v6].vPosition.x;
1506  v5 = pActors[v6].vPosition.y;
1507  v21 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z);
1508  } else if (PID_TYPE(sTargetPid) == OBJECT_Player) {
1509  v4 = pParty->vPosition.x;
1510  v5 = pParty->vPosition.y;
1511  v21 = pParty->vPosition.z + pParty->sEyelevel;
1512  } else {
1513  Error("Should not get here");
1514  return;
1515  }
1516  v19 = v3->uActorHeight;
1517  v7.z = v3->vPosition.z + (v19 * 0.75);
1518  v7.y = v3->vPosition.y;
1519  v7.x = v3->vPosition.x;
1520  if (sub_407A1C(v4, v5, v21, v7)) {
1521  if (pDir == nullptr) {
1522  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), sTargetPid,
1523  &a3, 0);
1524  v9 = &a3;
1525  } else {
1526  v9 = pDir;
1527  }
1528  v3->uYawAngle = (short)v9->uYawAngle;
1529  v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]]
1530  .uAnimLength;
1531  v3->uCurrentActionLength = 8 * v13;
1532  v3->uCurrentActionTime = 0;
1533  v3->uAIState = AttackingRanged3;
1534  Actor::PlaySound(uActorID, 0);
1535  pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime;
1536  if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].Active()) pDira *= 2;
1537  if (pParty->bTurnBasedModeOn) {
1538  v3->pMonsterInfo.uRecoveryTime = pDira;
1539  } else {
1540  v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength + (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333);
1541  }
1542  v16 = v3->pMonsterInfo.uSpell1ID;
1543  v3->vVelocity.z = 0;
1544  v3->vVelocity.y = 0;
1545  v3->vVelocity.x = 0;
1546  if (ShouldMonsterPlayAttackAnim(v3->pMonsterInfo.uSpell1ID)) {
1547  v3->uCurrentActionLength = 64;
1548  v3->uCurrentActionTime = 0;
1549  v3->uAIState = Fidgeting;
1550  v3->UpdateAnimation();
1551  v3->uAIState = AttackingRanged3;
1552  } else {
1553  v3->UpdateAnimation();
1554  }
1555  } else {
1556  Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir);
1557  }
1558 }
1559 
1560 //----- (0040368B) --------------------------------------------------------
1561 void Actor::AI_MissileAttack2(unsigned int uActorID, signed int sTargetPid,
1562  AIDirection *pDir) {
1563  Actor *v3; // ebx@1
1564  int16_t v4; // esi@3
1565  int16_t v5; // edi@3
1566  signed int v6; // eax@4
1567  Vec3_int_ v7; // ST04_12@6
1568  AIDirection *v9; // eax@8
1569  __int16 v13; // ax@10
1570  AIDirection a3; // [sp+Ch] [bp-48h]@9
1571  AIDirection v17; // [sp+28h] [bp-2Ch]@9
1572  int v18; // [sp+44h] [bp-10h]@6
1573  int v20; // [sp+4Ch] [bp-8h]@3
1574  unsigned int pDira; // [sp+5Ch] [bp+8h]@10
1575 
1576  v3 = &pActors[uActorID];
1577  if (PID_TYPE(sTargetPid) == OBJECT_Actor) {
1578  v6 = PID_ID(sTargetPid);
1579  v4 = pActors[v6].vPosition.x;
1580  v5 = pActors[v6].vPosition.y;
1581  v20 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z);
1582  } else if (PID_TYPE(sTargetPid) == OBJECT_Player) {
1583  v4 = pParty->vPosition.x;
1584  v5 = pParty->vPosition.y;
1585  v20 = pParty->vPosition.z + pParty->sEyelevel;
1586  } else {
1587  Error("Should not get here");
1588  return;
1589  }
1590  v18 = v3->uActorHeight;
1591  v7.z = v3->vPosition.z + (v18 * 0.75);
1592  v7.y = v3->vPosition.y;
1593  v7.x = v3->vPosition.x;
1594  if (sub_407A1C(v4, v5, v20, v7)) {
1595  if (pDir == nullptr) {
1596  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), sTargetPid,
1597  &a3, 0);
1598  v9 = &a3;
1599  } else {
1600  v9 = pDir;
1601  }
1602  v3->uYawAngle = (short)v9->uYawAngle;
1603  v13 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]]
1604  .uAnimLength;
1605  v3->uCurrentActionLength = 8 * v13;
1606  v3->uCurrentActionTime = 0;
1607  v3->uAIState = AttackingRanged2;
1608  Actor::PlaySound(uActorID, 0);
1609  pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime;
1610  if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].Active()) pDira *= 2;
1611  if (!pParty->bTurnBasedModeOn) {
1612  v3->pMonsterInfo.uRecoveryTime = (int)(flt_6BE3A8_debug_recmod2 * pDira * 2.133333333333333);
1613  } else {
1614  v3->pMonsterInfo.uRecoveryTime = pDira;
1615  }
1616  v3->vVelocity.z = 0;
1617  v3->vVelocity.y = 0;
1618  v3->vVelocity.x = 0;
1619  v3->UpdateAnimation();
1620  } else {
1621  Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir);
1622  }
1623 }
1624 
1625 //----- (00403476) --------------------------------------------------------
1626 void Actor::AI_MissileAttack1(unsigned int uActorID, signed int sTargetPid,
1627  AIDirection *pDir) {
1628  Actor *v3; // ebx@1
1629  int v4; // esi@3
1630  int v5; // edi@3
1631  signed int v6; // eax@4
1632  Vec3_int_ v7; // ST04_12@6
1633  AIDirection *v10; // eax@9
1634  __int16 v14; // ax@11
1635  AIDirection a3; // [sp+Ch] [bp-48h]@10
1636  AIDirection v18; // [sp+28h] [bp-2Ch]@10
1637  int v19; // [sp+44h] [bp-10h]@6
1638  // signed int a2; // [sp+48h] [bp-Ch]@1
1639  int v22 = 0; // [sp+50h] [bp-4h]@3
1640  unsigned int pDira; // [sp+5Ch] [bp+8h]@11
1641 
1642  v3 = &pActors[uActorID];
1643  // a2 = edx0;
1644  if (PID_TYPE(sTargetPid) == OBJECT_Actor) {
1645  v6 = PID_ID(sTargetPid);
1646  v4 = pActors[v6].vPosition.x;
1647  v5 = pActors[v6].vPosition.y;
1648  v22 = (int)(pActors[v6].uActorHeight * 0.75 + pActors[v6].vPosition.z);
1649  } else {
1650  if (PID_TYPE(sTargetPid) == OBJECT_Player) {
1651  v4 = pParty->vPosition.x;
1652  v5 = pParty->vPosition.y;
1653  v22 = pParty->vPosition.z + pParty->sEyelevel;
1654  } else {
1655  v4 = (int)pDir;
1656  v5 = (int)pDir;
1657  }
1658  }
1659  v19 = v3->uActorHeight;
1660  v7.z = v3->vPosition.z + (v19 * 0.75);
1661  v7.y = v3->vPosition.y;
1662  v7.x = v3->vPosition.x;
1663  if (sub_407A1C(v4, v5, v22, v7) ||
1664  sub_407A1C(v7.x, v7.y, v7.z, Vec3_int_(v4, v5, v22))) {
1665  if (pDir == nullptr) {
1666  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), sTargetPid,
1667  &a3, 0);
1668  v10 = &a3;
1669  } else {
1670  v10 = pDir;
1671  }
1672  v3->uYawAngle = (short)v10->uYawAngle;
1673  v14 = pSpriteFrameTable->pSpriteSFrames[v3->pSpriteIDs[ANIM_AtkRanged]]
1674  .uAnimLength;
1675  v3->uCurrentActionLength = 8 * v14;
1676  v3->uCurrentActionTime = 0;
1677  v3->uAIState = AttackingRanged1;
1678  Actor::PlaySound(uActorID, 0);
1679  pDira = pMonsterStats->pInfos[v3->pMonsterInfo.uID].uRecoveryTime;
1680  if (v3->pActorBuffs[ACTOR_BUFF_SLOWED].Active()) pDira *= 2;
1681  if (pParty->bTurnBasedModeOn) {
1682  v3->pMonsterInfo.uRecoveryTime = pDira;
1683  } else {
1684  v3->pMonsterInfo.uRecoveryTime = v3->uCurrentActionLength - (int)(flt_6BE3A8_debug_recmod2 * pDira * -2.133333333333333);
1685  }
1686  v3->vVelocity.z = 0;
1687  v3->vVelocity.y = 0;
1688  v3->vVelocity.x = 0;
1689  v3->UpdateAnimation();
1690  } else {
1691  Actor::AI_Pursue1(uActorID, sTargetPid, uActorID, 64, pDir);
1692  }
1693 }
1694 
1695 //----- (004032B2) --------------------------------------------------------
1696 void Actor::AI_RandomMove(unsigned int uActor_id, unsigned int uTarget_id,
1697  int radius, int uActionLength) {
1698  int x; // ebx@1
1699  int absy; // eax@1
1700  unsigned int v9; // ebx@11
1701  int v10; // ebx@13
1702  AIDirection doNotInitializeBecauseShouldBeRandom; // [sp+Ch] [bp-30h]@7
1703  int y; // [sp+30h] [bp-Ch]@1
1704  int absx; // [sp+38h] [bp-4h]@1
1705 
1706  x = pActors[uActor_id].vInitialPosition.x - pActors[uActor_id].vPosition.x;
1707  y = pActors[uActor_id].vInitialPosition.y - pActors[uActor_id].vPosition.y;
1708  absx = abs(x);
1709  absy = abs(y);
1710  if (absx <= absy)
1711  absx = absy + (absx / 2);
1712  else
1713  absx = absx + absy / 2;
1716  if (!uActionLength) uActionLength = 256;
1717  Actor::AI_StandOrBored(uActor_id, OBJECT_Player, uActionLength,
1718  &doNotInitializeBecauseShouldBeRandom);
1719  return;
1720  }
1721  if (pActors[uActor_id].pMonsterInfo.uMovementType ==
1723  absx < 128) {
1724  Actor::AI_Stand(uActor_id, uTarget_id, 256,
1725  &doNotInitializeBecauseShouldBeRandom);
1726  return;
1727  }
1728  absx += ((rand() & 0xF) * radius) / 16;
1729  v9 = (stru_5C6E00->uIntegerDoublePi - 1) & stru_5C6E00->Atan2(x, y);
1730  if (rand() % 100 < 25) {
1731  Actor::StandAwhile(uActor_id);
1732  return;
1733  }
1734  v10 = v9 + rand() % 256 - 128;
1735  if (abs(v10 - pActors[uActor_id].uYawAngle) > 256 &&
1736  !(pActors[uActor_id].uAttributes & ACTOR_ANIMATION)) {
1737  Actor::AI_Stand(uActor_id, uTarget_id, 256,
1738  &doNotInitializeBecauseShouldBeRandom);
1739  return;
1740  }
1741  pActors[uActor_id].uYawAngle = v10;
1742  if (pActors[uActor_id].uMovementSpeed)
1743  pActors[uActor_id].uCurrentActionLength =
1744  32 * absx / pActors[uActor_id].uMovementSpeed;
1745  else
1746  pActors[uActor_id].uCurrentActionLength = 0;
1747  pActors[uActor_id].uCurrentActionTime = 0;
1748  pActors[uActor_id].uAIState = Tethered;
1749  if (rand() % 100 < 2) Actor::PlaySound(uActor_id, 3);
1750  pActors[uActor_id].UpdateAnimation();
1751 }
1752 
1753 //----- (004031C1) --------------------------------------------------------
1755  unsigned int uActorID, signed int a2,
1756  int a3) { // attempted to implement something like jobs for actors, but
1757  // apparently was never finished
1758  return 0;
1759  /*unsigned int v3; // edi@1
1760  Actor *v4; // esi@1
1761  ActorJob *v5; // eax@1
1762  signed int v6; // edx@2
1763  ActorJob *v7; // eax@2
1764  signed int v8; // edi@2
1765  ActorJob *v9; // ecx@2
1766  __int16 v10; // cx@15
1767  signed int v12; // [sp+8h] [bp-4h]@1
1768 
1769  v3 = uActorID;
1770  v12 = a2;
1771  v4 = &pActors[uActorID];
1772  v5 = (ActorJob *)pActors[uActorID].CanAct();
1773  if ( v5 )
1774  {
1775  v6 = 65535;
1776  v7 = &v4->pScheduledJobs[v3];
1777  v8 = 7;
1778  v9 = &v7[7];//(char *)&v7[7].uHour;
1779  while ( !(v9->uAttributes & 1) || v9->uHour > v12 )
1780  {
1781  --v8;
1782  --v9;
1783  if ( v8 < 0 )
1784  break;
1785  }
1786  if( v8 >= 0 )
1787  v6 = v8;
1788  if ( !v8 && v6 == 65535 )
1789  v6 = 7;
1790  v5 = &v7[v6];
1791  if ( v4->vInitialPosition.x != v5->vPos.x
1792  || v4->vInitialPosition.y != v5->vPos.y
1793  || v4->vInitialPosition.z != v5->vPos.z
1794  || v4->pMonsterInfo.uMovementType != v5->uAction )
1795  {
1796  v4->vInitialPosition.x = v5->vPos.x;
1797  v4->vInitialPosition.y = v5->vPos.y;
1798  v10 = v5->vPos.z;
1799  v4->vInitialPosition.z = v10;
1800  LOBYTE(v5) = v5->uAction;
1801  v4->pMonsterInfo.uMovementType = MONSTER_MOVEMENT_TYPE_STAIONARY;
1802  if ( a3 == 1 )
1803  {
1804  v4->vPosition.x = v4->vInitialPosition.x;
1805  v4->vPosition.y = v4->vInitialPosition.y;
1806  LOBYTE(v5) = v10;
1807  v4->vPosition.z = v10;
1808  }
1809  }
1810  }
1811  return (char)v5;*/
1812 }
1813 
1814 //----- (004030AD) --------------------------------------------------------
1815 void Actor::AI_Stun(unsigned int uActorID, signed int edx0,
1816  int stunRegardlessOfState) {
1817  __int16 v7; // ax@16
1818  AIDirection a3; // [sp+Ch] [bp-40h]@16
1819 
1820  if (pActors[uActorID].uAIState == Fleeing)
1821  pActors[uActorID].uAttributes |= ACTOR_FLEEING;
1822  if (pActors[uActorID].pMonsterInfo.uHostilityType != 4) {
1823  pActors[uActorID].uAttributes &= 0xFFFFFFFB; // ~0x4
1824  pActors[uActorID].pMonsterInfo.uHostilityType =
1826  }
1827  if (pActors[uActorID].pActorBuffs[ACTOR_BUFF_CHARM].Active())
1828  pActors[uActorID].pActorBuffs[ACTOR_BUFF_CHARM].Reset();
1829  if (pActors[uActorID].pActorBuffs[ACTOR_BUFF_AFRAID].Active())
1830  pActors[uActorID].pActorBuffs[ACTOR_BUFF_AFRAID].Reset();
1831  if (stunRegardlessOfState ||
1832  (pActors[uActorID].uAIState != Stunned &&
1833  pActors[uActorID].uAIState != AttackingRanged1 &&
1834  pActors[uActorID].uAIState != AttackingRanged2 &&
1835  pActors[uActorID].uAIState != AttackingRanged3 &&
1836  pActors[uActorID].uAIState != AttackingRanged4 &&
1837  pActors[uActorID].uAIState != AttackingMelee)) {
1838  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), edx0, &a3, 0);
1839  // v10 = &a3;
1840  pActors[uActorID].uYawAngle = (short)a3.uYawAngle;
1841  v7 = pSpriteFrameTable
1842  ->pSpriteSFrames[pActors[uActorID].pSpriteIDs[ANIM_GotHit]]
1843  .uAnimLength;
1844  pActors[uActorID].uCurrentActionTime = 0;
1845  pActors[uActorID].uAIState = Stunned;
1846  pActors[uActorID].uCurrentActionLength = 8 * v7;
1847  Actor::PlaySound(uActorID, 2);
1848  pActors[uActorID].UpdateAnimation();
1849  }
1850 }
1851 
1852 //----- (00402F87) --------------------------------------------------------
1853 void Actor::AI_Bored(unsigned int uActorID, unsigned int uObjID,
1854  AIDirection *a4) {
1855  unsigned int v7; // eax@3
1856  unsigned int v9; // eax@3
1857 
1858  Actor *actor = &pActors[uActorID];
1859 
1860  AIDirection a3; // [sp+Ch] [bp-5Ch]@2
1861  if (!a4) {
1862  Actor::GetDirectionInfo(PID(OBJECT_Actor, uActorID), uObjID, &a3, 0);
1863  a4 = &a3;
1864  }
1865 
1866  actor->uCurrentActionLength =
1868  .uAnimLength;
1869 
1871  actor->vPosition.y - pIndoorCameraD3D->vPartyPos.y);
1872  v9 = stru_5C6E00->uIntegerPi + actor->uYawAngle +
1873  ((signed int)stru_5C6E00->uIntegerPi >> 3) - v7;
1874 
1875  if (v9 & 0x700) { // turned away - just stand
1876  Actor::AI_Stand(uActorID, uObjID, actor->uCurrentActionLength, a4);
1877  } else { // facing player - play bored anim
1878  actor->uAIState = Fidgeting;
1879  actor->uCurrentActionTime = 0;
1880  actor->uYawAngle = a4->uYawAngle;
1881  actor->vVelocity.z = 0;
1882  actor->vVelocity.y = 0;
1883  actor->vVelocity.x = 0;
1884  if (rand() % 100 < 5) Actor::PlaySound(uActorID, 3);
1885  actor->UpdateAnimation();
1886  }
1887 }
1888 
1889 //----- (00402F27) --------------------------------------------------------
1890 void Actor::Resurrect(unsigned int uActorID) {
1891  Actor *pActor; // esi@1
1892 
1893  pActor = &pActors[uActorID];
1894  pActor->uCurrentActionTime = 0;
1895  pActor->uAIState = Resurrected;
1897  pActor->uCurrentActionLength =
1899  .uAnimLength;
1900  pActor->sCurrentHP = (short)pActor->pMonsterInfo.uHP;
1901  Actor::PlaySound(uActorID, 1);
1902  pActor->UpdateAnimation();
1903 }
1904 
1905 //----- (00402D6E) --------------------------------------------------------
1906 void Actor::Die(unsigned int uActorID) {
1907  Actor *actor = &pActors[uActorID];
1908 
1909  actor->uCurrentActionTime = 0;
1910  actor->uAIState = Dying;
1912  actor->sCurrentHP = 0;
1913  actor->uCurrentActionLength =
1915  .uAnimLength;
1918  Actor::PlaySound(uActorID, 1);
1919  actor->UpdateAnimation();
1920 
1921  for (uint i = 0; i < 5; ++i)
1922  if (pParty->monster_id_for_hunting[i] == actor->pMonsterInfo.uID)
1924 
1925  for (uint i = 0; i < 22; ++i) actor->pActorBuffs[i].Reset();
1926 
1927  ItemGen drop;
1928  drop.Reset();
1929  switch (actor->pMonsterInfo.uID) {
1930  case MONSTER_HARPY_1:
1931  case MONSTER_HARPY_2:
1932  case MONSTER_HARPY_3:
1933  drop.uItemID = ITEM_HARPY_FEATHER;
1934  break;
1935 
1936  case MONSTER_OOZE_1:
1937  case MONSTER_OOZE_2:
1938  case MONSTER_OOZE_3:
1940  break;
1941 
1942  case MONSTER_TROLL_1:
1943  case MONSTER_TROLL_2:
1944  case MONSTER_TROLL_3:
1945  drop.uItemID = ITEM_TROLL_BLOOD;
1946  break;
1947 
1948  case MONSTER_DEVIL_1:
1949  case MONSTER_DEVIL_2:
1950  case MONSTER_DEVIL_3:
1951  drop.uItemID = ITEM_DEVIL_ICHOR;
1952  break;
1953 
1954  case MONSTER_DRAGON_1:
1955  case MONSTER_DRAGON_2:
1956  case MONSTER_DRAGON_3:
1957  drop.uItemID = ITEM_DRAGON_EYE;
1958  break;
1959  }
1960 
1961  if (rand() % 100 < 20 && drop.uItemID != 0) {
1963  (SPRITE_OBJECT_TYPE)pItemsTable->pItems[drop.uItemID].uSpriteID,
1964  actor->vPosition.x, actor->vPosition.y, actor->vPosition.z + 16,
1965  rand() % 200 + 200, 1, 1, 0, &drop);
1966  }
1967 
1968  if (actor->pMonsterInfo.uSpecialAbilityType ==
1970  Actor::Explode(uActorID);
1971 }
1972 
1973 //----- (00402CED) --------------------------------------------------------
1974 void Actor::PlaySound(unsigned int uActorID, unsigned int uSoundID) {
1975  SoundID sound_sample_id =
1976  (SoundID)pActors[uActorID].pSoundSampleIDs[uSoundID];
1977  if (sound_sample_id) {
1978  if (!pActors[uActorID].pActorBuffs[ACTOR_BUFF_SHRINK].Active()) {
1979  pAudioPlayer->PlaySound(sound_sample_id,
1980  PID(OBJECT_Actor, uActorID), 0, -1, 0,
1981  0);
1982  } else {
1983  switch (pActors[uActorID].pActorBuffs[ACTOR_BUFF_SHRINK].uPower) {
1984  case 1:
1985  pAudioPlayer->PlaySound(sound_sample_id, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0);
1986  break;
1987  case 2:
1988  pAudioPlayer->PlaySound(sound_sample_id, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0);
1989  break;
1990  case 3:
1991  case 4:
1992  pAudioPlayer->PlaySound(sound_sample_id, PID(OBJECT_Actor, uActorID), 0, 0, 0, 0);
1993  break;
1994  default:
1995  pAudioPlayer->PlaySound(sound_sample_id, PID(OBJECT_Actor, uActorID), 0, -1, 0, 0);
1996  break;
1997  }
1998  }
1999  }
2000 }
2001 
2002 //----- (00402AD7) --------------------------------------------------------
2003 void Actor::AI_Pursue1(unsigned int uActorID, unsigned int a2, signed int arg0,
2004  signed int uActionLength, AIDirection *pDir) {
2005  int v6; // eax@1
2006  Actor *v7; // ebx@1
2007  unsigned int v8; // ecx@1
2008  AIDirection *v10; // esi@6
2009  AIDirection a3; // [sp+Ch] [bp-5Ch]@7
2010  unsigned int v18; // [sp+64h] [bp-4h]@1
2011 
2012  v6 = 0;
2013  v7 = &pActors[uActorID];
2014  v8 = PID(OBJECT_Actor, uActorID);
2015  if (v7->pMonsterInfo.uFlying != 0 &&
2016  !pParty->bFlying) { // TODO(_): Does v6 have a point?
2018  v6 = v7->uActorRadius + 512;
2019  else
2020  v6 = pParty->uPartyHeight;
2021  }
2022 
2023  if (pDir == nullptr) {
2024  Actor::GetDirectionInfo(v8, a2, &a3, v6);
2025  v10 = &a3;
2026  } else {
2027  v10 = pDir;
2028  }
2031  if (!uActionLength) uActionLength = 256;
2032  Actor::AI_StandOrBored(uActorID, 4, uActionLength, v10);
2033  return;
2034  }
2035  if (v10->uDistance < 307.2) {
2036  if (!uActionLength) uActionLength = 256;
2037  Actor::AI_Stand(uActorID, a2, uActionLength, v10);
2038  return;
2039  }
2040  if (v7->uMovementSpeed == 0) {
2041  Actor::AI_Stand(uActorID, a2, uActionLength, v10);
2042  return;
2043  }
2044  if (arg0 % 2)
2045  v18 = -16;
2046  else
2047  v18 = 16;
2048 
2049  v7->uYawAngle = stru_5C6E00->Atan2(
2050  pParty->vPosition.x +
2052  v10->uYawAngle),
2053  v10->uDistanceXZ) -
2054  v7->vPosition.x,
2055  pParty->vPosition.y +
2057  v10->uYawAngle),
2058  v10->uDistanceXZ) -
2059  v7->vPosition.y);
2060  if (uActionLength)
2061  v7->uCurrentActionLength = uActionLength;
2062  else
2063  v7->uCurrentActionLength = 128;
2064  v7->uPitchAngle = (short)v10->uPitchAngle;
2065  v7->uAIState = Pursuing;
2066  v7->UpdateAnimation();
2067 }
2068 
2069 //----- (00402968) --------------------------------------------------------
2070 void Actor::AI_Flee(unsigned int uActorID, signed int sTargetPid,
2071  int uActionLength, AIDirection *a4) {
2072  Actor *v5; // ebx@1
2073  int v7; // ecx@2
2074  AIDirection v10; // [sp+8h] [bp-7Ch]@4
2075  AIDirection a3; // [sp+24h] [bp-60h]@3
2076  AIDirection *v13; // [sp+5Ch] [bp-28h]@4
2077 
2078  v5 = &pActors[uActorID];
2079  if (v5->CanAct()) {
2080  v7 = PID(OBJECT_Actor, uActorID);
2081  if (!a4) {
2082  Actor::GetDirectionInfo(v7, sTargetPid, &a3,
2083  v5->pMonsterInfo.uFlying);
2084  a4 = &a3;
2085  }
2086  Actor::GetDirectionInfo(v7, 4u, &v10, 0);
2087  v13 = &v10;
2090  PID_TYPE(sTargetPid) == OBJECT_Actor && v13->uDistance < 307.2) {
2091  if (!uActionLength) uActionLength = 256;
2092  Actor::AI_StandOrBored(uActorID, 4, uActionLength, v13);
2093  } else {
2094  if (v5->uMovementSpeed)
2095  v5->uCurrentActionLength =
2096  (signed int)(a4->uDistanceXZ << 7) / v5->uMovementSpeed;
2097  else
2098  v5->uCurrentActionLength = 0;
2099  if (v5->uCurrentActionLength > 256) v5->uCurrentActionLength = 256;
2100  v5->uYawAngle =
2101  (short)stru_5C6E00->uIntegerHalfPi + (short)a4->uYawAngle;
2102  v5->uYawAngle =
2103  (short)stru_5C6E00->uDoublePiMask &
2104  (v5->uYawAngle + rand() % (signed int)stru_5C6E00->uIntegerPi);
2105  v5->uCurrentActionTime = 0;
2106  v5->uPitchAngle = (short)a4->uPitchAngle;
2107  v5->uAIState = Fleeing;
2108  v5->UpdateAnimation();
2109  }
2110  }
2111 }
2112 
2113 //----- (0040281C) --------------------------------------------------------
2114 void Actor::AI_Pursue2(unsigned int uActorID, unsigned int a2,
2115  signed int uActionLength, AIDirection *pDir, int a5) {
2116  int v6; // eax@1
2117  Actor *v7; // ebx@1
2118  unsigned int v8; // ecx@1
2119  AIDirection *v10; // esi@7
2120  signed __int16 v13; // cx@19
2121  unsigned __int16 v14; // ax@25
2122  AIDirection a3; // [sp+Ch] [bp-40h]@8
2123  AIDirection v18; // [sp+28h] [bp-24h]@8
2124 
2125  v6 = 0;
2126  v7 = &pActors[uActorID];
2127  v8 = PID(OBJECT_Actor, uActorID);
2128  if (v7->pMonsterInfo.uFlying != 0 && !pParty->bFlying) {
2129  if (v7->pMonsterInfo.uMissleAttack1Type &&
2131  v6 = v7->uActorRadius + 512;
2132  else
2133  v6 = pParty->uPartyHeight;
2134  }
2135  v10 = pDir;
2136  if (!pDir) {
2137  Actor::GetDirectionInfo(v8, a2, &a3, v6);
2138  v10 = &a3;
2139  }
2142  if (!uActionLength) uActionLength = 256;
2143  Actor::AI_StandOrBored(uActorID, 4, uActionLength, v10);
2144  return;
2145  }
2146  if ((signed int)v10->uDistance < a5) {
2147  if (!uActionLength) uActionLength = 256;
2148  Actor::AI_StandOrBored(uActorID, a2, uActionLength, v10);
2149  return;
2150  }
2151  if (uActionLength) {
2152  v7->uCurrentActionLength = uActionLength;
2153  } else {
2154  v13 = v7->uMovementSpeed;
2155  if (v13)
2156  v7->uCurrentActionLength =
2157  (signed int)(v10->uDistanceXZ << 7) / v13;
2158  else
2159  v7->uCurrentActionLength = 0;
2160  if (v7->uCurrentActionLength > 32) v7->uCurrentActionLength = 32;
2161  }
2162  v7->uYawAngle = (short)v10->uYawAngle;
2163  v14 = (short)v10->uPitchAngle;
2164  v7->uCurrentActionTime = 0;
2165  v7->uPitchAngle = v14;
2166  v7->uAIState = Pursuing;
2167  v7->UpdateAnimation();
2168 }
2169 
2170 //----- (00402686) --------------------------------------------------------
2171 void Actor::AI_Pursue3(unsigned int uActorID, unsigned int a2,
2172  signed int uActionLength, AIDirection *a4) {
2173  int v5; // eax@1
2174  Actor *v6; // ebx@1
2175  int v7; // ecx@1
2176  signed __int16 v12; // cx@19
2177  __int16 v14; // ax@25
2178  unsigned __int16 v16; // ax@28
2179  AIDirection a3; // [sp+Ch] [bp-40h]@8
2180  AIDirection *v20; // [sp+28h] [bp-24h]@8
2181 
2182  v5 = 0;
2183  v6 = &pActors[uActorID];
2184  v7 = PID(OBJECT_Actor, uActorID);
2185  if (v6->pMonsterInfo.uFlying != 0 && !pParty->bFlying) {
2186  if (v6->pMonsterInfo.uMissleAttack1Type &&
2188  v5 = v6->uActorRadius + 512;
2189  else
2190  v5 = pParty->uPartyHeight;
2191  }
2192  if (!a4) {
2193  Actor::GetDirectionInfo(v7, a2, &a3, v5);
2194  v20 = &a3;
2195  }
2198  if (!uActionLength) uActionLength = 256;
2199  return Actor::AI_StandOrBored(uActorID, 4, uActionLength, a4);
2200  }
2201  if (a4->uDistance < 307.2) {
2202  if (!uActionLength) uActionLength = 256;
2203  return Actor::AI_StandOrBored(uActorID, a2, uActionLength, a4);
2204  }
2205  if (uActionLength) {
2206  v6->uCurrentActionLength = uActionLength + rand() % uActionLength;
2207  } else {
2208  v12 = v6->uMovementSpeed;
2209  if (v12)
2210  v6->uCurrentActionLength = (signed int)(a4->uDistanceXZ << 7) / v12;
2211  else
2212  v6->uCurrentActionLength = 0;
2213  if (v6->uCurrentActionLength > 128) v6->uCurrentActionLength = 128;
2214  }
2215  v14 = (short)a4->uYawAngle;
2216  if (rand() % 2)
2217  v14 += 256;
2218  else
2219  v14 -= 256;
2220  v6->uYawAngle = v14;
2221  v16 = (short)a4->uPitchAngle;
2222  v6->uCurrentActionTime = 0;
2223  v6->uPitchAngle = v16;
2224  v6->uAIState = Pursuing;
2225  if (rand() % 100 < 2) Actor::PlaySound(uActorID, 2);
2226  v6->UpdateAnimation();
2227 }
2228 
2229 //----- (00401221) --------------------------------------------------------
2230 void Actor::_SelectTarget(unsigned int uActorID, int *a2,
2231  bool can_target_party) {
2232  int v5; // ecx@1
2233  signed int v10; // eax@13
2234  uint v11; // ebx@16
2235  uint v12; // eax@16
2236  signed int v14; // eax@31
2237  uint v15; // edi@43
2238  uint v16; // ebx@45
2239  uint v17; // eax@45
2240  signed int closestId; // [sp+14h] [bp-1Ch]@1
2241  uint v23; // [sp+1Ch] [bp-14h]@16
2242  unsigned int lowestRadius; // [sp+24h] [bp-Ch]@1
2243  uint v27; // [sp+2Ch] [bp-4h]@16
2244  uint v28; // [sp+2Ch] [bp-4h]@45
2245 
2246  lowestRadius = UINT_MAX;
2247  v5 = 0;
2248  *a2 = 0;
2249  closestId = 0;
2250  assert(uActorID < uNumActors);
2251  Actor *thisActor = &pActors[uActorID];
2252 
2253  for (uint i = 0; i < uNumActors; ++i) {
2254  Actor *actor = &pActors[i];
2255  if (actor->uAIState == Dead || actor->uAIState == Dying ||
2256  actor->uAIState == Removed || actor->uAIState == Summoned ||
2257  actor->uAIState == Disabled || uActorID == i)
2258  continue;
2259 
2260  if (thisActor->uLastCharacterIDToHit == 0 ||
2261  PID(OBJECT_Actor, v5) != thisActor->uLastCharacterIDToHit) {
2262  v10 = thisActor->GetActorsRelation(actor);
2263  if (v10 == 0) continue;
2264  } else if (thisActor->IsNotAlive()) {
2265  thisActor->uLastCharacterIDToHit = 0;
2266  v10 = thisActor->GetActorsRelation(actor);
2267  if (v10 == 0) continue;
2268  } else {
2269  if ((actor->uGroup != 0 || thisActor->uGroup != 0) &&
2270  actor->uGroup == thisActor->uGroup)
2271  continue;
2272  v10 = 4;
2273  }
2274  if (thisActor->pMonsterInfo.uHostilityType)
2275  v10 = pMonsterStats->pInfos[thisActor->pMonsterInfo.uID]
2276  .uHostilityType;
2277  v11 = _4DF380_hostilityRanges[v10];
2278  v23 = abs(thisActor->vPosition.x - actor->vPosition.x);
2279  v27 = abs(thisActor->vPosition.y - actor->vPosition.y);
2280  v12 = abs(thisActor->vPosition.z - actor->vPosition.z);
2281  if (v23 <= v11 && v27 <= v11 && v12 <= v11 &&
2283  PID(OBJECT_Actor, uActorID)) &&
2284  v23 * v23 + v27 * v27 + v12 * v12 < lowestRadius) {
2285  lowestRadius = v23 * v23 + v27 * v27 + v12 * v12;
2286  closestId = i;
2287  }
2288  }
2289 
2290  if (lowestRadius != UINT_MAX) {
2291  *a2 = PID(OBJECT_Actor, closestId);
2292  }
2293 
2294  if (can_target_party && !pParty->Invisible()) {
2295  if (thisActor->ActorEnemy() &&
2296  !thisActor->pActorBuffs[ACTOR_BUFF_ENSLAVED].Active() &&
2297  !thisActor->pActorBuffs[ACTOR_BUFF_CHARM].Active() &&
2298  !thisActor->pActorBuffs[ACTOR_BUFF_SUMMONED].Active())
2299  v14 = 4;
2300  else
2301  v14 = thisActor->GetActorsRelation(0);
2302  if (v14 != 0) {
2303  if (!thisActor->pMonsterInfo.uHostilityType)
2304  v15 = _4DF380_hostilityRanges[v14];
2305  else
2306  v15 = _4DF380_hostilityRanges[4];
2307  v16 = abs(thisActor->vPosition.x - pParty->vPosition.x);
2308  v28 = abs(thisActor->vPosition.y - pParty->vPosition.y);
2309  v17 = abs(thisActor->vPosition.z - pParty->vPosition.z);
2310  if (v16 <= v15 && v28 <= v15 && v17 <= v15 &&
2311  (v16 * v16 + v28 * v28 + v17 * v17 < lowestRadius)) {
2312  *a2 = OBJECT_Player;
2313  }
2314  }
2315  }
2316 }
2317 
2318 //----- (0040104C) --------------------------------------------------------
2319 signed int Actor::GetActorsRelation(Actor *otherActPtr) {
2320  unsigned int thisGroup; // ebp@19
2321  int otherGroup; // eax@22
2322  unsigned int thisAlly; // edx@25
2323  unsigned int otherAlly; // edx@33
2324 
2325  if (otherActPtr) {
2326  if (otherActPtr->uGroup != 0 && this->uGroup != 0 &&
2327  otherActPtr->uGroup == this->uGroup)
2328  return 0;
2329  }
2330 
2331  if (this->pActorBuffs[ACTOR_BUFF_BERSERK].Active()) return 4;
2332  thisAlly = this->uAlly;
2333  if (this->pActorBuffs[ACTOR_BUFF_ENSLAVED].Active() || thisAlly == 9999)
2334  thisGroup = 0;
2335  else if (thisAlly > 0)
2336  thisGroup = thisAlly;
2337  else
2338  thisGroup = (this->pMonsterInfo.uID - 1) / 3 + 1;
2339 
2340  if (otherActPtr) {
2341  if (otherActPtr->pActorBuffs[ACTOR_BUFF_BERSERK].Active()) return 4;
2342  otherAlly = otherActPtr->uAlly;
2343  if (otherActPtr->pActorBuffs[ACTOR_BUFF_ENSLAVED].Active() ||
2344  otherAlly == 9999)
2345  otherGroup = 0;
2346  else if (otherAlly > 0)
2347  otherGroup = otherAlly;
2348  else
2349  otherGroup = (otherActPtr->pMonsterInfo.uID - 1) / 3 + 1;
2350  } else {
2351  otherGroup = 0;
2352  }
2353 
2354  if (this->pActorBuffs[ACTOR_BUFF_CHARM].Active() && !otherGroup ||
2355  otherActPtr && otherActPtr->pActorBuffs[ACTOR_BUFF_CHARM].Active() &&
2356  !thisGroup)
2357  return 0;
2358  if (!this->pActorBuffs[ACTOR_BUFF_ENSLAVED].Active() &&
2359  this->ActorEnemy() && !otherGroup)
2360  return 4;
2361  if (thisGroup >= 89 || otherGroup >= 89) return 0;
2362 
2363  if (thisGroup == 0) {
2364  if ((!otherActPtr || this->pActorBuffs[ACTOR_BUFF_ENSLAVED].Active() &&
2365  otherActPtr->ActorFriend()) &&
2366  !pFactionTable->relations[otherGroup][0])
2367  return pFactionTable->relations[0][otherGroup];
2368  else
2369  return 4;
2370  } else {
2371  return pFactionTable->relations[thisGroup][otherGroup];
2372  }
2373 }
2374 
2375 //----- (0045976D) --------------------------------------------------------
2377  ResetAnimation();
2378  switch (uAIState) {
2379  case Tethered:
2381  break;
2382 
2383  case AttackingMelee:
2385  uAttributes |= ACTOR_ANIMATION;
2386  break;
2387 
2388  case AttackingRanged1:
2389  case AttackingRanged2:
2390  case AttackingRanged3:
2391  case AttackingRanged4:
2393  uAttributes |= ACTOR_ANIMATION;
2394  break;
2395 
2396  case Dying:
2397  case Resurrected:
2399  uAttributes |= ACTOR_ANIMATION;
2400  break;
2401 
2402  case Pursuing:
2403  case Fleeing:
2405  uAttributes |= ACTOR_ANIMATION;
2406  break;
2407 
2408  case Stunned:
2410  uAttributes |= ACTOR_ANIMATION;
2411  break;
2412 
2413  case Fidgeting:
2415  uAttributes |= ACTOR_ANIMATION;
2416  break;
2417 
2418  case Standing:
2419  case Interacting:
2420  case Summoned:
2422  uAttributes |= ACTOR_ANIMATION;
2423  break;
2424 
2425  case Dead:
2427  .hw_sprites[0] == nullptr)
2428  uAIState = Removed;
2429  else
2431  break;
2432 
2433  case Removed:
2434  case Disabled:
2435  return;
2436 
2437  default:
2438  assert(false);
2439  }
2440 }
2441 
2442 //----- (00459671) --------------------------------------------------------
2444  this->pActorName[0] = 0;
2445  this->word_000086_some_monster_id = 0;
2446  this->sNPC_ID = 0;
2447  this->vPosition.z = 0;
2448  this->vPosition.y = 0;
2449  this->vPosition.x = 0;
2450  this->vVelocity.z = 0;
2451  this->vVelocity.y = 0;
2452  this->vVelocity.x = 0;
2453  this->uYawAngle = 0;
2454  this->uPitchAngle = 0;
2455  this->uAttributes = 0;
2456  this->uSectorID = 0;
2457  this->uCurrentActionTime = 0;
2458  this->vInitialPosition.z = 0;
2459  this->vInitialPosition.y = 0;
2460  this->vInitialPosition.x = 0;
2461  this->vGuardingPosition.z = 0;
2462  this->vGuardingPosition.y = 0;
2463  this->vGuardingPosition.x = 0;
2464  this->uTetherDistance = 256;
2465  this->uActorRadius = 32;
2466  this->uActorHeight = 128;
2467  this->uAIState = Standing;
2469  this->uMovementSpeed = 200;
2470  this->uCarriedItemID = 0;
2471  this->uGroup = 0;
2472  this->uAlly = 0;
2473  this->uSummonerID = 0;
2474  this->uLastCharacterIDToHit = 0;
2475  this->dword_000334_unique_name = 0;
2476  memset(this->pSpriteIDs, 0, sizeof(pSpriteIDs));
2477  memset(this->pActorBuffs, 0, 0x160u);
2478 }
2479 
2480 //----- (0045959A) --------------------------------------------------------
2481 void Actor::PrepareSprites(char load_sounds_if_bit1_set) {
2482  MonsterDesc *v3; // esi@1
2483  MonsterInfo *v9; // [sp+84h] [bp-10h]@1
2484 
2486  v9 = &pMonsterStats->pInfos[pMonsterInfo.uID /*- 1 + 1*/];
2487  // v12 = pSpriteIDs;
2488  // Source = (char *)v3->pSpriteNames;
2489  // do
2490  for (uint i = 0; i < 8; ++i) {
2491  // strcpy(pSpriteName, v3->pSpriteNames[i]);
2492  pSpriteIDs[i] = pSpriteFrameTable->FastFindSprite(v3->pSpriteNames[i]);
2494  }
2495  uActorHeight = v3->uMonsterHeight;
2496  uActorRadius = v3->uMonsterRadius;
2497  uMovementSpeed = v9->uBaseSpeed;
2498  if (!(load_sounds_if_bit1_set & 1)) {
2499  for (int i = 0; i < 4; ++i) pSoundSampleIDs[i] = v3->pSoundSampleIDs[i];
2500  }
2501 }
2502 
2503 //----- (00459667) --------------------------------------------------------
2504 void Actor::Remove() { this->uAIState = Removed; }
2505 
2506 //----- (0043B1B0) --------------------------------------------------------
2507 void Actor::ActorDamageFromMonster(signed int attacker_id,
2508  unsigned int actor_id, Vec3_int_ *pVelocity,
2509  signed int a4) {
2510  int v4; // ebx@1
2511  int dmgToRecv; // qax@8
2512  signed int v12; // ecx@20
2513  int finalDmg; // edi@30
2514  int pushDistance; // [sp+20h] [bp+Ch]@34
2515 
2516  v4 = 0;
2517  if (PID_TYPE(attacker_id) == OBJECT_Item) {
2518  v4 = pSpriteObjects[PID_ID(attacker_id)]
2519  .field_60_distance_related_prolly_lod;
2520  attacker_id = pSpriteObjects[PID_ID(attacker_id)].spell_caster_pid;
2521  }
2522  if (PID_TYPE(attacker_id) == OBJECT_Actor) {
2523  if (!pActors[actor_id].IsNotAlive()) {
2524  pActors[actor_id].uLastCharacterIDToHit = attacker_id;
2525  if (pActors[actor_id].uAIState == Fleeing)
2526  pActors[actor_id].uAttributes |= ACTOR_FLEEING;
2527  if (pActors[PID_ID(attacker_id)]._4273BB_DoesHitOtherActor(
2528  &pActors[actor_id], v4, 0)) {
2529  dmgToRecv = pActors[PID_ID(attacker_id)]._43B3E0_CalcDamage(a4);
2530  if (pActors[PID_ID(attacker_id)]
2532  .Active()) {
2533  if (pActors[PID_ID(attacker_id)]
2535  .uPower > 0)
2536  dmgToRecv =
2537  dmgToRecv / pActors[PID_ID(attacker_id)]
2538  .pActorBuffs[ACTOR_BUFF_SHRINK]
2539  .uPower;
2540  }
2541  if (pActors[actor_id].pActorBuffs[ACTOR_BUFF_STONED].Active())
2542  dmgToRecv = 0;
2543  if (a4 == 0) {
2544  v12 =
2545  pActors[PID_ID(attacker_id)].pMonsterInfo.uAttack1Type;
2546  } else if (a4 == 1) {
2547  v12 =
2548  pActors[PID_ID(attacker_id)].pMonsterInfo.uAttack2Type;
2549  if (pActors[actor_id]
2551  .Active())
2552  dmgToRecv = dmgToRecv / 2;
2553  } else if (a4 == 2) {
2554  v12 = pSpellStats
2555  ->pInfos[pActors[actor_id].pMonsterInfo.uSpell1ID]
2556  .uSchool;
2557  } else if (a4 == 3) {
2558  v12 = pSpellStats
2559  ->pInfos[pActors[actor_id].pMonsterInfo.uSpell2ID]
2560  .uSchool;
2561  } else if (a4 == 4) {
2562  v12 = pActors[PID_ID(attacker_id)]
2563  .pMonsterInfo.field_3C_some_special_attack;
2564  } else {
2565  v12 = 4;
2566  }
2567  finalDmg = pActors[actor_id].CalcMagicalDamageToActor(
2568  (DAMAGE_TYPE)v12, dmgToRecv);
2569  pActors[actor_id].sCurrentHP -= finalDmg;
2570  if (finalDmg) {
2571  if (pActors[actor_id].sCurrentHP > 0)
2572  Actor::AI_Stun(actor_id, attacker_id, 0);
2573  else
2574  Actor::Die(actor_id);
2575  Actor::AggroSurroundingPeasants(actor_id, 0);
2576  pushDistance =
2577  20 * finalDmg / pActors[actor_id].pMonsterInfo.uHP;
2578  if (pushDistance > 10) pushDistance = 10;
2580  pActors[actor_id].pMonsterInfo.uID,
2582  pVelocity->x =
2583  (int32)fixpoint_mul(pushDistance, pVelocity->x);
2584  pVelocity->y =
2585  (int32)fixpoint_mul(pushDistance, pVelocity->y);
2586  pVelocity->z =
2587  (int32)fixpoint_mul(pushDistance, pVelocity->z);
2588  pActors[actor_id].vVelocity.x =
2589  50 * (short)pVelocity->x;
2590  pActors[actor_id].vVelocity.y =
2591  50 * (short)pVelocity->y;
2592  pActors[actor_id].vVelocity.z =
2593  50 * (short)pVelocity->z;
2594  }
2595  Actor::AddBloodsplatOnDamageOverlay(actor_id, 1, finalDmg);
2596  } else {
2597  Actor::AI_Stun(actor_id, attacker_id, 0);
2598  }
2599  return;
2600  }
2601  }
2602  }
2603 }
2604 
2605 //----- (0044FD29) --------------------------------------------------------
2606 void Actor::SummonMinion(int summonerId) {
2607  unsigned __int8 extraSummonLevel; // al@1
2608  int summonMonsterBaseType; // esi@1
2609  int v5; // edx@2
2610  int v7; // edi@10
2611  Actor *actor; // esi@10
2612  MonsterInfo *v9; // ebx@10
2613  // MonsterDesc *v10; // edi@10
2614  int v13; // ebx@10
2615  int64 v15; // edi@10
2616  int64 v17; // ebx@10
2617  unsigned int v19; // qax@10
2618  int result; // eax@13
2619  unsigned int monsterId; // [sp+10h] [bp-18h]@8
2620  int v27; // [sp+18h] [bp-10h]@10
2621  int actorSector; // [sp+1Ch] [bp-Ch]@8
2622 
2623  actorSector = 0;
2625  actorSector = pIndoor->GetSector(this->vPosition.x, this->vPosition.y,
2626  this->vPosition.z);
2627 
2628  v19 = this->uAlly;
2629  if (!this->uAlly) {
2630  monsterId = this->pMonsterInfo.uID - 1;
2631  v19 = (uint)(monsterId * 0.33333334);
2632  }
2633  v27 = uCurrentlyLoadedLevelType == LEVEL_Outdoor ? 128 : 64;
2634  v13 = rand() % 2048;
2635  v15 = fixpoint_mul(stru_5C6E00->Cos(v13), v27) + this->vPosition.x;
2636  v17 = fixpoint_mul(stru_5C6E00->Sin(v13), v27) + this->vPosition.y;
2637 
2639  result = pIndoor->GetSector(v15, v17, this->vPosition.z);
2640  if (result != actorSector) return;
2641  result = BLV_GetFloorLevel(v15, v17, v27, result, &monsterId);
2642  if (result != -30000) return;
2643  if (abs(result - v27) > 1024) return;
2644  }
2645 
2646  extraSummonLevel = this->pMonsterInfo.uSpecialAbilityDamageDiceRolls;
2647  summonMonsterBaseType = this->pMonsterInfo.field_3C_some_special_attack;
2648  if (extraSummonLevel) {
2649  if (extraSummonLevel >= 1 && extraSummonLevel <= 3)
2650  summonMonsterBaseType =
2651  summonMonsterBaseType + extraSummonLevel - 1;
2652  } else {
2653  v5 = rand() % 100;
2654  if (v5 >= 90)
2655  summonMonsterBaseType += 2;
2656  else if (v5 >= 60)
2657  summonMonsterBaseType += 1;
2658  }
2659  v7 = summonMonsterBaseType - 1;
2660  actor = &pActors[uNumActors];
2661  v9 = &pMonsterStats->pInfos[v7 + 1];
2662  pActors[uNumActors].Reset();
2663  strcpy(actor->pActorName, v9->pName);
2664  actor->sCurrentHP = (short)v9->uHP;
2665  memcpy(&actor->pMonsterInfo, v9, sizeof(actor->pMonsterInfo));
2666  actor->word_000086_some_monster_id = summonMonsterBaseType;
2669  actor->pMonsterInfo.uTreasureDiceRolls = 0;
2670  actor->pMonsterInfo.uTreasureType = 0;
2671  actor->pMonsterInfo.uExp = 0;
2673 
2674  actor->vInitialPosition.x = v15;
2675  actor->vInitialPosition.y = v17;
2676  actor->vInitialPosition.z = this->vPosition.z;
2677  actor->vPosition.x = v15;
2678  actor->vPosition.y = v17;
2679  actor->vPosition.z = this->vPosition.z;
2680 
2681  actor->uTetherDistance = 256;
2682  actor->uSectorID = actorSector;
2683  actor->PrepareSprites(0);
2685  actor->uAlly = v19;
2686  actor->uCurrentActionTime = 0;
2687  actor->uGroup = this->uGroup;
2688  actor->uAIState = Summoned;
2689  actor->uCurrentActionLength = 256;
2690  actor->UpdateAnimation();
2691 
2692  ++uNumActors;
2694  if (ActorEnemy()) actor->uAttributes |= ACTOR_AGGRESSOR;
2695  actor->uSummonerID = PID(OBJECT_Actor, summonerId);
2696 }
2697 // 46DF1A: using guessed type int 46DF1A_collide_against_actor(int, int);
2698 //----- (0046DF1A) --------------------------------------------------------
2700  Actor *v2; // edi@1
2701  unsigned __int16 v3; // ax@1
2702  int v4; // esi@6
2703  int v8; // ecx@14
2704  int v9; // eax@14
2705  int v10; // ebx@14
2706  int v11; // esi@14
2707  int v12; // ebx@15
2708  int v13; // ebx@17
2709 
2710  v2 = &pActors[a1];
2711  v3 = v2->uAIState;
2712  if (v3 == Removed || v3 == Dying || v3 == Disabled || v3 == Dead ||
2713  v3 == Summoned)
2714  return 0;
2715  v4 = v2->uActorRadius;
2716  if (a2) v4 = a2;
2717 
2718  if (stru_721530.sMaxX > v2->vPosition.x + v4 ||
2719  stru_721530.sMinX < v2->vPosition.x - v4 ||
2720  stru_721530.sMaxY > v2->vPosition.y + v4 ||
2721  stru_721530.sMinY < v2->vPosition.y - v4 ||
2722  stru_721530.sMaxZ > v2->vPosition.z + v2->uActorHeight ||
2723  stru_721530.sMinZ < v2->vPosition.z) {
2724  return false;
2725  }
2726  v8 = v2->vPosition.x - stru_721530.normal.x;
2727  v9 = v2->vPosition.y - stru_721530.normal.y;
2728  v10 = stru_721530.prolly_normal_d + v4;
2729  v11 = (v8 * stru_721530.direction.y - v9 * stru_721530.direction.x) >> 16;
2730  v12 = (v8 * stru_721530.direction.x + v9 * stru_721530.direction.y) >> 16;
2731  if (abs(v11) > v10 || v12 <= 0) return false;
2733  v2->vPosition.z)
2734  return false;
2735 
2736  v13 = v12 - integer_sqrt(v10 * v10 - v11 * v11);
2737  if (v13 < 0) v13 = 0;
2738  if (v13 < stru_721530.field_7C) {
2739  stru_721530.field_7C = v13;
2740  stru_721530.pid = PID(OBJECT_Actor, a1);
2741  }
2742  return true;
2743 }
2744 //----- (00401A91) --------------------------------------------------------
2746  signed int v4; // edi@10
2747  signed int sDmg; // eax@14
2748  Player *pPlayer; // ecx@21
2749  Actor *pActor; // esi@34
2750  // unsigned __int16 v22; // ax@86
2751  unsigned int v27; // ecx@123
2752  unsigned int v28; // eax@123
2753  int v33; // eax@144
2754  int v34; // eax@147
2755  char v35; // al@150
2756  unsigned int v36; // edi@152
2757  signed int v37; // eax@154
2758  double v42; // st7@176
2759  double v43; // st6@176
2760  int v45; // eax@192
2761  unsigned __int8 v46; // cl@197
2762  signed int v47; // st7@206
2763  uint v58; // st7@246
2764  unsigned int v65; // [sp-10h] [bp-C0h]@144
2765  int v70; // [sp-10h] [bp-C0h]@213
2766  AIDirection v72; // [sp+0h] [bp-B0h]@246
2767  AIDirection a3; // [sp+1Ch] [bp-94h]@129
2768  int target_pid_type; // [sp+70h] [bp-40h]@83
2769  signed int a1; // [sp+74h] [bp-3Ch]@129
2770  int v78; // [sp+78h] [bp-38h]@79
2771  AIDirection *pDir; // [sp+7Ch] [bp-34h]@129
2772  float radiusMultiplier; // [sp+98h] [bp-18h]@33
2773  int v81; // [sp+9Ch] [bp-14h]@100
2774  signed int target_pid; // [sp+ACh] [bp-4h]@83
2775  AIState uAIState;
2776  uint v38;
2777 
2778  // Build AI array
2781  else
2783 
2784  // Armageddon damage mechanic
2786  pParty->armageddon_timer > 0) {
2787  if (pParty->armageddon_timer > 417) {
2788  pParty->armageddon_timer = 0;
2789  } else {
2791  (pParty->sRotationY + rand() % 16 - 8);
2792  pParty->sRotationX = pParty->sRotationX + rand() % 16 - 8;
2793  if (pParty->sRotationX > 128)
2794  pParty->sRotationX = 128;
2795  else if (pParty->sRotationX < -128)
2796  pParty->sRotationX = -128;
2797 
2798  pParty->uFlags |= 2u;
2800  v4 = pParty->armageddonDamage + 50;
2801  if (pParty->armageddon_timer <= 0) {
2802  pParty->armageddon_timer = 0;
2803  for (size_t i = 0; i < uNumActors; i++) {
2804  pActor = &pActors[i];
2805  if (pActor->CanAct()) {
2806  sDmg = pActor->CalcMagicalDamageToActor((DAMAGE_TYPE)5,
2807  v4);
2808  pActor->sCurrentHP -= sDmg;
2809  if (sDmg) {
2810  if (pActor->sCurrentHP >= 0) {
2811  Actor::AI_Stun(i, 4, 0);
2812  } else {
2813  Actor::Die(i);
2814  if (pActor->pMonsterInfo.uExp)
2817  ->pInfos[pActor->pMonsterInfo.uID]
2818  .uExp);
2819  }
2820  }
2821  }
2822  }
2823  for (int i = 1; i <= 4; i++) {
2824  pPlayer = pPlayers[i];
2825  if (!pPlayer->conditions_times[Condition_Dead] &&
2828  pPlayer->ReceiveDamage(v4, DMGT_MAGICAL);
2829  }
2830  }
2832  }
2833  }
2834 
2835  // Turn-based mode: return
2836  if (pParty->bTurnBasedModeOn) {
2838  return;
2839  }
2840 
2841  for (uint i = 0; i < uNumActors; ++i) {
2842  pActor = &pActors[i];
2844 
2845  // Skip actor if: Dead / Removed / Disabled / uAttributes & 0x0400
2846  if (pActor->uAIState == Dead || pActor->uAIState == Removed ||
2847  pActor->uAIState == Disabled || pActor->uAttributes & ACTOR_ALIVE)
2848  continue;
2849 
2850  // Kill actor if HP == 0
2851  if (!pActor->sCurrentHP && pActor->uAIState != Dying) Actor::Die(i);
2852 
2853  // Kill buffs if expired
2854  for (uint j = 0; j < 22; ++j) {
2855  if (j != 10)
2856  pActor->pActorBuffs[j].IsBuffExpiredToTime(
2857  pParty->GetPlayingTime());
2858  }
2859 
2860  // If shrink expired: reset height
2861  if (pActor->pActorBuffs[ACTOR_BUFF_SHRINK].Expired()) {
2862  pActor->uActorHeight =
2863  pMonsterList->pMonsters[pActor->pMonsterInfo.uID - 1]
2864  .uMonsterHeight;
2865  }
2866 
2867  // If Charm still active: make actor friendly
2868  if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].Active()) {
2869  pActor->pMonsterInfo.uHostilityType =
2871  } else if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].Expired()) {
2872  // Else: reset hostilty
2873  pActor->pMonsterInfo.uHostilityType =
2875  }
2876 
2877  // If actor Paralyzed or Stoned: skip
2878  if (pActor->pActorBuffs[ACTOR_BUFF_PARALYZED].Active() ||
2880  continue;
2881 
2882  // Calculate RecoveryTime
2883  pActor->pMonsterInfo.uRecoveryTime = std::max((signed int)
2885 
2887  if (pActor->uCurrentActionTime < pActor->uCurrentActionLength) continue;
2888 
2889  if (pActor->uAIState == Dying) {
2890  pActor->uAIState = Dead;
2891  } else {
2892  if (pActor->uAIState != Summoned) {
2893  Actor::AI_StandOrBored(i, OBJECT_Player, 256, nullptr);
2894  continue;
2895  }
2896  pActor->uAIState = Standing;
2897  }
2898 
2899  pActor->uCurrentActionTime = 0;
2900  pActor->uCurrentActionLength = 0;
2901  pActor->UpdateAnimation();
2902  }
2903 
2904  for (v78 = 0; v78 < ai_arrays_size; ++v78) {
2905  uint actor_id = ai_near_actors_ids[v78];
2906  assert(actor_id < uNumActors);
2907 
2908  pActor = &pActors[actor_id];
2909 
2910  v47 = (signed int)(pActor->pMonsterInfo.uRecoveryTime *
2911  2.133333333333333);
2912 
2913  Actor::_SelectTarget(actor_id, &ai_near_actors_targets_pid[actor_id],
2914  true);
2915 
2916  if (pActor->pMonsterInfo.uHostilityType &&
2917  !ai_near_actors_targets_pid[actor_id])
2918  pActor->pMonsterInfo.uHostilityType =
2920 
2921  target_pid = ai_near_actors_targets_pid[actor_id];
2922  target_pid_type = PID_TYPE(target_pid);
2923 
2924  if (target_pid_type == OBJECT_Actor)
2925  radiusMultiplier = 0.5;
2926  else
2927  radiusMultiplier = 1.0;
2928 
2929  // v22 = pActor->uAIState;
2930  if (pActor->uAIState == Dying || pActor->uAIState == Dead ||
2931  pActor->uAIState == Removed || pActor->uAIState == Disabled ||
2932  pActor->uAIState == Summoned)
2933  continue;
2934 
2935  if (!pActor->sCurrentHP) Actor::Die(actor_id);
2936 
2937  for (int i = 0; i < 22; i++) {
2938  if (i != 10)
2939  pActor->pActorBuffs[i].IsBuffExpiredToTime(
2940  pParty->GetPlayingTime());
2941  }
2942 
2943  if (pActor->pActorBuffs[ACTOR_BUFF_SHRINK].Expired()) {
2944  pActor->uActorHeight =
2945  pMonsterList->pMonsters[pActor->pMonsterInfo.uID - 1]
2946  .uMonsterHeight;
2947  }
2948 
2949  if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].Active()) {
2950  pActor->pMonsterInfo.uHostilityType =
2952  } else if (pActor->pActorBuffs[ACTOR_BUFF_CHARM].Expired()) {
2953  pActor->pMonsterInfo.uHostilityType =
2955  }
2956 
2957  // If actor is summoned and buff expired: continue and set state to
2958  // Removed
2959  if (pActor->pActorBuffs[ACTOR_BUFF_SUMMONED].Expired()) {
2960  pActor->uAIState = Removed;
2961  continue;
2962  }
2963 
2964  if (pActor->pActorBuffs[ACTOR_BUFF_STONED].Active() ||
2966  continue;
2967  }
2968 
2969  v27 = pMiscTimer->uTimeElapsed;
2970  v28 = pActor->pMonsterInfo.uRecoveryTime;
2972 
2973  if ((signed int)v28 > 0) pActor->pMonsterInfo.uRecoveryTime = v28 - v27;
2974  if (pActor->pMonsterInfo.uRecoveryTime < 0)
2975  pActor->pMonsterInfo.uRecoveryTime = 0;
2976  if (!pActor->ActorNearby()) pActor->uAttributes |= ACTOR_NEARBY;
2977 
2978  a1 = PID(OBJECT_Actor, actor_id);
2979  Actor::GetDirectionInfo(PID(OBJECT_Actor, actor_id), target_pid, &a3,
2980  0);
2981  pDir = &a3;
2982  uAIState = pActor->uAIState;
2983 
2984  if (pActor->pMonsterInfo.uHostilityType ==
2986  (signed int)pActor->pMonsterInfo.uRecoveryTime > 0 ||
2987  radiusMultiplier * 307.2 < pDir->uDistance ||
2988  uAIState != Pursuing && uAIState != Standing &&
2989  uAIState != Tethered && uAIState != Fidgeting &&
2990  !pActor->pMonsterInfo.uMissleAttack1Type ||
2991  uAIState != Stunned) {
2992  if (pActor->uCurrentActionTime < pActor->uCurrentActionLength) {
2993  continue;
2994  } else if (pActor->uAIState == AttackingMelee) {
2995  v35 = pActor->special_ability_use_check(actor_id);
2996  AttackerInfo.Add(a1, 5120, pActor->vPosition.x,
2997  pActor->vPosition.y,
2998  pActor->vPosition.z +
2999  ((signed int)pActor->uActorHeight >> 1),
3000  v35, 1);
3001  } else if (pActor->uAIState == AttackingRanged1) {
3002  v34 = pActor->pMonsterInfo.uMissleAttack1Type;
3003  Actor::AI_RangedAttack(actor_id, pDir, v34, 0); // light missile
3004  } else if (pActor->uAIState == AttackingRanged2) {
3005  v34 = pActor->pMonsterInfo.uMissleAttack2Type;
3006  Actor::AI_RangedAttack(actor_id, pDir, v34, 1); // arrow
3007  } else if (pActor->uAIState == AttackingRanged3) {
3008  v65 = pActor->pMonsterInfo.uSpellSkillAndMastery1;
3009  v33 = pActor->pMonsterInfo.uSpell1ID;
3010  Actor::AI_SpellAttack(actor_id, pDir, v33, 2, v65);
3011  } else if (pActor->uAIState == AttackingRanged4) {
3012  v65 = pActor->pMonsterInfo.uSpellSkillAndMastery2;
3013  v33 = pActor->pMonsterInfo.uSpell2ID;
3014  Actor::AI_SpellAttack(actor_id, pDir, v33, 3, v65);
3015  }
3016  }
3017 
3018  v36 = pDir->uDistance;
3019 
3020  if (pActor->pMonsterInfo.uHostilityType ==
3022  if (target_pid_type == OBJECT_Actor) {
3023  v36 = pDir->uDistance;
3024  v37 = pFactionTable->relations
3025  [(pActor->pMonsterInfo.uID - 1) / 3 + 1]
3026  [(pActors[PID_ID(target_pid)].pMonsterInfo.uID - 1) /
3027  3 +
3028  1];
3029  } else {
3030  v37 = 4;
3031  }
3032  v38 = 0;
3033  if (v37 == 2)
3034  v38 = 1024;
3035  else if (v37 == 3)
3036  v38 = 2560;
3037  else if (v37 == 4)
3038  v38 = 5120;
3039  if (v37 >= 1 && v37 <= 4 && v36 < v38 || v37 == 1)
3040  pActor->pMonsterInfo.uHostilityType =
3042  }
3043 
3044  // If actor afraid: flee or if out of range random move
3045  if (pActor->pActorBuffs[ACTOR_BUFF_AFRAID].Active()) {
3046  if ((signed int)v36 >= 10240)
3047  Actor::AI_RandomMove(actor_id, target_pid, 1024, 0);
3048  else
3049  Actor::AI_Flee(actor_id, target_pid, 0, pDir);
3050  continue;
3051  }
3052 
3053  if (pActor->pMonsterInfo.uHostilityType ==
3055  target_pid) {
3056  if (pActor->pMonsterInfo.uAIType == 1) {
3057  if (pActor->pMonsterInfo.uMovementType ==
3059  Actor::AI_Stand(actor_id, target_pid,
3060  (uint)(pActor->pMonsterInfo.uRecoveryTime *
3061  2.133333333333333),
3062  pDir);
3063  } else {
3064  Actor::AI_Flee(actor_id, target_pid, 0, pDir);
3065  continue;
3066  }
3067  }
3068  if (!(pActor->uAttributes & ACTOR_FLEEING)) {
3069  if (pActor->pMonsterInfo.uAIType == 2 ||
3070  pActor->pMonsterInfo.uAIType == 3) {
3071  if (pActor->pMonsterInfo.uAIType == 2)
3072  v43 =
3073  (double)(signed int)pActor->pMonsterInfo.uHP * 0.2;
3074  if (pActor->pMonsterInfo.uAIType == 3)
3075  v43 =
3076  (double)(signed int)pActor->pMonsterInfo.uHP * 0.1;
3077  v42 = (double)pActor->sCurrentHP;
3078  if (v43 > v42 && (signed int)v36 < 10240) {
3079  Actor::AI_Flee(actor_id, target_pid, 0, pDir);
3080  continue;
3081  }
3082  }
3083  }
3084 
3085  v81 = v36 - pActor->uActorRadius;
3086  if (target_pid_type == OBJECT_Actor)
3087  v81 -= pActors[PID_ID(target_pid)].uActorRadius;
3088  if (v81 < 0) v81 = 0;
3089  // rand();
3090  pActor->uAttributes &= ~ACTOR_UNKNOW5; // ~0x40000
3091  if (v81 < 5120) {
3092  v45 = pActor->special_ability_use_check(actor_id);
3093  if (v45 == 0) {
3094  if (pActor->pMonsterInfo.uMissleAttack1Type) {
3095  if ((int)pActor->pMonsterInfo.uRecoveryTime <= 0) {
3096  Actor::AI_MissileAttack1(actor_id, target_pid,
3097  pDir);
3098  } else if (pActor->pMonsterInfo.uMovementType ==
3100  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3101  } else {
3102  if (radiusMultiplier * 307.2 > (double)v81)
3103  Actor::AI_Stand(actor_id, target_pid, v47,
3104  pDir);
3105  else
3106  Actor::AI_Pursue1(actor_id, target_pid,
3107  actor_id, v47, pDir);
3108  }
3109  } else {
3110  if ((double)v81 >= radiusMultiplier * 307.2) {
3111  if (pActor->pMonsterInfo.uMovementType ==
3113  Actor::AI_Stand(actor_id, target_pid, v47,
3114  pDir);
3115  } else if (v81 >= 1024) { // monsters
3116  Actor::AI_Pursue3(actor_id, target_pid, 0,
3117  pDir);
3118  } else {
3119  v70 = (signed int)(radiusMultiplier * 307.2);
3120  // monsters
3121  // guard after player runs away
3122  // follow player
3123  Actor::AI_Pursue2(actor_id, target_pid, 0, pDir,
3124  v70);
3125  }
3126  } else if ((signed int)
3127  pActor->pMonsterInfo.uRecoveryTime > 0) {
3128  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3129  } else {
3130  // monsters
3131  Actor::AI_MeleeAttack(actor_id, target_pid, pDir);
3132  }
3133  }
3134  continue;
3135  } else if (v45 == 2 || v45 == 3) {
3136  if (v45 == 2)
3137  v46 = pActor->pMonsterInfo.uSpell1ID;
3138  else
3139  v46 = pActor->pMonsterInfo.uSpell2ID;
3140  if (v46) {
3141  if ((signed int)pActor->pMonsterInfo.uRecoveryTime <=
3142  0) {
3143  if (v45 == 2)
3144  Actor::AI_SpellAttack1(actor_id, target_pid,
3145  pDir);
3146  else
3147  Actor::AI_SpellAttack2(actor_id, target_pid,
3148  pDir);
3149  } else if (radiusMultiplier * 307.2 > (double)v81 ||
3150  pActor->pMonsterInfo.uMovementType ==
3152  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3153  } else {
3154  Actor::AI_Pursue1(actor_id, target_pid, actor_id,
3155  v47, pDir);
3156  }
3157  } else {
3158  if ((double)v81 >= radiusMultiplier * 307.2) {
3159  if (pActor->pMonsterInfo.uMovementType ==
3161  Actor::AI_Stand(actor_id, target_pid, v47,
3162  pDir);
3163  } else if (v81 >= 1024) {
3164  Actor::AI_Pursue3(actor_id, target_pid, 256,
3165  pDir);
3166  } else {
3167  v70 = (signed int)(radiusMultiplier * 307.2);
3168  Actor::AI_Pursue2(actor_id, target_pid, 0, pDir,
3169  v70);
3170  }
3171  } else if ((signed int)
3172  pActor->pMonsterInfo.uRecoveryTime > 0) {
3173  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3174  } else {
3175  Actor::AI_MeleeAttack(actor_id, target_pid, pDir);
3176  }
3177  }
3178  continue;
3179  }
3180  }
3181  }
3182 
3183  if (pActor->pMonsterInfo.uHostilityType !=
3185  !target_pid || v81 >= 5120 || v45 != 1) {
3186  if (pActor->pMonsterInfo.uMovementType ==
3188  Actor::AI_RandomMove(actor_id, 4, 1024, 0);
3189  } else if (pActor->pMonsterInfo.uMovementType ==
3191  Actor::AI_RandomMove(actor_id, 4, 2560, 0);
3192  } else if (pActor->pMonsterInfo.uMovementType ==
3194  Actor::AI_RandomMove(actor_id, 4, 5120, 0);
3195  } else if (pActor->pMonsterInfo.uMovementType ==
3197  Actor::AI_RandomMove(actor_id, 4, 10240, 0);
3198  } else if (pActor->pMonsterInfo.uMovementType ==
3200  Actor::GetDirectionInfo(a1, 4, &v72, 0);
3201  v58 = (uint)(pActor->pMonsterInfo.uRecoveryTime *
3202  2.133333333333333);
3203  Actor::AI_Stand(actor_id, 4, v58, &v72);
3204  }
3205  } else if (!pActor->pMonsterInfo.uMissleAttack2Type) {
3206  if ((double)v81 >= radiusMultiplier * 307.2) {
3207  if (pActor->pMonsterInfo.uMovementType ==
3209  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3210  } else if (v81 >= 1024) {
3211  Actor::AI_Pursue3(actor_id, target_pid, 256, pDir);
3212  } else {
3213  v70 = (int)(radiusMultiplier * 307.2);
3214  Actor::AI_Pursue2(actor_id, target_pid, 0, pDir, v70);
3215  }
3216  } else if ((signed int)pActor->pMonsterInfo.uRecoveryTime > 0) {
3217  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3218  } else {
3219  Actor::AI_MeleeAttack(actor_id, target_pid, pDir);
3220  }
3221  } else if ((signed int)pActor->pMonsterInfo.uRecoveryTime > 0) {
3222  if (radiusMultiplier * 307.2 > (double)v81 ||
3223  pActor->pMonsterInfo.uMovementType ==
3225  Actor::AI_Stand(actor_id, target_pid, v47, pDir);
3226  else
3227  Actor::AI_Pursue1(actor_id, target_pid, actor_id, v47, pDir);
3228  } else {
3229  Actor::AI_MissileAttack2(actor_id, target_pid, pDir);
3230  }
3231  }
3232 }
3233 
3234 //----- (0044665D) --------------------------------------------------------
3235 // uType: 0 -> any monster
3236 // 1 -> uParam is GroupID
3237 // 2 -> uParam is MonsterID
3238 // 3 -> uParam is ActorID
3239 // uNumAlive: 0 -> all must be alive
3240 int IsActorAlive(unsigned int uType, unsigned int uParam,
3241  unsigned int uNumAlive) {
3242  unsigned int uAliveActors; // eax@6
3243  unsigned int uTotalActors; // [sp+0h] [bp-4h]@1
3244 
3245  uTotalActors = 0;
3246  if (uType) {
3247  if (uType == 1) {
3248  uAliveActors = Actor::SearchActorByGroup(&uTotalActors, uParam);
3249  } else {
3250  if (uType == 2) {
3251  uAliveActors =
3252  Actor::SearchActorByMonsterID(&uTotalActors, uParam);
3253  } else {
3254  if (uType != 3) return 0;
3255  uAliveActors = Actor::SearchActorByID(&uTotalActors, uParam);
3256  }
3257  }
3258  } else {
3259  uAliveActors = Actor::SearchAliveActors(&uTotalActors);
3260  }
3261 
3262  if (uNumAlive)
3263  return uAliveActors >= uNumAlive;
3264  else
3265  return uTotalActors == uAliveActors;
3266 }
3267 //----- (00408B54) --------------------------------------------------------
3268 unsigned int Actor::SearchActorByID(unsigned int *pTotalActors,
3269  unsigned int a2) {
3270  // int v4; // eax@1
3271  unsigned int result; // ebx@1
3272 
3273  // v4 = GetAlertStatus();
3274  *pTotalActors = 0;
3275  result = 0;
3276  if ((pActors[a2].uAttributes & ACTOR_UNKNOW7) == GetAlertStatus()) {
3277  *pTotalActors = 1;
3278  if (pActors[a2].IsNotAlive() == 1) result = 1;
3279  }
3280  return result;
3281 }
3282 //----- (00408AE7) --------------------------------------------------------
3283 unsigned int Actor::SearchActorByGroup(unsigned int *pTotalActors,
3284  unsigned int uGroup) {
3285  unsigned int result; // [sp+10h] [bp-4h]@1
3286 
3287  int v8 = GetAlertStatus();
3288  *pTotalActors = 0;
3289  result = 0;
3290  for (uint i = 0; i < uNumActors; i++) {
3291  if ((pActors[i].uAttributes & ACTOR_UNKNOW7) == v8 &&
3292  pActors[i].uGroup == uGroup) {
3293  ++*pTotalActors;
3294  if (pActors[i].IsNotAlive() == 1) ++result;
3295  }
3296  }
3297  return result;
3298 }
3299 //----- (00408A7E) --------------------------------------------------------
3300 unsigned int Actor::SearchActorByMonsterID(unsigned int *pTotalActors,
3301  int uMonsterID) {
3302  int v8; // [sp+Ch] [bp-8h]@1
3303  unsigned int result; // [sp+10h] [bp-4h]@1
3304 
3305  v8 = GetAlertStatus();
3306  *pTotalActors = 0;
3307  result = 0;
3308  for (uint i = 0; i < uNumActors; i++) {
3309  if ((pActors[i].uAttributes & ACTOR_UNKNOW7) == v8 &&
3310  pActors[i].pMonsterInfo.field_33 == uMonsterID) {
3311  ++*pTotalActors;
3312  if (pActors[i].IsNotAlive() == 1) ++result;
3313  }
3314  }
3315  return result;
3316 }
3317 //----- (00408A27) --------------------------------------------------------
3318 unsigned int Actor::SearchAliveActors(unsigned int *pTotalActors) {
3319  int v2; // eax@1
3320  unsigned int result; // ebp@1
3321 
3322  v2 = GetAlertStatus();
3323  result = 0;
3324  *pTotalActors = 0;
3325  for (uint i = 0; i < uNumActors; i++) {
3326  if ((pActors[i].uAttributes & ACTOR_UNKNOW7) == v2) {
3327  ++*pTotalActors;
3328  if (pActors[i].IsNotAlive() == 1) ++result;
3329  }
3330  }
3331  return result;
3332 }
3333 //----- (00408768) --------------------------------------------------------
3335  bool bCelestia = false;
3336  bool bPit = false;
3337  bool good = false;
3338  bool evil = false;
3339  if (pCurrentMapName == "d25.blv") { // the Celestia
3340  bCelestia = true;
3341  }
3342  if (pCurrentMapName == "d26.blv") { // the Pit
3343  bPit = true;
3344  }
3345  if (pParty->IsPartyGood()) good = true;
3346  if (pParty->IsPartyEvil()) evil = true;
3347 
3348  logger->Warning(
3349  L"%S %S %u", __FILE__, __FUNCTION__,
3350  __LINE__); // ai_near_actors_targets_pid[i] for AI_Stand seems always
3351  // 0; original code behaviour is identical
3352  for (uint i = 0; i < uNumActors; ++i) {
3353  Actor *actor = &pActors[i];
3354 
3355  if (actor->CanAct() || actor->uAIState == Disabled) {
3356  actor->vPosition.x = actor->vInitialPosition.x;
3357  actor->vPosition.y = actor->vInitialPosition.y;
3358  actor->vPosition.z = actor->vInitialPosition.z;
3359  actor->sCurrentHP = actor->pMonsterInfo.uHP;
3360  if (actor->uAIState != Disabled) {
3362  actor->pMonsterInfo.uRecoveryTime, 0);
3363  }
3364  }
3365 
3367 
3368  if (!bCelestia || good)
3369  if (!bPit || evil)
3370  if (actor->IsPeasant()) actor->ResetAggressor(); // ~0x80000
3371 
3372  actor->ResetHasItem(); // ~0x800000
3373  if (actor->uAttributes & ACTOR_UNKNOW9)
3375  1);
3376  }
3377 }
3378 //----- (00439474) --------------------------------------------------------
3379 void Actor::DamageMonsterFromParty(signed int a1, unsigned int uActorID_Monster,
3380  Vec3_int_ *pVelocity) {
3381  SpriteObject *projectileSprite; // ebx@1
3382  Actor *pMonster; // esi@7
3383  unsigned __int16 v16; // cx@25
3384  int v33; // eax@100
3385  int v40; // ebx@107
3386  int extraRecoveryTime; // qax@125
3387  unsigned __int16 v43; // ax@132
3388  unsigned __int16 v45; // ax@132
3389  // unsigned __int64 v46; // [sp+Ch] [bp-60h]@6
3390  char *pPlayerName; // [sp+18h] [bp-54h]@12
3391  char *pMonsterName; // [sp+1Ch] [bp-50h]@6
3392  signed int a4; // [sp+44h] [bp-28h]@1
3393  bool IsAdditionalDamagePossible; // [sp+50h] [bp-1Ch]@1
3394  int v61; // [sp+58h] [bp-14h]@1
3395  bool isLifeStealing; // [sp+5Ch] [bp-10h]@1
3396  int uDamageAmount; // [sp+60h] [bp-Ch]@1
3397  DAMAGE_TYPE attackElement; // [sp+64h] [bp-8h]@27
3398 
3399  projectileSprite = 0;
3400  uDamageAmount = 0;
3401  a4 = 0;
3402  v61 = 0;
3403  IsAdditionalDamagePossible = false;
3404  isLifeStealing = 0;
3405  if (PID_TYPE(a1) == OBJECT_Item) {
3406  projectileSprite = &pSpriteObjects[PID_ID(a1)];
3407  v61 = projectileSprite->field_60_distance_related_prolly_lod;
3408  a1 = projectileSprite->spell_caster_pid;
3409  }
3410  if (PID_TYPE(a1) != OBJECT_Player) return;
3411 
3412  assert(PID_ID(abs(a1)) < 4);
3413  Player *player = &pParty->pPlayers[PID_ID(a1)];
3414  pMonster = &pActors[uActorID_Monster];
3415  if (pMonster->IsNotAlive()) return;
3416 
3417  pMonster->uAttributes |= 0xC000;
3418  if (pMonster->uAIState == Fleeing) pMonster->uAttributes |= ACTOR_FLEEING;
3419  bool hit_will_stun = false, hit_will_paralyze = false;
3420  if (!projectileSprite) {
3421  int main_hand_idx = player->pEquipment.uMainHand;
3422  IsAdditionalDamagePossible = true;
3423  if (player->HasItemEquipped(EQUIP_TWO_HANDED)) {
3424  uint main_hand_skill =
3425  player->GetMainHandItem()->GetPlayerSkillType();
3426  uint main_hand_mastery =
3427  SkillToMastery(player->pActiveSkills[main_hand_skill]);
3428  switch (main_hand_skill) {
3429  case PLAYER_SKILL_STAFF:
3430  if (main_hand_mastery >= 3) {
3431  if (rand() % 100 <
3433  0x3F)) // stun chance when mastery >= 3
3434  hit_will_stun = true;
3435  }
3436  break;
3437 
3438  case PLAYER_SKILL_MACE:
3439  if (main_hand_mastery >= 3) {
3440  if (rand() % 100 <
3442  0x3F))
3443  hit_will_stun = true;
3444  }
3445  if (main_hand_mastery >= 4) {
3446  if (rand() % 100 <
3448  0x3F))
3449  hit_will_paralyze = true;
3450  }
3451  break;
3452  }
3453  }
3454  attackElement = DMGT_PHISYCAL;
3455  uDamageAmount = player->CalculateMeleeDamageTo(
3456  false, false, pMonster->pMonsterInfo.uID);
3457  if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3458  player->PlaySound(SPEECH_52, 0);
3459  return;
3460  }
3461  } else {
3462  v61 = projectileSprite->field_60_distance_related_prolly_lod;
3463  if (projectileSprite->spell_id != SPELL_DARK_SOULDRINKER) {
3464  int d1 = abs(pParty->vPosition.x - projectileSprite->vPosition.x);
3465  int d2 = abs(pParty->vPosition.y - projectileSprite->vPosition.y);
3466  int d3 = abs(pParty->vPosition.z - projectileSprite->vPosition.z);
3467  v61 = int_get_vector_length(d1, d2, d3);
3468 
3469  if (v61 >= 5120 && !(pMonster->uAttributes & ACTOR_ALIVE)) // 0x400
3470  return;
3471  else if (v61 >= 2560)
3472  v61 = 2;
3473  else
3474  v61 = 1;
3475  }
3476 
3477  switch (projectileSprite->spell_id) {
3479  v16 = player->pActiveSkills[PLAYER_SKILL_BLASTER];
3480  v61 = 1;
3481  if (SkillToMastery(v16) >= 3)
3482  a4 = player->pActiveSkills[PLAYER_SKILL_BLASTER] & 0x3F;
3483  attackElement = DMGT_PHISYCAL;
3484  uDamageAmount = player->CalculateMeleeDamageTo(true, true, 0);
3485  if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3486  player->PlaySound(SPEECH_52, 0);
3487  return;
3488  }
3489  break;
3490  case SPELL_101:
3491  attackElement = DMGT_FIRE;
3492  uDamageAmount = player->CalculateRangedDamageTo(0);
3493  if (pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].Active())
3494  uDamageAmount >>= 1;
3495  IsAdditionalDamagePossible = true;
3496  if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3497  player->PlaySound(SPEECH_52, 0);
3498  return;
3499  }
3500  break;
3501  case SPELL_EARTH_BLADES:
3502  a4 = 5 * projectileSprite->spell_level;
3503  attackElement =
3505  uDamageAmount = _43AFE3_calc_spell_damage(
3506  39, projectileSprite->spell_level,
3507  projectileSprite->spell_skill, pMonster->sCurrentHP);
3508  if (pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].Active())
3509  uDamageAmount >>= 1;
3510  IsAdditionalDamagePossible = false;
3511  if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3512  player->PlaySound(SPEECH_52, 0);
3513  return;
3514  }
3515  break;
3516  case SPELL_EARTH_STUN:
3517  uDamageAmount = 0;
3518  attackElement = DMGT_PHISYCAL;
3519  hit_will_stun = 1;
3520  if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3521  player->PlaySound(SPEECH_52, 0);
3522  return;
3523  }
3524  break;
3525  case SPELL_BOW_ARROW:
3526  attackElement = DMGT_PHISYCAL;
3527  uDamageAmount = player->CalculateRangedDamageTo(
3528  pMonster->word_000086_some_monster_id);
3529  if (pMonster->pActorBuffs[ACTOR_BUFF_SHIELD].Active())
3530  uDamageAmount /= 2;
3531  IsAdditionalDamagePossible = true;
3532  if (projectileSprite->containing_item.uItemID != 0 &&
3533  projectileSprite->containing_item.special_enchantment ==
3534  3) { // of carnage
3535  attackElement = DMGT_FIRE;
3536  } else if (!player->PlayerHitOrMiss(pMonster, v61, a4)) {
3537  player->PlaySound(SPEECH_52, 0);
3538  return;
3539  }
3540  break;
3541 
3542  default:
3543  attackElement = (DAMAGE_TYPE)player->GetSpellSchool(
3544  projectileSprite->spell_id);
3545  IsAdditionalDamagePossible = false;
3546  uDamageAmount = _43AFE3_calc_spell_damage(
3547  projectileSprite->spell_id, projectileSprite->spell_level,
3548  projectileSprite->spell_skill, pMonster->sCurrentHP);
3549  break;
3550  }
3551  }
3552 
3553  if (player->IsWeak()) uDamageAmount /= 2;
3554  if (pMonster->pActorBuffs[ACTOR_BUFF_STONED].Active()) uDamageAmount = 0;
3555  v61 = pMonster->CalcMagicalDamageToActor(attackElement, uDamageAmount);
3556  if (!projectileSprite && player->IsUnarmed() &&
3557  player->pPlayerBuffs[PLAYER_BUFF_HAMMERHANDS].Active()) {
3558  v61 += pMonster->CalcMagicalDamageToActor(
3559  (DAMAGE_TYPE)8,
3560  player->pPlayerBuffs[PLAYER_BUFF_HAMMERHANDS].uPower);
3561  }
3562  uDamageAmount = v61;
3563  if (IsAdditionalDamagePossible) {
3564  if (projectileSprite) {
3565  a4 =
3567  &attackElement, &isLifeStealing);
3568  if (isLifeStealing && pMonster->sCurrentHP > 0) {
3569  player->sHealth += v61 / 5;
3570  if (player->sHealth > player->GetMaxHealth())
3571  player->sHealth = player->GetMaxHealth();
3572  }
3573  uDamageAmount +=
3574  pMonster->CalcMagicalDamageToActor(attackElement, a4);
3575  } else {
3576  for (int i = 0; i < 2; i++) {
3577  if (player->HasItemEquipped((ITEM_EQUIP_TYPE)i)) {
3578  ItemGen *item;
3579  if (i == 0)
3580  item = player->GetOffHandItem();
3581  else
3582  item = player->GetMainHandItem();
3583  a4 = item->_439DF3_get_additional_damage(&attackElement,
3584  &isLifeStealing);
3585  if (isLifeStealing && pMonster->sCurrentHP > 0) {
3586  player->sHealth += v61 / 5;
3587  if (player->sHealth > player->GetMaxHealth())
3588  player->sHealth = player->GetMaxHealth();
3589  }
3590  uDamageAmount +=
3591  pMonster->CalcMagicalDamageToActor(attackElement, a4);
3592  }
3593  }
3594  }
3595  }
3596  pMonster->sCurrentHP -= uDamageAmount;
3597  if (uDamageAmount == 0 && !hit_will_stun) {
3598  player->PlaySound(SPEECH_52, 0);
3599  return;
3600  }
3601  if (pMonster->sCurrentHP > 0) {
3602  Actor::AI_Stun(uActorID_Monster, a1, 0);
3603  Actor::AggroSurroundingPeasants(uActorID_Monster, 1);
3604  if (!engine->config->NoShowDamage()) {
3605  String str;
3606  if (projectileSprite)
3607  str = localization->FormatString(
3608  189, player->pName, pMonster->pActorName,
3609  uDamageAmount); // "%s shoots %s for %lu points"
3610  else
3611  str = localization->FormatString(
3612  164, player->pName, pMonster->pActorName,
3613  uDamageAmount); // "%s hits %s for %lu damage"
3615  }
3616  } else {
3617  if (pMonsterStats->pInfos[pMonster->pMonsterInfo.uID].bQuestMonster & 1) {
3618  if (!engine->config->NoBloodsplats()) {
3619  v33 = _4D864C_force_sw_render_rules && !engine->config->NoHugeBloodsplats()
3620  ? 10 * pMonster->uActorRadius
3621  : pMonster->uActorRadius;
3622  decal_builder->AddBloodsplat((float)pMonster->vPosition.x,
3623  (float)pMonster->vPosition.y,
3624  (float)pMonster->vPosition.z, 1.0,
3625  0.0, 0.0, (float)v33, 0, 0);
3626  }
3627  }
3628  Actor::Die(uActorID_Monster);
3629  Actor::ApplyFineForKillingPeasant(uActorID_Monster);
3630  Actor::AggroSurroundingPeasants(uActorID_Monster, 1);
3631  if (pMonster->pMonsterInfo.uExp)
3633  pMonsterStats->pInfos[pMonster->pMonsterInfo.uID].uExp);
3634  v40 = SPEECH_51;
3635  if (rand() % 100 < 20)
3636  v40 = ((signed int)pMonster->pMonsterInfo.uHP >= 100) + 1;
3637  player->PlaySound((PlayerSpeech)v40, 0);
3638  if (!engine->config->NoShowDamage()) {
3639  pMonsterName = (char *)uDamageAmount;
3640  pPlayerName = player->pName;
3641 
3642  auto str = localization->FormatString(
3643  175, player->pName, uDamageAmount,
3644  pMonster); // "%s inflicts %lu points killing %s"
3646  }
3647  }
3648  if (pMonster->pActorBuffs[ACTOR_BUFF_PAIN_REFLECTION].Active() &&
3649  uDamageAmount != 0)
3650  player->ReceiveDamage(uDamageAmount, attackElement);
3651  int knockbackValue = 20 * v61 / (signed int)pMonster->pMonsterInfo.uHP;
3653  hit_will_stun) &&
3654  pMonster->DoesDmgTypeDoDamage(DMGT_EARTH)) {
3655  extraRecoveryTime = 20;
3656  knockbackValue = 10;
3657  if (!pParty->bTurnBasedModeOn)
3658  extraRecoveryTime =
3659  (int)(flt_6BE3A8_debug_recmod2 * 42.66666666666666);
3660  pMonster->pMonsterInfo.uRecoveryTime += extraRecoveryTime;
3661  if (!engine->config->NoShowDamage()) {
3662  pMonsterName = player->pName;
3663 
3664  auto str = localization->FormatString(635, player->pName,
3665  pMonster); // "%s stuns %s"
3667  }
3668  }
3669  if (hit_will_paralyze && pMonster->CanAct() &&
3670  pMonster->DoesDmgTypeDoDamage(DMGT_EARTH)) {
3671  v43 = player->GetActualSkillLevel(PLAYER_SKILL_MACE);
3672  v45 = SkillToMastery(v43);
3673  GameTime v46 = GameTime(0, v43 & 63); // ??
3674  pMonster->pActorBuffs[ACTOR_BUFF_PARALYZED].Apply((pParty->GetPlayingTime() + v46), v45, 0, 0, 0);
3675  if (!engine->config->NoShowDamage()) {
3676  pMonsterName = player->pName;
3677 
3678  auto str = localization->FormatString(
3679  636, player->pName, pMonster); // "%s paralyzes %s"
3681  }
3682  }
3683  if (knockbackValue > 10) knockbackValue = 10;
3686  pVelocity->x = fixpoint_mul(knockbackValue, pVelocity->x);
3687  pVelocity->y = fixpoint_mul(knockbackValue, pVelocity->y);
3688  pVelocity->z = fixpoint_mul(knockbackValue, pVelocity->z);
3689  pMonster->vVelocity.x = 50 * (short)pVelocity->x;
3690  pMonster->vVelocity.y = 50 * (short)pVelocity->y;
3691  pMonster->vVelocity.z = 50 * (short)pVelocity->z;
3692  }
3693  Actor::AddBloodsplatOnDamageOverlay(uActorID_Monster, 1, v61);
3694 }
3695 
3696 //----- (004BBF61) --------------------------------------------------------
3697 void Actor::Arena_summon_actor(int monster_id, __int16 x, int y, int z) {
3698  // int v12; // ebx@7
3699  // int v13; // eax@8
3700  __int16 v16; // [sp+10h] [bp-4h]@3
3701 
3702  if (uNumActors < 500) {
3703  v16 = 0;
3705  v16 = pIndoor->GetSector(x, y, z);
3706  pActors[uNumActors].Reset();
3707  strcpy(pActors[uNumActors].pActorName,
3708  pMonsterStats->pInfos[monster_id].pName);
3709  pActors[uNumActors].sCurrentHP =
3710  (short)pMonsterStats->pInfos[monster_id].uHP;
3711  memcpy(&pActors[uNumActors].pMonsterInfo,
3712  &pMonsterStats->pInfos[monster_id], 0x58u);
3713  pActors[uNumActors].word_000086_some_monster_id = monster_id;
3714  pActors[uNumActors].uActorRadius =
3715  pMonsterList->pMonsters[monster_id - 1].uMonsterRadius;
3716  pActors[uNumActors].uActorHeight =
3717  pMonsterList->pMonsters[monster_id - 1].uMonsterHeight;
3718  pActors[uNumActors].uMovementSpeed =
3719  pMonsterList->pMonsters[monster_id - 1].uMovementSpeed;
3720  pActors[uNumActors].vInitialPosition.x = x;
3721  pActors[uNumActors].vPosition.x = x;
3722  pActors[uNumActors].uAttributes |= ACTOR_AGGRESSOR;
3723  pActors[uNumActors].pMonsterInfo.uTreasureType = 0;
3724  pActors[uNumActors].pMonsterInfo.uTreasureLevel = 0;
3725  pActors[uNumActors].pMonsterInfo.uTreasureDiceSides = 0;
3726  pActors[uNumActors].pMonsterInfo.uTreasureDiceRolls = 0;
3727  pActors[uNumActors].pMonsterInfo.uTreasureDropChance = 0;
3728  pActors[uNumActors].vInitialPosition.y = y;
3729  pActors[uNumActors].vPosition.y = y;
3730  pActors[uNumActors].vInitialPosition.z = z;
3731  pActors[uNumActors].vPosition.z = z;
3732  pActors[uNumActors].uTetherDistance = 256;
3733  pActors[uNumActors].uSectorID = v16;
3734  pActors[uNumActors].uGroup = 1;
3735  pActors[uNumActors].pMonsterInfo.uHostilityType =
3737  pActors[uNumActors].PrepareSprites(0);
3738  // for ( int i = 0; i < 4; i++)
3739  // pSoundList->LoadSound(pMonsterList->pMonsters[monster_id -
3740  // 1].pSoundSampleIDs[i], 0);
3741  // v12 = 0;
3742  // do
3743  // {
3744  // v13 = pSoundList->LoadSound(v12 +
3745  // word_4EE088_sound_ids[pMonsterStats->pInfos[monster_id].uSpell1ID],
3746  // 1); v12++;
3747  // }
3748  // while ( v13 );
3749  ++uNumActors;
3750  }
3751 }
3752 
3753 //----- (00426E10) --------------------------------------------------------
3755  signed int v2; // ebx@1
3756  bool flag; // edi@37
3757  int v22; // [sp+8h] [bp-140h]@3
3758  int Victims_list[60]; // [sp+48h] [bp-100h]@48
3759  int for_sex; // [sp+13Ch] [bp-Ch]@1
3760  int for_race; // [sp+140h] [bp-8h]@1
3761  int for_class; // [sp+144h] [bp-4h]@1
3762 
3763  for_class = -1;
3764  for_race = -1;
3765  for_sex = -1;
3766  v2 = 0;
3767  if (pActor->pMonsterInfo.uAttackPreference) {
3768  for (uint i = 0; i < 16; i++) {
3769  v22 = pActor->pMonsterInfo.uAttackPreference & (1 << i);
3770  if (v22) {
3771  switch (v22) {
3772  case 1:
3773  for_class = 0;
3774  break;
3775  case 2:
3776  for_class = 12;
3777  break;
3778  case 4:
3779  for_class = 16;
3780  break;
3781  case 8:
3782  for_class = 28;
3783  break;
3784  case 16:
3785  for_class = 24;
3786  break;
3787  case 32:
3788  for_class = 32;
3789  break;
3790  case 64:
3791  for_class = 20;
3792  break;
3793  case 128:
3794  for_class = 4;
3795  break;
3796  case 256:
3797  for_class = 8;
3798  break;
3799  case 512:
3800  for_sex = 0;
3801  break;
3802  case 1024:
3803  for_sex = 1;
3804  break;
3805  case 2048:
3806  for_race = 0;
3807  break;
3808  case 4096:
3809  for_race = 1;
3810  break;
3811  case 8192:
3812  for_race = 3;
3813  break;
3814  case 16384:
3815  for_race = 2;
3816  break;
3817  }
3818  v2 = 0;
3819  for (uint j = 0; j < 4; ++j) {
3820  flag = 0;
3821  if (for_class != -1 &&
3822  for_class == pPlayers[j + 1]->classType)
3823  flag = true;
3824  if (for_sex != -1 && for_sex == pPlayers[j + 1]->uSex)
3825  flag = true;
3826  if (for_race != -1 &&
3827  for_race == pPlayers[j + 1]->GetRace())
3828  flag = true;
3829  if (flag == true) {
3830  if (!(pPlayers[j + 1]
3831  ->conditions_times[Condition_Paralyzed] ||
3832  pPlayers[j + 1]
3833  ->conditions_times[Condition_Unconcious] ||
3834  pPlayers[j + 1]
3835  ->conditions_times[Condition_Dead] ||
3836  pPlayers[j + 1]
3837  ->conditions_times[Condition_Pertified] ||
3838  pPlayers[j + 1]
3839  ->conditions_times[Condition_Eradicated]))
3840  Victims_list[v2++] = j;
3841  }
3842  }
3843  }
3844  }
3845  if (v2) return Victims_list[rand() % v2];
3846  }
3847  for (uint i = 0; i < 4; ++i) {
3848  if (!(pPlayers[i + 1]->conditions_times[Condition_Paralyzed] ||
3849  pPlayers[i + 1]->conditions_times[Condition_Unconcious] ||
3850  pPlayers[i + 1]->conditions_times[Condition_Dead] ||
3851  pPlayers[i + 1]->conditions_times[Condition_Pertified] ||
3852  pPlayers[i + 1]->conditions_times[Condition_Eradicated]))
3853  Victims_list[v2++] = i;
3854  }
3855  if (v2)
3856  return Victims_list[rand() % v2];
3857  else
3858  return 0;
3859 }
3860 
3861 //----- (00427546) --------------------------------------------------------
3862 int stru319::_427546(int a2) {
3863  int result; // eax@2
3864 
3865  if (a2 >= 0) {
3866  if (a2 >= 1)
3867  result = (a2 >= 2) + 2;
3868  else
3869  result = 1;
3870  } else {
3871  result = 0;
3872  }
3873  return result;
3874 }
3875 //----- (0042F184) --------------------------------------------------------
3876 int stru319::FindClosestActor(int pick_depth, int a3, int a4) {
3877  int v4; // edi@1
3878  stru319 *v5; // esi@1
3879  int v6; // eax@2
3880  int v7; // eax@4
3881  // int result; // eax@5
3882  // int *v9; // edx@8
3883  // signed int v10; // ebx@10
3884  // int v11; // edi@11
3885  // Actor *v12; // esi@12
3886  // unsigned __int16 v13; // ax@12
3887  // int v14; // eax@22
3888  // char v15; // zf@30
3889  // int v16; // esi@32
3890  // int v17; // ecx@34
3891  // stru319 *v18; // eax@39
3892  // int v19; // edx@39
3893  // int v20; // ecx@41
3894  // unsigned __int16 v21; // ax@42
3895  // unsigned int v22; // [sp+8h] [bp-24h]@11
3896  // unsigned int v23; // [sp+Ch] [bp-20h]@7
3897  stru319 *v24; // [sp+10h] [bp-1Ch]@1
3898  // unsigned int v25; // [sp+14h] [bp-18h]@8
3899  // int *v26; // [sp+18h] [bp-14h]@8
3900  // int v27; // [sp+1Ch] [bp-10h]@10
3901  // int *v28; // [sp+20h] [bp-Ch]@10
3902  // unsigned int v29; // [sp+24h] [bp-8h]@7
3903  // int v30; // [sp+28h] [bp-4h]@6
3904  // int i; // [sp+38h] [bp+Ch]@33
3905  // signed int v32; // [sp+3Ch] [bp+10h]@32
3906 
3907  v4 = 0;
3908  v5 = this;
3909  v24 = this;
3910  // if ( render->pRenderD3D )
3911  {
3912  v6 = a3 != 0;
3913  if (a4) v6 |= 8;
3914  v7 = vis->PickClosestActor(OBJECT_Actor, pick_depth, v6, 657456, -1);
3915  if (v7 != -1)
3916  return (unsigned __int16)v7;
3917  else
3918  return 0;
3919  }
3920  /*else // software impl
3921  {
3922  v30 = 0;
3923  if ( render->pActiveZBuffer )
3924  {
3925  if ( (signed int)viewparams->uScreen_topL_Y < (signed
3926  int)viewparams->uScreen_BttmR_Y )
3927  {
3928  v9 = &render->pActiveZBuffer[viewparams->uScreen_topL_X + 640 *
3929  viewparams->uScreen_topL_Y]; v26 =
3930  &render->pActiveZBuffer[viewparams->uScreen_topL_X + 640 *
3931  viewparams->uScreen_topL_Y]; for ( v25 = viewparams->uScreen_BttmR_Y -
3932  viewparams->uScreen_topL_Y; v25; --v25 )
3933  {
3934  if ( (signed int)viewparams->uScreen_topL_X < (signed
3935  int)viewparams->uScreen_BttmR_X )
3936  {
3937  v28 = v9;
3938  v10 = v4;
3939  for ( v27 = viewparams->uScreen_BttmR_X - viewparams->uScreen_topL_X; v27;
3940  --v27 )
3941  {
3942  v22 = *v28;
3943  v11 = *v28 & 0xFFFF;
3944  if (PID_TYPE(v11) == OBJECT_Actor)
3945  {
3946  if ( pActors[PID_ID(v11)].uAIState != Dead )
3947  {
3948  if ( pActors[PID_ID(v11)].uAIState != Dying && pActors[PID_ID(v11)].uAIState
3949  != Removed
3950  && pActors[PID_ID(v11)].uAIState != Summoned &&
3951  pActors[PID_ID(v11)].uAIState != Disabled
3952  && (!a3 || pActors[PID_ID(v11)].GetActorsRelation(0)) )
3953  {
3954  if ( (!a4 ||
3955  MonsterStats::BelongsToSupertype(pActors[PID_ID(v11)].pMonsterInfo.uID,
3956  MONSTER_SUPERTYPE_UNDEAD))
3957  && v22 <= pick_depth << 16 )
3958  {
3959  v14 = 0;
3960  if ( v10 > 0 )
3961  {
3962  for ( v14; v14 < v30; ++v14 )
3963  {
3964  if ( dword_50BDA0[v14] == v11 )
3965  break;
3966  }
3967  }
3968  if ( v14 == v30 && v10 < 100 )
3969  {
3970  ++v30;
3971  dword_50BC10[v10] = v22;
3972  dword_50BDA0[v10] = v11;
3973  ++v10;
3974  }
3975  }
3976  }
3977  }
3978  }
3979  ++v28;
3980  }
3981  v4 = v30;
3982  v5 = v24;
3983  }
3984  v9 = v26 + 640;
3985  v26 += 640;
3986  }
3987  }
3988  if ( v4 > 0 )
3989  {
3990  v16 = (int)dword_50BC10.data();
3991  for ( v32 = 1; v32 - 1 < v4; ++v32 )
3992  {
3993  for ( i = v32; i < v4; ++i )
3994  {
3995  v17 = dword_50BC10[i];
3996  if ( dword_50BC10[i] < *(int *)v16 )
3997  {
3998  dword_50BC10[i] = *(int *)v16;
3999  *(int *)v16 = v17;
4000  }
4001  }
4002  v16 += 4;
4003  }
4004  v5 = v24;
4005  if ( v4 > 0 )
4006  {
4007  v18 = v24;
4008  for ( v19 = v4; v19; --v19 )
4009  {
4010  *(int *)&v18->field_0 = (*(int *)&v18[(char *)dword_50BC10.data() - (char
4011  *)v24].field_0 >> 3) & 0x1FFF; v18 += 4;
4012  }
4013  }
4014  }
4015  v20 = 0;
4016  for ( *(int *)&v5[2000].field_0 = v4; v20 < v4; ++v20 )
4017  {
4018  v21 = pActors[*(int *)&v5[4 * v20].field_0].uAIState;
4019  if ( v21 != 4 && v21 != 5 )
4020  break;
4021  }
4022  if ( v20 != v4 )
4023  {
4024  result = 8 * *(int *)&v5[4 * v20].field_0;
4025  LOBYTE(result) = result | 3;
4026  return result;
4027  }
4028  }
4029  }
4030  return 0;*/
4031 }
4032 
4033 //----- (0042F4DA) --------------------------------------------------------
4035  unsigned int distance; // edi@1
4036  int for_x; // ebx@5
4037  int for_y; // [sp+Ch] [bp-10h]@5
4038  int for_z; // [sp+10h] [bp-Ch]@5
4039 
4040  distance = 5120;
4042 
4043  if ((signed int)uNumActors <= 0) return false;
4044  for (uint i = 0; i < (signed int)uNumActors; ++i) {
4045  for_x = abs(pActors[i].vInitialPosition.x - pParty->vPosition.x);
4046  for_y = abs(pActors[i].vInitialPosition.y - pParty->vPosition.y);
4047  for_z = abs(pActors[i].vInitialPosition.z - pParty->vPosition.z);
4048  if (int_get_vector_length(for_x, for_y, for_z) < distance) {
4049  if (pActors[i].uAIState != Dead) {
4050  if (pActors[i].uAIState != Dying &&
4051  pActors[i].uAIState != Removed &&
4052  pActors[i].uAIState != Disabled &&
4053  pActors[i].uAIState != Summoned &&
4054  (pActors[i].ActorEnemy() ||
4055  pActors[i].GetActorsRelation(0)))
4056  return true;
4057  }
4058  }
4059  }
4060  return false;
4061 }
4062 
4063 //----- (00426A5A) --------------------------------------------------------
4065  signed int v2; // edi@1
4066  unsigned __int8 v7; // al@30
4067  char *v9; // [sp-4h] [bp-3Ch]@10
4068  char *v10; // [sp-4h] [bp-3Ch]@31
4069  // char *v11; // [sp-4h] [bp-3Ch]@38
4070  ItemGen Dst; // [sp+Ch] [bp-2Ch]@1
4071  bool itemFound; // [sp+30h] [bp-8h]@1
4072  int v14; // [sp+34h] [bp-4h]@1
4073 
4075  Dst.Reset();
4076  v2 = 0;
4077  itemFound = false;
4078  v14 = 0;
4079  if (!ActorHasItem()) {
4080  for (uchar i = 0; i < this->pMonsterInfo.uTreasureDiceRolls; i++)
4081  v14 += rand() % this->pMonsterInfo.uTreasureDiceSides + 1;
4082  if (v14) {
4083  pParty->PartyFindsGold(v14, 0);
4085  }
4086  } else {
4087  if (this->ActorHasItems[3].uItemID != 0 &&
4088  this->ActorHasItems[3].GetItemEquipType() == EQUIP_GOLD) {
4089  v14 = this->ActorHasItems[3].special_enchantment;
4090  this->ActorHasItems[3].Reset();
4091  if (v14) {
4092  pParty->PartyFindsGold(v14, 0);
4094  }
4095  }
4096  }
4097  if (this->uCarriedItemID) {
4098  Dst.Reset();
4099  Dst.uItemID = this->uCarriedItemID;
4100  v9 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName;
4101 
4102  if (v14)
4104  else
4106 
4107  if (Dst.GetItemEquipType() == 12) {
4108  Dst.uNumCharges = rand() % 6 + Dst.GetDamageMod() + 1;
4109  Dst.uMaxCharges = Dst.uNumCharges;
4110  }
4111  if (pItemsTable->pItems[Dst.uItemID].uEquipType == 14 &&
4112  Dst.uItemID != 220)
4113  Dst.uEnchantmentType = 2 * rand() % 4 + 2;
4115  if (!pParty->AddItemToParty(&Dst)) pParty->SetHoldingItem(&Dst);
4116  this->uCarriedItemID = 0;
4117  if (this->ActorHasItems[0].uItemID) {
4118  if (!pParty->AddItemToParty(this->ActorHasItems)) {
4121  }
4122  this->ActorHasItems[0].Reset();
4123  }
4124  if (this->ActorHasItems[1].uItemID) {
4125  if (!pParty->AddItemToParty(&this->ActorHasItems[1])) {
4127  pParty->SetHoldingItem(&this->ActorHasItems[1]);
4128  }
4129  this->ActorHasItems[1].Reset();
4130  }
4131  this->Remove();
4132  return;
4133  }
4134  if (this->ActorHasItem()) {
4135  if (this->ActorHasItems[3].uItemID) {
4136  memcpy(&Dst, &this->ActorHasItems[3], sizeof(Dst));
4137  this->ActorHasItems[3].Reset();
4138  // v11 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName;
4139 
4140  if (v14)
4142  490, v14,
4143  pItemsTable->pItems[Dst.uItemID].pUnidentifiedName));
4144  else
4146  471, pItemsTable->pItems[Dst.uItemID].pUnidentifiedName));
4147 
4148  if (!pParty->AddItemToParty(&Dst)) pParty->SetHoldingItem(&Dst);
4149  itemFound = true;
4150  }
4151  } else {
4152  if (rand() % 100 < this->pMonsterInfo.uTreasureDropChance &&
4153  (v7 = this->pMonsterInfo.uTreasureLevel) != 0) {
4155  &Dst);
4156  v10 = pItemsTable->pItems[Dst.uItemID].pUnidentifiedName;
4157 
4158  if (v14)
4160  490, v14,
4161  v10)); // You found %d gold and an item (%s)! Вы нашли
4162  // ^I[%d] золот^L[ой;ых;ых] и предмет (%s)!
4163  else
4165  471, v10)); // You found %s! Вы нашли ^Pv[%s]!
4166 
4167  if (!pParty->AddItemToParty(&Dst)) pParty->SetHoldingItem(&Dst);
4168  itemFound = true;
4169  }
4170  }
4171  if (this->ActorHasItems[0].uItemID) {
4172  if (!pParty->AddItemToParty(this->ActorHasItems)) {
4175  itemFound = true;
4176  }
4177  this->ActorHasItems[0].Reset();
4178  }
4179  if (this->ActorHasItems[1].uItemID) {
4180  if (!pParty->AddItemToParty(&this->ActorHasItems[1])) {
4182  pParty->SetHoldingItem(&this->ActorHasItems[1]);
4183  itemFound = true;
4184  }
4185  this->ActorHasItems[1].Reset();
4186  }
4187  if (!itemFound || rand() % 100 < 90) // for repeatedly get gold and item
4188  this->Remove();
4189 }
4190 
4191 //----- (00427102) --------------------------------------------------------
4193  switch (spell) {
4194  case SPELL_BODY_POWER_CURE: {
4195  if (this->sCurrentHP >= this->pMonsterInfo.uHP) return false;
4196  return true;
4197  }
4198 
4199  case SPELL_LIGHT_DISPEL_MAGIC: {
4200  for (int i = 0; i < 20; i++) {
4201  if (pParty->pPartyBuffs[i].Active()) return true;
4202  }
4203  for (int i = 1; i <= 4; i++) {
4204  for (int j = 0; j < 22; j++) {
4205  if (pPlayers[i]->pPlayerBuffs[j].Active()) return true;
4206  }
4207  }
4208  return false;
4209  }
4210 
4219  case SPELL_FIRE_HASTE:
4220  return this->pActorBuffs[ACTOR_BUFF_HASTE].Expired();
4221  case SPELL_AIR_SHIELD:
4222  return this->pActorBuffs[ACTOR_BUFF_SHIELD].Expired();
4223  case SPELL_EARTH_STONESKIN:
4224  return this->pActorBuffs[ACTOR_BUFF_STONESKIN].Expired();
4225  case SPELL_SPIRIT_BLESS:
4226  return this->pActorBuffs[ACTOR_BUFF_BLESS].Expired();
4227  case SPELL_SPIRIT_FATE:
4228  return this->pActorBuffs[ACTOR_BUFF_FATE].Expired();
4229  case SPELL_SPIRIT_HEROISM:
4230  return this->pActorBuffs[ACTOR_BUFF_HEROISM].Expired();
4231  default:
4232  return true;
4233  }
4234 }
4235 
4236 //----- (0042704B) --------------------------------------------------------
4238  signed int okToCastSpell1; // ebx@5
4239  signed int okToCastSpell2; // edi@5
4240 
4241  if (this->pMonsterInfo.uSpecialAbilityType == 2 &&
4242  this->pMonsterInfo.uSpecialAbilityDamageDiceBonus < 3 &&
4243  rand() % 100 < 5)
4244  this->SummonMinion(a2);
4245  okToCastSpell1 =
4247  okToCastSpell2 =
4249  if (okToCastSpell1 && this->pMonsterInfo.uSpell1UseChance &&
4250  rand() % 100 < this->pMonsterInfo.uSpell1UseChance)
4251  return ABILITY_SPELL1;
4252  if (okToCastSpell2 && this->pMonsterInfo.uSpell2UseChance &&
4253  rand() % 100 < this->pMonsterInfo.uSpell2UseChance)
4254  return ABILITY_SPELL2;
4255  if (this->pMonsterInfo.uAttack2Chance &&
4256  rand() % 100 < this->pMonsterInfo.uAttack2Chance)
4257  return ABILITY_ATTACK2;
4258  return ABILITY_ATTACK1;
4259 }
4260 
4261 //----- (004273BB) --------------------------------------------------------
4262 bool Actor::_4273BB_DoesHitOtherActor(Actor *defender, int a3, int a4) {
4263  signed int v6; // ebx@1
4264  signed int v7; // esi@1
4265  int armorSum; // ebx@10
4266  signed int a2a; // [sp+18h] [bp+Ch]@1
4267 
4268  v6 = defender->pMonsterInfo.uAC;
4269  v7 = 0;
4270  a2a = 0;
4272  v6 /= 2;
4273  if (defender->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Active())
4275  if (defender->pActorBuffs[ACTOR_BUFF_STONESKIN].Active() &&
4276  defender->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower > v7)
4277  v7 = defender->pActorBuffs[ACTOR_BUFF_STONESKIN].uPower;
4278  armorSum = v7 + v6;
4279  if (this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Active())
4281  if (this->pActorBuffs[ACTOR_BUFF_BLESS].Active() &&
4282  this->pActorBuffs[ACTOR_BUFF_BLESS].uPower > a2a)
4283  a2a = this->pActorBuffs[ACTOR_BUFF_BLESS].uPower;
4284  if (this->pActorBuffs[ACTOR_BUFF_FATE].Active()) {
4285  a2a += this->pActorBuffs[ACTOR_BUFF_FATE].uPower;
4287  }
4288  return rand() % (armorSum + 2 * this->pMonsterInfo.uLevel + 10) + a2a + 1 >
4289  armorSum + 5;
4290 }
4291 
4292 //----- (004274AD) --------------------------------------------------------
4294  signed int v3; // edi@1
4295  signed int v4; // esi@8
4296  int v5; // esi@8
4297 
4298  v3 = 0;
4299  if (this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Active())
4301  if (this->pActorBuffs[ACTOR_BUFF_BLESS].Active() &&
4302  this->pActorBuffs[ACTOR_BUFF_BLESS].uPower > v3)
4304  if (this->pActorBuffs[ACTOR_BUFF_FATE].Active()) {
4307  }
4308  v4 = pPlayer->GetActualAC() + 2 * this->pMonsterInfo.uLevel + 10;
4309  v5 = rand() % v4 + 1;
4310  return (v3 + v5 > pPlayer->GetActualAC() + 5);
4311 }
4312 
4313 //----- (0042756B) --------------------------------------------------------
4315  signed int incomingDmg) {
4316  int v4; // edx@1
4317  int v5; // ecx@1
4318  signed int v6; // eax@4
4319  signed int result; // eax@17
4320  signed int v8; // esi@18
4321 
4322  v4 = 0;
4323  v5 = 0;
4324  if (this->pActorBuffs[ACTOR_BUFF_HOUR_OF_POWER].Active())
4326  switch (dmgType) {
4327  case DMGT_FIRE:
4328  v6 = this->pMonsterInfo.uResFire;
4329  v4 = v5;
4330  break;
4331  case DMGT_ELECTR:
4332  v6 = this->pMonsterInfo.uResAir;
4333  v4 = v5;
4334  break;
4335  case DMGT_COLD:
4336  v6 = this->pMonsterInfo.uResWater;
4337  v4 = v5;
4338  break;
4339  case DMGT_EARTH:
4340  v6 = this->pMonsterInfo.uResEarth;
4341  v4 = v5;
4342  break;
4343  case DMGT_PHISYCAL:
4344  v6 = this->pMonsterInfo.uResPhysical;
4345  break;
4346  case DMGT_SPIRIT:
4347  v6 = this->pMonsterInfo.uResSpirit;
4348  break;
4349  case DMGT_MIND:
4350  v6 = this->pMonsterInfo.uResMind;
4351  v4 = v5;
4352  break;
4353  case DMGT_BODY:
4354  v6 = this->pMonsterInfo.uResBody;
4355  v4 = v5;
4356  break;
4357  case DMGT_LIGHT:
4358  v6 = this->pMonsterInfo.uResLight;
4359  break;
4360  case DMGT_DARK:
4361  v6 = this->pMonsterInfo.uResDark;
4362  break;
4363  default:
4364  v6 = 0;
4365  break;
4366  }
4367  if (v6 < 200) {
4368  v8 = v4 + v6 + 30;
4369  for (int i = 0; i < 4; i++) {
4370  if (rand() % v8 < 30) break;
4371  incomingDmg /= 2;
4372  }
4373  result = incomingDmg;
4374  } else {
4375  result = 0;
4376  }
4377  return result;
4378 }
4379 
4380 //----- (00427662) --------------------------------------------------------
4382  signed int resist; // esi@2
4383  bool result; // eax@13
4384 
4385  switch (uType) {
4386  case 0:
4387  resist = this->pMonsterInfo.uResFire;
4388  break;
4389  case 1:
4390  resist = this->pMonsterInfo.uResAir;
4391  break;
4392  case 2:
4393  resist = this->pMonsterInfo.uResWater;
4394  break;
4395  case 3:
4396  resist = this->pMonsterInfo.uResEarth;
4397  break;
4398  case 4:
4399  resist = this->pMonsterInfo.uResPhysical;
4400  break;
4401  case 6:
4402  resist = this->pMonsterInfo.uResSpirit;
4403  break;
4404  case 7:
4405  resist = this->pMonsterInfo.uResMind;
4406  case 8:
4407  resist = this->pMonsterInfo.uResBody;
4408  break;
4409  case 9:
4410  resist = this->pMonsterInfo.uResLight;
4411  break;
4412  case 10:
4413  resist = this->pMonsterInfo.uResDark;
4414  break;
4415  default:
4416  return 1;
4417  }
4418  if (resist < 200)
4419  result = rand() % ((this->pMonsterInfo.uLevel >> 2) + resist + 30) < 30;
4420  else
4421  result = 0;
4422  return result;
4423 }
4424 
4425 //----- (00448A98) --------------------------------------------------------
4426 void ToggleActorGroupFlag(unsigned int uGroupID, unsigned int uFlag,
4427  unsigned int bToggle) {
4428  if (uGroupID) {
4429  if (bToggle) {
4430  for (uint i = 0; i < (unsigned int)uNumActors; ++i) {
4431  if (pActors[i].uGroup == uGroupID) {
4432  pActors[i].uAttributes |= uFlag;
4433  if (uFlag == 0x10000) {
4434  pActors[i].uAIState = Disabled;
4435  pActors[i].UpdateAnimation();
4436  }
4437  }
4438  }
4439  } else {
4440  for (uint i = 0; i < (unsigned int)uNumActors; ++i) {
4441  if (pActors[i].uGroup == uGroupID) {
4442  if (uFlag == 0x10000) {
4443  if (pActors[i].uAIState != Dead) {
4444  if (pActors[i].uAIState != 4 &&
4445  pActors[i].uAIState != 11)
4446  pActors[i].uAIState = Standing;
4447  }
4448  }
4449  HEXRAYS_LODWORD(pActors[i].uAttributes) &= ~uFlag;
4450  }
4451  }
4452  }
4453  }
4454 }
4455 
4456 //----- (004014E6) --------------------------------------------------------
4458  int v1; // eax@4
4459  unsigned int v7; // ST20_4@10
4460  int distance; // edi@10
4461  // int v10; // ebx@14
4462  int v21; // [sp+Ch] [bp-14h]@4
4463  int v22; // [sp+10h] [bp-10h]@4
4464 
4465  pParty->uFlags &= 0xFFFFFFCF; // ~0x30
4466 
4467  ai_arrays_size = 0;
4468  for (uint i = 0; i < uNumActors; ++i) {
4469  Actor *actor = &pActors[i];
4470 
4471  actor->ResetAlive(); // ~0x400
4472  if (!actor->CanAct()) {
4473  actor->ResetActive();
4474  continue;
4475  }
4476 
4477  v22 = abs(pParty->vPosition.z - actor->vPosition.z);
4478  v21 = abs(pParty->vPosition.y - actor->vPosition.y);
4479  v1 = abs(pParty->vPosition.x - actor->vPosition.x);
4480  v7 = int_get_vector_length(v22, v21, v1);
4481  distance = v7 - actor->uActorRadius;
4482  if (distance < 0) distance = 0;
4483 
4484  if (distance < 5632) {
4485  actor->ResetHostile();
4486  if (actor->ActorEnemy() || actor->GetActorsRelation(0)) {
4487  // v11 = (pParty->uFlags & 0x10) == 0;
4488  actor->uAttributes |= ACTOR_HOSTILE;
4489  if (distance < 5120) pParty->SetYellowAlert();
4490  if (distance < 307) pParty->SetRedAlert();
4491  }
4492  actor->uAttributes |= ACTOR_ACTIVE;
4495  } else {
4496  actor->ResetActive();
4497  }
4498  }
4499 
4500  /*
4501  result = v27;
4502  if ( v27 > 0 )
4503  {
4504  v14 = 0;
4505  v15 = 1;
4506  v26 = 1;
4507  do
4508  {
4509  while ( 1 )
4510  {
4511  v24 = v15;
4512  if ( v15 >= result )
4513  break;
4514  v16 = ai_near_actors_distances[v14];
4515  if ( v16 > ai_near_actors_distances[v15] )
4516  {
4517  v17 = &ai_near_actors_ids[v15];
4518  v18 = ai_near_actors_ids[v14];
4519  ai_near_actors_ids[v14] = *v17;
4520  *v17 = v18;
4521  v15 = v24;
4522  ai_near_actors_distances[v14] = ai_near_actors_distances[v24];
4523  ai_near_actors_distances[v24] = v16;
4524  }
4525  result = v27;
4526  ++v15;
4527  }
4528  ++v14;
4529  v15 = v26 + 1;
4530  v26 = v15;
4531  }
4532  while ( v15 - 1 < result );
4533  }*/
4534 
4535  for (int i = 0; i < ai_arrays_size; ++i) {
4536  for (int j = 0; j < i; ++j) {
4538  int tmp = ai_near_actors_distances[j];
4540  ai_near_actors_distances[i] = tmp;
4541 
4542  tmp = ai_near_actors_ids[j];
4544  ai_near_actors_ids[i] = tmp;
4545  }
4546  }
4547  }
4548 
4549  if (ai_arrays_size > 30) ai_arrays_size = 30;
4550 
4551  for (int i = 0; i < ai_arrays_size; ++i)
4552  pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_ALIVE; // 0x400
4553 }
4554 
4555 //----- (004016FA) --------------------------------------------------------
4557  int v1; // eax@4
4558  int distance; // edi@10
4559  int v13; // edx@24
4560  int v15; // ebx@26
4561  unsigned int v17; // esi@27
4562  int v18; // ecx@31
4563  signed int v19; // edi@31
4564  signed int v25; // eax@40
4565  uint j; // edi@45
4566  int v30; // eax@48
4567  int v37; // [sp+Ch] [bp-18h]@1
4568  int v38; // [sp+10h] [bp-14h]@4
4569  int v39; // [sp+14h] [bp-10h]@4
4570  uint i; // [sp+18h] [bp-Ch]@31
4571  uint v45; // [sp+20h] [bp-4h]@1
4572 
4573  // __debugbreak(); // refactor for blv ai
4574  pParty->uFlags &= 0xFFFFFFCF; // ~0x30
4576  pParty->vPosition.z);
4577  v45 = 0;
4578  for (uint i = 0; i < uNumActors; ++i) {
4579  pActors[i].ResetAlive(); // ~0x0400
4580  if (!pActors[i].CanAct()) {
4581  pActors[i].ResetActive();
4582  continue;
4583  }
4584  v1 = abs(pParty->vPosition.x - pActors[i].vPosition.x);
4585  v38 = abs(pParty->vPosition.y - pActors[i].vPosition.y);
4586  v39 = abs(pParty->vPosition.z - pActors[i].vPosition.z);
4587 
4588  distance =
4589  int_get_vector_length(v39, v38, v1) - pActors[i].uActorRadius;
4590  if (distance < 0) distance = 0;
4591  if (distance < 10240) {
4592  pActors[i].ResetHostile(); // ~0x01000000
4593  if (pActors[i].ActorEnemy() || pActors[i].GetActorsRelation(0)) {
4594  pActors[i].uAttributes |= ACTOR_HOSTILE;
4595  if (!(pParty->uFlags & 0x10) && (double)distance < 307.2)
4596  pParty->SetRedAlert();
4597  if (!(pParty->uFlags & 0x20) && distance < 5120)
4599  }
4601  ai_near_actors_ids[v45] = i;
4602  v45++;
4603  } else {
4604  pActors[i].ResetActive();
4605  }
4606  }
4607  v13 = 0;
4608  if (v45 > 0) {
4609  for (uint i = 1; i < v45; i++) {
4610  for (uint j = 1; j < v45; ++j) {
4611  v15 = ai_near_actors_distances[v13];
4612  if (ai_near_actors_distances[v13] >
4614  v17 = ai_near_actors_ids[v13];
4616  ai_near_actors_ids[j] = v17;
4618  ai_near_actors_distances[j] = v15;
4619  }
4620  }
4621  ++v13;
4622  }
4623  }
4624  v18 = 0;
4625  v19 = 0;
4626  for (i = 0; i < v45; i++) {
4629  PID(OBJECT_Actor, ai_near_actors_ids[i]), 4)) {
4630  pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_NEARBY;
4633  if (v19 >= 30) break;
4634  }
4635  }
4636  ai_arrays_size = v19;
4637  if ((signed int)uNumActors > 0) {
4638  for (uint i = 0; i < (signed int)uNumActors; ++i) {
4639  if (pActors[i].CanAct() && pActors[i].uSectorID == v37) {
4640  v25 = 0;
4641  if (v19 <= 0) {
4642  pActors[i].uAttributes |= ACTOR_ACTIVE;
4644  } else {
4645  while (ai_array_4F6638_actor_ids[v25] != i) {
4646  ++v25;
4647  if (v25 >= v19) {
4648  pActors[i].uAttributes |= ACTOR_ACTIVE;
4650  break;
4651  }
4652  }
4653  }
4654  }
4655  }
4656  }
4657  for (j = 0; j < v45; ++j) {
4658  if (pActors[ai_near_actors_ids[j]].uAttributes & 0xC000 &&
4660  v30 = 0;
4661  if (ai_arrays_size <= 0) {
4663  ai_near_actors_ids[j];
4664  } else {
4665  while (ai_array_4F6638_actor_ids[v30] !=
4666  ai_near_actors_ids[j]) {
4667  ++v30;
4668  if (v30 >= ai_arrays_size) {
4670  ai_near_actors_ids[j];
4671  break;
4672  }
4673  }
4674  }
4675  }
4676  }
4677  if (ai_arrays_size > 30) ai_arrays_size = 30;
4678  memcpy(ai_near_actors_ids.data(), ai_array_4F6638_actor_ids.data(),
4679  4 * ai_arrays_size);
4680  memcpy(ai_near_actors_distances.data(), ai_array_4F5E68.data(),
4681  4 * ai_arrays_size);
4682  for (int i = 0; i < ai_arrays_size; i++)
4683  pActors[ai_near_actors_ids[i]].uAttributes |= ACTOR_ALIVE; // 0x400
4684  return ai_arrays_size;
4685 }
4686 
4687 //----- (004070EF) --------------------------------------------------------
4688 bool sub_4070EF_prolly_detect_player(unsigned int uObjID,
4689  unsigned int uObj2ID) {
4690  signed int v2; // eax@1
4691  int obj1_sector; // eax@4
4692  float v8; // ST24_4@5
4693  signed int v12; // eax@7
4694  int obj2_z; // edi@11
4695  int obj2_x; // esi@11
4696  int obj2_sector; // eax@13
4697  float v20; // ST24_4@14
4698  int dist_x; // ebx@16
4699  signed int dist_3d; // ecx@16
4700  int v25; // eax@18
4701  BLVFace *v29; // ebx@32
4702  Vec3_short_ *v30; // esi@32
4703  int v31; // eax@32
4704  int v32; // ST50_4@44
4705  int v33; // ST54_4@44
4706  int v34; // eax@44
4707  int v38; // esi@45
4708  __int16 next_sector; // bx@58
4709  int v47; // [sp+18h] [bp-50h]@20
4710  int v48; // [sp+1Ch] [bp-4Ch]@20
4711  int v49; // [sp+20h] [bp-48h]@20
4712  int dist_z; // [sp+24h] [bp-44h]@16
4713  int higher_z; // [sp+24h] [bp-44h]@27
4714  int lower_z; // [sp+28h] [bp-40h]@26
4715  int higher_y; // [sp+2Ch] [bp-3Ch]@23
4716  int lower_y; // [sp+30h] [bp-38h]@22
4717  int higher_x; // [sp+34h] [bp-34h]@21
4718  int lower_x; // [sp+38h] [bp-30h]@20
4719  int sectors_visited; // [sp+3Ch] [bp-2Ch]@28
4720  int v58; // [sp+44h] [bp-24h]@50
4721  int v59; // [sp+48h] [bp-20h]@44
4722  int obj2_y; // [sp+50h] [bp-18h]@11
4723  int obj1_x; // [sp+58h] [bp-10h]@4
4724  int obj1_y; // [sp+5Ch] [bp-Ch]@4
4725  int obj1_z; // [sp+60h] [bp-8h]@4
4726  int current_sector; // [sp+64h] [bp-4h]@7
4727  int dist_y;
4728  int v70;
4729 
4730  v2 = PID_ID(uObjID);
4731  switch (PID_TYPE(uObjID)) {
4732  case OBJECT_Decoration:
4733  obj1_x = pLevelDecorations[v2].vPosition.x;
4734  obj1_y = pLevelDecorations[v2].vPosition.y;
4735  obj1_z = pLevelDecorations[v2].vPosition.z;
4736  obj1_sector = pIndoor->GetSector(obj1_x, obj1_y, obj1_z);
4737  break;
4738  case OBJECT_Actor:
4739  obj1_x = pActors[v2].vPosition.x;
4740  obj1_y = pActors[v2].vPosition.y;
4741  v8 = (float)pActors[v2].uActorHeight * 0.69999999;
4742  // v9 = v8 + 6.7553994e15;
4743  // obj1_z = LODWORD(v9) + pActors[v2].vPosition.z;
4744  obj1_z = (int)v8 + pActors[v2].vPosition.z;
4745  obj1_sector = pActors[v2].uSectorID;
4746  break;
4747  case OBJECT_Item:
4748  obj1_x = pSpriteObjects[v2].vPosition.x;
4749  obj1_y = pSpriteObjects[v2].vPosition.y;
4750  obj1_z = pSpriteObjects[v2].vPosition.z;
4751  obj1_sector = pSpriteObjects[v2].uSectorID;
4752  break;
4753  default:
4754  return 0;
4755  }
4756  v12 = PID_ID(uObj2ID);
4757  switch (PID_TYPE(uObj2ID)) {
4758  case OBJECT_Decoration:
4759  obj2_z = pLevelDecorations[v12].vPosition.z;
4760  obj2_x = pLevelDecorations[v12].vPosition.x;
4761  obj2_y = pLevelDecorations[v12].vPosition.y;
4762  obj2_sector = pIndoor->GetSector(obj2_x, obj2_y, obj2_z);
4763  break;
4764  case OBJECT_Player:
4765  obj2_x = pParty->vPosition.x;
4766  obj2_z = pParty->sEyelevel + pParty->vPosition.z;
4767  obj2_y = pParty->vPosition.y;
4768  obj2_sector =
4771  break;
4772  case OBJECT_Actor:
4773  obj2_y = pActors[v12].vPosition.y;
4774  obj2_x = pActors[v12].vPosition.x;
4775  v20 = (float)pActors[v12].uActorHeight * 0.69999999;
4776  // v21 = v20 + 6.7553994e15;
4777  // obj2_z = LODWORD(v21) + pActors[v12].vPosition.z;
4778  obj2_z = (int)v20 + pActors[v12].vPosition.z;
4779  obj2_sector = pActors[v12].uSectorID;
4780  break;
4781  case OBJECT_Item:
4782  obj2_x = pSpriteObjects[v12].vPosition.x;
4783  obj2_z = pSpriteObjects[v12].vPosition.z;
4784  obj2_y = pSpriteObjects[v12].vPosition.y;
4785  obj2_sector = pSpriteObjects[v12].uSectorID;
4786  break;
4787  default:
4788  return 0;
4789  }
4790  dist_x = obj2_x - obj1_x;
4791  dist_z = obj2_z - obj1_z;
4792  dist_y = obj2_y - obj1_y;
4793  dist_3d = integer_sqrt(dist_x * dist_x + dist_y * dist_y + dist_z * dist_z);
4794  // range check
4795  if (dist_3d > 5120) return 0;
4796  if (uCurrentlyLoadedLevelType == LEVEL_Outdoor) return 1;
4797  v25 = 65536;
4798  if (dist_3d) v25 = 65536 / dist_3d;
4799  v49 = dist_x * v25;
4800  v47 = dist_z * v25;
4801  v48 = dist_y * v25;
4802  if (obj1_x < obj2_x) {
4803  lower_x = obj1_x;
4804  higher_x = obj2_x;
4805  } else {
4806  lower_x = obj2_x;
4807  higher_x = obj1_x;
4808  }
4809  if (obj1_y < obj2_y) {
4810  lower_y = obj1_y;
4811  higher_y = obj2_y;
4812  } else {
4813  lower_y = obj2_y;
4814  higher_y = obj1_y;
4815  }
4816  if (obj1_z < obj2_z) {
4817  lower_z = obj1_z;
4818  higher_z = obj2_z;
4819  } else {
4820  lower_z = obj2_z;
4821  higher_z = obj1_z;
4822  }
4823  sectors_visited = 0;
4824  // monster in same sector with player
4825  if (obj1_sector == obj2_sector) return 1;
4826  // search starts from monster
4827  current_sector = obj1_sector;
4828  for (int current_portal = 0;
4829  current_portal < pIndoor->pSectors[current_sector].uNumPortals;
4830  current_portal++) {
4831  v29 = &pIndoor->pFaces[pIndoor->pSectors[current_sector]
4832  .pPortals[current_portal]];
4833  v30 = &pIndoor->pVertices[*v29->pVertexIDs];
4834  v31 = v29->pFacePlane_old.vNormal.z * (v30->z - obj1_z) +
4835  v29->pFacePlane_old.vNormal.y * (v30->y - obj1_y) +
4836  v29->pFacePlane_old.vNormal.x * (v30->x - obj1_x);
4837 
4838  if (current_sector != v29->uSectorID) v31 = -v31;
4839 
4840  if (v31 >= 0 && v30->x != obj1_x && v30->y != obj1_y &&
4841  v30->z != obj1_z)
4842  continue;
4843 
4844  if (lower_x > v29->pBounding.x2 || higher_x < v29->pBounding.x1 ||
4845  lower_y > v29->pBounding.y2 || higher_y < v29->pBounding.y1 ||
4846  lower_z > v29->pBounding.z2 || higher_z < v29->pBounding.z1) {
4847  continue;
4848  }
4849 
4850  v32 = fixpoint_mul(v29->pFacePlane_old.vNormal.x, v49);
4851  v34 = fixpoint_mul(v29->pFacePlane_old.vNormal.y, v48);
4852  v33 = fixpoint_mul(v29->pFacePlane_old.vNormal.z, v47);
4853 
4854  v59 = v32 + v33 + v34;
4855  if (v59) {
4856  v70 = v29->pFacePlane_old.dist +
4857  obj1_z * v29->pFacePlane_old.vNormal.z +
4858  obj1_x * v29->pFacePlane_old.vNormal.x +
4859  obj1_y * v29->pFacePlane_old.vNormal.y;
4860  v38 = -v70;
4861 
4862  // if ( v59 <= 0 ^ v70 <= 0 )
4863 
4864  /* TEMPORARY
4865  if ( v59 <= 0 && v70 <= 0 )
4866  {
4867  continue;
4868  }
4869  if ( !(v59 <= 0 && v70 <= 0) )
4870  {
4871  continue;
4872  }
4873  */
4874 
4875  if (abs(v38) >> 14 > abs(v59)) continue;
4876 
4877  v58 = fixpoint_div(v38, v59);
4878 
4879  if (v58 < 0) continue;
4880 
4881  if (!sub_4075DB(obj1_x + ((fixpoint_mul(v49, v58) + 32768) >> 16),
4882  obj1_y + ((fixpoint_mul(v48, v58) + 32768) >> 16),
4883  obj1_z + ((fixpoint_mul(v47, v58) + 32768) >> 16),
4884  v29)) {
4885  continue;
4886  }
4887 
4888  // if there is no next sector turn back
4889  if (v29->uSectorID == current_sector)
4890  next_sector = v29->uBackSectorID;
4891  else
4892  next_sector = v29->uSectorID;
4893 
4894  // no more portals, quit
4895  if (next_sector == current_sector) break;
4896 
4897  ++sectors_visited;
4898  current_sector = next_sector;
4899 
4900  // found player, quit
4901  if (next_sector == obj2_sector) return 1;
4902 
4903  current_sector = next_sector;
4904 
4905  // did we hit limit for portals?
4906  // does the next room have portals?
4907  if (sectors_visited < 30 &&
4908  pIndoor->pSectors[current_sector].uNumPortals > 0) {
4909  current_portal = -1;
4910  continue;
4911  } else {
4912  break;
4913  }
4914  }
4915  }
4916  // did we stop in the sector where player is?
4917  if (current_sector != obj2_sector) return 0;
4918  return 1;
4919 }
4920 
4921 //----- (00450B0A) --------------------------------------------------------
4922 bool SpawnActor(unsigned int uMonsterID) {
4923  unsigned int v1; // ebx@1
4924  bool result; // eax@2
4925  unsigned int v6; // ecx@5
4926  Actor actor; // [sp+4h] [bp-350h]@5
4927  Vec3_int_ pOut; // [sp+348h] [bp-Ch]@5
4928 
4929  v1 = uMonsterID;
4930  if (uNumActors == 499) {
4931  result = 0;
4932  } else {
4933  if ((signed int)uMonsterID >= (signed int)pMonsterList->uNumMonsters)
4934  v1 = 0;
4935  memset(&actor, 0, sizeof(Actor));
4936  strcpy(actor.pActorName, pMonsterStats->pInfos[v1 + 1].pName);
4937  actor.sCurrentHP = (short)pMonsterStats->pInfos[v1 + 1].uHP;
4938  memcpy(&actor.pMonsterInfo, &pMonsterStats->pInfos[v1 + 1],
4939  sizeof(MonsterInfo));
4940  actor.word_000086_some_monster_id = v1 + 1;
4944 
4945  Vec3_int_::Rotate(200, pParty->sRotationY, 0, pParty->vPosition,
4946  &pOut.x, &pOut.z, &pOut.y);
4947  actor.vInitialPosition.x = pOut.x;
4948  actor.vPosition.x = pOut.x;
4949  actor.uTetherDistance = 256;
4950  actor.vInitialPosition.y = (short)pOut.z;
4951  actor.vPosition.y = (short)pOut.z;
4952  actor.vInitialPosition.z = (short)pOut.y;
4953  actor.vPosition.z = (short)pOut.y;
4956  v6 = uNumActors - 1;
4957  if (dword_5C6DF8 == 1) {
4958  dword_5C6DF8 = 0;
4959  v6 = uNumActors++;
4960  }
4961  memcpy(&pActors[v6], &actor, sizeof(Actor));
4962  pActors[v6].PrepareSprites(1);
4963  result = 1;
4964  }
4965  return result;
4966 }
4967 
4968 //----- (0044FA4C) --------------------------------------------------------
4969 int sub_44FA4C_spawn_light_elemental(int spell_power, int caster_skill_level,
4970  int duration_game_seconds) {
4971  int result; // eax@13
4972  int v10; // ebx@16
4973  const char *cMonsterName; // [sp-4h] [bp-24h]@2
4974  unsigned int uFaceID; // [sp+8h] [bp-18h]@16
4975  int v19; // [sp+Ch] [bp-14h]@16
4976  // size_t uActorIndex; // [sp+10h] [bp-10h]@6
4977  int v21; // [sp+14h] [bp-Ch]@14
4978  unsigned int uMonsterID; // [sp+1Ch] [bp-4h]@6
4979 
4980  if (caster_skill_level == 4)
4981  cMonsterName = "Elemental Light C";
4982  else if (caster_skill_level == 3)
4983  cMonsterName = "Elemental Light B";
4984  else
4985  cMonsterName = "Elemental Light A";
4986 
4987  uMonsterID = pMonsterList->GetMonsterIDByName(cMonsterName);
4988 
4989  // find first free index
4990  uint uActorIndex = 0;
4991  for (uActorIndex; uActorIndex < uNumActors; uActorIndex++) {
4992  if (pActors[uActorIndex].uAIState == Removed) break;
4993  }
4994 
4995  result = uNumActors + 1;
4996 
4997 
4998  // use free slot or first new slot
4999  if (uActorIndex != uNumActors || result < 500) {
5000  v21 = 0;
5003  pParty->vPosition.z);
5004  v19 = (((uCurrentlyLoadedLevelType != LEVEL_Outdoor) - 1) & 0x40) + 64;
5005  pActors[uActorIndex].Reset();
5006  strcpy(pActors[uActorIndex].pActorName, pMonsterStats->pInfos[uMonsterID + 1].pName);
5007  pActors[uActorIndex].sCurrentHP = pMonsterStats->pInfos[uMonsterID + 1].uHP;
5008  memcpy(&pActors[uActorIndex].pMonsterInfo, &pMonsterStats->pInfos[uMonsterID + 1],
5009  sizeof(MonsterInfo));
5010  pActors[uActorIndex].word_000086_some_monster_id = uMonsterID + 1;
5011  pActors[uActorIndex].uActorRadius = pMonsterList->pMonsters[uMonsterID].uMonsterRadius;
5012  pActors[uActorIndex].uActorHeight = pMonsterList->pMonsters[uMonsterID].uMonsterHeight;
5013  pActors[uActorIndex].pMonsterInfo.uTreasureDiceRolls = 0;
5014  pActors[uActorIndex].pMonsterInfo.uTreasureType = 0;
5015  pActors[uActorIndex].pMonsterInfo.uExp = 0;
5016  pActors[uActorIndex].uMovementSpeed =
5017  pMonsterList->pMonsters[uMonsterID].uMovementSpeed;
5018  v10 = rand() % 2048;
5019  pActors[uActorIndex].vInitialPosition.x =
5020  pParty->vPosition.x + fixpoint_mul(stru_5C6E00->Cos(v10), v19);
5021  pActors[uActorIndex].vPosition.x = pActors[uActorIndex].vInitialPosition.x;
5022  pActors[uActorIndex].vInitialPosition.y =
5023  pParty->vPosition.y + fixpoint_mul(stru_5C6E00->Sin(v10), v19);
5024  pActors[uActorIndex].vPosition.y = pActors[uActorIndex].vInitialPosition.y;
5025  pActors[uActorIndex].vInitialPosition.z = pParty->vPosition.z;
5026  pActors[uActorIndex].vPosition.z = pActors[uActorIndex].vInitialPosition.z;
5027  pActors[uActorIndex].uTetherDistance = 256;
5028  pActors[uActorIndex].uSectorID = v21;
5029  pActors[uActorIndex].PrepareSprites(0);
5030  pActors[uActorIndex].pMonsterInfo.uHostilityType =
5032  pActors[uActorIndex].uAlly = 9999;
5033  pActors[uActorIndex].uGroup = 0;
5034  pActors[uActorIndex].uCurrentActionTime = 0;
5035  pActors[uActorIndex].uAIState = Summoned;
5036  pActors[uActorIndex].uCurrentActionLength = 256;
5037  pActors[uActorIndex].UpdateAnimation();
5038 
5039  result = pIndoor->GetSector(pActors[uActorIndex].vPosition.x,
5040  pActors[uActorIndex].vPosition.y,
5041  pActors[uActorIndex].vPosition.z);
5043  result == v21 &&
5045  pActors[uActorIndex].vPosition.x, pActors[uActorIndex].vPosition.y,
5046  pActors[uActorIndex].vPosition.z, result, &uFaceID),
5047  result != -30000) &&
5048  (result = abs(result - pParty->vPosition.z), result <= 1024)) {
5049  if (uActorIndex == uNumActors) ++uNumActors;
5050  pActors[uActorIndex].uSummonerID = PID(OBJECT_Player, spell_power);
5051 
5052  GameTime spell_length = GameTime::FromSeconds(duration_game_seconds);
5053 
5054  result = pActors[uActorIndex].pActorBuffs[ACTOR_BUFF_SUMMONED].Apply(
5055  (pParty->GetPlayingTime() + spell_length),
5056  caster_skill_level, spell_power, 0, 0);
5057  }
5058  }
5059  return result;
5060 }
5061 
5062 //----- (0044F57C) --------------------------------------------------------
5063 void SpawnEncounter(MapInfo *pMapInfo, SpawnPointMM7 *spawn, int a3, int a4, int a5) {
5064  // a3 for abc modify
5065  // a4 count
5066 
5067  int v7; // eax@2
5068  char v8; // zf@5
5069  int v12; // edx@9
5070  // int v18; // esi@31
5071  Actor *pMonster; // esi@35
5072  int v23; // edx@36
5073  int v24; // edi@36
5074  int v25; // ecx@36
5075  MonsterDesc *v27; // edi@48
5076  signed int v28; // eax@48
5077  int v32; // eax@50
5078  int v37; // eax@51
5079  int v38; // eax@52
5080  int v39; // edi@52
5081  String v40; // [sp-18h] [bp-100h]@60
5082  const char *v44; // [sp-8h] [bp-F0h]@13
5083  char *pTexture; // [sp-4h] [bp-ECh]@9
5084  // char Str[32]; // [sp+Ch] [bp-DCh]@60
5085  char Str2[120]; // [sp+2Ch] [bp-BCh]@29
5086  unsigned int uFaceID; // [sp+A4h] [bp-44h]@52
5087  MonsterInfo *Src; // [sp+A8h] [bp-40h]@50
5088  int v50; // [sp+ACh] [bp-3Ch]@47
5089  char Source[32]; // [sp+B0h] [bp-38h]@20
5090  int v52; // [sp+D0h] [bp-18h]@34
5091  int v53; // [sp+D4h] [bp-14h]@34
5092  int pSector; // [sp+D8h] [bp-10h]@32
5093  int pPosX; // [sp+DCh] [bp-Ch]@32
5094  int NumToSpawn; // [sp+E0h] [bp-8h]@8
5095  int v57; // [sp+E4h] [bp-4h]@1
5096 
5097  // auto a2 = spawn;
5098  v57 = 0;
5099  // v5 = pMapInfo;
5100  // v6 = spawn;
5102  v7 = pOutdoor->ddm.field_C_alert;
5104  v7 = pIndoor->dlv.field_C_alert;
5105  else
5106  v7 = 0;
5107 
5108  if (v7)
5109  v8 = (spawn->uAttributes & 1) == 0;
5110  else
5111  v8 = (spawn->uAttributes & 1) == 1;
5112  if (v8) return;
5113 
5114  // result = (void *)(spawn->uIndex - 1);
5115  NumToSpawn = 1;
5116  switch (spawn->uIndex - 1) {
5117  case 0:
5118  // v9 = pMapInfo->uEncounterMonster1AtLeast;
5119  // v10 = rand();
5120  // v11 = pMapInfo->uEncounterMonster1AtMost;
5121  // pTexture = pMapInfo->pEncounterMonster1Texture;
5122  v12 = rand() % (pMapInfo->uEncounterMonster1AtMost -
5123  pMapInfo->uEncounterMonster1AtLeast + 1);
5124  // v13 = pMapInfo->Dif_M1;
5125  v57 = pMapInfo->Dif_M1;
5126  NumToSpawn = pMapInfo->uEncounterMonster1AtLeast + v12;
5127  strcpy(Source, pMapInfo->pEncounterMonster1Texture.c_str());
5128  break;
5129  case 3:
5130  // pTexture = pMapInfo->pEncounterMonster1Texture;
5131  // v44 = "%s A";
5132  sprintf(Source, "%s A", pMapInfo->pEncounterMonster1Texture.c_str());
5133  break;
5134  case 4:
5135  // pTexture = pMapInfo->pEncounterMonster2Texture;
5136  // v44 = "%s A";
5137  sprintf(Source, "%s A", pMapInfo->pEncounterMonster2Texture.c_str());
5138  break;
5139  case 5:
5140  // pTexture = pMapInfo->pEncounterMonster3Texture;
5141  // v44 = "%s A";
5142  sprintf(Source, "%s A", pMapInfo->pEncounterMonster3Texture.c_str());
5143  break;
5144  case 1:
5145  // v9 = pMapInfo->uEncounterMonster2AtLeast;
5146  // v14 = rand();
5147  // v15 = pMapInfo->uEncounterMonster2AtMost;
5148  // pTexture = pMapInfo->pEncounterMonster2Texture;
5149  v12 = rand() % (pMapInfo->uEncounterMonster2AtMost -
5150  pMapInfo->uEncounterMonster2AtLeast + 1);
5151  // v13 = pMapInfo->Dif_M2;
5152  v57 = pMapInfo->Dif_M2;
5153  NumToSpawn = pMapInfo->uEncounterMonster2AtLeast + v12;
5154  strcpy(Source, pMapInfo->pEncounterMonster2Texture.c_str());
5155  break;
5156  case 6:
5157  // pTexture = pMapInfo->pEncounterMonster1Texture;
5158  // v44 = "%s B";
5159  sprintf(Source, "%s B", pMapInfo->pEncounterMonster1Texture.c_str());
5160  break;
5161  case 7:
5162  // pTexture = pMapInfo->pEncounterMonster2Texture;
5163  // v44 = "%s B";
5164  sprintf(Source, "%s B", pMapInfo->pEncounterMonster2Texture.c_str());
5165  break;
5166  case 8:
5167  // pTexture = pMapInfo->pEncounterMonster3Texture;
5168  // v44 = "%s B";
5169  sprintf(Source, "%s B", pMapInfo->pEncounterMonster3Texture.c_str());
5170  break;
5171  case 2:
5172  // v9 = pMapInfo->uEncounterMonster3AtLeast;
5173  // v16 = rand();
5174  // v17 = pMapInfo->uEncounterMonster3AtMost;
5175  // pTexture = pMapInfo->pEncounterMonster3Texture;
5176  v12 = rand() % (pMapInfo->uEncounterMonster3AtMost -
5177  pMapInfo->uEncounterMonster3AtLeast + 1);
5178  // v13 = pMapInfo->Dif_M3;
5179  v57 = pMapInfo->Dif_M3;
5180  NumToSpawn = pMapInfo->uEncounterMonster3AtLeast + v12;
5181  strcpy(Source, pMapInfo->pEncounterMonster3Texture.c_str());
5182  break;
5183  case 9:
5184  // pTexture = pMapInfo->pEncounterMonster1Texture;
5185  // v44 = "%s C";
5186  sprintf(Source, "%s C", pMapInfo->pEncounterMonster1Texture.c_str());
5187  break;
5188  case 10:
5189  // pTexture = pMapInfo->pEncounterMonster2Texture;
5190  // v44 = "%s C";
5191  sprintf(Source, "%s C", pMapInfo->pEncounterMonster2Texture.c_str());
5192  break;
5193  case 11:
5194  // pTexture = pMapInfo->pEncounterMonster3Texture;
5195  // v44 = "%s C";
5196  sprintf(Source, "%s C", pMapInfo->pEncounterMonster3Texture.c_str());
5197  break;
5198  default:
5199  return;
5200  }
5201 
5202  if (Source[0] == '0') return;
5203 
5204  v57 += a3;
5205  if (v57 > 4) v57 = 4;
5206  strcpy(Str2, Source);
5207  if (a4) NumToSpawn = a4;
5208  // v18 = NumToSpawn;
5209  if (NumToSpawn <= 0) return;
5210  if ((signed int)(NumToSpawn + uNumActors) >= 500) return;
5211 
5212  pSector = 0;
5213  pPosX = spawn->vPosition.x;
5214  a4 = spawn->vPosition.y;
5215  a3 = spawn->vPosition.z;
5217  pSector = pIndoor->GetSector(spawn->vPosition.x, spawn->vPosition.y,
5218  spawn->vPosition.z);
5219  v53 = 0;
5220  v52 = (((uCurrentlyLoadedLevelType != LEVEL_Outdoor) - 1) & 0x40) + 64;
5221 
5222  // spawning loop
5223  for (int i = v53; i < NumToSpawn; ++i) {
5224  pMonster = &pActors[uNumActors];
5225  pActors[uNumActors].Reset();
5226 
5227  // random monster levels ABC
5228  if (v57) {
5229  v23 = rand() % 100;
5230  v24 = 3; // 2 , 10 , 20
5231  v25 = (uint16_t)word_4E8152[3 * v57];
5232  if (v23 >= v25) {
5233  if (v23 < v25 + (uint16_t)word_4E8152[3 * v57 + 1]) {
5234  v24 = 2; // 8 , 20 , 30
5235  }
5236  } else {
5237  v24 = 1; // 90 , 70 , 50
5238  }
5239 
5240  if (v24 == 1) {
5241  pTexture = Source;
5242  v44 = "%s A";
5243  } else if (v24 == 2) {
5244  pTexture = Source;
5245  v44 = "%s B";
5246  } else {
5247  if (v24 != 3) continue;
5248  pTexture = Source;
5249  v44 = "%s C";
5250  }
5251 
5252  sprintf(Str2, v44, pTexture);
5253  }
5254 
5255  v50 = pMonsterList->GetMonsterIDByName(Str2);
5256  pTexture = Str2;
5257  if ((signed __int16)v50 == -1) {
5258  logger->Warning(
5259  L"Can't create random monster: '%S'! See MapStats.txt and "
5260  L"Monsters.txt!",
5261  pTexture);
5263  }
5264 
5265  v27 = &pMonsterList->pMonsters[(signed __int16)v50];
5266  v28 = pMonsterStats->FindMonsterByTextureName(pTexture);
5267  if (!v28) v28 = 1;
5268  Src = &pMonsterStats->pInfos[v28];
5269  strcpy(pMonster->pActorName, Src->pName);
5270  pMonster->sCurrentHP = Src->uHP;
5271  assert(sizeof(MonsterInfo) == 88);
5272  memcpy(&pMonster->pMonsterInfo, Src,
5273  sizeof(MonsterInfo)); // Uninitialized portail memory access
5274  pMonster->word_000086_some_monster_id = v50 + 1;
5275  pMonster->uActorRadius = v27->uMonsterRadius;
5276  pMonster->uActorHeight = v27->uMonsterHeight;
5277  pMonster->uMovementSpeed = v27->uMovementSpeed;
5278  pMonster->vInitialPosition.x = spawn->vPosition.x;
5279  pMonster->vPosition.x = spawn->vPosition.x;
5280  pMonster->uTetherDistance = 256;
5281  pMonster->vInitialPosition.y = a4;
5282  pMonster->vPosition.y = a4;
5283  pMonster->vInitialPosition.z = a3;
5284  pMonster->vPosition.z = a3;
5285  pMonster->uSectorID = pSector;
5286  pMonster->uGroup = spawn->uGroup;
5287  pMonster->PrepareSprites(0);
5289  v32 = rand();
5290  a3 = fixpoint_mul(stru_5C6E00->Cos(v32 % 2048), v52);
5291  pPosX = a3 + spawn->vPosition.x;
5292  a3 = fixpoint_mul(stru_5C6E00->Sin(v32 % 2048), v52);
5293  a4 = a3 + spawn->vPosition.y;
5294  a3 = spawn->vPosition.z;
5296  if (a5) pMonster->uAttributes |= ACTOR_AGGRESSOR;
5297  ++uNumActors;
5298  continue;
5299  }
5300  v37 = pIndoor->GetSector(pPosX, a4, spawn->vPosition.z);
5301  if (v37 == pSector) {
5302  v38 = BLV_GetFloorLevel(pPosX, a4, a3, v37, &uFaceID);
5303  v39 = v38;
5304  if (v38 != -30000) {
5305  if (abs(v38 - a3) <= 1024) {
5306  a3 = v39;
5307  if (a5) pMonster->uAttributes |= ACTOR_AGGRESSOR;
5308  ++uNumActors;
5309  continue;
5310  }
5311  }
5312  }
5313  // v53 = (char *)v53 + 1;
5314  // result = v53;
5315  }
5316  // while ( (signed int)v53 < NumToSpawn );
5317 }
5318 
5319 //----- (00438F8F) --------------------------------------------------------
5320 void area_of_effect__damage_evaluate() { // not damaging party correctly
5321  int attacker_PID_type; // ecx@3
5322  signed int attacker_PID_id; // eax@3
5323  unsigned int target_id; // edi@6
5324  int target_type; // eax@6
5325  int v10; // edi@8
5326  Vec3_int_ attacker_coord; // ST04_12@9
5327  // int v12; // ST0C_4@10
5328  int v15; // edx@15
5329  int v19; // edi@15
5330  int v23; // edx@18
5331  int v24; // eax@18
5332  // int v30; // eax@29
5333  int v31; // edx@29
5334  int v32; // eax@29
5335  int v33; // ST24_4@29
5336  SpriteObject *sprite_obj_ptr = nullptr; // [sp+0h] [bp-28h]@0
5337  int attack_index; // [sp+10h] [bp-18h]@1
5338  int v44; // [sp+14h] [bp-14h]@15
5339  // Vec3_int_ *pVelocity; // [sp+1Ch] [bp-Ch]@2
5340  signed int a1; // [sp+20h] [bp-8h]@8
5341  int v48; // [sp+24h] [bp-4h]@8
5342 
5343  for (attack_index = 0; attack_index < AttackerInfo.count; ++attack_index) {
5344  attacker_PID_type = PID_TYPE(AttackerInfo.pIDs[attack_index]);
5345  // pid types - enum ObjectType
5346  attacker_PID_id = PID_ID(AttackerInfo.pIDs[attack_index]);
5347 
5348  // attacker is an item (sprite)
5349  if (attacker_PID_type == OBJECT_Item) {
5350  sprite_obj_ptr = &pSpriteObjects[attacker_PID_id];
5351  attacker_PID_type = PID_TYPE(pSpriteObjects[attacker_PID_id].spell_caster_pid);
5352  attacker_PID_id = PID_ID(pSpriteObjects[attacker_PID_id].spell_caster_pid);
5353  }
5354 
5355  if (AttackerInfo.field_3EC[attack_index] & 1) {
5356  target_id = PID_ID(ai_near_actors_targets_pid[attacker_PID_id]);
5357  target_type = PID_TYPE(ai_near_actors_targets_pid[attacker_PID_id]) - 3;
5358  if (target_type) {
5359  if (target_type == 1) { // party damage from monsters(повреждения
5360  // группе от монстров)
5361  v10 = pParty->vPosition.y - AttackerInfo.pYs[attack_index];
5362  a1 = pParty->vPosition.x - AttackerInfo.pXs[attack_index];
5363  v48 = pParty->vPosition.y - AttackerInfo.pYs[attack_index];
5364  if (a1 * a1 + v10 * v10 +
5365  ((signed int)(pParty->vPosition.z +
5366  pParty->uPartyHeight) >>
5367  (1 - AttackerInfo.pZs[attack_index])) *
5368  ((signed int)(pParty->vPosition.z +
5369  pParty->uPartyHeight) >>
5370  (1 - AttackerInfo.pZs[attack_index])) <
5371  (unsigned int)((AttackerInfo.field_324[attack_index] +
5372  32) *
5373  (AttackerInfo.field_324[attack_index] +
5374  32))) {
5375  attacker_coord.x = AttackerInfo.pXs[attack_index];
5376  attacker_coord.y = AttackerInfo.pYs[attack_index];
5377  attacker_coord.z = AttackerInfo.pZs[attack_index];
5380  attacker_coord))
5382  AttackerInfo.pIDs[attack_index],
5383  AttackerInfo.field_450[attack_index],
5384  &AttackerInfo.vec_4B4[attack_index],
5386  &pActors[attacker_PID_id]));
5387  }
5388  }
5389  } else { // Actor damage from monsters(повреждение местного жителя)
5390  if (pActors[target_id]
5391  .pActorBuffs[ACTOR_BUFF_PARALYZED]
5392  .Active() ||
5393  pActors[target_id].CanAct()) {
5394  v15 = pActors[target_id].vPosition.y -
5395  AttackerInfo.pYs[attack_index];
5396  a1 = pActors[target_id].vPosition.x -
5397  AttackerInfo.pXs[attack_index];
5398  v44 = pActors[target_id].vPosition.z;
5399  v19 = AttackerInfo.field_324[attack_index] +
5400  pActors[target_id].uActorRadius;
5401  v48 = v15;
5402  if (a1 * a1 + v15 * v15 +
5403  (pActors[target_id].vPosition.z +
5404  (pActors[target_id].uActorHeight >> 1) -
5405  AttackerInfo.pZs[attack_index]) *
5406  (pActors[target_id].vPosition.z +
5407  (pActors[target_id].uActorHeight >> 1) -
5408  AttackerInfo.pZs[attack_index]) <
5409  (unsigned int)(v19 * v19)) {
5410  attacker_coord.x = AttackerInfo.pXs[attack_index];
5411  attacker_coord.y = AttackerInfo.pYs[attack_index];
5412  attacker_coord.z = AttackerInfo.pZs[attack_index];
5413  if (sub_407A1C(pActors[target_id].vPosition.x,
5414  pActors[target_id].vPosition.y,
5415  pActors[target_id].vPosition.z + 50,
5416  attacker_coord)) {
5417  Vec3_int_::Normalize(&a1, &v48, &v44);
5418  AttackerInfo.vec_4B4[attack_index].x = a1;
5419  AttackerInfo.vec_4B4[attack_index].y = v48;
5420  AttackerInfo.vec_4B4[attack_index].z = v44;
5422  AttackerInfo.pIDs[attack_index], target_id,
5423  &AttackerInfo.vec_4B4[attack_index],
5424  AttackerInfo.field_450[attack_index]);
5425  }
5426  }
5427  }
5428  }
5429  } else { // damage from spells(повреждения от заклов(метеоритный дождь))
5430  v23 = pParty->vPosition.y - AttackerInfo.pYs[attack_index];
5431  v24 = ((signed int)pParty->uPartyHeight / 2) -
5432  AttackerInfo.pZs[attack_index];
5433  a1 = pParty->vPosition.x - AttackerInfo.pXs[attack_index];
5434  v48 = pParty->vPosition.y - AttackerInfo.pYs[attack_index];
5435  if (a1 * a1 + v23 * v23 +
5436  (pParty->vPosition.z + v24) * (pParty->vPosition.z + v24) <
5437  (unsigned int)((AttackerInfo.field_324[attack_index] + 32) *
5438  (AttackerInfo.field_324[attack_index] +
5439  32))) { // party damage (повреждения группе)
5440  attacker_coord.x = AttackerInfo.pXs[attack_index];
5441  attacker_coord.y = AttackerInfo.pYs[attack_index];
5442  attacker_coord.z = AttackerInfo.pZs[attack_index];
5445  attacker_coord)) {
5446  for (uint i = 0; i < 4; ++i) {
5447  if (!pParty->pPlayers[i]
5448  .conditions_times[Condition_Dead] &&
5449  !pParty->pPlayers[i]
5450  .conditions_times[Condition_Pertified] &&
5451  !pParty->pPlayers[i]
5452  .conditions_times[Condition_Eradicated]) {
5454  AttackerInfo.pIDs[attack_index],
5455  AttackerInfo.field_450[attack_index],
5456  &AttackerInfo.vec_4B4[attack_index], i);
5457  }
5458  }
5459  }
5460  }
5461 
5462  if (uNumActors >
5463  0) { // actors damage(повреждения другим участникам)
5464  for (int actorID = 0;
5465  (signed int)actorID < (signed int)uNumActors; ++actorID) {
5466  if (pActors[actorID].CanAct()) {
5467  // v30 = pActors[actorID].vPosition.y -
5468  // AttackerInfo.pYs[attack_index];
5469  a1 = pActors[actorID].vPosition.x -
5470  AttackerInfo.pXs[attack_index];
5471  v31 = pActors[actorID].vPosition.z;
5472  v48 = pActors[actorID].vPosition.y -
5473  AttackerInfo.pYs[attack_index];
5474  v44 = pActors[actorID].vPosition.z;
5475  v32 = (pActors[actorID].uActorHeight / 2) -
5476  AttackerInfo.pZs[attack_index];
5477  v33 = pActors[actorID].uActorRadius +
5478  AttackerInfo.field_324[attack_index];
5479  if (a1 * a1 + v48 * v48 + (v31 + v32) * (v31 + v32) <
5480  (unsigned int)(v33 * v33)) {
5481  attacker_coord.x = AttackerInfo.pXs[attack_index];
5482  attacker_coord.y = AttackerInfo.pYs[attack_index];
5483  attacker_coord.z = AttackerInfo.pZs[attack_index];
5484  if (sub_407A1C(pActors[actorID].vPosition.x,
5485  pActors[actorID].vPosition.y,
5486  pActors[actorID].vPosition.z + 50,
5487  attacker_coord)) { // что делает ф-ция?
5488  Vec3_int_::Normalize(&a1, &v48, &v44);
5489  AttackerInfo.vec_4B4[attack_index].x = a1;
5490  AttackerInfo.vec_4B4[attack_index].y = v48;
5491  AttackerInfo.vec_4B4[attack_index].z = v44;
5492  switch (attacker_PID_type) {
5493  case OBJECT_Player:
5495  AttackerInfo.pIDs[attack_index],
5496  actorID,
5497  &AttackerInfo.vec_4B4[attack_index]);
5498  break;
5499  case OBJECT_Actor:
5500  if (sprite_obj_ptr &&
5501  pActors[attacker_PID_id].GetActorsRelation(
5502  &pActors[actorID]))
5504  AttackerInfo.pIDs[attack_index],
5505  actorID,
5506  &AttackerInfo
5507  .vec_4B4[attack_index],
5508  sprite_obj_ptr->field_61);
5509  break;
5510  case OBJECT_Item:
5512  AttackerInfo.pIDs[attack_index],
5513  actorID,
5514  &AttackerInfo.vec_4B4[attack_index]);
5515  break;
5516  }
5517  }
5518  }
5519  }
5520  }
5521  }
5522  }
5523  }
5524  AttackerInfo.count = 0;
5525 }
5526 
5527 //----- (0043AE12) --------------------------------------------------------
5528 double sub_43AE12(signed int a1) {
5529  // signed int v1; // ST00_4@1
5530  signed int v2; // ecx@1
5531  double v3; // st7@1
5532  double result; // st7@6
5533 
5534  v3 = (double)a1;
5535  for (v2 = 0; v2 < 5; ++v2) {
5536  if (v3 < flt_4E4A80[v2 + 5]) break;
5537  }
5538  if (v2 <= 0 || v2 >= 5) {
5539  if (v2)
5540  result = flt_4E4A80[4];
5541  else
5542  result = flt_4E4A80[0];
5543  } else {
5544  result = (flt_4E4A80[v2] - flt_4E4A80[v2 - 1]) *
5545  (v3 - flt_4E4A80[v2 + 4]) /
5546  (flt_4E4A80[v2 + 5] - flt_4E4A80[v2 + 4]) +
5547  flt_4E4A80[v2];
5548  }
5549  return result;
5550 }
5551 
5552 //----- (0043B057) --------------------------------------------------------
5553 void ItemDamageFromActor(unsigned int uObjID, unsigned int uActorID,
5554  Vec3_int_ *pVelocity) {
5555  int v6; // eax@4
5556  int damage; // edi@4
5557  int a2a; // [sp+Ch] [bp-4h]@8
5558 
5559  if (!pActors[uActorID].IsNotAlive()) {
5560  if (PID_TYPE(uObjID) == OBJECT_Item) {
5561  if (pSpriteObjects[PID_ID(uObjID)].spell_id) {
5563  pSpriteObjects[PID_ID(uObjID)].spell_id,
5564  pSpriteObjects[PID_ID(uObjID)].spell_level,
5565  pSpriteObjects[PID_ID(uObjID)].spell_skill,
5566  pActors[uActorID].sCurrentHP);
5567  damage = pActors[uActorID].CalcMagicalDamageToActor(
5568  (DAMAGE_TYPE)0, v6);
5569  pActors[uActorID].sCurrentHP -= damage;
5570  if (damage) {
5571  if (pActors[uActorID].sCurrentHP > 0)
5572  Actor::AI_Stun(uActorID, uObjID, 0);
5573  else
5574  Actor::Die(uActorID);
5575  a2a = 20 * damage /
5576  (signed int)pActors[uActorID].pMonsterInfo.uHP;
5577  if (20 * damage /
5578  (signed int)pActors[uActorID].pMonsterInfo.uHP >
5579  10)
5580  a2a = 10;
5582  pActors[uActorID].pMonsterInfo.uID,
5584  pVelocity->x = fixpoint_mul(a2a, pVelocity->x);
5585  pVelocity->y = fixpoint_mul(a2a, pVelocity->y);
5586  pVelocity->z = fixpoint_mul(a2a, pVelocity->z);
5587  pActors[uActorID].vVelocity.x =
5588  50 * (short)pVelocity->x;
5589  pActors[uActorID].vVelocity.y =
5590  50 * (short)pVelocity->y;
5591  pActors[uActorID].vVelocity.z =
5592  50 * (short)pVelocity->z;
5593  }
5594  Actor::AddBloodsplatOnDamageOverlay(uActorID, 1, damage);
5595  } else {
5596  Actor::AI_Stun(uActorID, uObjID, 0);
5597  }
5598  }
5599  }
5600  }
5601 }
stru298::field_450
char field_450[100]
Definition: stru298.h:19
MonsterInfo::uMissleAttack1Type
uint8_t uMissleAttack1Type
Definition: Monsters.h:139
UIGame.h
SPRITE_PROJECTILE_530
@ SPRITE_PROJECTILE_530
Definition: SpriteObject.h:22
uint16_t
unsigned __int16 uint16_t
Definition: SDL_config.h:37
SpriteObject
Definition: SpriteObject.h:189
spell_sprite_mapping
std::array< stru324_spell_id_to_sprite_mapping, 103 > spell_sprite_mapping
Definition: Spells.cpp:35
Actor::pSoundSampleIDs
uint16_t pSoundSampleIDs[4]
Definition: Actor.h:314
MONSTER_OOZE_1
@ MONSTER_OOZE_1
Definition: Monsters.h:26
int32
int int32
Definition: MM7.h:54
ObjectDesc::uSpeed
int16_t uSpeed
Definition: ObjectList.h:31
Player::SetRecoveryTime
void SetRecoveryTime(signed int sRecoveryTime)
Definition: Player.cpp:2593
Player
Definition: Player.h:401
Actor::CanAct
bool CanAct()
Definition: Actor.cpp:157
SPELL_EARTH_STONESKIN
@ SPELL_EARTH_STONESKIN
Definition: Spells.h:53
Actor::vPosition
struct Vec3_short_ vPosition
Definition: Actor.h:298
Player::StealFromActor
int StealFromActor(unsigned int uActorID, int _steal_perm, int reputation)
Definition: Player.cpp:1667
PLAYER_SKILL_BLASTER
@ PLAYER_SKILL_BLASTER
Definition: Player.h:178
uNumActors
size_t uNumActors
Definition: Actor.cpp:39
Player::IsWeak
bool IsWeak() const
Definition: Player.cpp:7412
MONSTER_DEVIL_3
@ MONSTER_DEVIL_3
Definition: Monsters.h:9
DMGT_PHISYCAL
@ DMGT_PHISYCAL
Definition: Items.h:15
Party::vPosition
Vec3_int_ vPosition
Definition: Party.h:250
Engine_::IocContainer
Definition: IocContainer.h:15
MONSTER_HARPY_3
@ MONSTER_HARPY_3
Definition: Monsters.h:23
sub_407A1C
bool sub_407A1C(int x, int y, int z, Vec3_int_ v)
Definition: Indoor.cpp:3199
Actor::ActorHasItems
struct ItemGen ActorHasItems[4]
Definition: Actor.h:316
Player::PlayerHitOrMiss
bool PlayerHitOrMiss(Actor *pActor, int distancemod, int skillmod)
Definition: Player.cpp:7600
AttackingRanged2
@ AttackingRanged2
Definition: Actor.h:87
ItemGen::GetDamageMod
unsigned __int8 GetDamageMod()
Definition: Items.cpp:1533
Actor::AI_Stun
static void AI_Stun(unsigned int uActorID, signed int edx0, int arg0)
Definition: Actor.cpp:1815
Actor::StealFrom
static void StealFrom(unsigned int uActorID)
Definition: Actor.cpp:1385
int_get_vector_length
uint32_t int_get_vector_length(int32_t x, int32_t y, int32_t z)
Definition: VectorTypes.cpp:8
Actor::ResetActive
void ResetActive()
Definition: Actor.h:180
Actor::AI_RandomMove
static void AI_RandomMove(unsigned int uActor_id, unsigned int uTarget_id, int radius, int uActionLength)
Definition: Actor.cpp:1696
MONSTER_DEVIL_1
@ MONSTER_DEVIL_1
Definition: Monsters.h:7
MonsterInfo::uSpell2UseChance
uint8_t uSpell2UseChance
Definition: Monsters.h:148
MonsterInfo::uResBody
uint8_t uResBody
Definition: Monsters.h:156
MONSTER_TROLL_3
@ MONSTER_TROLL_3
Definition: Monsters.h:44
SpriteFrame::hw_sprites
Sprite * hw_sprites[8]
Definition: Sprites.h:46
AttackingMelee
@ AttackingMelee
Definition: Actor.h:77
AIDirection::uDistanceXZ
unsigned int uDistanceXZ
Definition: Actor.h:129
pLevelDecorations
std::array< LevelDecoration, 3000 > pLevelDecorations
Definition: Decoration.cpp:8
stru193_math::uIntegerDoublePi
static const unsigned int uIntegerDoublePi
Definition: OurMath.h:90
MonsterInfo::uAttackPreference
unsigned int uAttackPreference
Definition: Monsters.h:180
DMGT_DARK
@ DMGT_DARK
Definition: Items.h:21
SPRITE_BLASTER_PROJECTILE
@ SPRITE_BLASTER_PROJECTILE
Definition: SpriteObject.h:30
Actor::uActorHeight
uint16_t uActorHeight
Definition: Actor.h:296
stru298::vec_4B4
Vec3_int_ vec_4B4[100]
Definition: stru298.h:20
Dying
@ Dying
Definition: Actor.h:79
int16_t
signed __int16 int16_t
Definition: SDL_config.h:36
ANIM_GotHit
@ ANIM_GotHit
Definition: Actor.h:103
ACTOR_BUFF_PAIN_REFLECTION
@ ACTOR_BUFF_PAIN_REFLECTION
Definition: Actor.h:58
Actor::uPitchAngle
uint16_t uPitchAngle
Definition: Actor.h:301
Actor::UpdateAnimation
void UpdateAnimation()
Definition: Actor.cpp:2376
Timer::uTimeElapsed
unsigned int uTimeElapsed
Definition: Time.h:133
SpriteObject::uFacing
unsigned __int16 uFacing
Definition: SpriteObject.h:220
Actor::ArePeasantsOfSameFaction
static bool ArePeasantsOfSameFaction(Actor *a1, Actor *a2)
Definition: Actor.cpp:700
Player::GetAttackRecoveryTime
int GetAttackRecoveryTime(bool bRangedAttack)
Definition: Player.cpp:2203
MapStats::pInfos
MapInfo pInfos[77]
Definition: MapInfo.h:79
MonsterInfo::uBaseSpeed
unsigned int uBaseSpeed
Definition: Monsters.h:178
SPRITE_PROJECTILE_535
@ SPRITE_PROJECTILE_535
Definition: SpriteObject.h:24
SPELL_101
@ SPELL_101
Definition: Spells.h:122
Actor::ToggleFlag
static void ToggleFlag(signed int uActorID, unsigned int uFlag, int bToggle)
Definition: Actor.cpp:112
Party::GetPlayingTime
GameTime & GetPlayingTime()
Definition: Party.h:230
SPELL_LIGHT_LIGHT_BOLT
@ SPELL_LIGHT_LIGHT_BOLT
Definition: Spells.h:97
stru193_math::uDoublePiMask
static const unsigned int uDoublePiMask
Definition: OurMath.h:91
Actor::AI_StandOrBored
static void AI_StandOrBored(unsigned int uActorID, signed int uObjID, int uActionLength, struct AIDirection *a4)
Definition: Actor.cpp:1100
BLVFace::pFacePlane_old
struct Plane_int_ pFacePlane_old
Definition: Indoor.h:471
PLAYER_SKILL_STAFF
@ PLAYER_SKILL_STAFF
Definition: Player.h:171
MapInfo::pEncounterMonster1Texture
String pEncounterMonster1Texture
Definition: MapInfo.h:40
Vec2::x
T x
Definition: VectorTypes.h:12
GUIWindow
Definition: GUIWindow.h:433
ITEM_DRAGON_EYE
@ ITEM_DRAGON_EYE
Definition: Items.h:104
Player::CalculateRangedDamageTo
int CalculateRangedDamageTo(int uMonsterInfoID)
Definition: Player.cpp:1365
Actor::DoesDmgTypeDoDamage
bool DoesDmgTypeDoDamage(DAMAGE_TYPE uType)
Definition: Actor.cpp:4381
SPELL_MIND_PSYCHIC_SHOCK
@ SPELL_MIND_PSYCHIC_SHOCK
Definition: Spells.h:82
pSpriteFrameTable
struct SpriteFrameTable * pSpriteFrameTable
Definition: Sprites.cpp:22
MonsterInfo::uHostilityType
HostilityRadius uHostilityType
Definition: Monsters.h:131
IndoorLocation::pSectors
struct BLVSector * pSectors
Definition: Indoor.h:634
ABILITY_ATTACK1
@ ABILITY_ATTACK1
Definition: Actor.h:31
Actor::dword_000334_unique_name
int dword_000334_unique_name
Definition: Actor.h:322
pSpriteObjects
std::array< SpriteObject, MAX_SPRITE_OBJECTS > pSpriteObjects
Definition: SpriteObject.cpp:34
ToggleActorGroupFlag
void ToggleActorGroupFlag(unsigned int uGroupID, unsigned int uFlag, unsigned int bToggle)
Definition: Actor.cpp:4426
pSprites_LOD
LODFile_Sprites * pSprites_LOD
Definition: LOD.cpp:20
BLVFace::pVertexIDs
uint16_t * pVertexIDs
Definition: Indoor.h:476
stru141_actor_collision_object::sMaxZ
int sMaxZ
Definition: Indoor.h:180
SPELL_DARK_PAIN_REFLECTION
@ SPELL_DARK_PAIN_REFLECTION
Definition: Spells.h:115
SpriteObject::field_60_distance_related_prolly_lod
char field_60_distance_related_prolly_lod
Definition: SpriteObject.h:234
Actor::AI_MeleeAttack
static void AI_MeleeAttack(unsigned int uActorID, signed int sTargetPid, struct AIDirection *arg0)
Definition: Actor.cpp:1148
OBJECT_Item
@ OBJECT_Item
Definition: Actor.h:66
ai_arrays_size
int ai_arrays_size
Definition: mm7_data.cpp:503
pMonsterStats
struct MonsterStats * pMonsterStats
Definition: Monsters.cpp:8
OtherOverlayList::_4418B6
int _4418B6(int uOverlayID, int16_t a3, int a4, int a5, int16_t a6)
Definition: Overlays.cpp:32
ItemsTable::SetSpecialBonus
void SetSpecialBonus(ItemGen *pItem)
Definition: Items.cpp:472
Actor::SearchActorByGroup
static unsigned int SearchActorByGroup(unsigned int *pTotalActors, unsigned int uGroup)
Definition: Actor.cpp:3283
Party::uFine
int uFine
Definition: Party.h:324
ItemGen::GetItemEquipType
ITEM_EQUIP_TYPE GetItemEquipType()
Definition: Items.cpp:1504
SpawnActor
bool SpawnActor(unsigned int uMonsterID)
Definition: Actor.cpp:4922
Party::sRotationX
int sRotationX
Definition: Party.h:252
ai_array_4F5E68
std::array< int, 500 > ai_array_4F5E68
Definition: mm7_data.cpp:500
Party::SetYellowAlert
void SetYellowAlert()
Definition: Party.h:228
MonsterInfo::uAttack1DamageBonus
uint8_t uAttack1DamageBonus
Definition: Monsters.h:138
_449B57_test_bit
bool _449B57_test_bit(unsigned __int8 *a1, __int16 a2)
Definition: Party.cpp:1185
Player::ReceiveDamage
int ReceiveDamage(signed int amount, DAMAGE_TYPE dmg_type)
Definition: Player.cpp:1816
dword_5C6DF8
int dword_5C6DF8
Definition: mm7_data.cpp:651
SpellStats::pInfos
SpellInfo pInfos[100]
Definition: Spells.h:192
z
GLdouble GLdouble z
Definition: SDL_opengl_glext.h:407
DecalBuilder::AddBloodsplat
void AddBloodsplat(float x, float y, float z, float r, float g, float b, float radius, int a8, int a9)
Definition: DecalBuilder.cpp:50
sub_448518_npc_set_item
void sub_448518_npc_set_item(int npc, unsigned int item, int a3)
Definition: Actor.cpp:127
DMGT_FIRE
@ DMGT_FIRE
Definition: Items.h:11
ACTOR_BUFF_DAY_OF_PROTECTION
@ ACTOR_BUFF_DAY_OF_PROTECTION
Definition: Actor.h:51
SPELL_LIGHT_HOUR_OF_POWER
@ SPELL_LIGHT_HOUR_OF_POWER
Definition: Spells.h:105
SpellInfo::uSchool
SPELL_SCHOOL uSchool
Definition: Spells.h:183
Actor::AI_Pursue1
static void AI_Pursue1(unsigned int uActorID, unsigned int a2, signed int arg0, signed int uActionLength, struct AIDirection *pDir)
Definition: Actor.cpp:2003
OtherOverlayList::_4418B1
int _4418B1(int a2, int a3, int a4, int a5)
Definition: Overlays.cpp:29
Actor::PlaySound
static void PlaySound(unsigned int uActorID, unsigned int uSoundID)
Definition: Actor.cpp:1974
fixpoint_div
__int64 fixpoint_div(int a1, int a2)
Definition: OurMath.cpp:147
MapStats::GetMapInfo
MAP_TYPE GetMapInfo(const String &Str2)
Definition: MapInfo.cpp:225
Actor::AI_SpellAttack
static void AI_SpellAttack(unsigned int uActorID, struct AIDirection *pDir, int uSpellID, int a4, unsigned int uSkillLevel)
Definition: Actor.cpp:199
Player::IsUnarmed
bool IsUnarmed()
Definition: Player.cpp:1576
ANIM_Standing
@ ANIM_Standing
Definition: Actor.h:99
ai_array_4F6638_actor_ids
std::array< int, 500 > ai_array_4F6638_actor_ids
Definition: mm7_data.cpp:501
SpellBuff::IsBuffExpiredToTime
bool IsBuffExpiredToTime(GameTime time)
Definition: Spells.cpp:351
SkillToMastery
unsigned int SkillToMastery(unsigned int skill_value)
Definition: Player.cpp:7854
MapInfo::uEncounterMonster2AtMost
uint8_t uEncounterMonster2AtMost
Definition: MapInfo.h:62
SPELL_LIGHT_DAY_OF_PROTECTION
@ SPELL_LIGHT_DAY_OF_PROTECTION
Definition: Spells.h:104
stru298::field_324
int16_t field_324[100]
Definition: stru298.h:17
SPELL_EARTH_ROCK_BLAST
@ SPELL_EARTH_ROCK_BLAST
Definition: Spells.h:56
Actor
Definition: Actor.h:151
Actor::Reset
void Reset()
Definition: Actor.cpp:2443
Party::sEyelevel
int sEyelevel
Definition: Party.h:239
SpriteObject::uSectorID
__int16 uSectorID
Definition: SpriteObject.h:223
AudioPlayer::PlaySound
void PlaySound(SoundID eSoundID, int pid, unsigned int uNumRepeats, int x, int y, int a7)
Definition: AudioPlayer.cpp:195
BBox_short_::x1
int16_t x1
Definition: VectorTypes.h:114
SpriteObject.h
MonsterInfo::Hostility_Friendly
@ Hostility_Friendly
Definition: Monsters.h:111
MonsterInfo::uSpell1ID
uint8_t uSpell1ID
Definition: Monsters.h:147
engine
std::shared_ptr< Engine > engine
Definition: Engine.cpp:130
Actor::vVelocity
struct Vec3_short_ vVelocity
Definition: Actor.h:299
Player::CanAct
bool CanAct()
Definition: Player.cpp:549
ItemDamageFromActor
void ItemDamageFromActor(unsigned int uObjID, unsigned int uActorID, Vec3_int_ *pVelocity)
Definition: Actor.cpp:5553
MonsterInfo::uResDark
uint8_t uResDark
Definition: Monsters.h:158
stru193_math::uIntegerHalfPi
static const unsigned int uIntegerHalfPi
Definition: OurMath.h:89
MonsterInfo::uAC
unsigned int uAC
Definition: Monsters.h:176
MonsterInfo::uResLight
uint8_t uResLight
Definition: Monsters.h:157
Actor::uCarriedItemID
uint16_t uCarriedItemID
Definition: Actor.h:309
Actor::AI_MissileAttack1
static void AI_MissileAttack1(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir)
Definition: Actor.cpp:1626
MapInfo::uEncounterMonster3AtMost
uint8_t uEncounterMonster3AtMost
Definition: MapInfo.h:65
stru262_TurnBased::ApplyPlayerAction
void ApplyPlayerAction()
Definition: TurnEngine.cpp:101
ACTOR_BUFF_HEROISM
@ ACTOR_BUFF_HEROISM
Definition: Actor.h:56
DMGT_SPIRIT
@ DMGT_SPIRIT
Definition: Items.h:17
Actor::AI_FaceObject
static void AI_FaceObject(unsigned int uActorID, unsigned int uObjID, int UNUSED, struct AIDirection *Dir_In)
Definition: Actor.cpp:1072
ANIM_Dying
@ ANIM_Dying
Definition: Actor.h:104
ABILITY_INDEX
ABILITY_INDEX
Definition: Actor.h:30
Actor::IsPeasant
bool IsPeasant()
Definition: Actor.cpp:1369
localization
Localization * localization
Definition: Localization.cpp:11
SPELL_BODY_HARM
@ SPELL_BODY_HARM
Definition: Spells.h:88
MonsterInfo::uResFire
uint8_t uResFire
Definition: Monsters.h:150
MonsterInfo::field_3C_some_special_attack
int16_t field_3C_some_special_attack
Definition: Monsters.h:173
Player::CalculateMeleeDamageTo
int CalculateMeleeDamageTo(bool ignoreSkillBonus, bool ignoreOffhand, unsigned int uTargetActorID)
Definition: Player.cpp:1202
MonsterInfo::uAttack2Chance
uint8_t uAttack2Chance
Definition: Monsters.h:140
Actor::ResetAlive
void ResetAlive()
Definition: Actor.h:181
Party::uCurrentHour
unsigned int uCurrentHour
Definition: Party.h:275
MonsterInfo::uTreasureType
uint8_t uTreasureType
Definition: Monsters.h:127
MONSTER_MOVEMENT_TYPE_FREE
@ MONSTER_MOVEMENT_TYPE_FREE
Definition: Monsters.h:64
ObjectList::ObjectIDByItemID
unsigned int ObjectIDByItemID(unsigned int uItemID)
Definition: ObjectList.cpp:7
BBox_short_::y1
int16_t y1
Definition: VectorTypes.h:116
MonsterInfo::uSpecialAbilityDamageDiceBonus
uint8_t uSpecialAbilityDamageDiceBonus
Definition: Monsters.h:166
Actor::CalcMagicalDamageToActor
int CalcMagicalDamageToActor(DAMAGE_TYPE dmgType, int incomingDmg)
Definition: Actor.cpp:4314
MonsterInfo::uAttack1DamageDiceSides
uint8_t uAttack1DamageDiceSides
Definition: Monsters.h:137
ItemGen::_439DF3_get_additional_damage
int _439DF3_get_additional_damage(DAMAGE_TYPE *a2, bool *vampiyr)
Definition: Items.cpp:42
stru298::count
int count
Definition: stru298.h:12
Standing
@ Standing
Definition: Actor.h:75
MONSTER_TROLL_2
@ MONSTER_TROLL_2
Definition: Monsters.h:43
stru141_actor_collision_object::normal
Vec3_int_ normal
Definition: Indoor.h:159
Actor::_4031C1_update_job_never_gets_called
static char _4031C1_update_job_never_gets_called(unsigned int uActorID, signed int a2, int a3)
Definition: Actor.cpp:1754
AttackingRanged4
@ AttackingRanged4
Definition: Actor.h:93
Party::pPlayers
std::array< Player, 4 > pPlayers
Definition: Party.h:310
EQUIP_GOLD
@ EQUIP_GOLD
Definition: Items.h:246
ai_near_actors_targets_pid
std::array< int, 500 > ai_near_actors_targets_pid
Definition: mm7_data.cpp:502
ITEM_EQUIP_TYPE
ITEM_EQUIP_TYPE
Definition: Items.h:226
Player::GetSpecialItemBonus
int GetSpecialItemBonus(ITEM_ENCHANTMENT enchantment)
Definition: Player.cpp:2634
sub_43AE12
double sub_43AE12(signed int a1)
Definition: Actor.cpp:5528
SpawnPointMM7
Definition: Indoor.h:304
SpriteObject::uType
SPRITE_OBJECT_TYPE uType
Definition: SpriteObject.h:215
ACTOR_BUFF_SLOWED
@ ACTOR_BUFF_SLOWED
Definition: Actor.h:45
pFactionTable
struct FactionTable * pFactionTable
Definition: mm7_data.cpp:672
SPELL_MIND_MIND_BLAST
@ SPELL_MIND_MIND_BLAST
Definition: Spells.h:74
Party::sub_421B2C_PlaceInInventory_or_DropPickedItem
void sub_421B2C_PlaceInInventory_or_DropPickedItem()
Definition: Party.cpp:1048
SpellFxRenderer.h
Actor::ActorHitOrMiss
bool ActorHitOrMiss(Player *pPlayer)
Definition: Actor.cpp:4293
SOUND_Bless
@ SOUND_Bless
Definition: AudioPlayer.h:100
Player::GetActualAC
int GetActualAC()
Definition: Player.cpp:2452
game_ui_monster_hp_yellow
Image * game_ui_monster_hp_yellow
Definition: UIGame.cpp:62
MonsterInfo::uAttack2DamageBonus
uint8_t uAttack2DamageBonus
Definition: Monsters.h:144
OBJECT_Decoration
@ OBJECT_Decoration
Definition: Actor.h:69
game_ui_monster_hp_green
Image * game_ui_monster_hp_green
Definition: UIGame.cpp:61
MonsterInfo::uTreasureDropChance
uint8_t uTreasureDropChance
Definition: Monsters.h:123
Actor::Die
static void Die(unsigned int uActorID)
Definition: Actor.cpp:1906
AttackingRanged1
@ AttackingRanged1
Definition: Actor.h:78
SPRITE_PROJECTILE_500
@ SPRITE_PROJECTILE_500
Definition: SpriteObject.h:10
SPELL_DARK_SHARPMETAL
@ SPELL_DARK_SHARPMETAL
Definition: Spells.h:113
Actor::uGroup
unsigned int uGroup
Definition: Actor.h:317
SPELL_WATER_ICE_BOLT
@ SPELL_WATER_ICE_BOLT
Definition: Spells.h:40
SPELL_FIRE_METEOR_SHOWER
@ SPELL_FIRE_METEOR_SHOWER
Definition: Spells.h:21
SPEECH_51
@ SPEECH_51
Definition: Player.h:97
ItemGen::Reset
void Reset()
Definition: Items.cpp:133
SPELL_TYPE
SPELL_TYPE
Definition: Spells.h:10
Player::pActiveSkills
std::array< unsigned __int16, 37 > pActiveSkills
Definition: Player.h:711
Condition_Paralyzed
@ Condition_Paralyzed
Definition: Conditions.h:20
pPlayers
NZIArray< struct Player *, 5 > pPlayers
Definition: Player.cpp:46
MonsterInfo::uSpecialAbilityDamageDiceSides
uint8_t uSpecialAbilityDamageDiceSides
Definition: Monsters.h:165
MapInfo::uEncounterMonster1AtMost
uint8_t uEncounterMonster1AtMost
Definition: MapInfo.h:59
Actor::UpdateActorAI
static void UpdateActorAI()
Definition: Actor.cpp:2745
SpriteObject::uSpriteFrameID
unsigned __int16 uSpriteFrameID
Definition: SpriteObject.h:224
BBox_short_::z2
int16_t z2
Definition: VectorTypes.h:119
Actor::AI_Stand
static void AI_Stand(unsigned int uActorID, unsigned int object_to_face_pid, unsigned int uActionLength, struct AIDirection *a4)
Definition: Actor.cpp:1109
pIndoor
IndoorLocation * pIndoor
Definition: Indoor.cpp:49
Actor::_46DF1A_collide_against_actor
static bool _46DF1A_collide_against_actor(int a1, int a2)
Definition: Actor.cpp:2699
Engine.h
ItemGen::uEnchantmentType
int uEnchantmentType
Definition: Items.h:327
ACTOR_BUFF_AFRAID
@ ACTOR_BUFF_AFRAID
Definition: Actor.h:42
Plane_int_::vNormal
Vec3_int_ vNormal
Definition: VectorTypes.h:107
pTurnEngine
struct stru262_TurnBased * pTurnEngine
Definition: TurnEngine.cpp:21
ACTOR_BUFF_FATE
@ ACTOR_BUFF_FATE
Definition: Actor.h:49
Dead
@ Dead
Definition: Actor.h:80
Resurrected
@ Resurrected
Definition: Actor.h:91
ACTOR_BUFF_SHRINK
@ ACTOR_BUFF_SHRINK
Definition: Actor.h:41
Player::GetMainHandItem
ItemGen * GetMainHandItem()
Definition: Player.cpp:7542
Tethered
@ Tethered
Definition: Actor.h:76
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9435
pMapStats
struct MapStats * pMapStats
Definition: mm7_data.cpp:20
MonsterInfo::uSpecialAbilityDamageDiceRolls
uint8_t uSpecialAbilityDamageDiceRolls
Definition: Monsters.h:164
SpriteObject::uObjectDescID
unsigned __int16 uObjectDescID
Definition: SpriteObject.h:217
SPELL_FIRE_FIRE_BOLT
@ SPELL_FIRE_FIRE_BOLT
Definition: Spells.h:14
AIDirection
Definition: Actor.h:126
Party::pPartyBuffs
std::array< SpellBuff, 20 > pPartyBuffs
Definition: Party.h:309
Actor::AI_SpellAttack2
static void AI_SpellAttack2(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir)
Definition: Actor.cpp:1412
Actor::uAIState
AIState uAIState
Definition: Actor.h:307
OBJECT_Actor
@ OBJECT_Actor
Definition: Actor.h:67
uLevelMapStatsID
unsigned int uLevelMapStatsID
Definition: mm7_data.cpp:713
area_of_effect__damage_evaluate
void area_of_effect__damage_evaluate()
Definition: Actor.cpp:5320
Actor::AI_RangedAttack
static void AI_RangedAttack(unsigned int uActorID, struct AIDirection *a2, int type, char a4)
Definition: Actor.cpp:747
SpellBuff::Reset
void Reset()
Definition: Spells.cpp:337
Party::uPartyHeight
unsigned int uPartyHeight
Definition: Party.h:237
sub_44FA4C_spawn_light_elemental
int sub_44FA4C_spawn_light_elemental(int spell_power, int caster_skill_level, int duration_game_seconds)
Definition: Actor.cpp:4969
ai_near_actors_distances
std::array< int, 500 > ai_near_actors_distances
Definition: mm7_data.cpp:504
MONSTER_MOVEMENT_TYPE_GLOBAL
@ MONSTER_MOVEMENT_TYPE_GLOBAL
Definition: Monsters.h:63
SpawnPointMM7::uAttributes
uint16_t uAttributes
Definition: Indoor.h:318
Actor::ApplyFineForKillingPeasant
static void ApplyFineForKillingPeasant(unsigned int uActorID)
Definition: Actor.cpp:1223
Actor.h
SpriteObject::field_61
char field_61
Definition: SpriteObject.h:235
MONSTER_HARPY_2
@ MONSTER_HARPY_2
Definition: Monsters.h:22
stru298::field_3EC
char field_3EC[100]
Definition: stru298.h:18
Party::AddItemToParty
bool AddItemToParty(ItemGen *pItem)
Definition: Party.cpp:1096
MonsterInfo::uTreasureDiceRolls
uint8_t uTreasureDiceRolls
Definition: Monsters.h:124
pItemsTable
struct ItemsTable * pItemsTable
Definition: Items.cpp:37
Party::PartyFindsGold
void PartyFindsGold(unsigned int uNumGold, int _1_dont_share_with_followers___2_the_same_but_without_a_message__else_normal)
Definition: Party.cpp:976
SPRITE_PROJECTILE_525
@ SPRITE_PROJECTILE_525
Definition: SpriteObject.h:20
decal_builder
static DecalBuilder * decal_builder
Definition: Actor.cpp:35
stru319::which_player_to_attack
int which_player_to_attack(struct Actor *pActor)
Definition: Actor.cpp:3754
GetAlertStatus
int GetAlertStatus()
Definition: Indoor.cpp:5287
Localization.h
Actor::StandAwhile
static void StandAwhile(unsigned int uActorID)
Definition: Actor.cpp:1137
Actor::uLastCharacterIDToHit
unsigned int uLastCharacterIDToHit
Definition: Actor.h:321
y
EGLSurface EGLint EGLint y
Definition: SDL_egl.h:1596
MONSTER_MOVEMENT_TYPE_MEDIUM
@ MONSTER_MOVEMENT_TYPE_MEDIUM
Definition: Monsters.h:61
ItemGen::special_enchantment
ITEM_ENCHANTMENT special_enchantment
Definition: Items.h:330
ItemGen::uMaxCharges
char uMaxCharges
Definition: Items.h:351
IndoorCameraD3D::vPartyPos
Vec3< int > vPartyPos
Definition: IndoorCameraD3D.h:253
AIDirection::uYawAngle
unsigned int uYawAngle
Definition: Actor.h:130
SPELL_DARK_SOULDRINKER
@ SPELL_DARK_SOULDRINKER
Definition: Spells.h:119
MONSTER_SPECIAL_ABILITY_EXPLODE
@ MONSTER_SPECIAL_ABILITY_EXPLODE
Definition: Monsters.h:56
Vec2::y
T y
Definition: VectorTypes.h:13
DMGT_MAGICAL
@ DMGT_MAGICAL
Definition: Items.h:16
SPELL_LASER_PROJECTILE
@ SPELL_LASER_PROJECTILE
Definition: Spells.h:123
DAMAGE_TYPE
DAMAGE_TYPE
Definition: Items.h:10
SpriteObject::vPosition
struct Vec3_int_ vPosition
Definition: SpriteObject.h:218
DDM_DLV_Header::field_C_alert
int field_C_alert
Definition: Indoor.h:97
CheckActors_proximity
bool CheckActors_proximity()
Definition: Actor.cpp:4034
MapInfo::Dif_M3
char Dif_M3
Definition: MapInfo.h:63
pParty
Party * pParty
Definition: Party.cpp:30
Image
Definition: Image.h:19
MonsterInfo::uSpecialAbilityType
uint8_t uSpecialAbilityType
Definition: Monsters.h:160
MonsterInfo::uAIType
uint8_t uAIType
Definition: Monsters.h:130
MonsterInfo::uResEarth
uint8_t uResEarth
Definition: Monsters.h:153
Fidgeting
@ Fidgeting
Definition: Actor.h:84
MonsterInfo::uMissleAttack2Type
uint8_t uMissleAttack2Type
Definition: Monsters.h:145
MONSTER_MOVEMENT_TYPE_LONG
@ MONSTER_MOVEMENT_TYPE_LONG
Definition: Monsters.h:62
SPEECH_52
@ SPEECH_52
Definition: Player.h:98
Actor::uCurrentActionTime
unsigned int uCurrentActionTime
Definition: Actor.h:312
ACTOR_BUFF_CHARM
@ ACTOR_BUFF_CHARM
Definition: Actor.h:39
stru141_actor_collision_object::sMinY
int sMinY
Definition: Indoor.h:179
Party::bFlying
unsigned int bFlying
Definition: Party.h:266
MonsterInfo::uResSpirit
uint8_t uResSpirit
Definition: Monsters.h:155
SPRITE_PROJECTILE_510
@ SPRITE_PROJECTILE_510
Definition: SpriteObject.h:14
ACTOR_BUFF_PARALYZED
@ ACTOR_BUFF_PARALYZED
Definition: Actor.h:44
Actor::AI_Pursue2
static void AI_Pursue2(unsigned int uActorID, unsigned int a2, signed int uActionLength, struct AIDirection *pDir, int a5)
Definition: Actor.cpp:2114
MonsterInfo::uSpell1UseChance
uint8_t uSpell1UseChance
Definition: Monsters.h:146
Actor::ResetHostile
void ResetHostile()
Definition: Actor.h:183
SPRITE_PROJECTILE_515
@ SPRITE_PROJECTILE_515
Definition: SpriteObject.h:16
OBJECT_BModel
@ OBJECT_BModel
Definition: Actor.h:70
stru319::vis
Vis * vis
Definition: Actor.h:24
BLVSector::pPortals
uint16_t * pPortals
Definition: Indoor.h:538
ITEM_TROLL_BLOOD
@ ITEM_TROLL_BLOOD
Definition: Items.h:102
x
EGLSurface EGLint x
Definition: SDL_egl.h:1596
GameTime::FromMinutes
static GameTime FromMinutes(int minutes)
Definition: Time.h:86
MonsterInfo::uResPhysical
uint8_t uResPhysical
Definition: Monsters.h:159
AudioPlayer::PlaySpellSound
void PlaySpellSound(unsigned int spell, unsigned int pid)
Definition: AudioPlayer.cpp:476
flt_4E4A80
std::array< float, 10 > flt_4E4A80
Definition: mm7_data.cpp:251
MonsterInfo::uSpellSkillAndMastery1
uint16_t uSpellSkillAndMastery1
Definition: Monsters.h:171
Actor::LootActor
void LootActor()
Definition: Actor.cpp:4064
ABILITY_SPELL2
@ ABILITY_SPELL2
Definition: Actor.h:34
stru141_actor_collision_object::field_7C
int field_7C
Definition: Indoor.h:172
SPRITE_PROJECTILE_520
@ SPRITE_PROJECTILE_520
Definition: SpriteObject.h:18
Actor::SetRandomGoldIfTheresNoItem
void SetRandomGoldIfTheresNoItem()
Definition: Actor.cpp:174
viewparams
struct ViewingParams * viewparams
Definition: mm7_data.cpp:22
ItemsTable::GenerateItem
void GenerateItem(int treasure_level, unsigned int uTreasureType, ItemGen *pItem)
Definition: Items.cpp:680
MapInfo::uEncounterMonster3AtLeast
uint8_t uEncounterMonster3AtLeast
Definition: MapInfo.h:64
Disabled
@ Disabled
Definition: Actor.h:94
MONSTER_MOVEMENT_TYPE_SHORT
@ MONSTER_MOVEMENT_TYPE_SHORT
Definition: Monsters.h:60
MapInfo::Dif_M1
char Dif_M1
Definition: MapInfo.h:57
uchar
unsigned char uchar
Definition: MM7.h:44
stru298::pYs
int16_t pYs[100]
Definition: stru298.h:15
Condition_Dead
@ Condition_Dead
Definition: Conditions.h:22
Actor::uAttributes
unsigned int uAttributes
Definition: Actor.h:289
MonsterInfo::uID
uint16_t uID
Definition: Monsters.h:169
Actor::special_ability_use_check
ABILITY_INDEX special_ability_use_check(int a2)
Definition: Actor.cpp:4237
ACTOR_BUFF_SOMETHING_THAT_HALVES_AC
@ ACTOR_BUFF_SOMETHING_THAT_HALVES_AC
Definition: Actor.h:46
BBox_short_::y2
int16_t y2
Definition: VectorTypes.h:117
BLVFace::uSectorID
uint16_t uSectorID
Definition: Indoor.h:484
BLVFace
Definition: Indoor.h:424
ItemGen::uItemID
int uItemID
Definition: Items.h:326
Engine_::IocContainer::ResolveDecalBuilder
static DecalBuilder * ResolveDecalBuilder()
Definition: IocContainer.cpp:60
MonsterInfo::uExp
unsigned int uExp
Definition: Monsters.h:177
Actor::Resurrect
static void Resurrect(unsigned int uActorID)
Definition: Actor.cpp:1890
SPELL_LIGHT_DISPEL_MAGIC
@ SPELL_LIGHT_DISPEL_MAGIC
Definition: Spells.h:99
ABILITY_SPELL1
@ ABILITY_SPELL1
Definition: Actor.h:33
IsActorAlive
int IsActorAlive(unsigned int uType, unsigned int uParam, unsigned int uNumAlive)
Definition: Actor.cpp:3240
MonsterList::GetMonsterIDByName
int16_t GetMonsterIDByName(const char *pMonsterName)
Definition: Monsters.cpp:1192
DMGT_COLD
@ DMGT_COLD
Definition: Items.h:13
ItemGen::GetPlayerSkillType
unsigned char GetPlayerSkillType()
Definition: Items.cpp:1512
stru298::pIDs
int16_t pIDs[100]
Definition: stru298.h:13
v1
GLfloat GLfloat v1
Definition: SDL_opengl_glext.h:694
SpriteObject::spell_id
int spell_id
Definition: SpriteObject.h:228
Actor::uTetherDistance
uint16_t uTetherDistance
Definition: Actor.h:306
SPELL_BODY_HAMMERHANDS
@ SPELL_BODY_HAMMERHANDS
Definition: Spells.h:91
IndoorLocation::dlv
struct DDM_DLV_Header dlv
Definition: Indoor.h:648
Log::Warning
void Warning(const wchar_t *pFormat,...)
Definition: Log.cpp:28
ACTOR_BUFF_HASTE
@ ACTOR_BUFF_HASTE
Definition: Actor.h:57
SOUND_9armageddon01
@ SOUND_9armageddon01
Definition: AudioPlayer.h:104
Actor::Remove
void Remove()
Definition: Actor.cpp:2504
DMGT_LIGHT
@ DMGT_LIGHT
Definition: Items.h:20
MonsterInfo::bQuestMonster
uint16_t bQuestMonster
Definition: Monsters.h:170
_4DF380_hostilityRanges
std::array< uint, 5 > _4DF380_hostilityRanges
Definition: Actor.cpp:43
Actor::GetDirectionInfo
static void GetDirectionInfo(unsigned int uObj1ID, unsigned int uObj2ID, struct AIDirection *pOut, int a4)
Definition: Actor.cpp:890
fixpoint_mul
__int64 fixpoint_mul(int a1, int a2)
Definition: OurMath.cpp:138
pActors
std::array< Actor, 500 > pActors
Definition: Actor.cpp:38
int32_t
signed __int32 int32_t
Definition: SDL_config.h:38
SpriteFrameTable::pSpriteSFrames
SpriteFrame * pSpriteSFrames
Definition: Sprites.h:77
Actor::uActorRadius
uint16_t uActorRadius
Definition: Actor.h:295
MONSTER_OOZE_3
@ MONSTER_OOZE_3
Definition: Monsters.h:28
ITEM_OOZE_ENDOPLASM_VIAL
@ ITEM_OOZE_ENDOPLASM_VIAL
Definition: Items.h:117
PLAYER_SKILL_MACE
@ PLAYER_SKILL_MACE
Definition: Player.h:177
Party::IsPartyGood
bool IsPartyGood()
Definition: Party.cpp:1141
Actor::MakeActorAIList_ODM
static void MakeActorAIList_ODM()
Definition: Actor.cpp:4457
MapInfo::uEncounterMonster1AtLeast
uint8_t uEncounterMonster1AtLeast
Definition: MapInfo.h:58
window
EGLSurface EGLNativeWindowType * window
Definition: SDL_egl.h:1580
SPELL_EARTH_STUN
@ SPELL_EARTH_STUN
Definition: Spells.h:49
Player::pName
char pName[16]
Definition: Player.h:637
SPELL_AIR_SHIELD
@ SPELL_AIR_SHIELD
Definition: Spells.h:30
Party::uFlags
unsigned int uFlags
Definition: Party.h:313
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
Actor::SearchAliveActors
static unsigned int SearchAliveActors(unsigned int *pTotalActors)
Definition: Actor.cpp:3318
ANIM_Dead
@ ANIM_Dead
Definition: Actor.h:105
MonsterStats::pInfos
MonsterInfo pInfos[265]
Definition: Monsters.h:194
type
EGLenum type
Definition: SDL_egl.h:850
Player::GetSpellSchool
unsigned int GetSpellSchool(unsigned int uSpellID)
Definition: Player.cpp:2198
DDM_DLV_Header::uReputation
int uReputation
Definition: Indoor.h:96
SPELL_BODY_POWER_CURE
@ SPELL_BODY_POWER_CURE
Definition: Spells.h:95
Actor::sNPC_ID
int16_t sNPC_ID
Definition: Actor.h:287
MonsterInfo::uAttack2DamageDiceSides
uint8_t uAttack2DamageDiceSides
Definition: Monsters.h:143
Actor::pSpriteIDs
uint16_t pSpriteIDs[8]
Definition: Actor.h:313
stru_50C198
stru319 stru_50C198
Definition: Actor.cpp:41
MonsterDesc::uMonsterRadius
uint16_t uMonsterRadius
Definition: Monsters.h:215
BLVSector::uNumPortals
int16_t uNumPortals
Definition: Indoor.h:536
LEVEL_Outdoor
@ LEVEL_Outdoor
Definition: Indoor.h:287
DDM_DLV_Header
Definition: Indoor.h:82
Actor::IsNotAlive
bool IsNotAlive()
Definition: Actor.cpp:166
MonsterInfo::uMovementType
uint8_t uMovementType
Definition: Monsters.h:129
ITEM_GOLD_SMALL
@ ITEM_GOLD_SMALL
Definition: Items.h:97
Actor::uSummonerID
unsigned int uSummonerID
Definition: Actor.h:320
Player::GetMaxHealth
int GetMaxHealth()
Definition: Player.cpp:2354
SOUND_Fate
@ SOUND_Fate
Definition: AudioPlayer.h:101
Actor::ResetHasItem
void ResetHasItem()
Definition: Actor.h:182
ABILITY_ATTACK2
@ ABILITY_ATTACK2
Definition: Actor.h:32
MapInfo::uEncounterMonster2AtLeast
uint8_t uEncounterMonster2AtLeast
Definition: MapInfo.h:61
ANIM_AtkMelee
@ ANIM_AtkMelee
Definition: Actor.h:101
MapInfo
Definition: MapInfo.h:35
MonsterInfo::Hostility_Long
@ Hostility_Long
Definition: Monsters.h:115
int64
ll int64
Definition: MM7.h:57
Actor::AddBloodsplatOnDamageOverlay
static void AddBloodsplatOnDamageOverlay(unsigned int uActorID, int a2, int a3)
Definition: Actor.cpp:1257
Actor::_SelectTarget
static void _SelectTarget(unsigned int uActorID, int *a2, bool can_target_party)
Definition: Actor.cpp:2230
AIDirection::uDistance
unsigned int uDistance
Definition: Actor.h:128
ITEM_ENCHANTMENT
ITEM_ENCHANTMENT
Definition: Items.h:38
pCurrentMapName
String pCurrentMapName
Definition: mm7_data.cpp:712
Actor::Arena_summon_actor
static void Arena_summon_actor(int monster_id, int16_t x, int y, int z)
Definition: Actor.cpp:3697
Actor::uSectorID
int16_t uSectorID
Definition: Actor.h:302
Removed
@ Removed
Definition: Actor.h:86
Interacting
@ Interacting
Definition: Actor.h:85
Actor::_4273BB_DoesHitOtherActor
bool _4273BB_DoesHitOtherActor(Actor *defender, int a3, int a4)
Definition: Actor.cpp:4262
pPaletteManager
PaletteManager * pPaletteManager
Definition: PaletteManager.cpp:7
stru141_actor_collision_object::sMaxX
int sMaxX
Definition: Indoor.h:176
stru319::FindClosestActor
int FindClosestActor(int a2, int a3, int a4)
Definition: Actor.cpp:3876
flt_6BE3A8_debug_recmod2
float flt_6BE3A8_debug_recmod2
Definition: mm7_data.cpp:717
AIDirection::uPitchAngle
signed int uPitchAngle
Definition: Actor.h:131
stru141_actor_collision_object::sMinX
int sMinX
Definition: Indoor.h:177
PlayerEquipment::uMainHand
unsigned int uMainHand
Definition: Player.h:320
DMGT_ELECTR
@ DMGT_ELECTR
Definition: Items.h:12
Actor::SearchActorByMonsterID
static unsigned int SearchActorByMonsterID(unsigned int *pTotalActors, int uMonsterID)
Definition: Actor.cpp:3300
Actor::AI_Pursue3
static void AI_Pursue3(unsigned int uActorID, unsigned int a2, signed int uActionLength, struct AIDirection *a4)
Definition: Actor.cpp:2171
BLVFace::uBackSectorID
int16_t uBackSectorID
Definition: Indoor.h:485
game_ui_monster_hp_background
Image * game_ui_monster_hp_background
Definition: UIGame.cpp:64
stru262_TurnBased::AITurnBasedAction
void AITurnBasedAction()
Definition: TurnEngine.cpp:260
DMGT_BODY
@ DMGT_BODY
Definition: Items.h:19
BLVFace::pBounding
struct BBox_short_ pBounding
Definition: Indoor.h:486
pMiscTimer
Timer * pMiscTimer
Definition: Time.cpp:7
stru141_actor_collision_object::sMaxY
int sMaxY
Definition: Indoor.h:178
pSpellStats
struct SpellStats * pSpellStats
Definition: Spells.cpp:32
SpriteFrameTable::InitializeSprite
void InitializeSprite(signed int uSpriteID)
Definition: Sprites.cpp:46
Engine_DeinitializeAndTerminate
void Engine_DeinitializeAndTerminate(int exitCode)
Definition: Engine.cpp:157
Party::GetPartyReputation
int GetPartyReputation()
Definition: Party.cpp:922
OutdoorLocation::ddm
struct DDM_DLV_Header ddm
Definition: Outdoor.h:131
SPRITE_PROJECTILE_505
@ SPRITE_PROJECTILE_505
Definition: SpriteObject.h:12
Actor::ActorDamageFromMonster
static void ActorDamageFromMonster(int attacker_id, unsigned int actor_id, struct Vec3_int_ *pVelocity, int a4)
Definition: Actor.cpp:2507
FactionTable::relations
char relations[89][89]
Definition: FactionTable.h:8
stru319::_427546
int _427546(int a2)
Definition: Actor.cpp:3862
LEVEL_Indoor
@ LEVEL_Indoor
Definition: Indoor.h:286
Plane_int_::dist
int dist
Definition: VectorTypes.h:108
word_4E8152
std::array< int16_t, 11 > word_4E8152
Definition: mm7_data.cpp:303
Party::GivePartyExp
void GivePartyExp(unsigned int pEXPNum)
Definition: Party.cpp:938
SpriteObject::Create
int Create(int yaw, int pitch, int a4, int a5)
Definition: SpriteObject.cpp:56
SpriteObject::containing_item
struct ItemGen containing_item
Definition: SpriteObject.h:227
SPELL_FIRE_FIREBALL
@ SPELL_FIRE_FIREBALL
Definition: Spells.h:18
stru298::Add
void Add(int16_t uID, int16_t a3, int16_t x, int16_t y, int16_t z, char a7, char a8)
Definition: stru298.cpp:4
MonsterDesc
Definition: Monsters.h:213
EQUIP_TWO_HANDED
@ EQUIP_TWO_HANDED
Definition: Items.h:228
SPRITE_OBJECT_TYPE
SPRITE_OBJECT_TYPE
Definition: SpriteObject.h:5
distance
GLsizei GLsizei GLfloat distance
Definition: SDL_opengl_glext.h:9203
AudioPlayer.h
MonsterInfo::uResMind
uint8_t uResMind
Definition: Monsters.h:154
OBJECT_Player
@ OBJECT_Player
Definition: Actor.h:68
Party::bTurnBasedModeOn
bool bTurnBasedModeOn
Definition: Party.h:305
Summoned
@ Summoned
Definition: Actor.h:92
ACTOR_BUFF_HOUR_OF_POWER
@ ACTOR_BUFF_HOUR_OF_POWER
Definition: Actor.h:52
Player::conditions_times
std::array< GameTime, 20 > conditions_times
Definition: Player.h:635
ItemGen::uNumCharges
int uNumCharges
Definition: Items.h:348
MapInfo::Dif_M2
char Dif_M2
Definition: MapInfo.h:60
SPELL_SPIRIT_BLESS
@ SPELL_SPIRIT_BLESS
Definition: Spells.h:62
MonsterStats::BelongsToSupertype
static bool BelongsToSupertype(unsigned int uMonsterInfoID, enum MONSTER_SUPERTYPE eSupertype)
Definition: Monsters.cpp:1200
SpriteObject::uSoundID
unsigned __int16 uSoundID
Definition: SpriteObject.h:221
SpriteFrameTable::FastFindSprite
int FastFindSprite(const char *pSpriteName)
Definition: Sprites.cpp:243
_4D864C_force_sw_render_rules
char _4D864C_force_sw_render_rules
Definition: mm7_data.cpp:208
ITEM_HARPY_FEATHER
@ ITEM_HARPY_FEATHER
Definition: Items.h:107
MapInfo::pEncounterMonster3Texture
String pEncounterMonster3Texture
Definition: MapInfo.h:42
Party::armageddon_timer
int armageddon_timer
Definition: Party.h:320
MonsterList::pMonsters
struct MonsterDesc * pMonsters
Definition: Monsters.h:237
MONSTER_TROLL_1
@ MONSTER_TROLL_1
Definition: Monsters.h:42
PaletteManager::ResetNonTestLocked
int ResetNonTestLocked()
Definition: PaletteManager.cpp:619
Actor::vInitialPosition
struct Vec3_short_ vInitialPosition
Definition: Actor.h:304
Player::GetOffHandItem
ItemGen * GetOffHandItem()
Definition: Player.cpp:7540
MonsterInfo::uAttack1DamageDiceRolls
uint8_t uAttack1DamageDiceRolls
Definition: Monsters.h:136
MonsterStats::FindMonsterByTextureName
signed int FindMonsterByTextureName(const char *Str2)
Definition: Monsters.cpp:440
Actor::ResetAnimation
void ResetAnimation()
Definition: Actor.h:178
SpellFxRenderer
Definition: SpellFxRenderer.h:97
Actor::ActorFriend
bool ActorFriend() const
Definition: Actor.h:188
ACTOR_BUFF_SHIELD
@ ACTOR_BUFF_SHIELD
Definition: Actor.h:53
MONSTER_SUPERTYPE_TREANT
@ MONSTER_SUPERTYPE_TREANT
Definition: Monsters.h:75
Vis::PickClosestActor
unsigned short PickClosestActor(int object_id, unsigned int pick_depth, int a4, int a5, int a6)
Definition: Vis.cpp:403
MonsterInfo::uResAir
uint8_t uResAir
Definition: Monsters.h:151
MONSTER_OOZE_2
@ MONSTER_OOZE_2
Definition: Monsters.h:27
stru193_math::Atan2
unsigned int Atan2(int x, int y)
Definition: OurMath.cpp:46
SpriteFrame::uAnimLength
int uAnimLength
Definition: Sprites.h:53
pOtherOverlayList
struct OtherOverlayList * pOtherOverlayList
Definition: Overlays.cpp:19
SOUND_Stoneskin
@ SOUND_Stoneskin
Definition: AudioPlayer.h:99
SpellBuff::Expired
bool Expired() const
Definition: Spells.h:163
Actor::ActorEnemy
bool ActorEnemy() const
Definition: Actor.h:185
SPELL_AIR_SPARKS
@ SPELL_AIR_SPARKS
Definition: Spells.h:28
SpriteObject::spell_level
int spell_level
Definition: SpriteObject.h:229
Actor::sCurrentHP
int16_t sCurrentHP
Definition: Actor.h:290
game_ui_monster_hp_border_right
Image * game_ui_monster_hp_border_right
Definition: UIGame.cpp:66
Actor::AggroSurroundingPeasants
static void AggroSurroundingPeasants(unsigned int uActorID, int a2)
Definition: Actor.cpp:717
ITEM_NULL
@ ITEM_NULL
Definition: Items.h:74
MonsterInfo::uHP
unsigned int uHP
Definition: Monsters.h:175
stru141_actor_collision_object::prolly_normal_d
int prolly_normal_d
Definition: Indoor.h:152
DamagePlayerFromMonster
void DamagePlayerFromMonster(unsigned int uObjID, int dmgSource, Vec3_int_ *pPos, signed int a4)
Definition: Player.cpp:6928
ACTOR_BUFF_STONED
@ ACTOR_BUFF_STONED
Definition: Actor.h:43
pMonsterList
struct MonsterList * pMonsterList
Definition: Monsters.cpp:9
ANIM_Bored
@ ANIM_Bored
Definition: Actor.h:106
stru319
Definition: Actor.h:13
SpellBuff::Active
bool Active() const
Definition: Spells.h:162
UIStatusBar.h
SpriteObject::spell_target_pid
int spell_target_pid
Definition: SpriteObject.h:233
Actor::Explode
static void Explode(unsigned int uActorID)
Definition: Actor.cpp:850
spell_fx_renderer
static SpellFxRenderer * spell_fx_renderer
Definition: Actor.cpp:36
MONSTER_MOVEMENT_TYPE_STAIONARY
@ MONSTER_MOVEMENT_TYPE_STAIONARY
Definition: Monsters.h:65
SPELL_SPIRIT_FATE
@ SPELL_SPIRIT_FATE
Definition: Spells.h:63
v2
GLfloat GLfloat GLfloat v2
Definition: SDL_opengl_glext.h:695
sub_4070EF_prolly_detect_player
bool sub_4070EF_prolly_detect_player(unsigned int uObjID, unsigned int uObj2ID)
Definition: Actor.cpp:4688
flt_6BE3A4_debug_recmod1
float flt_6BE3A4_debug_recmod1
Definition: mm7_data.cpp:716
Actor::vGuardingPosition
struct Vec3_short_ vGuardingPosition
Definition: Actor.h:305
SPELL_WATER_ACID_BURST
@ SPELL_WATER_ACID_BURST
Definition: Spells.h:43
SPELL_DARK_DRAGON_BREATH
@ SPELL_DARK_DRAGON_BREATH
Definition: Spells.h:117
SPRITE_ARROW_PROJECTILE
@ SPRITE_ARROW_PROJECTILE
Definition: SpriteObject.h:28
ANIM_Walking
@ ANIM_Walking
Definition: Actor.h:100
integer_sqrt
int integer_sqrt(int val)
Definition: OurMath.cpp:164
uint
unsigned int uint
Definition: MM7.h:4
sub_4075DB
bool sub_4075DB(int x, int y, int z, BLVFace *face)
Definition: Indoor.cpp:5424
MonsterInfo::uSpell2ID
uint8_t uSpell2ID
Definition: Monsters.h:149
uActiveCharacter
unsigned int uActiveCharacter
Definition: mm7_data.cpp:555
v3
GLfloat GLfloat GLfloat GLfloat v3
Definition: SDL_opengl_glext.h:696
Localization::FormatString
String FormatString(unsigned int index,...) const
Definition: Localization.cpp:17
Party::IsPartyEvil
bool IsPartyEvil()
Definition: Party.cpp:1139
_449B7E_toggle_bit
void _449B7E_toggle_bit(unsigned char *pArray, __int16 a2, unsigned __int16 bToggle)
Definition: Party.cpp:1190
Fleeing
@ Fleeing
Definition: Actor.h:82
ShouldMonsterPlayAttackAnim
bool ShouldMonsterPlayAttackAnim(signed int spell_id)
Definition: Actor.cpp:47
Actor::AI_Flee
static void AI_Flee(unsigned int uActorID, signed int edx0, int uActionLength, struct AIDirection *a4)
Definition: Actor.cpp:2070
Actor::_43B3E0_CalcDamage
int _43B3E0_CalcDamage(signed int dmgSource)
Definition: Actor.cpp:1314
Actor::AI_MissileAttack2
static void AI_MissileAttack2(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir)
Definition: Actor.cpp:1561
Actor::ResetAggressor
void ResetAggressor()
Definition: Actor.h:184
MapInfo::_steal_perm
int _steal_perm
Definition: MapInfo.h:47
AttackerInfo
stru298 AttackerInfo
Definition: mm7_data.cpp:24
SOUND_94dayofprotection03
@ SOUND_94dayofprotection03
Definition: AudioPlayer.h:103
SpellBuff::uPower
unsigned __int16 uPower
Definition: Spells.h:166
SpriteObject::sub_42F7EB_DropItemAt
static bool sub_42F7EB_DropItemAt(SPRITE_OBJECT_TYPE sprite, int x, int y, int z, int a4, int count, int a7, unsigned __int16 attributes, ItemGen *a9)
Definition: SpriteObject.cpp:937
Actor::GetActorsRelation
signed int GetActorsRelation(Actor *a2)
Definition: Actor.cpp:2319
Actor::MakeActorAIList_BLV
static int MakeActorAIList_BLV()
Definition: Actor.cpp:4556
GameUI_StatusBar_OnEvent
void GameUI_StatusBar_OnEvent(const String &str, unsigned int num_seconds)
Definition: UIStatusBar.cpp:33
stru141_actor_collision_object::direction
Vec3_int_ direction
Definition: Indoor.h:165
SPRITE_OBJECT_EXPLODE
@ SPRITE_OBJECT_EXPLODE
Definition: SpriteObject.h:32
Party::SetHoldingItem
void SetHoldingItem(ItemGen *pItem)
Definition: Party.cpp:150
Player::sHealth
int sHealth
Definition: Player.h:766
Player::PlaySound
void PlaySound(PlayerSpeech speech, int a3)
Definition: Player.cpp:7874
MONSTER_DRAGON_2
@ MONSTER_DRAGON_2
Definition: Monsters.h:11
SpriteObject::spell_skill
int spell_skill
Definition: SpriteObject.h:230
SPELL_EARTH_BLADES
@ SPELL_EARTH_BLADES
Definition: Spells.h:54
SpawnPointMM7::vPosition
Vec3_int_ vPosition
Definition: Indoor.h:314
stru193_math::Cos
int Cos(int angle)
Definition: OurMath.cpp:28
MONSTER_DEVIL_2
@ MONSTER_DEVIL_2
Definition: Monsters.h:8
MonsterDesc::uMovementSpeed
uint16_t uMovementSpeed
Definition: Monsters.h:216
Actor::uAlly
unsigned int uAlly
Definition: Actor.h:318
Condition_Unconcious
@ Condition_Unconcious
Definition: Conditions.h:21
Actor::ActorHasItem
bool ActorHasItem() const
Definition: Actor.h:191
SPELL_BOW_ARROW
@ SPELL_BOW_ARROW
Definition: Spells.h:121
stru_5C6E00
struct stru193_math * stru_5C6E00
Definition: mm7_data.cpp:19
MONSTER_HARPY_1
@ MONSTER_HARPY_1
Definition: Monsters.h:21
ViewingParams::bRedrawGameUI
int bRedrawGameUI
Definition: Viewport.h:74
IndoorLocation::pVertices
struct Vec3_short_ * pVertices
Definition: Indoor.h:628
Actor::GiveItem
static void GiveItem(signed int uActorID, unsigned int uItemID, unsigned int bGive)
Definition: Actor.cpp:134
MonsterInfo::field_33
char field_33
Definition: Monsters.h:168
ACTOR_BUFF_SUMMONED
@ ACTOR_BUFF_SUMMONED
Definition: Actor.h:40
SoundID
SoundID
Definition: AudioPlayer.h:10
MonsterInfo::uTreasureDiceSides
uint8_t uTreasureDiceSides
Definition: Monsters.h:125
ANIM_AtkRanged
@ ANIM_AtkRanged
Definition: Actor.h:102
Actor::SearchActorByID
static unsigned int SearchActorByID(unsigned int *pTotalActors, unsigned int a2)
Definition: Actor.cpp:3268
Actor::uCurrentActionLength
uint16_t uCurrentActionLength
Definition: Actor.h:303
Actor::uMovementSpeed
uint16_t uMovementSpeed
Definition: Actor.h:297
AIState
AIState
Definition: Actor.h:74
uCurrentlyLoadedLevelType
LEVEL_TYPE uCurrentlyLoadedLevelType
Definition: Indoor.cpp:52
MonsterInfo::pName
char * pName
Definition: Monsters.h:120
stru_721530
stru141_actor_collision_object stru_721530
Definition: Indoor.cpp:58
Actor::pActorName
char pActorName[32]
Definition: Actor.h:286
ACTOR_BUFF_STONESKIN
@ ACTOR_BUFF_STONESKIN
Definition: Actor.h:54
IndoorLocation::GetSector
int GetSector(int sX, int sY, int sZ)
Definition: Indoor.cpp:1279
IndoorLocation::pFaces
struct BLVFace * pFaces
Definition: Indoor.h:630
SOUND_51heroism03
@ SOUND_51heroism03
Definition: AudioPlayer.h:102
ACTOR_BUFF_BLESS
@ ACTOR_BUFF_BLESS
Definition: Actor.h:55
MonsterInfo::uSpellSkillAndMastery2
uint16_t uSpellSkillAndMastery2
Definition: Monsters.h:172
stru298::pXs
int16_t pXs[100]
Definition: stru298.h:14
MONSTER_DRAGON_1
@ MONSTER_DRAGON_1
Definition: Monsters.h:10
ITEM_ENCHANTMENT_OF_FORCE
@ ITEM_ENCHANTMENT_OF_FORCE
Definition: Items.h:56
ObjectList::pObjects
struct ObjectDesc * pObjects
Definition: ObjectList.h:54
stru193_math::Sin
int Sin(int angle)
Definition: OurMath.cpp:133
SPELL_AIR_LIGHNING_BOLT
@ SPELL_AIR_LIGHNING_BOLT
Definition: Spells.h:31
BBox_short_::x2
int16_t x2
Definition: VectorTypes.h:115
pAudioPlayer
AudioPlayer * pAudioPlayer
Definition: AudioPlayer.cpp:20
Actor::uYawAngle
uint16_t uYawAngle
Definition: Actor.h:300
SpawnEncounter
void SpawnEncounter(MapInfo *pMapInfo, SpawnPointMM7 *spawn, int a3, int a4, int a5)
Definition: Actor.cpp:5063
Player::GetActualSkillLevel
int GetActualSkillLevel(PLAYER_SKILL_TYPE uSkillType)
Definition: Player.cpp:3017
Condition_Eradicated
@ Condition_Eradicated
Definition: Conditions.h:24
DMGT_EARTH
@ DMGT_EARTH
Definition: Items.h:14
Player::HasItemEquipped
bool HasItemEquipped(ITEM_EQUIP_TYPE uEquipIndex)
Definition: Player.cpp:1583
stru298::pZs
int16_t pZs[100]
Definition: stru298.h:16
GUIWindow.h
ItemGen
Definition: Items.h:263
Actor::GetObjDescId
static unsigned short GetObjDescId(int spellId)
Definition: Actor.cpp:696
Actor::AI_Bored
static void AI_Bored(unsigned int uActorID, unsigned int uObjID, struct AIDirection *a4)
Definition: Actor.cpp:1853
ObjectList.h
SPRITE_PROJECTILE_540
@ SPRITE_PROJECTILE_540
Definition: SpriteObject.h:26
logger
Log * logger
Definition: IocContainer.cpp:47
CastSpellInfoHelpers::Cancel_Spell_Cast_In_Progress
void Cancel_Spell_Cast_In_Progress()
Definition: CastSpellInfo.cpp:4350
PlayerSpeech
PlayerSpeech
Definition: Player.h:46
Actor::PrepareSprites
void PrepareSprites(char load_sounds_if_bit1_set)
Definition: Actor.cpp:2481
SOUND_Sacrifice2
@ SOUND_Sacrifice2
Definition: AudioPlayer.h:105
SpawnPointMM7::uGroup
unsigned int uGroup
Definition: Indoor.h:319
PLAYER_BUFF_HAMMERHANDS
@ PLAYER_BUFF_HAMMERHANDS
Definition: Player.h:20
SPELL_DARK_TOXIC_CLOUD
@ SPELL_DARK_TOXIC_CLOUD
Definition: Spells.h:110
MonsterList::uNumMonsters
signed int uNumMonsters
Definition: Monsters.h:236
ACTOR_BUFF_PAIN_HAMMERHANDS
@ ACTOR_BUFF_PAIN_HAMMERHANDS
Definition: Actor.h:59
Condition_Pertified
@ Condition_Pertified
Definition: Conditions.h:23
Engine_::IocContainer::ResolveSpellFxRenderer
static SpellFxRenderer * ResolveSpellFxRenderer()
Definition: IocContainer.cpp:74
pOutdoor
OutdoorLocation * pOutdoor
Definition: Outdoor.cpp:48
MonsterInfo::uAttack2DamageDiceRolls
uint8_t uAttack2DamageDiceRolls
Definition: Monsters.h:142
SpellBuff::Apply
bool Apply(GameTime time, unsigned __int16 uSkillLevel, unsigned __int16 uPower, int uOverlayID, unsigned __int8 caster)
Definition: Spells.cpp:363
SPRITE_PROJECTILE_550
@ SPRITE_PROJECTILE_550
Definition: SpriteObject.h:29
ACTOR_BUFF_BERSERK
@ ACTOR_BUFF_BERSERK
Definition: Actor.h:47
MonsterInfo::uResWater
uint8_t uResWater
Definition: Monsters.h:152
SpawnPointMM7::uIndex
uint16_t uIndex
Definition: Indoor.h:317
SpriteObject::uAttributes
unsigned __int16 uAttributes
Definition: SpriteObject.h:222
BBox_short_::z1
int16_t z1
Definition: VectorTypes.h:118
game_ui_monster_hp_red
Image * game_ui_monster_hp_red
Definition: UIGame.cpp:63
Actor::uCurrentActionAnimation
uint16_t uCurrentActionAnimation
Definition: Actor.h:308
Actor::DamageMonsterFromParty
static void DamageMonsterFromParty(int a1, unsigned int uActorID_Monster, struct Vec3_int_ *pVelocity)
Definition: Actor.cpp:3379
pIndoorCameraD3D
IndoorCameraD3D * pIndoorCameraD3D
Definition: IndoorCameraD3D.cpp:21
MonsterInfo::uTreasureLevel
uint8_t uTreasureLevel
Definition: Monsters.h:126
Actor::pMonsterInfo
struct MonsterInfo pMonsterInfo
Definition: Actor.h:292
ai_near_actors_ids
std::array< unsigned int, 500 > ai_near_actors_ids
Definition: mm7_data.cpp:505
Actor::ActorNearby
bool ActorNearby() const
Definition: Actor.h:194
LODFile_Sprites::DeleteSomeSprites
void DeleteSomeSprites()
Definition: LOD.cpp:299
stru262_TurnBased::pending_actions
int pending_actions
Definition: TurnEngine.h:81
game_ui_monster_hp_border_left
Image * game_ui_monster_hp_border_left
Definition: UIGame.cpp:65
SPELL_FIRE_HASTE
@ SPELL_FIRE_HASTE
Definition: Spells.h:17
Player::pEquipment
PlayerEquipment pEquipment
Definition: Player.h:769
MonsterInfo
Definition: Monsters.h:109
MONSTER_DRAGON_3
@ MONSTER_DRAGON_3
Definition: Monsters.h:12
SpellFxRenderer::_4A7E89_sparkles_on_actor_after_it_casts_buff
void _4A7E89_sparkles_on_actor_after_it_casts_buff(struct Actor *pActor, unsigned int uDiffuse)
Definition: SpellFxRenderer.cpp:576
BLV_GetFloorLevel
int BLV_GetFloorLevel(int x, int y, int z, unsigned int uSectorID, unsigned int *pFaceID)
Definition: Indoor.cpp:2530
Party::sRotationY
int sRotationY
Definition: Party.h:251
Actor::word_000086_some_monster_id
int16_t word_000086_some_monster_id
Definition: Actor.h:294
MonsterInfo::uFlying
uint8_t uFlying
Definition: Monsters.h:128
stru193_math::uIntegerPi
static const unsigned int uIntegerPi
Definition: OurMath.h:88
String
std::string String
Definition: Strings.h:10
ITEM_DEVIL_ICHOR
@ ITEM_DEVIL_ICHOR
Definition: Items.h:114
AIDirection::vDirection
Vec3_int_ vDirection
Definition: Actor.h:127
Pursuing
@ Pursuing
Definition: Actor.h:81
Actor::AI_SpellAttack1
static void AI_SpellAttack1(unsigned int uActorID, signed int sTargetPid, struct AIDirection *pDir)
Definition: Actor.cpp:1486
GameTime
Definition: Time.h:14
Actor::DrawHealthBar
static void DrawHealthBar(Actor *actor, GUIWindow *window)
Definition: Actor.cpp:67
Actor::_427102_IsOkToCastSpell
bool _427102_IsOkToCastSpell(enum SPELL_TYPE spell)
Definition: Actor.cpp:4192
Party::monster_for_hunting_killed
std::array< __int16, 5 > monster_for_hunting_killed
Definition: Party.h:289
Player::pPlayerBuffs
std::array< SpellBuff, 24 > pPlayerBuffs
Definition: Player.h:756
MonsterInfo::uRecoveryTime
signed int uRecoveryTime
Definition: Monsters.h:179
SPELL_FIRE_INCINERATE
@ SPELL_FIRE_INCINERATE
Definition: Spells.h:23
Stunned
@ Stunned
Definition: Actor.h:83
Actor::InitializeActors
static void InitializeActors()
Definition: Actor.cpp:3334
MonsterInfo::uLevel
uint8_t uLevel
Definition: Monsters.h:122
Party::SetRedAlert
void SetRedAlert()
Definition: Party.h:224
pObjectList
struct ObjectList * pObjectList
Definition: ObjectList.cpp:5
MapInfo::pEncounterMonster2Texture
String pEncounterMonster2Texture
Definition: MapInfo.h:41
SPELL_SPIRIT_HEROISM
@ SPELL_SPIRIT_HEROISM
Definition: Spells.h:67
Party::Invisible
bool Invisible()
Definition: Party.h:217
Party::monster_id_for_hunting
std::array< __int16, 5 > monster_id_for_hunting
Definition: Party.h:288
GameTime::FromSeconds
static GameTime FromSeconds(int seconds)
Definition: Time.h:83
ItemsTable::pItems
NZIArray< ItemDesc, 800 > pItems
Definition: Items.h:460
DMGT_MIND
@ DMGT_MIND
Definition: Items.h:18
MonsterDesc::uMonsterHeight
uint16_t uMonsterHeight
Definition: Monsters.h:214
SOUND_Haste
@ SOUND_Haste
Definition: AudioPlayer.h:96
SpriteObject::spell_caster_pid
int spell_caster_pid
Definition: SpriteObject.h:232
Party::armageddonDamage
int armageddonDamage
Definition: Party.h:321
DecalBuilder
Definition: DecalBuilder.h:123
Actor::SummonMinion
void SummonMinion(int summonerId)
Definition: Actor.cpp:2606
stru141_actor_collision_object::pid
unsigned int pid
Definition: Indoor.h:171
AttackingRanged3
@ AttackingRanged3
Definition: Actor.h:88
_43AFE3_calc_spell_damage
int _43AFE3_calc_spell_damage(int spellId, int spellLevel, signed int skillMastery, int currentHp)
Definition: Spells.cpp:745
Time.h
ACTOR_BUFF_ENSLAVED
@ ACTOR_BUFF_ENSLAVED
Definition: Actor.h:50
stru141_actor_collision_object::sMinZ
int sMinZ
Definition: Indoor.h:181
Actor::pActorBuffs
struct SpellBuff pActorBuffs[22]
Definition: Actor.h:315
render
std::shared_ptr< IRender > render
Definition: RenderOpenGL.cpp:52