devilutionX/Source/monster.cpp
Ogodei 69f6b90dd3 Update monster.cpp
In the monster data tables, the "mType" comment has been renamed as
Seeding size. The game, as depicted by Jarulf, uses that number to
calculate how many monster type can spawn within a level (iirc the max
seeding is 4000, and each monster type takes a part of it).  I hope this
helps!
2018-12-13 20:28:27 +01:00

7085 lines
267 KiB
C++

//HEADER_GOES_HERE
#include "../types.h"
// Tracks which missile files are already loaded
int MissileFileFlag;
int monster_cpp_init_value; // weak
int monstkills[MAXMONSTERS];
int monstactive[MAXMONSTERS];
int nummonsters;
int sgbSaveSoundOn; // weak
MonsterStruct monster[MAXMONSTERS];
int totalmonsters; // weak
CMonster Monsters[16];
// int END_Monsters_17; // weak
int monstimgtot; // weak
int uniquetrans;
int nummtypes;
const int monster_inf = 0x7F800000; // weak
const char plr2monst[9] = { 0, 5, 3, 7, 1, 4, 6, 0, 2 };
const unsigned char counsmiss[4] = { MIS_FIREBOLT, MIS_CBOLT, MIS_LIGHTCTRL, MIS_FIREBALL };
/* data */
MonsterData monsterdata[112] = {
// clang-format off
// width, mImage, GraphicType, has_special, sndfile, snd_special, has_trans, TransFile, Frames[6], Rate[6], mName, mMinDLvl, mMaxDLvl, mLevel, mMinHP, mMaxHP, mAi, mFlags, mInt, mHit, mAFNum, mMinDamage, mMaxDamage, mHit2, mAFNum2, mMinDamage2, mMaxDamage2, mArmorClass, mMonstClass, mMagicRes , mMagicRes2 , mTreasure, mSelFlag, mExp
{ 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, FALSE, NULL, { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Zombie", 1, 3, 1, 4, 7, AI_ZOMBIE, 0 , 0, 10, 8, 2, 5, 0, 0, 0, 0, 5, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 54 },
{ 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "Monsters\\Zombie\\Bluered.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Ghoul", 2, 4, 2, 7, 11, AI_ZOMBIE, 0 , 1, 10, 8, 3, 10, 0, 0, 0, 0, 10, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 58 },
{ 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "Monsters\\Zombie\\Grey.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Rotting Carcass", 2, 6, 4, 15, 25, AI_ZOMBIE, 0 , 2, 25, 8, 5, 15, 0, 0, 0, 0, 15, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 3, 136 },
{ 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "Monsters\\Zombie\\Yellow.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Black Death", 4, 8, 6, 25, 40, AI_ZOMBIE, 0 , 3, 30, 8, 6, 22, 0, 0, 0, 0, 20, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 240 },
{ 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSpear\\FallenT.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Fallen One", 1, 3, 1, 1, 4, AI_FALLEN, 0 , 0, 15, 7, 1, 3, 0, 5, 0, 0, 0, MC_ANIMAL, 0 , 0 , 0, 3, 46 },
{ 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSpear\\Dark.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Carver", 2, 5, 3, 4, 8, AI_FALLEN, 0 , 2, 20, 7, 2, 5, 0, 5, 0, 0, 5, MC_ANIMAL, 0 , 0 , 0, 3, 80 },
{ 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, FALSE, NULL, { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Devil Kin", 3, 7, 5, 12, 24, AI_FALLEN, 0 , 2, 25, 7, 3, 7, 0, 5, 0, 0, 10, MC_ANIMAL, 0 , RESIST_FIRE , 0, 3, 155 },
{ 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSpear\\Blue.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Dark One", 5, 9, 7, 20, 36, AI_FALLEN, 0 , 3, 30, 7, 4, 8, 0, 5, 0, 0, 15, MC_ANIMAL, IMUNE_NULL_40, RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 255 },
{ 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "Monsters\\SkelAxe\\White.TRN", { 12, 8, 13, 6, 17, 16 }, { 5, 0, 0, 0, 0, 0 }, "Skeleton", 1, 3, 1, 2, 4, AI_SKELSD, 0 , 0, 20, 8, 1, 4, 0, 0, 0, 0, 0, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 64 },
{ 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "Monsters\\SkelAxe\\Skelt.TRN", { 12, 8, 13, 6, 17, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Axe", 2, 5, 2, 4, 7, AI_SKELSD, 0 , 1, 25, 8, 3, 5, 0, 0, 0, 0, 0, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 68 },
{ 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 13, 6, 17, 16 }, { 2, 0, 0, 0, 0, 0 }, "Burning Dead", 2, 6, 4, 8, 12, AI_SKELSD, 0 , 2, 30, 8, 3, 7, 0, 0, 0, 0, 5, MC_UNDEAD, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 3, 154 },
{ 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "Monsters\\SkelAxe\\Black.TRN", { 12, 8, 13, 6, 17, 16 }, { 3, 0, 0, 0, 0, 0 }, "Horror", 4, 8, 6, 12, 20, AI_SKELSD, 0 , 3, 35, 8, 4, 9, 0, 0, 0, 0, 15, MC_UNDEAD, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 264 },
{ 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSword\\FallenT.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Fallen One", 1, 3, 1, 2, 5, AI_FALLEN, 0 , 0, 15, 8, 1, 4, 0, 5, 0, 0, 10, MC_ANIMAL, 0 , 0 , 0, 3, 52 },
{ 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSword\\Dark.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Carver", 2, 5, 3, 5, 9, AI_FALLEN, 0 , 1, 20, 8, 2, 7, 0, 5, 0, 0, 15, MC_ANIMAL, 0 , 0 , 0, 3, 90 },
{ 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, FALSE, NULL, { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Devil Kin", 3, 7, 5, 16, 24, AI_FALLEN, 0 , 2, 25, 8, 4, 10, 0, 5, 0, 0, 20, MC_ANIMAL, 0 , RESIST_FIRE , 0, 3, 180 },
{ 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "Monsters\\FalSword\\Blue.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Dark One", 5, 9, 7, 24, 36, AI_FALLEN, 0 , 3, 30, 8, 4, 12, 0, 5, 0, 0, 25, MC_ANIMAL, IMUNE_NULL_40, RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 280 },
{ 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Scavenger", 1, 4, 2, 3, 6, AI_SCAV, 0 , 0, 20, 7, 1, 5, 0, 0, 0, 0, 10, MC_ANIMAL, 0 , RESIST_FIRE , 0, 3, 80 },
{ 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "Monsters\\Scav\\ScavBr.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Plague Eater", 3, 6, 4, 12, 24, AI_SCAV, 0 , 1, 30, 7, 1, 8, 0, 0, 0, 0, 20, MC_ANIMAL, 0 , RESIST_LIGHTNING , 0, 3, 188 },
{ 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "Monsters\\Scav\\ScavBe.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Shadow Beast", 4, 8, 6, 24, 36, AI_SCAV, 0 , 2, 35, 7, 3, 12, 0, 0, 0, 0, 25, MC_ANIMAL, IMUNE_NULL_40, RESIST_FIRE | IMUNE_NULL_40, 0, 3, 375 },
{ 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "Monsters\\Scav\\ScavW.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Bone Gasher", 6, 10, 8, 28, 40, AI_SCAV, 0 , 3, 35, 7, 5, 15, 0, 0, 0, 0, 30, MC_ANIMAL, RESIST_MAGIC | IMUNE_NULL_40, RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 552 },
{ 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "Monsters\\SkelBow\\White.TRN", { 9, 8, 16, 5, 16, 16 }, { 4, 0, 0, 0, 0, 0 }, "Skeleton", 2, 5, 3, 2, 4, AI_SKELBOW, 0 , 0, 15, 12, 1, 2, 0, 0, 0, 0, 0, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 110 },
{ 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "Monsters\\SkelBow\\Skelt.TRN", { 9, 8, 16, 5, 16, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Bow", 3, 7, 5, 8, 16, AI_SKELBOW, 0 , 1, 25, 12, 1, 4, 0, 0, 0, 0, 0, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 210 },
{ 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, FALSE, NULL, { 9, 8, 16, 5, 16, 16 }, { 2, 0, 0, 0, 0, 0 }, "Burning Dead", 5, 9, 7, 10, 24, AI_SKELBOW, 0 , 2, 30, 12, 1, 6, 0, 0, 0, 0, 5, MC_UNDEAD, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 3, 364 },
{ 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "Monsters\\SkelBow\\Black.TRN", { 9, 8, 16, 5, 16, 16 }, { 3, 0, 0, 0, 0, 0 }, "Horror", 7, 11, 9, 15, 45, AI_SKELBOW, 0 , 3, 35, 12, 2, 9, 0, 0, 0, 0, 15, MC_UNDEAD, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 594 },
{ 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", TRUE, TRUE, "Monsters\\SkelSd\\White.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Skeleton Captain", 1, 4, 2, 3, 6, AI_SKELSD, 0 , 0, 20, 8, 2, 7, 0, 0, 0, 0, 10, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 90 },
{ 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, TRUE, "Monsters\\SkelSd\\Skelt.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Captain", 2, 6, 4, 12, 20, AI_SKELSD, 0 , 1, 30, 8, 3, 9, 0, 0, 0, 0, 5, MC_UNDEAD, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 200 },
{ 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, FALSE, NULL, { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Burning Dead Captain", 4, 8, 6, 16, 30, AI_SKELSD, 0 , 2, 35, 8, 4, 10, 0, 0, 0, 0, 15, MC_UNDEAD, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 3, 393 },
{ 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, TRUE, "Monsters\\SkelSd\\Black.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Horror Captain", 6, 10, 8, 35, 50, AI_SKELSD, MFLAG_SEARCH , 3, 40, 8, 5, 14, 0, 0, 0, 0, 30, MC_UNDEAD, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 604 },
{ 128, 2000, "Monsters\\TSneak\\TSneak%c.CL2", FALSE, "Monsters\\TSneak\\Sneakl%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 15, 11, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Invisible Lord", 14, 14, 14, 278, 278, AI_SKELSD, MFLAG_SEARCH , 3, 65, 8, 16, 30, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 2000 },
{ 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, FALSE, NULL, { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Hidden", 3, 8, 5, 8, 24, AI_SNEAK, MFLAG_HIDDEN , 0, 35, 8, 3, 6, 0, 0, 0, 0, 25, MC_DEMON, 0 , IMUNE_NULL_40, 0, 3, 278 },
{ 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "Monsters\\Sneak\\Sneakv2.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Stalker", 8, 12, 9, 30, 45, AI_SNEAK, MFLAG_HIDDEN | MFLAG_SEARCH , 1, 40, 8, 8, 16, 0, 0, 0, 0, 30, MC_DEMON, 0 , IMUNE_NULL_40, 0, 3, 630 },
{ 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "Monsters\\Sneak\\Sneakv3.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Unseen", 10, 14, 11, 35, 50, AI_SNEAK, MFLAG_HIDDEN | MFLAG_SEARCH , 2, 45, 8, 12, 20, 0, 0, 0, 0, 30, MC_DEMON, RESIST_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 935 },
{ 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "Monsters\\Sneak\\Sneakv1.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Illusion Weaver", 14, 18, 13, 40, 60, AI_SNEAK, MFLAG_HIDDEN | MFLAG_SEARCH , 3, 60, 8, 16, 24, 0, 0, 0, 0, 30, MC_DEMON, RESIST_MAGIC | RESIST_FIRE , IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 3, 1500 },
{ 160, 2000, "Monsters\\GoatLord\\GoatL%c.CL2", FALSE, "Monsters\\GoatLord\\Goatl%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 14, 9, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Lord Sayter", 13, 13, 12, 351, 351, AI_SKELSD, MFLAG_SEARCH , 3, 80, 8, 14, 24, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 3, 1500 },
{ 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Flesh Clan", 6, 10, 8, 30, 45, AI_GOATMC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 50, 8, 4, 10, 0, 0, 0, 0, 40, MC_DEMON, 0 , 0 , 0, 3, 460 },
{ 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "Monsters\\GoatMace\\Beige.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Stone Clan", 8, 12, 10, 40, 55, AI_GOATMC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 60, 8, 6, 12, 0, 0, 0, 0, 40, MC_DEMON, RESIST_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 685 },
{ 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "Monsters\\GoatMace\\Red.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Fire Clan", 10, 14, 12, 50, 65, AI_GOATMC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 70, 8, 8, 16, 0, 0, 0, 0, 45, MC_DEMON, RESIST_FIRE , IMUNE_FIRE , 0, 3, 906 },
{ 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "Monsters\\GoatMace\\Gray.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Night Clan", 12, 16, 14, 55, 70, AI_GOATMC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 80, 8, 10, 20, 15, 0, 30, 30, 50, MC_DEMON, RESIST_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 1190 },
{ 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "Monsters\\Bat\\red.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Fiend", 2, 5, 3, 3, 6, AI_BAT, 0 , 0, 35, 5, 1, 6, 0, 0, 0, 0, 0, MC_ANIMAL, 0 , 0 , 0x4000, 6, 102 },
{ 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, FALSE, NULL, { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Blink", 5, 9, 7, 12, 28, AI_BAT, 0 , 1, 45, 5, 1, 8, 0, 0, 0, 0, 15, MC_ANIMAL, 0 , 0 , 0x4000, 6, 340 },
{ 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "Monsters\\Bat\\grey.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Gloom", 7, 11, 9, 28, 36, AI_BAT, MFLAG_SEARCH , 2, 70, 5, 4, 12, 0, 0, 0, 0, 35, MC_ANIMAL, RESIST_MAGIC , RESIST_MAGIC | IMUNE_NULL_40, 0x4000, 6, 509 },
{ 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "Monsters\\Bat\\orange.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Familiar", 11, 15, 13, 20, 35, AI_BAT, MFLAG_SEARCH , 3, 50, 5, 4, 16, 0, 0, 0, 0, 35, MC_DEMON, RESIST_MAGIC | IMUNE_LIGHTNING , RESIST_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0x4000, 6, 448 },
{ 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Flesh Clan", 6, 10, 8, 20, 35, AI_GOATBOW, MFLAG_CAN_OPEN_DOOR, 0, 35, 13, 1, 7, 0, 0, 0, 0, 35, MC_DEMON, 0 , 0 , 0, 3, 448 },
{ 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "Monsters\\GoatBow\\Beige.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Stone Clan", 8, 12, 10, 30, 40, AI_GOATBOW, MFLAG_CAN_OPEN_DOOR, 1, 40, 13, 2, 9, 0, 0, 0, 0, 35, MC_DEMON, RESIST_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 645 },
{ 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "Monsters\\GoatBow\\Red.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Fire Clan", 10, 14, 12, 40, 50, AI_GOATBOW, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 45, 13, 3, 11, 0, 0, 0, 0, 35, MC_DEMON, RESIST_FIRE , IMUNE_FIRE , 0, 3, 822 },
{ 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "Monsters\\GoatBow\\Gray.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Night Clan", 12, 16, 14, 50, 65, AI_GOATBOW, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 50, 13, 4, 13, 15, 0, 0, 0, 40, MC_DEMON, RESIST_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 3, 1092 },
{ 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, FALSE, NULL, { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Acid Beast", 10, 14, 11, 40, 66, AI_ACID, 0 , 0, 40, 8, 4, 12, 25, 8, 0, 0, 30, MC_ANIMAL, IMUNE_ACID , IMUNE_MAGIC | IMUNE_ACID , 0, 3, 846 },
{ 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "Monsters\\Acid\\AcidBlk.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Poison Spitter", 14, 18, 15, 60, 85, AI_ACID, 0 , 1, 45, 8, 4, 16, 25, 8, 0, 0, 30, MC_ANIMAL, IMUNE_ACID , IMUNE_MAGIC | IMUNE_ACID , 0, 3, 1248 },
{ 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "Monsters\\Acid\\AcidB.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Pit Beast", 18, 22, 21, 80, 110, AI_ACID, 0 , 2, 55, 8, 8, 18, 35, 8, 0, 0, 35, MC_ANIMAL, RESIST_MAGIC | IMUNE_ACID , IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_ACID , 0, 3, 2060 },
{ 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "Monsters\\Acid\\AcidR.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Lava Maw", 22, 27, 25, 100, 150, AI_ACID, 0 , 3, 65, 8, 10, 20, 40, 8, 0, 0, 35, MC_ANIMAL, RESIST_MAGIC | IMUNE_FIRE | IMUNE_ACID , IMUNE_MAGIC | IMUNE_FIRE | IMUNE_ACID , 0, 3, 2940 },
{ 160, 1010, "Monsters\\SKing\\SKing%c.CL2", TRUE, "Monsters\\SKing\\SKing%c%i.WAV", TRUE, TRUE, "Monsters\\SkelAxe\\White.TRN", { 8, 6, 16, 6, 16, 6 }, { 2, 0, 0, 0, 0, 2 }, "Skeleton King", 6, 6, 9, 140, 140, AI_SKELKING, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 60, 8, 6, 16, 0, 0, 0, 0, 70, MC_UNDEAD, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0x8001, 7, 570 },
{ 128, 980, "Monsters\\FatC\\FatC%c.CL2", FALSE, "Monsters\\FatC\\FatC%c%i.WAV", FALSE, FALSE, NULL, { 10, 8, 12, 6, 16, 0 }, { 1, 0, 0, 0, 0, 0 }, "The Butcher", 0, 0, 1, 320, 320, AI_CLEAVER, 0 , 3, 50, 8, 6, 12, 0, 0, 0, 0, 50, MC_DEMON, RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING , 0x8000, 3, 710 },
{ 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, NULL, { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Overlord", 8, 12, 10, 60, 80, AI_FAT, 0 , 0, 55, 8, 6, 12, 0, 0, 0, 0, 55, MC_DEMON, 0 , RESIST_FIRE , 0, 3, 635 },
{ 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "Monsters\\Fat\\Blue.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Mud Man", 13, 17, 14, 100, 125, AI_FAT, MFLAG_SEARCH , 1, 60, 8, 8, 16, 0, 0, 0, 0, 60, MC_DEMON, 0 , IMUNE_LIGHTNING , 0, 3, 1165 },
{ 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "Monsters\\Fat\\FatB.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Toad Demon", 15, 19, 16, 135, 160, AI_FAT, MFLAG_SEARCH , 2, 70, 8, 8, 16, 40, 0, 8, 20, 65, MC_DEMON, IMUNE_MAGIC , IMUNE_MAGIC | RESIST_LIGHTNING , 0, 3, 1380 },
{ 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "Monsters\\Fat\\FatF.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Flayed One", 19, 23, 20, 160, 200, AI_FAT, MFLAG_SEARCH , 3, 85, 8, 10, 20, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 3, 2058 },
{ 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Wyrm", 9, 13, 11, 60, 90, AI_SKELSD, 0 , 0, 40, 8, 4, 10, 0, 0, 0, 0, 25, MC_ANIMAL, RESIST_MAGIC , RESIST_MAGIC , 0, 3, 660 },
{ 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Cave Slug", 11, 15, 13, 75, 110, AI_SKELSD, 0 , 1, 50, 8, 6, 13, 0, 0, 0, 0, 30, MC_ANIMAL, RESIST_MAGIC , RESIST_MAGIC , 0, 3, 994 },
{ 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Devil Wyrm", 13, 17, 15, 100, 140, AI_SKELSD, 0 , 2, 55, 8, 8, 16, 0, 0, 0, 0, 30, MC_ANIMAL, RESIST_MAGIC | RESIST_FIRE , RESIST_MAGIC | RESIST_FIRE , 0, 3, 1320 },
{ 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Devourer", 15, 19, 17, 125, 200, AI_SKELSD, 0 , 3, 60, 8, 10, 20, 0, 0, 0, 0, 35, MC_ANIMAL, RESIST_MAGIC | RESIST_FIRE | IMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 3, 1827 },
{ 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, FALSE, NULL, { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Magma Demon", 14, 17, 13, 50, 70, AI_MAGMA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 45, 4, 2, 10, 50, 13, 0, 0, 45, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 1076 },
{ 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "Monsters\\Magma\\Yellow.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Blood Stone", 15, 19, 14, 55, 75, AI_MAGMA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 50, 4, 2, 12, 50, 14, 0, 0, 45, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 1309 },
{ 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "Monsters\\Magma\\Blue.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Hell Stone", 16, 20, 16, 60, 80, AI_MAGMA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 60, 4, 2, 20, 60, 14, 0, 0, 50, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 1680 },
{ 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "Monsters\\Magma\\Wierd.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Lava Lord", 17, 21, 18, 70, 85, AI_MAGMA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 75, 4, 4, 24, 60, 14, 0, 0, 60, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 2124 },
{ 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, FALSE, NULL, { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Horned Demon", 12, 16, 13, 40, 80, AI_RHINO, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 60, 7, 2, 16, 100, 0, 5, 32, 40, MC_ANIMAL, 0 , RESIST_FIRE , 0, 7, 1172 },
{ 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "Monsters\\Rhino\\Orange.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Mud Runner", 14, 18, 15, 50, 90, AI_RHINO, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 70, 7, 6, 18, 100, 0, 12, 36, 45, MC_ANIMAL, 0 , RESIST_FIRE , 0, 7, 1404 },
{ 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "Monsters\\Rhino\\Blue.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Frost Charger", 16, 20, 17, 60, 100, AI_RHINO, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 80, 7, 8, 20, 100, 0, 20, 40, 50, MC_ANIMAL, IMUNE_MAGIC | RESIST_LIGHTNING , IMUNE_MAGIC | RESIST_LIGHTNING , 0, 7, 1720 },
{ 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "Monsters\\Rhino\\RhinoB.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Obsidian Lord", 18, 22, 19, 70, 110, AI_RHINO, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 90, 7, 10, 22, 100, 0, 20, 50, 55, MC_ANIMAL, IMUNE_MAGIC | RESIST_LIGHTNING , IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING , 0, 7, 1809 },
{ 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, FALSE, "Monsters\\Thin\\Thinv3.TRN", { 10, 8, 20, 6, 24, 16 }, { 3, 0, 0, 0, 0, 0 }, "Bone Demon", 10, 14, 12, 70, 70, AI_STORM, 0 , 0, 60, 8, 6, 14, 12, 0, 0, 0, 50, MC_DEMON, IMUNE_MAGIC | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_NULL_40, 0, 7, 1344 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Red Death", 14, 18, 16, 96, 96, AI_STORM, 0 , 1, 75, 5, 10, 20, 0, 0, 0, 0, 60, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 2168 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Litch Demon", 16, 20, 18, 110, 110, AI_STORM, 0 , 2, 80, 5, 10, 24, 0, 0, 0, 0, 45, MC_DEMON, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 2736 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Undead Balrog", 20, 24, 22, 130, 130, AI_STORM, 0 , 3, 85, 5, 12, 30, 0, 0, 0, 0, 65, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 3575 },
{ 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Incinerator", 14, 18, 16, 30, 45, AI_FIREMAN, 0 , 0, 75, 8, 8, 16, 0, 0, 0, 0, 25, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 3, 1888 },
{ 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Flame Lord", 16, 20, 18, 40, 55, AI_FIREMAN, 0 , 1, 75, 8, 10, 20, 0, 0, 0, 0, 25, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 3, 2250 },
{ 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Doom Fire", 18, 22, 20, 50, 65, AI_FIREMAN, 0 , 2, 80, 8, 12, 24, 0, 0, 0, 0, 30, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 2740 },
{ 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Hell Burner", 20, 24, 22, 60, 80, AI_FIREMAN, 0 , 3, 85, 8, 15, 30, 0, 0, 0, 0, 30, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 3355 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Red Storm", 17, 21, 18, 55, 110, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 80, 5, 8, 18, 75, 8, 4, 16, 30, MC_DEMON, IMUNE_MAGIC | RESIST_LIGHTNING , IMUNE_MAGIC | IMUNE_LIGHTNING , 0, 7, 2160 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, FALSE, NULL, { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Storm Rider", 19, 23, 20, 60, 120, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 80, 5, 8, 18, 80, 8, 4, 16, 30, MC_DEMON, RESIST_MAGIC | IMUNE_LIGHTNING , IMUNE_MAGIC | IMUNE_LIGHTNING , 0, 7, 2391 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv2.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Storm Lord", 21, 25, 22, 75, 135, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 85, 5, 12, 24, 75, 8, 4, 16, 35, MC_DEMON, RESIST_MAGIC | IMUNE_LIGHTNING , IMUNE_MAGIC | IMUNE_LIGHTNING , 0, 7, 2775 },
{ 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE , TRUE, "Monsters\\Thin\\Thinv1.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Maelstorm", 23, 27, 24, 90, 150, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 90, 5, 12, 28, 75, 8, 4, 16, 40, MC_DEMON, RESIST_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 3177 },
{ 128, 1650, "Monsters\\BigFall\\Fallg%c.CL2", TRUE, "Monsters\\BigFall\\Bfal%c%i.WAV", FALSE, FALSE, NULL, { 10, 8, 11, 8, 17, 0 }, { 0, 0, 0, 0, 2, 2 }, "Devil Kin Brute", 20, 20, 24, 160, 220, AI_SKELSD, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 100, 6, 18, 24, 0, 0, 0, 0, 75, MC_ANIMAL, 0 , 0 , 0, 6, 2000 },
{ 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, FALSE, NULL, { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Winged-Demon", 8, 12, 9, 45, 60, AI_GARG, MFLAG_CAN_OPEN_DOOR, 0, 50, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 6, 662 },
{ 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "Monsters\\Gargoyle\\GarE.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Gargoyle", 12, 16, 13, 60, 90, AI_GARG, MFLAG_CAN_OPEN_DOOR, 1, 65, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 6, 1205 },
{ 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "Monsters\\Gargoyle\\GargBr.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 0 }, "Blood Claw", 16, 20, 19, 75, 125, AI_GARG, MFLAG_CAN_OPEN_DOOR, 2, 80, 7, 14, 22, 0, 0, 0, 0, 50, MC_DEMON, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 6, 1873 },
{ 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "Monsters\\Gargoyle\\GargB.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 0 }, "Death Wing", 18, 22, 23, 90, 150, AI_GARG, MFLAG_CAN_OPEN_DOOR, 3, 95, 7, 16, 28, 0, 0, 0, 0, 60, MC_DEMON, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 6, 2278 },
{ 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, FALSE, NULL, { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Slayer", 19, 23, 20, 120, 140, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 100, 8, 12, 20, 0, 3, 0, 0, 60, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE , RESIST_MAGIC | IMUNE_FIRE , 0, 7, 2300 },
{ 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "Monsters\\Mega\\Guard.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Guardian", 21, 25, 22, 140, 160, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 110, 8, 14, 22, 0, 3, 0, 0, 65, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE , RESIST_MAGIC | IMUNE_FIRE , 0, 7, 2714 },
{ 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "Monsters\\Mega\\Vtexl.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Vortex Lord", 23, 26, 24, 160, 180, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 120, 8, 18, 24, 0, 3, 0, 0, 70, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, RESIST_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 3252 },
{ 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "Monsters\\Mega\\Balr.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Balrog", 25, 29, 26, 180, 200, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 130, 8, 22, 30, 0, 3, 0, 0, 75, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, RESIST_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 3643 },
{ 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, FALSE, NULL, { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Cave Viper", 20, 24, 21, 100, 150, AI_SNAKE, MFLAG_SEARCH , 0, 90, 8, 8, 20, 0, 0, 0, 0, 60, MC_DEMON, IMUNE_MAGIC , IMUNE_MAGIC , 0, 7, 2725 },
{ 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "Monsters\\Snake\\SnakR.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Fire Drake", 22, 26, 23, 120, 170, AI_SNAKE, MFLAG_SEARCH , 1, 105, 8, 12, 24, 0, 0, 0, 0, 65, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE , IMUNE_MAGIC | IMUNE_FIRE , 0, 7, 3139 },
{ 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "Monsters\\Snake\\Snakg.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Gold Viper", 24, 27, 25, 140, 180, AI_SNAKE, MFLAG_SEARCH , 2, 120, 8, 15, 26, 0, 0, 0, 0, 70, MC_DEMON, IMUNE_MAGIC | RESIST_LIGHTNING , IMUNE_MAGIC | RESIST_LIGHTNING , 0, 7, 3540 },
{ 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "Monsters\\Snake\\Snakb.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Azure Drake", 28, 30, 27, 160, 200, AI_SNAKE, MFLAG_SEARCH , 3, 130, 8, 18, 30, 0, 0, 0, 0, 75, MC_DEMON, RESIST_FIRE | RESIST_LIGHTNING , IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING , 0, 7, 3791 },
{ 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, FALSE, NULL, { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Black Knight", 23, 27, 24, 150, 150, AI_SKELSD, MFLAG_SEARCH , 0, 110, 8, 15, 20, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, RESIST_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 3360 },
{ 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "Monsters\\Black\\BlkKntRT.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Doom Guard", 25, 29, 26, 165, 165, AI_SKELSD, MFLAG_SEARCH , 0, 130, 8, 18, 25, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMUNE_NULL_40, RESIST_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 7, 3650 },
{ 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "Monsters\\Black\\BlkKntBT.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Steel Lord", 27, 30, 28, 180, 180, AI_SKELSD, MFLAG_SEARCH , 1, 120, 8, 20, 30, 0, 0, 0, 0, 80, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 4252 },
{ 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "Monsters\\Black\\BlkKntBe.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Blood Knight", 24, 26, 30, 200, 200, AI_SKELSD, MFLAG_SEARCH , 1, 130, 8, 25, 35, 0, 0, 0, 0, 85, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 5130 },
{ 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Unraveler", 26, 28, 25, 70, 150, AI_SKELSD, 0 , 0, 75, 7, 10, 20, 0, 0, 0, 0, 70, MC_UNDEAD, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 3, 3812 },
{ 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hollow One", 28, 30, 27, 135, 240, AI_SKELSD, 0 , 1, 75, 7, 12, 24, 0, 0, 0, 0, 75, MC_UNDEAD, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 4374 },
{ 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Pain Master", 27, 30, 29, 110, 200, AI_SKELSD, 0 , 2, 80, 7, 16, 30, 0, 0, 0, 0, 80, MC_UNDEAD, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 5147 },
{ 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Reality Weaver", 28, 30, 30, 135, 240, AI_SKELSD, 0 , 3, 85, 7, 20, 35, 0, 0, 0, 0, 85, MC_UNDEAD, RESIST_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, RESIST_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 3, 5925 },
{ 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, FALSE, NULL, { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Succubus", 22, 26, 24, 120, 150, AI_SUCC, MFLAG_CAN_OPEN_DOOR, 0, 100, 10, 1, 20, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC , IMUNE_MAGIC | RESIST_FIRE , 0, 3, 3696 },
{ 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "Monsters\\Succ\\Succb.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Snow Witch", 25, 28, 26, 135, 175, AI_SUCC, MFLAG_CAN_OPEN_DOOR, 1, 110, 10, 1, 24, 0, 0, 0, 0, 65, MC_DEMON, RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 3, 4084 },
{ 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "Monsters\\Succ\\Succrw.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hell Spawn", 27, 30, 28, 150, 200, AI_SUCC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 115, 10, 1, 30, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | IMUNE_LIGHTNING , IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 4480 },
{ 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "Monsters\\Succ\\Succbw.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Soul Burner", 28, 30, 30, 140, 225, AI_SUCC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 120, 10, 1, 35, 0, 0, 0, 0, 85, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING , 0, 3, 4644 },
{ 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, FALSE, NULL, { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Counselor", 24, 26, 25, 70, 70, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 0, 90, 8, 8, 20, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 7, 4070 },
{ 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselg.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Magistrate", 26, 28, 27, 85, 85, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 1, 100, 8, 10, 24, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 4478 },
{ 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselgd.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Cabalist", 28, 30, 29, 120, 120, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 2, 110, 8, 14, 30, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 4929 },
{ 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselbk.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Advocate", 30, 30, 30, 145, 145, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 3, 120, 8, 15, 25, 0, 0, 0, 0, 0, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 4968 },
{ 96, 386, "Monsters\\Golem\\Golem%c.CL2", TRUE, "Monsters\\Golem\\Golm%c%i.WAV", FALSE, FALSE, NULL, { 0, 16, 12, 0, 12, 20 }, { 0, 0, 0, 0, 0, 0 }, "Golem", 0, 0, 12, 1, 1, AI_GOLUM, MFLAG_CAN_OPEN_DOOR, 0, 0, 7, 1, 1, 0, 0, 0, 0, 1, MC_DEMON, 0 , 0 , 0, 0, 0 },
{ 160, 2000, "Monsters\\Diablo\\Diablo%c.CL2", TRUE, "Monsters\\Diablo\\Diablo%c%i.WAV", TRUE, FALSE, NULL, { 16, 6, 16, 6, 16, 16 }, { 0, 0, 0, 0, 0, 0 }, "The Dark Lord", 50, 50, 30, 1666, 1666, AI_DIABLO, MFLAG_KNOCKBACK | MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 220, 4, 30, 60, 0, 11, 0, 0, 70, MC_DEMON, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 7, 31666 },
{ 128, 1060, "Monsters\\DarkMage\\Dmage%c.CL2", TRUE, "Monsters\\DarkMage\\Dmag%c%i.WAV", FALSE, FALSE, NULL, { 6, 1, 21, 6, 23, 18 }, { 0, 0, 0, 0, 0, 0 }, "The Arch-Litch Malignus", 30, 30, 30, 160, 160, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 3, 120, 8, 20, 40, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 7, 4968 }
// clang-format on
};
char MonstConvTbl[128] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 29, 30,
31, 32, 34, 35, 36, 37, 38, 40, 39, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 52,
53, 54, 55, 56, 57, 59, 58, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70, 71, 0,
0, 0, 0, 72, 73, 74, 75, 0, 0, 0,
0, 77, 76, 78, 79, 81, 82, 83, 84, 85,
86, 87, 88, 89, 90, 92, 91, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
106, 107, 108, 0, 110, 0, 109, 0, 0, 0,
0, 0, 0, 0, 0, 0, 80, 111
};
unsigned char MonstAvailTbl[112] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 2,
2, 2, 2, 0, 2, 2, 2, 2, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 0
};
UniqMonstStruct UniqMonst[98] = {
// clang-format off
// mtype, mName, mTrnName, mlevel, mmaxhp, mAi, mint, mMinDamage, mMaxDamage, mMagicRes, mUnqAttr, mUnqVar1, mUnqVar2, mtalkmsg
{ MT_NGOATMC, "Gharbad the Weak", "BSDB", 4, 120, AI_GARBUD, 3, 8, 16, IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, QUEST_GARBUD1 },
{ MT_SKING, "Skeleton King", "GENRL", 0, 240, AI_SKELKING, 3, 6, 16, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 1, 0, 0, 0 },
{ MT_COUNSLR, "Zhar the Mad", "GENERAL", 8, 360, AI_ZHAR, 3, 16, 40, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 0, 0, QUEST_ZHAR1 },
{ MT_BFALLSP, "Snotspill", "BNG", 4, 220, AI_SNOTSPIL, 3, 10, 18, RESIST_LIGHTNING , 0, 0, 0, QUEST_BANNER10 },
{ MT_ADVOCATE, "Arch-Bishop Lazarus", "GENERAL", 0, 600, AI_LAZURUS, 3, 30, 50, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, QUEST_VILE13 },
{ MT_HLSPWN, "Red Vex", "REDV", 0, 400, AI_LAZHELP, 3, 30, 50, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 0, 0, QUEST_VILE13 },
{ MT_HLSPWN, "BlackJade", "BLKJD", 0, 400, AI_LAZHELP, 3, 30, 50, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, QUEST_VILE13 },
{ MT_RBLACK, "Lachdanan", "BHKA", 14, 500, AI_LACHDAN, 3, 0, 0, 0 , 0, 0, 0, QUEST_VEIL9 },
{ MT_BTBLACK, "Warlord of Blood", "GENERAL", 13, 850, AI_WARLORD, 3, 35, 50, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, QUEST_WARLRD9 },
{ MT_CLEAVER, "The Butcher", "GENRL", 0, 220, AI_CLEAVER, 3, 6, 12, RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_TSKELAX, "Bonehead Keenaxe", "BHKA", 2, 91, AI_SKELSD, 2, 4, 10, IMUNE_MAGIC | IMUNE_NULL_40, 7, 100, 0, 0 },
{ MT_RFALLSD, "Bladeskin the Slasher", "BSTS", 2, 51, AI_FALLEN, 0, 6, 18, RESIST_FIRE , 11, 45, 0, 0 },
{ MT_NZOMBIE, "Soulpus", "GENERAL", 2, 133, AI_ZOMBIE, 0, 4, 8, RESIST_FIRE | RESIST_LIGHTNING , 0, 0, 0, 0 },
{ MT_RFALLSP, "Pukerat the Unclean", "PTU", 2, 77, AI_FALLEN, 3, 1, 5, RESIST_FIRE , 0, 0, 0, 0 },
{ MT_WSKELAX, "Boneripper", "BR", 2, 54, AI_BAT, 0, 6, 15, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_NZOMBIE, "Rotfeast the Hungry", "ETH", 2, 85, AI_SKELSD, 3, 4, 12, IMUNE_MAGIC | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_DFALLSD, "Gutshank the Quick", "GTQ", 3, 66, AI_BAT, 2, 6, 16, RESIST_FIRE , 3, 0, 0, 0 },
{ MT_TSKELSD, "Brokenhead Bangshield", "BHBS", 3, 108, AI_SKELSD, 3, 12, 20, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_YFALLSP, "Bongo", "BNG", 3, 178, AI_FALLEN, 3, 9, 21, 0 , 3, 0, 0, 0 },
{ MT_BZOMBIE, "Rotcarnage", "RCRN", 3, 102, AI_ZOMBIE, 3, 9, 24, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 11, 45, 0, 0 },
{ MT_NSCAV, "Shadowbite", "SHBT", 2, 60, AI_SKELSD, 3, 3, 20, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_WSKELBW, "Deadeye", "DE", 2, 49, AI_GOATBOW, 0, 6, 9, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_RSKELAX, "Madeye the Dead", "MTD", 4, 75, AI_BAT, 0, 9, 21, IMUNE_MAGIC | IMUNE_FIRE , 11, 30, 0, 0 },
{ MT_BSCAV, "El Chupacabras", "GENERAL", 3, 120, AI_GOATMC, 0, 10, 18, RESIST_FIRE , 3, 30, 0, 0 },
{ MT_TSKELBW, "Skullfire", "SKFR", 3, 125, AI_GOATBOW, 1, 6, 10, IMUNE_FIRE , 0, 100, 0, 0 },
{ MT_SNEAK, "Warpskull", "TSPO", 3, 117, AI_SNEAK, 2, 6, 18, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_GZOMBIE, "Goretongue", "PMR", 3, 156, AI_SKELSD, 1, 15, 30, IMUNE_MAGIC | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_WSCAV, "Pulsecrawler", "BHKA", 4, 150, AI_SCAV, 0, 16, 20, IMUNE_FIRE | RESIST_LIGHTNING , 11, 45, 0, 0 },
{ MT_BLINK, "Moonbender", "GENERAL", 4, 135, AI_BAT, 0, 9, 27, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_BLINK, "Wrathraven", "GENERAL", 5, 135, AI_BAT, 2, 9, 22, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_YSCAV, "Spineeater", "GENERAL", 4, 180, AI_SCAV, 1, 18, 25, IMUNE_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_RSKELBW, "Blackash the Burning", "BASHTB", 4, 120, AI_GOATBOW, 0, 6, 16, IMUNE_MAGIC | IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_BFALLSD, "Shadowcrow", "GENERAL", 5, 270, AI_SNEAK, 2, 12, 25, 0 , 3, 0, 0, 0 },
{ MT_LRDSAYTR, "Blightstone the Weak", "BHKA", 4, 360, AI_SKELSD, 0, 4, 12, IMUNE_MAGIC | RESIST_LIGHTNING , 7, 70, 0, 0 },
{ MT_FAT, "Bilefroth the Pit Master", "BFTP", 6, 210, AI_BAT, 1, 16, 23, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_NGOATBW, "Bloodskin Darkbow", "BSDB", 5, 207, AI_GOATBOW, 0, 3, 16, RESIST_FIRE | RESIST_LIGHTNING , 11, 55, 0, 0 },
{ MT_GLOOM, "Foulwing", "DB", 5, 246, AI_RHINO, 3, 12, 28, RESIST_FIRE , 3, 0, 0, 0 },
{ MT_XSKELSD, "Shadowdrinker", "SHDR", 5, 300, AI_SNEAK, 1, 18, 26, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 8, 45, 0, 0 },
{ MT_UNSEEN, "Hazeshifter", "BHKA", 5, 285, AI_SNEAK, 3, 18, 30, IMUNE_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_NACID, "Deathspit", "BFDS", 6, 303, AI_ACIDUNIQ, 0, 12, 32, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_RGOATMC, "Bloodgutter", "BGBL", 6, 315, AI_BAT, 1, 24, 34, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_BGOATMC, "Deathshade Fleshmaul", "DSFM", 6, 276, AI_RHINO, 0, 12, 24, IMUNE_MAGIC | RESIST_FIRE , 8, 65, 0, 0 },
{ MT_WYRM, "Warmaggot the Mad", "GENERAL", 6, 246, AI_BAT, 3, 15, 30, RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_STORM, "Glasskull the Jagged", "BHKA", 7, 354, AI_STORM, 0, 18, 30, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_RGOATBW, "Blightfire", "BLF", 7, 321, AI_SUCC, 2, 13, 21, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_GARGOYLE, "Nightwing the Cold", "GENERAL", 7, 342, AI_BAT, 1, 18, 26, IMUNE_MAGIC | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_GGOATBW, "Gorestone", "GENERAL", 7, 303, AI_GOATBOW, 1, 15, 28, RESIST_LIGHTNING | IMUNE_NULL_40, 7, 70, 0, 0 },
{ MT_BMAGMA, "Bronzefist Firestone", "GENERAL", 8, 360, AI_MAGMA, 0, 30, 36, IMUNE_MAGIC | RESIST_FIRE , 3, 0, 0, 0 },
{ MT_INCIN, "Wrathfire the Doomed", "WFTD", 8, 270, AI_SKELSD, 2, 20, 30, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_NMAGMA, "Firewound the Grim", "BHKA", 8, 303, AI_MAGMA, 0, 18, 22, IMUNE_MAGIC | RESIST_FIRE , 3, 0, 0, 0 },
{ MT_MUDMAN, "Baron Sludge", "BSM", 8, 315, AI_SNEAK, 3, 25, 34, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 11, 75, 0, 0 },
{ MT_GGOATMC, "Blighthorn Steelmace", "BHSM", 7, 250, AI_RHINO, 0, 20, 28, RESIST_LIGHTNING , 11, 45, 0, 0 },
{ MT_RACID, "Chaoshowler", "GENERAL", 8, 240, AI_ACIDUNIQ, 0, 12, 20, 0 , 3, 0, 0, 0 },
{ MT_REDDTH, "Doomgrin the Rotting", "GENERAL", 8, 405, AI_STORM, 3, 25, 50, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_FLAMLRD, "Madburner", "GENERAL", 9, 270, AI_STORM, 0, 20, 40, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING , 3, 0, 0, 0 },
{ MT_LTCHDMN, "Bonesaw the Litch", "GENERAL", 9, 495, AI_STORM, 2, 30, 55, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_MUDRUN, "Breakspine", "GENERAL", 9, 351, AI_RHINO, 0, 25, 34, RESIST_FIRE , 3, 0, 0, 0 },
{ MT_REDDTH, "Devilskull Sharpbone", "GENERAL", 9, 444, AI_STORM, 1, 25, 40, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_STORM, "Brokenstorm", "GENERAL", 9, 411, AI_STORM, 2, 25, 36, IMUNE_LIGHTNING , 3, 0, 0, 0 },
{ MT_RSTORM, "Stormbane", "GENERAL", 9, 555, AI_STORM, 3, 30, 30, IMUNE_LIGHTNING , 3, 0, 0, 0 },
{ MT_TOAD, "Oozedrool", "GENERAL", 9, 483, AI_FAT, 3, 25, 30, RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_BLOODCLW, "Goldblight of the Flame", "GENERAL", 10, 405, AI_GARG, 0, 15, 35, IMUNE_MAGIC | IMUNE_FIRE , 11, 80, 0, 0 },
{ MT_OBLORD, "Blackstorm", "GENERAL", 10, 525, AI_RHINO, 3, 20, 40, IMUNE_MAGIC | IMUNE_LIGHTNING , 11, 90, 0, 0 },
{ MT_RACID, "Plaguewrath", "GENERAL", 10, 450, AI_ACIDUNIQ, 2, 20, 30, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_RSTORM, "The Flayer", "GENERAL", 10, 501, AI_STORM, 1, 20, 35, RESIST_MAGIC | RESIST_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_FROSTC, "Bluehorn", "GENERAL", 11, 477, AI_RHINO, 1, 25, 30, IMUNE_MAGIC | RESIST_FIRE , 11, 90, 0, 0 },
{ MT_HELLBURN, "Warpfire Hellspawn", "GENERAL", 11, 525, AI_FIREMAN, 3, 10, 40, RESIST_MAGIC | IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_NSNAKE, "Fangspeir", "GENERAL", 11, 444, AI_SKELSD, 1, 15, 32, IMUNE_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_UDEDBLRG, "Festerskull", "GENERAL", 11, 600, AI_STORM, 2, 15, 30, IMUNE_MAGIC | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_NBLACK, "Lionskull the Bent", "GENERAL", 12, 525, AI_SKELSD, 2, 25, 25, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_COUNSLR, "Blacktongue", "GENERAL", 12, 360, AI_COUNSLR, 3, 15, 30, RESIST_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_DEATHW, "Viletouch", "GENERAL", 12, 525, AI_GARG, 3, 20, 40, IMUNE_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_RSNAKE, "Viperflame", "GENERAL", 12, 570, AI_SKELSD, 1, 25, 35, IMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_BSNAKE, "Fangskin", "BHKA", 14, 681, AI_SKELSD, 2, 15, 50, IMUNE_MAGIC | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_SUCCUBUS, "Witchfire the Unholy", "GENERAL", 12, 444, AI_SUCC, 3, 10, 20, IMUNE_MAGIC | IMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_BALROG, "Blackskull", "BHKA", 13, 750, AI_SKELSD, 3, 25, 40, IMUNE_MAGIC | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_UNRAV, "Soulslash", "GENERAL", 12, 450, AI_SKELSD, 0, 25, 25, IMUNE_MAGIC | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_VTEXLRD, "Windspawn", "GENERAL", 12, 711, AI_SKELSD, 1, 35, 40, IMUNE_MAGIC | IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_GSNAKE, "Lord of the Pit", "GENERAL", 13, 762, AI_SKELSD, 2, 25, 42, RESIST_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_RTBLACK, "Rustweaver", "GENERAL", 13, 400, AI_SKELSD, 3, 1, 60, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_HOLOWONE, "Howlingire the Shade", "GENERAL", 13, 450, AI_SKELSD, 2, 40, 75, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_MAEL, "Doomcloud", "GENERAL", 13, 612, AI_STORM, 1, 1, 60, RESIST_FIRE | IMUNE_LIGHTNING , 0, 0, 0, 0 },
{ MT_PAINMSTR, "Bloodmoon Soulfire", "GENERAL", 13, 684, AI_SKELSD, 1, 15, 40, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_SNOWWICH, "Witchmoon", "GENERAL", 13, 310, AI_SUCC, 3, 30, 40, RESIST_LIGHTNING , 0, 0, 0, 0 },
{ MT_VTEXLRD, "Gorefeast", "GENERAL", 13, 771, AI_SKELSD, 3, 20, 55, RESIST_FIRE | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_RTBLACK, "Graywar the Slayer", "GENERAL", 14, 672, AI_SKELSD, 1, 30, 50, RESIST_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_MAGISTR, "Dreadjudge", "GENERAL", 14, 540, AI_COUNSLR, 1, 30, 40, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 },
{ MT_HLSPWN, "Stareye the Witch", "GENERAL", 14, 726, AI_SUCC, 2, 30, 50, IMUNE_FIRE , 0, 0, 0, 0 },
{ MT_BTBLACK, "Steelskull the Hunter", "GENERAL", 14, 831, AI_SKELSD, 3, 40, 50, RESIST_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_RBLACK, "Sir Gorash", "GENERAL", 16, 1050, AI_SKELSD, 1, 20, 60, IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_CABALIST, "The Vizier", "GENERAL", 15, 850, AI_COUNSLR, 2, 25, 40, IMUNE_FIRE , 3, 0, 0, 0 },
{ MT_REALWEAV, "Zamphir", "GENERAL", 15, 891, AI_SKELSD, 2, 30, 50, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_HLSPWN, "Bloodlust", "GENERAL", 15, 825, AI_SUCC, 1, 20, 55, IMUNE_MAGIC | IMUNE_LIGHTNING | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_HLSPWN, "Webwidow", "GENERAL", 16, 774, AI_SUCC, 1, 20, 50, IMUNE_MAGIC | IMUNE_FIRE | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_SOLBRNR, "Fleshdancer", "GENERAL", 16, 999, AI_SUCC, 3, 30, 50, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 0, 0, 0, 0 },
{ MT_OBLORD, "Grimspike", "GENERAL", 19, 534, AI_SNEAK, 1, 25, 40, IMUNE_MAGIC | RESIST_FIRE | IMUNE_NULL_40, 3, 0, 0, 0 },
{ MT_STORML, "Doomlock", "GENERAL", 28, 534, AI_SNEAK, 1, 35, 55, IMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_NULL_40, 3, 0, 0, 0 },
{ -1, NULL, NULL, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0 }
// clang-format on
};
int MWVel[24][3] = {
{ 256, 512, 1024 },
{ 128, 256, 512 },
{ 85, 170, 341 },
{ 64, 128, 256 },
{ 51, 102, 204 },
{ 42, 85, 170 },
{ 36, 73, 146 },
{ 32, 64, 128 },
{ 28, 56, 113 },
{ 26, 51, 102 },
{ 23, 46, 93 },
{ 21, 42, 85 },
{ 19, 39, 78 },
{ 18, 36, 73 },
{ 17, 34, 68 },
{ 16, 32, 64 },
{ 15, 30, 60 },
{ 14, 28, 57 },
{ 13, 26, 54 },
{ 12, 25, 51 },
{ 12, 24, 48 },
{ 11, 23, 46 },
{ 11, 22, 44 },
{ 10, 21, 42 }
};
char animletter[7] = "nwahds";
int left[8] = { 7, 0, 1, 2, 3, 4, 5, 6 };
int right[8] = { 1, 2, 3, 4, 5, 6, 7, 0 };
int opposite[8] = { 4, 5, 6, 7, 0, 1, 2, 3 };
int offset_x[8] = { 1, 0, -1, -1, -1, 0, 1, 1 };
int offset_y[8] = { 1, 1, 1, 0, -1, -1, -1, 0 };
/* unused */
int rnd5[4] = { 5, 10, 15, 20 };
int rnd10[4] = { 10, 15, 20, 30 };
int rnd20[4] = { 20, 30, 40, 50 };
int rnd60[4] = { 60, 70, 80, 90 };
//
void(__fastcall *AiProc[])(int i) = {
&MAI_Zombie,
&MAI_Fat,
&MAI_SkelSd,
&MAI_SkelBow,
&MAI_Scav,
&MAI_Rhino,
&MAI_GoatMc,
&MAI_GoatBow,
&MAI_Fallen,
&MAI_Magma,
&MAI_SkelKing,
&MAI_Bat,
&MAI_Garg,
&MAI_Cleaver,
&MAI_Succ,
&MAI_Sneak,
&MAI_Storm,
&MAI_Fireman,
&MAI_Garbud,
&MAI_Acid,
&MAI_AcidUniq,
&MAI_Golum,
&MAI_Zhar,
&MAI_SnotSpil,
&MAI_Snake,
&MAI_Counselor,
&MAI_Mega,
&MAI_Diablo,
&MAI_Lazurus,
&MAI_Lazhelp,
&MAI_Lachdanan,
&MAI_Warlord
};
struct monster_cpp_init {
monster_cpp_init()
{
monster_cpp_init_value = monster_inf;
}
} _monster_cpp_init;
// 47F130: using guessed type int monster_inf;
// 64CCE4: using guessed type int monster_cpp_init_value;
void __fastcall InitMonsterTRN(int monst, BOOL special)
{
BYTE *f = Monsters[monst].trans_file;
for (int i = 0; i < 256; i++) {
if (*f == 255) {
*f = 0;
}
f++;
}
int n = special ? 6 : 5;
for (int j = 0; j < n; ++j) {
if (j != 1 || Monsters[monst].mtype < MT_COUNSLR || Monsters[monst].mtype > MT_ADVOCATE) {
for (int k = 0; k < 8; k++) {
Cl2ApplyTrans(
Monsters[monst].Anims[j].Data[k],
Monsters[monst].trans_file,
Monsters[monst].Anims[j].Frames);
}
}
}
}
void __cdecl InitLevelMonsters()
{
int i;
nummtypes = 0;
monstimgtot = 0;
MissileFileFlag = 0;
for (i = 0; i < MAX_LVLMTYPES; i++) {
Monsters[i].mPlaceFlags = 0;
}
ClrAllMonsters();
nummonsters = 0;
totalmonsters = MAXMONSTERS;
for (i = 0; i < MAXMONSTERS; i++) {
monstactive[i] = i;
}
uniquetrans = 0;
}
int __fastcall AddMonsterType(int type, int placeflag)
{
BOOL done = FALSE;
int i;
for (i = 0; i < nummtypes && !done; i++) {
done = Monsters[i].mtype == type;
}
i--;
if (!done) {
i = nummtypes;
nummtypes++;
Monsters[i].mtype = type;
monstimgtot += monsterdata[type].mImage;
InitMonsterGFX(i);
InitMonsterSND(i);
}
Monsters[i].mPlaceFlags |= placeflag;
return i;
}
void __cdecl GetLevelMTypes()
{
int i;
// this array is merged with skeltypes down below.
int typelist[MAXMONSTERS];
int skeltypes[NUM_MTYPES];
int minl; // min level
int maxl; // max level
char mamask = 3; // monster availability mask
int nt; // number of types
AddMonsterType(MT_GOLEM, 2);
if (currlevel == 16) {
AddMonsterType(MT_ADVOCATE, 1);
AddMonsterType(MT_RBLACK, 1);
AddMonsterType(MT_DIABLO, 2);
return;
}
if (!setlevel) {
if (QuestStatus(QTYPE_BUTCH))
AddMonsterType(MT_CLEAVER, 2);
if (QuestStatus(QTYPE_GARB))
AddMonsterType(UniqMonst[0].mtype, 4);
if (QuestStatus(QTYPE_ZHAR))
AddMonsterType(UniqMonst[2].mtype, 4);
if (QuestStatus(QTYPE_BOL))
AddMonsterType(UniqMonst[3].mtype, 4);
if (QuestStatus(QTYPE_VEIL))
AddMonsterType(UniqMonst[7].mtype, 4);
if (QuestStatus(QTYPE_WARLRD))
AddMonsterType(UniqMonst[8].mtype, 4);
if (gbMaxPlayers != 1 && currlevel == quests[QTYPE_KING]._qlevel) {
AddMonsterType(MT_SKING, 4);
const int numskeltypes = 19;
nt = 0;
for (i = MT_WSKELAX; i <= MT_WSKELAX + numskeltypes; i++) {
if (IsSkel(i)) {
minl = 15 * monsterdata[i].mMinDLvl / 30 + 1;
maxl = 15 * monsterdata[i].mMaxDLvl / 30 + 1;
if (currlevel >= minl && currlevel <= maxl) {
if (MonstAvailTbl[i] & mamask) {
skeltypes[nt++] = i;
}
}
}
}
AddMonsterType(skeltypes[random(88, nt)], 1);
}
nt = 0;
for (i = 0; i < 111; i++) {
minl = 15 * monsterdata[i].mMinDLvl / 30 + 1;
maxl = 15 * monsterdata[i].mMaxDLvl / 30 + 1;
if (currlevel >= minl && currlevel <= maxl) {
if (MonstAvailTbl[i] & mamask) {
typelist[nt++] = i;
}
}
}
if (monstdebug) {
for (i = 0; i < debugmonsttypes; i++)
AddMonsterType(DebugMonsters[i], 1);
} else {
while (nt > 0 && nummtypes < MAX_LVLMTYPES && monstimgtot < 4000) {
for (i = 0; i < nt;) {
if (monsterdata[typelist[i]].mImage > 4000 - monstimgtot) {
typelist[i] = typelist[--nt];
continue;
}
i++;
}
if (nt != 0) {
i = random(88, nt);
AddMonsterType(typelist[i], 1);
typelist[i] = typelist[--nt];
}
}
}
} else {
if (setlvlnum == SL_SKELKING) {
AddMonsterType(MT_SKING, 4);
}
}
}
void __fastcall InitMonsterGFX(int monst)
{
int mtype = (unsigned char)Monsters[monst].mtype;
char strBuff[256];
for (int anim = 0; anim < 6; anim++) {
if ((animletter[anim] != 's' || monsterdata[mtype].has_special) && monsterdata[mtype].Frames[anim] > 0) {
sprintf(strBuff, monsterdata[mtype].GraphicType, animletter[anim]);
unsigned char *celBuf = LoadFileInMem(strBuff, NULL);
Monsters[monst].Anims[anim].CMem = celBuf;
if (Monsters[monst].mtype != MT_GOLEM || (animletter[anim] != 's' && animletter[anim] != 'd')) {
for (int i = 0; i < 8; i++) {
Monsters[monst].Anims[anim].Data[i] = &celBuf[((int *)celBuf)[i]];
}
} else {
for (int i = 0; i < 8; i++) {
Monsters[monst].Anims[anim].Data[i] = celBuf;
}
}
}
// TODO: either the AnimStruct members have wrong naming or the MonsterData ones it seems
Monsters[monst].Anims[anim].Frames = monsterdata[mtype].Frames[anim];
Monsters[monst].Anims[anim].Rate = monsterdata[mtype].Rate[anim];
}
Monsters[monst].width = monsterdata[mtype].width;
Monsters[monst].width2 = (monsterdata[mtype].width - 64) >> 1;
Monsters[monst].mMinHP = monsterdata[mtype].mMinHP;
Monsters[monst].mMaxHP = monsterdata[mtype].mMaxHP;
Monsters[monst].has_special = monsterdata[mtype].has_special;
Monsters[monst].mAFNum = monsterdata[mtype].mAFNum;
Monsters[monst].MData = &monsterdata[mtype];
if (monsterdata[mtype].has_trans) {
Monsters[monst].trans_file = LoadFileInMem(monsterdata[mtype].TransFile, NULL);
InitMonsterTRN(monst, monsterdata[mtype].has_special);
void *trans_file = Monsters[monst].trans_file;
Monsters[monst].trans_file = NULL;
mem_free_dbg(trans_file);
}
if (mtype >= MT_NMAGMA && mtype <= MT_WMAGMA && !(MissileFileFlag & 1)) {
MissileFileFlag |= 1;
LoadMissileGFX(MFILE_MAGBALL);
}
if (mtype >= MT_STORM && mtype <= MT_MAEL && !(MissileFileFlag & 2)) {
MissileFileFlag |= 2;
LoadMissileGFX(MFILE_THINLGHT);
}
if (mtype == MT_SUCCUBUS) {
if (MissileFileFlag & 4)
return;
MissileFileFlag |= 4;
LoadMissileGFX(MFILE_FLARE);
LoadMissileGFX(MFILE_FLAREEXP);
}
if (mtype == MT_SNOWWICH) {
if (MissileFileFlag & 0x20)
return;
MissileFileFlag |= 0x20;
LoadMissileGFX(MFILE_SCUBMISB);
LoadMissileGFX(MFILE_SCBSEXPB);
}
if (mtype == MT_HLSPWN) {
if (MissileFileFlag & 0x40)
return;
MissileFileFlag |= 0x40;
LoadMissileGFX(MFILE_SCUBMISD);
LoadMissileGFX(MFILE_SCBSEXPD);
}
if (mtype == MT_SOLBRNR) {
if (MissileFileFlag & 0x80)
return;
MissileFileFlag |= 0x80;
LoadMissileGFX(MFILE_SCUBMISC);
LoadMissileGFX(MFILE_SCBSEXPC);
}
if (mtype >= MT_INCIN && mtype <= MT_HELLBURN && !(MissileFileFlag & 8)) {
MissileFileFlag |= 8;
LoadMissileGFX(MFILE_KRULL);
}
if (mtype >= MT_NACID && mtype <= MT_XACID && !(MissileFileFlag & 0x10)) {
MissileFileFlag |= 0x10;
LoadMissileGFX(MFILE_ACIDBF);
LoadMissileGFX(MFILE_ACIDSPLA);
LoadMissileGFX(MFILE_ACIDPUD);
}
if (mtype == MT_DIABLO) {
LoadMissileGFX(MFILE_FIREPLAR);
}
}
void __fastcall ClearMVars(int i)
{
monster[i]._mVar1 = 0;
monster[i]._mVar2 = 0;
monster[i]._mVar3 = 0;
monster[i]._mVar4 = 0;
monster[i]._mVar5 = 0;
monster[i]._mVar6 = 0;
monster[i]._mVar7 = 0;
monster[i]._mVar8 = 0;
}
void __fastcall InitMonster(int i, int rd, int mtype, int x, int y)
{
CMonster *monst = &Monsters[mtype];
monster[i]._mdir = rd;
monster[i]._mx = x;
monster[i]._my = y;
monster[i]._mfutx = x;
monster[i]._mfuty = y;
monster[i]._moldx = x;
monster[i]._moldy = y;
monster[i]._mmode = MM_STAND;
monster[i]._mMTidx = mtype;
monster[i].mName = monst->MData->mName;
monster[i].MType = monst;
monster[i].MData = monst->MData;
monster[i]._mAnimData = monst->Anims[MA_STAND].Data[rd];
monster[i]._mAnimDelay = monst->Anims[MA_STAND].Rate;
monster[i]._mAnimCnt = random(88, monst->Anims[MA_STAND].Rate - 1);
monster[i]._mAnimLen = monst->Anims[MA_STAND].Frames;
monster[i]._mAnimFrame = random(88, monst->Anims[MA_STAND].Frames - 1) + 1;
if (monst->mtype == MT_DIABLO) {
monster[i]._mmaxhp = (random(88, 1) + 1666) << 6;
} else {
monster[i]._mmaxhp = (monst->mMinHP + random(88, monst->mMaxHP - monst->mMinHP + 1)) << 6;
}
if (gbMaxPlayers == 1) {
monster[i]._mmaxhp >>= 1;
if (monster[i]._mmaxhp < 64) {
monster[i]._mmaxhp = 64;
}
}
monster[i]._mhitpoints = monster[i]._mmaxhp;
monster[i]._mAi = monst->MData->mAi;
monster[i]._mint = monst->MData->mInt;
monster[i]._mgoal = MGOAL_NORMAL;
monster[i]._mgoalvar1 = 0;
monster[i]._mgoalvar2 = 0;
monster[i]._mgoalvar3 = 0;
monster[i]._pathcount = 0;
monster[i]._uniqtype = 0;
monster[i]._msquelch = 0;
monster[i].field_18 = 0;
monster[i]._mDelFlag = FALSE;
monster[i]._mRndSeed = GetRndSeed();
monster[i]._mAISeed = GetRndSeed();
monster[i].mWhoHit = 0;
monster[i].mLevel = monst->MData->mLevel;
monster[i].mExp = monst->MData->mExp;
monster[i].mHit = monst->MData->mHit;
monster[i].mMinDamage = monst->MData->mMinDamage;
monster[i].mMaxDamage = monst->MData->mMaxDamage;
monster[i].mHit2 = monst->MData->mHit2;
monster[i].mMinDamage2 = monst->MData->mMinDamage2;
monster[i].mMaxDamage2 = monst->MData->mMaxDamage2;
monster[i].mArmorClass = monst->MData->mArmorClass;
monster[i].mMagicRes = monst->MData->mMagicRes;
monster[i].leader = 0;
monster[i].leaderflag = 0;
monster[i]._mFlags = monst->MData->mFlags;
monster[i].mtalkmsg = 0;
if (monster[i]._mAi == AI_GARG) {
monster[i]._mAnimData = monst->Anims[MA_SPECIAL].Data[rd];
monster[i]._mAnimFrame = 1;
monster[i]._mFlags |= MFLAG_ALLOW_SPECIAL;
monster[i]._mmode = MM_SATTACK;
}
if (gnDifficulty == DIFF_NIGHTMARE) {
monster[i].mLevel += 15;
monster[i].mHit += 85;
monster[i].mHit2 += 85;
monster[i]._mmaxhp = 3 * monster[i]._mmaxhp + 64;
monster[i]._mhitpoints = monster[i]._mmaxhp;
monster[i].mExp = 2 * (monster[i].mExp + 1000);
monster[i].mMinDamage = 2 * (monster[i].mMinDamage + 2);
monster[i].mMaxDamage = 2 * (monster[i].mMaxDamage + 2);
monster[i].mMinDamage2 = 2 * (monster[i].mMinDamage2 + 2);
monster[i].mMaxDamage2 = 2 * (monster[i].mMaxDamage2 + 2);
monster[i].mArmorClass += 50;
}
if (gnDifficulty == DIFF_HELL) {
monster[i].mLevel += 30;
monster[i]._mmaxhp = 4 * monster[i]._mmaxhp + 192;
monster[i]._mhitpoints = monster[i]._mmaxhp;
monster[i].mHit += 120;
monster[i].mHit2 += 120;
monster[i].mExp = 4 * (monster[i].mExp + 1000);
monster[i].mMinDamage = 4 * monster[i].mMinDamage + 6;
monster[i].mMaxDamage = 4 * monster[i].mMaxDamage + 6;
monster[i].mMinDamage2 = 4 * monster[i].mMinDamage2 + 6;
monster[i].mMaxDamage2 = 4 * monster[i].mMaxDamage2 + 6;
monster[i].mArmorClass += 80;
monster[i].mMagicRes = monst->MData->mMagicRes2;
}
}
void __cdecl ClrAllMonsters()
{
MonsterStruct *Monst;
for (int i = 0; i < MAXMONSTERS; i++) {
Monst = &monster[i];
ClearMVars(i);
Monst->mName = "Invalid Monster";
Monst->_mgoal = 0;
Monst->_mmode = MM_STAND;
Monst->_mVar1 = 0;
Monst->_mVar2 = 0;
Monst->_mx = 0;
Monst->_my = 0;
Monst->_mfutx = 0;
Monst->_mfuty = 0;
Monst->_moldx = 0;
Monst->_moldy = 0;
Monst->_mdir = random(89, 8);
Monst->_mxvel = 0;
Monst->_myvel = 0;
Monst->_mAnimData = NULL;
Monst->_mAnimDelay = 0;
Monst->_mAnimCnt = 0;
Monst->_mAnimLen = 0;
Monst->_mAnimFrame = 0;
Monst->_mFlags = 0;
Monst->_mDelFlag = FALSE;
Monst->_menemy = random(89, gbActivePlayers);
Monst->_menemyx = plr[Monst->_menemy]._px;
Monst->_menemyy = plr[Monst->_menemy]._py;
}
}
BOOL __fastcall MonstPlace(int xp, int yp)
{
if (xp < 0 || xp >= MAXDUNX
|| yp < 0 || yp >= MAXDUNY
|| dMonster[xp][yp]
|| dPlayer[xp][yp]) {
return FALSE;
}
char f = dFlags[xp][yp];
if (f & DFLAG_VISIBLE) {
return FALSE;
}
if (f & DFLAG_POPULATED) {
return FALSE;
}
return !SolidLoc(xp, yp);
}
void __fastcall PlaceMonster(int i, int mtype, int x, int y)
{
dMonster[x][y] = i + 1;
int rd = random(90, 8);
InitMonster(i, rd, mtype, x, y);
}
void __fastcall PlaceUniqueMonst(int uniqindex, int miniontype, int packsize)
{
int xp;
int yp;
char filestr[64];
UniqMonstStruct *Uniq = &UniqMonst[uniqindex];
MonsterStruct *Monst = &monster[nummonsters];
int count = 0;
if ((uniquetrans + 19) << 8 >= LIGHTSIZE) {
return;
}
int uniqtype;
for (uniqtype = 0; uniqtype < nummtypes; uniqtype++) {
if (Monsters[uniqtype].mtype == Uniq->mtype) {
break;
}
}
while (true) {
xp = random(91, 80) + 16;
yp = random(91, 80) + 16;
int count2 = 0;
for (int x = xp - 3; x < xp + 3; x++) {
for (int y = yp - 3; y < yp + 3; y++) {
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && MonstPlace(x, y)) {
count2++;
}
}
}
if (count2 < 9) {
count++;
if (count < 1000) {
continue;
}
}
if (MonstPlace(xp, yp)) {
break;
}
}
if (uniqindex == 3) {
xp = 2 * setpc_x + 24;
yp = 2 * setpc_y + 28;
}
if (uniqindex == 8) {
xp = 2 * setpc_x + 22;
yp = 2 * setpc_y + 23;
}
if (uniqindex == 2) {
BOOL zharflag = TRUE;
for (int i = 0; i < themeCount; i++) {
if (i == zharlib && zharflag == TRUE) {
zharflag = FALSE;
xp = 2 * themeLoc[i].x + 20;
yp = 2 * themeLoc[i].y + 20;
}
}
}
if (gbMaxPlayers == 1) {
if (uniqindex == 4) {
xp = 32;
yp = 46;
}
if (uniqindex == 5) {
xp = 40;
yp = 45;
}
if (uniqindex == 6) {
xp = 38;
yp = 49;
}
if (uniqindex == 1) {
xp = 35;
yp = 47;
}
} else {
if (uniqindex == 4) {
xp = 2 * setpc_x + 19;
yp = 2 * setpc_y + 22;
}
if (uniqindex == 5) {
xp = 2 * setpc_x + 21;
yp = 2 * setpc_y + 19;
}
if (uniqindex == 6) {
xp = 2 * setpc_x + 21;
yp = 2 * setpc_y + 25;
}
}
if (uniqindex == 9) {
BOOL done = FALSE;
for (yp = 0; yp < MAXDUNY && !done; yp++) {
for (xp = 0; xp < MAXDUNX && !done; xp++) {
done = dPiece[xp][yp] == 367;
}
}
}
PlaceMonster(nummonsters, uniqtype, xp, yp);
Monst->_uniqtype = uniqindex + 1;
if (Uniq->mlevel) {
Monst->mLevel = 2 * Uniq->mlevel;
} else {
Monst->mLevel += 5;
}
Monst->mExp *= 2;
Monst->mName = Uniq->mName;
Monst->_mmaxhp = Uniq->mmaxhp << 6;
if (gbMaxPlayers == 1) {
Monst->_mmaxhp = Monst->_mmaxhp >> 1;
if (Monst->_mmaxhp < 64) {
Monst->_mmaxhp = 64;
}
}
Monst->_mhitpoints = Monst->_mmaxhp;
Monst->_mAi = Uniq->mAi;
Monst->_mint = Uniq->mint;
Monst->mMinDamage = Uniq->mMinDamage;
Monst->mMaxDamage = Uniq->mMaxDamage;
Monst->mMinDamage2 = Uniq->mMinDamage;
Monst->mMaxDamage2 = Uniq->mMaxDamage;
Monst->mMagicRes = Uniq->mMagicRes;
Monst->mtalkmsg = Uniq->mtalkmsg;
Monst->mlid = AddLight(Monst->_mx, Monst->_my, 3);
if (gbMaxPlayers == 1) {
if (Monst->mtalkmsg) {
Monst->_mgoal = MGOAL_INQUIRING;
}
} else {
if (Monst->_mAi == AI_LAZHELP) {
Monst->mtalkmsg = 0;
}
if (Monst->_mAi != AI_LAZURUS || quests[QTYPE_VB]._qvar1 <= 3) {
if (Monst->mtalkmsg) {
Monst->_mgoal = MGOAL_INQUIRING;
}
} else {
Monst->_mgoal = MGOAL_NORMAL;
}
}
if (gnDifficulty == DIFF_NIGHTMARE) {
Monst->mLevel += 15;
Monst->_mmaxhp = 3 * Monst->_mmaxhp + 64;
Monst->_mhitpoints = Monst->_mmaxhp;
Monst->mExp = 2 * (Monst->mExp + 1000);
Monst->mMinDamage = 2 * (Monst->mMinDamage + 2);
Monst->mMaxDamage = 2 * (Monst->mMaxDamage + 2);
Monst->mMinDamage2 = 2 * (Monst->mMinDamage2 + 2);
Monst->mMaxDamage2 = 2 * (Monst->mMaxDamage2 + 2);
}
if (gnDifficulty == DIFF_HELL) {
Monst->mLevel += 30;
Monst->_mmaxhp = 4 * Monst->_mmaxhp + 192;
Monst->_mhitpoints = Monst->_mmaxhp;
Monst->mExp = 4 * (Monst->mExp + 1000);
Monst->mMinDamage = 4 * Monst->mMinDamage + 6;
Monst->mMaxDamage = 4 * Monst->mMaxDamage + 6;
Monst->mMinDamage2 = 4 * Monst->mMinDamage2 + 6;
Monst->mMaxDamage2 = 4 * Monst->mMaxDamage2 + 6;
}
sprintf(filestr, "Monsters\\Monsters\\%s.TRN", Uniq->mTrnName);
LoadFileWithMem(filestr, &pLightTbl[256 * (uniquetrans + 19)]);
Monst->_uniqtrans = uniquetrans++;
if (Uniq->mUnqAttr & 4) {
Monst->mHit = Uniq->mUnqVar1;
Monst->mHit2 = Uniq->mUnqVar1;
}
if (Uniq->mUnqAttr & 8) {
Monst->mArmorClass = Uniq->mUnqVar1;
}
nummonsters++;
if (Uniq->mUnqAttr & 1) {
PlaceGroup(miniontype, packsize, Uniq->mUnqAttr, nummonsters - 1);
}
if (Monst->_mAi != AI_GARG) {
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir];
Monst->_mAnimFrame = random(88, Monst->_mAnimLen - 1) + 1;
Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL;
Monst->_mmode = MM_STAND;
}
}
void __cdecl PlaceQuestMonsters()
{
int skeltype;
unsigned char *setp;
if (!setlevel) {
if (QuestStatus(QTYPE_BUTCH)) {
PlaceUniqueMonst(9, 0, 0);
}
if (currlevel == quests[QTYPE_KING]._qlevel && gbMaxPlayers != 1) {
skeltype = 0;
for (skeltype = 0; skeltype < nummtypes; skeltype++) {
if (IsSkel(Monsters[skeltype].mtype)) {
break;
}
}
PlaceUniqueMonst(1, skeltype, 30);
}
if (QuestStatus(QTYPE_BOL)) {
setp = LoadFileInMem("Levels\\L1Data\\Banner1.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y);
mem_free_dbg(setp);
}
if (QuestStatus(QTYPE_BLOOD)) {
setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y);
mem_free_dbg(setp);
}
if (QuestStatus(QTYPE_BLIND)) {
setp = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y);
mem_free_dbg(setp);
}
if (QuestStatus(QTYPE_ANVIL)) {
setp = LoadFileInMem("Levels\\L3Data\\Anvil.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x + 2, 2 * setpc_y + 2);
mem_free_dbg(setp);
}
if (QuestStatus(QTYPE_WARLRD)) {
setp = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y);
mem_free_dbg(setp);
AddMonsterType(UniqMonst[8].mtype, 1);
}
if (QuestStatus(QTYPE_VEIL)) {
AddMonsterType(UniqMonst[7].mtype, 1);
}
if (QuestStatus(QTYPE_ZHAR) && zharlib == -1) {
quests[QTYPE_ZHAR]._qactive = 0;
}
if (currlevel == quests[QTYPE_VB]._qlevel && gbMaxPlayers != 1) {
AddMonsterType(UniqMonst[4].mtype, 4);
AddMonsterType(UniqMonst[5].mtype, 4);
PlaceUniqueMonst(4, 0, 0);
PlaceUniqueMonst(5, 0, 0);
PlaceUniqueMonst(6, 0, 0);
setp = LoadFileInMem("Levels\\L4Data\\Vile1.DUN", 0);
SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y);
mem_free_dbg(setp);
}
} else {
if (setlvlnum == SL_SKELKING) {
PlaceUniqueMonst(1, 0, 0);
}
}
}
void __fastcall PlaceGroup(int mtype, int num, int leaderf, int leader)
{
int placed = 0;
int xp;
int yp;
int x1;
int y1;
for (int try1 = 0; try1 < 10; try1++) {
while (placed) {
nummonsters--;
placed--;
dMonster[monster[nummonsters]._mx][monster[nummonsters]._my] = 0;
}
if (leaderf & 1) {
int offset = random(92, 8);
xp = monster[leader]._mx + offset_x[offset];
yp = monster[leader]._my + offset_y[offset];
x1 = xp;
y1 = yp;
} else {
do {
xp = random(93, 80) + 16;
x1 = xp;
yp = random(93, 80) + 16;
y1 = yp;
} while (!MonstPlace(xp, yp));
}
if (num + nummonsters > totalmonsters) {
num = totalmonsters - nummonsters;
}
int j = 0;
for (int try2 = 0; j < num && try2 < 100; xp += offset_x[random(94, 8)], yp += offset_x[random(94, 8)]) {
if (!MonstPlace(xp, yp)
|| (dung_map[x1][y1] != dung_map[xp][yp])
|| (leaderf & 2) && ((abs(xp - x1) >= 4) || (abs(yp - y1) >= 4))) {
try2++;
continue;
}
PlaceMonster(nummonsters, mtype, xp, yp);
if (leaderf & 1) {
monster[nummonsters]._mmaxhp *= 2;
monster[nummonsters]._mhitpoints = monster[nummonsters]._mmaxhp;
monster[nummonsters]._mint = monster[leader]._mint;
if (leaderf & 2) {
monster[nummonsters].leader = leader;
monster[nummonsters].leaderflag = 1;
monster[nummonsters]._mAi = monster[leader]._mAi;
}
if (monster[nummonsters]._mAi != AI_GARG) {
monster[nummonsters]._mAnimData = monster[nummonsters].MType->Anims[MA_STAND].Data[monster[nummonsters]._mdir];
monster[nummonsters]._mAnimFrame = random(88, monster[nummonsters]._mAnimLen - 1) + 1;
monster[nummonsters]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
monster[nummonsters]._mmode = MM_STAND;
}
}
nummonsters++;
placed++;
j++;
}
if (placed >= num) {
break;
}
}
if (leaderf & 2) {
monster[leader].packsize = placed;
}
}
void __cdecl LoadDiabMonsts()
{
unsigned char *lpSetPiece; // esi
lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", 0);
SetMapMonsters(lpSetPiece, 2 * diabquad1x, 2 * diabquad1y);
mem_free_dbg(lpSetPiece);
lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", 0);
SetMapMonsters(lpSetPiece, 2 * diabquad2x, 2 * diabquad2y);
mem_free_dbg(lpSetPiece);
lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", 0);
SetMapMonsters(lpSetPiece, 2 * diabquad3x, 2 * diabquad3y);
mem_free_dbg(lpSetPiece);
lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab4a.DUN", 0);
SetMapMonsters(lpSetPiece, 2 * diabquad4x, 2 * diabquad4y);
mem_free_dbg(lpSetPiece);
}
// 5289C4: using guessed type int diabquad1x;
// 5289C8: using guessed type int diabquad1y;
void __cdecl InitMonsters()
{
int v0; // ebp
int v1; // ebx
TriggerStruct *v2; // esi
signed int v3; // ebp
signed int v4; // edi
int v5; // edi
int v6; // esi
int v7; // eax
int v8; // ecx
int v9; // edx
int v10; // eax
int v11; // esi
unsigned char *v12; // edi
int v13; // ebx
int v15; // esi
int v17; // eax
int v18; // eax
int v19; // ebx
TriggerStruct *v20; // esi
signed int v21; // ebp
signed int v22; // edi
int max; // [esp+10h] [ebp-1C4h]
int v24; // [esp+14h] [ebp-1C0h]
int scattertypes[111]; // [esp+18h] [ebp-1BCh]
v0 = 0;
max = 0;
if (gbMaxPlayers != 1)
CheckDungeonClear();
if (!setlevel) {
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
if (!setlevel && currlevel == 16)
LoadDiabMonsts();
}
v24 = trigflag[4];
if (currlevel == 15)
v24 = 1;
v1 = v24;
if (v24 > 0) {
v2 = trigs;
do {
v3 = -2;
do {
v4 = -2;
do
DoVision(v3 + v2->_tx, v4++ + v2->_ty, 15, 0, 0);
while (v4 < 2);
++v3;
} while (v3 < 2);
++v2;
--v1;
} while (v1);
v0 = 0;
}
PlaceQuestMonsters();
if (!setlevel) {
PlaceUniques();
v5 = 16;
do {
v6 = 16;
do {
if (!SolidLoc(v5, v6))
++v0;
++v6;
} while (v6 < 96);
++v5;
} while (v5 < 96);
v7 = v0 / 30;
if (gbMaxPlayers != 1)
v7 += v7 >> 1;
v8 = nummonsters;
if (nummonsters + v7 > 190)
v7 = 190 - nummonsters;
v9 = nummtypes;
v10 = nummonsters + v7;
v11 = 0;
totalmonsters = v10;
if (nummtypes > 0) {
v12 = &Monsters[0].mPlaceFlags;
do {
if (*v12 & 1) {
v13 = max++;
scattertypes[v13] = v11;
}
++v11;
v12 += 328;
} while (v11 < v9);
}
if (v8 < v10) {
while (1) {
v15 = scattertypes[random(95, max)];
if (currlevel == 1)
break;
if (!random(95, 2))
break;
if (currlevel == 2) {
v17 = random(95, 2) + 1;
LABEL_40:
v18 = v17 + 1;
goto LABEL_41;
}
v18 = random(95, 3) + 3;
LABEL_41:
PlaceGroup(v15, v18, 0, 0);
if (nummonsters >= totalmonsters)
goto LABEL_42;
}
v17 = 0;
goto LABEL_40;
}
}
LABEL_42:
v19 = v24;
if (v24 > 0) {
v20 = trigs;
do {
v21 = -2;
do {
v22 = -2;
do
DoUnVision(v21 + v20->_tx, v22++ + v20->_ty, 15);
while (v22 < 2);
++v21;
} while (v21 < 2);
++v20;
--v19;
} while (v19);
}
}
// 5CF31D: using guessed type char setlevel;
// 658550: using guessed type int totalmonsters;
// 679660: using guessed type char gbMaxPlayers;
// 432637: using guessed type int var_1BC[111];
void __cdecl PlaceUniques()
{
int v0; // edi
int v1; // eax
UniqMonstStruct *v2; // ecx
int v3; // eax
int v4; // edx
CMonster *v5; // esi
int v6; // eax
int v7; // edx
v0 = 0;
if (UniqMonst[0].mtype != -1) {
v1 = 0;
v2 = UniqMonst;
while (UniqMonst[v1].mlevel != currlevel) {
LABEL_25:
v1 = ++v0;
v2 = &UniqMonst[v0];
if (v2->mtype == -1)
return;
}
v3 = 0;
v4 = 0;
if (nummtypes > 0) {
v5 = Monsters;
do {
if (v3)
break;
v6 = -((char)v2->mtype != (unsigned char)v5->mtype);
++v5;
v3 = v6 + 1;
++v4;
} while (v4 < nummtypes);
}
v7 = v4 - 1;
if (!v0) {
if (quests[QTYPE_GARB]._qactive)
goto LABEL_23;
v3 = 0;
}
if (v0 == 2) {
if (quests[QTYPE_ZHAR]._qactive)
goto LABEL_23;
v3 = 0;
}
if (v0 == 3) {
if (quests[QTYPE_BOL]._qactive)
goto LABEL_23;
v3 = 0;
}
if (v0 != 7) {
LABEL_20:
if (v0 == 8 && !quests[QTYPE_WARLRD]._qactive)
v3 = 0;
goto LABEL_23;
}
if (!quests[QTYPE_VEIL]._qactive) {
v3 = 0;
goto LABEL_20;
}
LABEL_23:
if (v3)
PlaceUniqueMonst(v0, v7, 8);
goto LABEL_25;
}
}
void __fastcall SetMapMonsters(unsigned char *pMap, int startx, int starty)
{
unsigned char *v3; // esi
unsigned short v4; // cx
int v5; // edx
int v6; // edi
int v7; // ecx
unsigned char *v8; // edx
int i; // esi
int v10; // eax
int v11; // ecx
int v12; // [esp+Ch] [ebp-Ch]
int v13; // [esp+10h] [ebp-8h]
unsigned char *v14; // [esp+14h] [ebp-4h]
int startya; // [esp+20h] [ebp+8h]
v12 = startx;
v3 = pMap;
AddMonsterType(MT_GOLEM, 2);
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
AddMonster(1, 0, 0, 0, 0);
if (setlevel && setlvlnum == SL_VILEBETRAYER) {
AddMonsterType((char)UniqMonst[4].mtype, 4);
AddMonsterType((char)UniqMonst[5].mtype, 4);
AddMonsterType((char)UniqMonst[6].mtype, 4);
PlaceUniqueMonst(4, 0, 0);
PlaceUniqueMonst(5, 0, 0);
PlaceUniqueMonst(6, 0, 0);
}
v4 = *((_WORD *)v3 + 1);
v5 = *(unsigned short *)v3 * v4;
v6 = (unsigned short)(2 * *(_WORD *)v3);
v7 = (unsigned short)(2 * v4);
v8 = &v3[2 * v5 + 4 + 2 * v7 * v6];
v14 = v8;
if (v7 > 0) {
v13 = v7;
startya = starty + 16;
do {
for (i = 0; i < v6; v14 += 2) {
if (*(_WORD *)v8) {
v10 = AddMonsterType(MonstConvTbl[*(unsigned short *)v8 - 1], 2); /* fix */
v11 = nummonsters++;
PlaceMonster(v11, v10, i + v12 + 16, startya);
}
v8 = v14 + 2;
++i;
}
++startya;
--v13;
} while (v13);
}
}
// 5CF31D: using guessed type char setlevel;
void __fastcall DeleteMonster(int i)
{
nummonsters--;
int temp = monstactive[nummonsters];
monstactive[nummonsters] = monstactive[i];
monstactive[i] = temp;
}
int __fastcall AddMonster(int x, int y, int dir, int mtype, int InMap)
{
if (nummonsters < MAXMONSTERS) {
int i = monstactive[nummonsters++];
if (InMap)
dMonster[x][y] = i + 1;
InitMonster(i, dir, mtype, x, y);
return i;
}
return -1;
}
void __fastcall NewMonsterAnim(int i, AnimStruct *anim, int md)
{
monster[i]._mAnimData = anim->Data[md];
monster[i]._mAnimCnt = 0;
monster[i]._mAnimLen = anim->Frames;
monster[i]._mAnimFrame = 1;
monster[i]._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL);
monster[i]._mAnimDelay = anim->Rate;
monster[i]._mdir = md;
}
BOOL __fastcall M_Ranged(int i)
{
char ai = monster[i]._mAi;
return ai == AI_SKELBOW || ai == AI_GOATBOW || ai == AI_SUCC || ai == AI_LAZHELP;
}
BOOL __fastcall M_Talker(int i)
{
char ai = monster[i]._mAi;
return ai == AI_LAZURUS
|| ai == AI_WARLORD
|| ai == AI_GARBUD
|| ai == AI_ZHAR
|| ai == AI_SNOTSPIL
|| ai == AI_LACHDAN
|| ai == AI_LAZHELP;
}
void __fastcall M_Enemy(int i)
{
MonsterStruct *v1; // esi
int *v2; // edi
int v3; // eax
int v4; // ecx
int v5; // ebx
int v6; // eax
int v7; // eax
int v8; // eax
int v9; // ecx
int v10; // edi
//int v11; // edx
int v12; // eax
int v13; // ecx
int v14; // ebx
int v15; // eax
int v16; // eax
int v17; // [esp+Ch] [ebp-20h]
int v18; // [esp+10h] [ebp-1Ch]
BOOL v19; // [esp+14h] [ebp-18h]
BOOL v20; // [esp+14h] [ebp-18h]
signed int v21; // [esp+18h] [ebp-14h]
int j; // [esp+18h] [ebp-14h]
signed int v23; // [esp+1Ch] [ebp-10h]
signed int v24; // [esp+20h] [ebp-Ch]
BOOL v25; // [esp+24h] [ebp-8h]
char v26; // [esp+2Ah] [ebp-2h]
char v27; // [esp+2Bh] [ebp-1h]
v24 = -1;
v18 = i;
v23 = -1;
v1 = &monster[i];
v25 = 0;
if (!(v1->_mFlags & MFLAG_GOLEM)) {
v21 = 0;
v2 = &plr[0].plrlevel;
do {
if (!*((_BYTE *)v2 - 23) || currlevel != *v2 || *((_BYTE *)v2 + 267) || !v2[89] && gbMaxPlayers != 1)
goto LABEL_18;
v3 = v1->_my;
v4 = v2[2];
v19 = dung_map[v2[1]][v4] == dung_map[v1->_mx][v3];
v5 = abs(v3 - v4);
if (abs(v1->_mx - v2[1]) <= v5)
v6 = v1->_my - v2[2];
else
v6 = v1->_mx - v2[1];
v7 = abs(v6);
if (v19) {
if (!v25)
goto LABEL_17;
} else if (v25) {
goto LABEL_16;
}
if (v7 < v23)
goto LABEL_17;
LABEL_16:
if (v24 == -1) {
LABEL_17:
v1->_mFlags &= ~MFLAG_TARGETS_MONSTER;
v24 = v21;
v27 = *((_BYTE *)v2 + 12);
v26 = *((_BYTE *)v2 + 16);
v23 = v7;
v25 = v19;
}
LABEL_18:
++v21;
v2 += 5430;
} while ((signed int)v2 < (signed int)&plr[4].plrlevel);
}
v8 = 0;
for (j = 0; j < nummonsters; v8 = j++ + 1) {
v9 = monstactive[v8];
v17 = monstactive[v8];
if (v9 == v18)
continue;
v10 = v9;
if (monster[v9]._mx == 1 && !monster[v10]._my)
continue;
if (M_Talker(v9) && monster[v10].mtalkmsg)
continue;
if (!(v1->_mFlags & MFLAG_GOLEM)
&& ((abs(monster[v10]._mx - v1->_mx) >= 2 || abs(monster[v10]._my - v1->_my) >= 2) && !M_Ranged(v18) /* v11 */
|| !(v1->_mFlags & MFLAG_GOLEM) && !(monster[v10]._mFlags & MFLAG_GOLEM))) {
continue;
}
v12 = v1->_my;
v13 = monster[v10]._my;
v20 = dung_map[monster[v10]._mx][v13] == dung_map[v1->_mx][v12];
v14 = abs(v12 - v13);
if (abs(v1->_mx - monster[v10]._mx) <= v14)
v15 = v1->_my - monster[v10]._my;
else
v15 = v1->_mx - monster[v10]._mx;
v16 = abs(v15);
if (v20) {
if (!v25)
goto LABEL_40;
} else if (v25) {
goto LABEL_39;
}
if (v16 < v23)
goto LABEL_40;
LABEL_39:
if (v24 == -1) {
LABEL_40:
v1->_mFlags |= MFLAG_TARGETS_MONSTER;
v24 = v17;
v27 = monster[v10]._mfutx;
v26 = monster[v10]._mfuty;
v23 = v16;
v25 = v20;
}
}
if (v24 == -1) {
v1->_mFlags |= MFLAG_NO_ENEMY;
} else {
v1->_mFlags &= ~MFLAG_NO_ENEMY;
v1->_menemy = v24;
v1->_menemyx = v27;
v1->_menemyy = v26;
}
}
// 679660: using guessed type char gbMaxPlayers;
int __fastcall M_GetDir(int i)
{
return GetDirection(monster[i]._mx, monster[i]._my, monster[i]._menemyx, monster[i]._menemyy);
}
void __fastcall M_CheckEFlag(int i)
{
int v1; // ecx
int v2; // edi
char *v3; // eax
signed int v4; // edx
v1 = i;
v2 = 0;
v3 = (char *)dpiece_defs_map_2 + 32 * (112 * (monster[v1]._mx - 1) + monster[v1]._my + 1);
if (v3 < (char *)dpiece_defs_map_2)
goto LABEL_9;
v4 = 2;
do
v2 |= *(unsigned short *)&v3[2 * v4++];
while (v4 < 10);
if (v2 | dArch[monster[v1]._mx - 1][monster[v1]._my + 1])
monster[v1]._meflag = 1;
else
LABEL_9:
monster[v1]._meflag = 0;
}
void __fastcall M_StartStand(int i, int md)
{
ClearMVars(i);
if (monster[i].MType->mtype == MT_GOLEM)
NewMonsterAnim(i, &monster[i].MType->Anims[MA_WALK], md);
else
NewMonsterAnim(i, &monster[i].MType->Anims[MA_STAND], md);
monster[i]._mVar1 = monster[i]._mmode;
monster[i]._mVar2 = 0;
monster[i]._mmode = MM_STAND;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
M_Enemy(i);
}
void __fastcall M_StartDelay(int i, int len)
{
if (len <= 0) {
return;
}
if (monster[i]._mAi != AI_LAZURUS) {
monster[i]._mVar2 = len;
monster[i]._mmode = MM_DELAY;
}
}
void __fastcall M_StartSpStand(int i, int md)
{
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], md);
monster[i]._mmode = MM_SPSTAND;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
}
void __fastcall M_StartWalk(int i, int xvel, int yvel, int xadd, int yadd, int EndDir)
{
int fx = xadd + monster[i]._mx;
int fy = yadd + monster[i]._my;
dMonster[fx][fy] = -(i + 1);
monster[i]._mmode = MM_WALK;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mfutx = fx;
monster[i]._mfuty = fy;
monster[i]._mxvel = xvel;
monster[i]._myvel = yvel;
monster[i]._mVar1 = xadd;
monster[i]._mVar2 = yadd;
monster[i]._mVar3 = EndDir;
monster[i]._mdir = EndDir;
NewMonsterAnim(i, &monster[i].MType->Anims[MA_WALK], EndDir);
monster[i]._mVar6 = 0;
monster[i]._mVar7 = 0;
monster[i]._mVar8 = 0;
M_CheckEFlag(i);
}
void __fastcall M_StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir)
{
int fx = xadd + monster[i]._mx;
int fy = yadd + monster[i]._my;
dMonster[monster[i]._mx][monster[i]._my] = -(i + 1);
monster[i]._mVar1 = monster[i]._mx;
monster[i]._mVar2 = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mx = fx;
monster[i]._my = fy;
monster[i]._mfutx = fx;
monster[i]._mfuty = fy;
dMonster[fx][fy] = i + 1;
if (monster[i]._uniqtype != 0)
ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my);
monster[i]._mxoff = xoff;
monster[i]._myoff = yoff;
monster[i]._mmode = MM_WALK2;
monster[i]._mxvel = xvel;
monster[i]._myvel = yvel;
monster[i]._mVar3 = EndDir;
monster[i]._mdir = EndDir;
NewMonsterAnim(i, &monster[i].MType->Anims[MA_WALK], EndDir);
monster[i]._mVar6 = 16 * xoff;
monster[i]._mVar7 = 16 * yoff;
monster[i]._mVar8 = 0;
M_CheckEFlag(i);
}
void __fastcall M_StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir)
{
int fx = xadd + monster[i]._mx;
int fy = yadd + monster[i]._my;
int x = mapx + monster[i]._mx;
int y = mapy + monster[i]._my;
if (monster[i]._uniqtype != 0)
ChangeLightXY(monster[i].mlid, x, y);
dMonster[monster[i]._mx][monster[i]._my] = -(i + 1);
dMonster[fx][fy] = -(i + 1);
monster[i]._mVar4 = x;
monster[i]._mVar5 = y;
dFlags[x][y] |= DFLAG_MONSTER;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mfutx = fx;
monster[i]._mfuty = fy;
monster[i]._mxoff = xoff;
monster[i]._myoff = yoff;
monster[i]._mmode = MM_WALK3;
monster[i]._mxvel = xvel;
monster[i]._myvel = yvel;
monster[i]._mVar1 = fx;
monster[i]._mVar2 = fy;
monster[i]._mVar3 = EndDir;
monster[i]._mdir = EndDir;
NewMonsterAnim(i, &monster[i].MType->Anims[MA_WALK], EndDir);
monster[i]._mVar6 = 16 * xoff;
monster[i]._mVar7 = 16 * yoff;
monster[i]._mVar8 = 0;
M_CheckEFlag(i);
}
void __fastcall M_StartAttack(int i)
{
int md = M_GetDir(i);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_ATTACK], md);
monster[i]._mmode = MM_ATTACK;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
}
void __fastcall M_StartRAttack(int i, int missile_type, int dam)
{
int md = M_GetDir(i);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_ATTACK], md);
monster[i]._mmode = MM_RATTACK;
monster[i]._mVar1 = missile_type;
monster[i]._mVar2 = dam;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
}
void __fastcall M_StartRSpAttack(int i, int missile_type, int dam)
{
int md = M_GetDir(i);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], md);
monster[i]._mmode = MM_RSPATTACK;
monster[i]._mVar1 = missile_type;
monster[i]._mVar2 = 0;
monster[i]._mVar3 = dam;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
}
void __fastcall M_StartSpAttack(int i)
{
int md = M_GetDir(i);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], md);
monster[i]._mmode = MM_SATTACK;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
monster[i]._mdir = md;
M_CheckEFlag(i);
}
void __fastcall M_StartEat(int i)
{
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], monster[i]._mdir);
monster[i]._mmode = MM_SATTACK;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
M_CheckEFlag(i);
}
void __fastcall M_ClearSquares(int i)
{
int mx = monster[i]._moldx;
int my = monster[i]._moldy;
int m1 = -1 - i;
int m2 = i + 1;
for (int y = my - 1; y <= my + 1; y++) {
if (y >= 0 && y < MAXDUNY) {
for (int x = mx - 1; x <= mx + 1; x++) {
if (x >= 0 && x < MAXDUNX && (dMonster[x][y] == m1 || dMonster[x][y] == m2))
dMonster[x][y] = 0;
}
}
}
if (mx + 1 < MAXDUNX)
dFlags[mx + 1][my] &= ~DFLAG_MONSTER;
if (my + 1 < MAXDUNY)
dFlags[mx][my + 1] &= ~DFLAG_MONSTER;
}
void __fastcall M_GetKnockback(int i)
{
int d = (monster[i]._mdir - 4) & 7;
if (DirOK(i, d)) {
M_ClearSquares(i);
monster[i]._moldx += offset_x[d];
monster[i]._moldy += offset_y[d];
NewMonsterAnim(i, &monster[i].MType->Anims[MA_GOTHIT], monster[i]._mdir);
monster[i]._mmode = MM_GOTHIT;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mx = monster[i]._moldx;
monster[i]._my = monster[i]._moldy;
monster[i]._mfutx = monster[i]._moldx;
monster[i]._mfuty = monster[i]._moldy;
M_CheckEFlag(i);
M_ClearSquares(i);
dMonster[monster[i]._mx][monster[i]._my] = i + 1;
}
}
void __fastcall M_StartHit(int i, int pnum, int dam)
{
if (pnum >= 0)
monster[i].mWhoHit |= 1 << pnum;
if (pnum == myplr) {
delta_monster_hp(i, monster[i]._mhitpoints, currlevel);
NetSendCmdParam2(FALSE, CMD_MONSTDAMAGE, i, dam);
}
PlayEffect(i, 1);
if (monster[i].MType->mtype >= MT_SNEAK && monster[i].MType->mtype <= MT_ILLWEAV || dam >> 6 >= monster[i].mLevel + 3) {
if (pnum >= 0) {
monster[i]._mFlags &= ~MFLAG_TARGETS_MONSTER;
monster[i]._menemy = pnum;
monster[i]._menemyx = plr[pnum]._px;
monster[i]._menemyy = plr[pnum]._py;
monster[i]._mdir = M_GetDir(i);
}
if (monster[i].MType->mtype == MT_BLINK) {
M_Teleport(i);
} else if (monster[i].MType->mtype >= MT_NSCAV && monster[i].MType->mtype <= MT_YSCAV) {
monster[i]._mgoal = MGOAL_NORMAL;
}
if (monster[i]._mmode != MM_STONE) {
NewMonsterAnim(i, &monster[i].MType->Anims[MA_GOTHIT], monster[i]._mdir);
monster[i]._mmode = MM_GOTHIT;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mx = monster[i]._moldx;
monster[i]._my = monster[i]._moldy;
monster[i]._mfutx = monster[i]._moldx;
monster[i]._mfuty = monster[i]._moldy;
M_CheckEFlag(i);
M_ClearSquares(i);
dMonster[monster[i]._mx][monster[i]._my] = i + 1;
}
}
}
void __fastcall M_DiabloDeath(int i, BOOL sendmsg)
{
int v2; // esi
int v3; // edi
int v4; // eax
int v5; // ebx
int v6; // esi
int v7; // ecx
int v8; // eax
int v9; // esi
int v10; // eax
double v11; // st7
int v12; // eax
int v13; // ecx
int v14; // esi
int v15; // [esp+8h] [ebp-8h]
int j; // [esp+Ch] [ebp-4h]
int v17; // [esp+Ch] [ebp-4h]
v15 = i;
v2 = sendmsg;
v3 = i;
PlaySFX(USFX_DIABLOD);
quests[QTYPE_MOD]._qactive = 3;
if (v2)
NetSendCmdQuest(TRUE, 5u);
gbProcessPlayers = FALSE;
_LOBYTE(sgbSaveSoundOn) = gbSoundOn;
v4 = 0;
for (j = 0; j < nummonsters; ++j) {
v5 = monstactive[v4];
if (v5 != v15 && monster[v3]._msquelch) {
v6 = v5;
NewMonsterAnim(monstactive[v4], &monster[v5].MType->Anims[MA_DEATH], monster[v5]._mdir);
v7 = monster[v5]._moldy;
monster[v6]._mxoff = 0;
monster[v6]._myoff = 0;
monster[v6]._mVar1 = 0;
v8 = monster[v5]._moldx;
monster[v6]._my = v7;
monster[v6]._mfuty = v7;
monster[v6]._mmode = MM_DEATH;
monster[v6]._mx = v8;
monster[v6]._mfutx = v8;
M_CheckEFlag(v5);
M_ClearSquares(v5);
dMonster[monster[v6]._mx][monster[v6]._my] = v5 + 1;
}
v4 = j + 1;
}
AddLight(monster[v3]._mx, monster[v3]._my, 8);
DoVision(monster[v3]._mx, monster[v3]._my, 8, 0, 1);
v9 = abs(ViewY - monster[v3]._my);
if (abs(ViewX - monster[v3]._mx) <= v9)
v10 = ViewY - monster[v3]._my;
else
v10 = ViewX - monster[v3]._mx;
v17 = abs(v10);
if (v17 > 20)
v17 = 20;
v11 = (double)v17;
v12 = ViewX << 16;
v13 = monster[v3]._mx << 16;
monster[v3]._mVar3 = ViewX << 16;
v14 = ViewY << 16;
monster[v3]._mVar4 = ViewY << 16;
monster[v3]._mVar5 = (signed __int64)((double)(v12 - v13) / v11);
monster[v3]._mVar6 = (signed __int64)((double)(v14 - (monster[v3]._my << 16)) / v11);
}
// 64D32C: using guessed type int sgbSaveSoundOn;
void __fastcall M2MStartHit(int mid, int i, int dam)
{
if ((DWORD)mid >= MAXMONSTERS) {
TermMsg("Invalid monster %d getting hit by monster", mid);
}
if (monster[mid].MType == NULL) {
TermMsg("Monster %d \"%s\" getting hit by monster: MType NULL", mid, monster[mid].mName);
}
if (i >= 0)
monster[i].mWhoHit |= 1 << i;
delta_monster_hp(mid, monster[mid]._mhitpoints, currlevel);
NetSendCmdParam2(FALSE, CMD_MONSTDAMAGE, mid, dam);
PlayEffect(mid, 1);
if (monster[mid].MType->mtype >= MT_SNEAK && monster[mid].MType->mtype <= MT_ILLWEAV || dam >> 6 >= monster[mid].mLevel + 3) {
if (i >= 0)
monster[mid]._mdir = (monster[i]._mdir - 4) & 7;
if (monster[mid].MType->mtype == MT_BLINK) {
M_Teleport(mid);
} else if (monster[mid].MType->mtype >= MT_NSCAV && monster[mid].MType->mtype <= MT_YSCAV) {
monster[mid]._mgoal = MGOAL_NORMAL;
}
if (monster[mid]._mmode != MM_STONE) {
if (monster[mid].MType->mtype != MT_GOLEM) {
NewMonsterAnim(mid, &monster[mid].MType->Anims[MA_GOTHIT], monster[mid]._mdir);
monster[mid]._mmode = MM_GOTHIT;
}
monster[mid]._mxoff = 0;
monster[mid]._myoff = 0;
monster[mid]._mx = monster[mid]._moldx;
monster[mid]._my = monster[mid]._moldy;
monster[mid]._mfutx = monster[mid]._moldx;
monster[mid]._mfuty = monster[mid]._moldy;
M_CheckEFlag(mid);
M_ClearSquares(mid);
dMonster[monster[mid]._mx][monster[mid]._my] = mid + 1;
}
}
}
void __fastcall MonstStartKill(int i, int pnum, BOOL sendmsg)
{
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("MonstStartKill: Invalid monster %d", i);
}
if (!monster[i].MType) {
TermMsg("MonstStartKill: Monster %d \"%s\" MType NULL", i, monster[i].mName);
}
if (pnum >= 0)
monster[i].mWhoHit |= 1 << pnum;
if (pnum < 4 && i > 4)
AddPlrMonstExper(monster[i].mLevel, monster[i].mExp, monster[i].mWhoHit);
monstkills[monster[i].MType->mtype]++;
monster[i]._mhitpoints = 0;
SetRndSeed(monster[i]._mRndSeed);
if (QuestStatus(QTYPE_GARB) && monster[i].mName == UniqMonst[0].mName) {
CreateTypeItem(monster[i]._mx + 1, monster[i]._my + 1, TRUE, 4, FALSE, TRUE, FALSE);
} else if (i > 3) {
SpawnItem(i, monster[i]._mx, monster[i]._my, sendmsg);
}
if (monster[i].MType->mtype == MT_DIABLO)
M_DiabloDeath(i, TRUE);
else
PlayEffect(i, 2);
int md;
if (pnum >= 0)
md = M_GetDir(i);
else
md = monster[i]._mdir;
monster[i]._mdir = md;
NewMonsterAnim(i, &monster[i].MType->Anims[MA_DEATH], md);
monster[i]._mmode = MM_DEATH;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mVar1 = 0;
monster[i]._mx = monster[i]._moldx;
monster[i]._my = monster[i]._moldy;
monster[i]._mfutx = monster[i]._moldx;
monster[i]._mfuty = monster[i]._moldy;
M_CheckEFlag(i);
M_ClearSquares(i);
dMonster[monster[i]._mx][monster[i]._my] = i + 1;
CheckQuestKill(i, sendmsg);
M_FallenFear(monster[i]._mx, monster[i]._my);
if (monster[i].MType->mtype >= MT_NACID && monster[i].MType->mtype <= MT_XACID)
AddMissile(monster[i]._mx, monster[i]._my, 0, 0, 0, MIS_ACIDPUD, 1, i, monster[i]._mint + 1, 0);
}
void __fastcall M2MStartKill(int i, int mid)
{
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("M2MStartKill: Invalid monster (attacker) %d", i);
TermMsg("M2MStartKill: Invalid monster (killed) %d", mid);
}
if (!monster[i].MType)
TermMsg("M2MStartKill: Monster %d \"%s\" MType NULL", mid, monster[mid].mName);
delta_kill_monster(mid, monster[mid]._mx, monster[mid]._my, currlevel);
NetSendCmdLocParam1(FALSE, CMD_MONSTDEATH, monster[mid]._mx, monster[mid]._my, mid);
monster[mid].mWhoHit |= 1 << i;
if (i < 4)
AddPlrMonstExper(monster[mid].mLevel, monster[mid].mExp, monster[mid].mWhoHit);
monstkills[monster[mid].MType->mtype]++;
monster[mid]._mhitpoints = 0;
SetRndSeed(monster[mid]._mRndSeed);
if (mid >= 4)
SpawnItem(mid, monster[mid]._mx, monster[mid]._my, TRUE);
if (monster[mid].MType->mtype == MT_DIABLO)
M_DiabloDeath(mid, TRUE);
else
PlayEffect(i, 2);
PlayEffect(mid, 2);
int md = (monster[i]._mdir - 4) & 7;
if (monster[mid].MType->mtype == MT_GOLEM)
md = 0;
monster[mid]._mdir = md;
NewMonsterAnim(mid, &monster[mid].MType->Anims[MA_DEATH], md);
monster[mid]._mmode = MM_DEATH;
monster[mid]._mxoff = 0;
monster[mid]._myoff = 0;
monster[mid]._mx = monster[mid]._moldx;
monster[mid]._my = monster[mid]._moldy;
monster[mid]._mfutx = monster[mid]._moldx;
monster[mid]._mfuty = monster[mid]._moldy;
M_CheckEFlag(mid);
M_ClearSquares(mid);
dMonster[monster[mid]._mx][monster[mid]._my] = mid + 1;
CheckQuestKill(mid, TRUE);
M_FallenFear(monster[mid]._mx, monster[mid]._my);
if (monster[mid].MType->mtype >= MT_NACID && monster[mid].MType->mtype <= MT_XACID)
AddMissile(monster[mid]._mx, monster[mid]._my, 0, 0, 0, MIS_ACIDPUD, 1, mid, monster[mid]._mint + 1, 0);
}
void __fastcall M_StartKill(int i, int pnum)
{
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("M_StartKill: Invalid monster %d", i);
}
if (myplr == pnum) {
delta_kill_monster(i, monster[i]._mx, monster[i]._my, currlevel);
if (i != pnum) {
NetSendCmdLocParam1(FALSE, CMD_MONSTDEATH, monster[i]._mx, monster[i]._my, i);
} else {
NetSendCmdLocParam1(FALSE, CMD_KILLGOLEM, monster[i]._mx, monster[i]._my, currlevel);
}
}
MonstStartKill(i, pnum, TRUE);
}
void __fastcall M_SyncStartKill(int i, int x, int y, int pnum)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_SyncStartKill: Invalid monster %d", i);
if (monster[i]._mhitpoints == 0 || monster[i]._mmode == MM_DEATH) {
return;
}
if (dMonster[x][y] == 0) {
M_ClearSquares(i);
monster[i]._mx = x;
monster[i]._my = y;
monster[i]._moldx = x;
monster[i]._moldy = y;
}
if (monster[i]._mmode == MM_STONE) {
MonstStartKill(i, pnum, FALSE);
monster[i]._mmode = MM_STONE;
} else {
MonstStartKill(i, pnum, FALSE);
}
}
void __fastcall M_StartFadein(int i, int md, BOOL backwards)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_StartFadein: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_StartFadein: Monster %d \"%s\" MType NULL", i, monster[i].mName);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], md);
monster[i]._mmode = MM_FADEIN;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
M_CheckEFlag(i);
monster[i]._mdir = md;
monster[i]._mFlags &= ~MFLAG_HIDDEN;
if (backwards) {
monster[i]._mFlags |= MFLAG_LOCK_ANIMATION;
monster[i]._mAnimFrame = monster[i]._mAnimLen;
}
}
void __fastcall M_StartFadeout(int i, int md, BOOL backwards)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_StartFadeout: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_StartFadeout: Monster %d \"%s\" MType NULL", i, monster[i].mName);
NewMonsterAnim(i, &monster[i].MType->Anims[MA_SPECIAL], md);
monster[i]._mmode = MM_FADEOUT;
monster[i]._mxoff = 0;
monster[i]._myoff = 0;
monster[i]._mfutx = monster[i]._mx;
monster[i]._mfuty = monster[i]._my;
monster[i]._moldx = monster[i]._mx;
monster[i]._moldy = monster[i]._my;
M_CheckEFlag(i);
monster[i]._mdir = md;
if (backwards) {
monster[i]._mFlags |= MFLAG_LOCK_ANIMATION;
monster[i]._mAnimFrame = monster[i]._mAnimLen;
}
}
void __fastcall M_StartHeal(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_StartHeal: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_StartHeal: Monster %d \"%s\" MType NULL", i, monster[i].mName);
MonsterStruct *Monst = &monster[i];
Monst->_mAnimData = Monst->MType->Anims[MA_SPECIAL].Data[Monst->_mdir];
Monst->_mAnimFrame = Monst->MType->Anims[MA_SPECIAL].Frames;
Monst->_mFlags |= MFLAG_LOCK_ANIMATION;
Monst->_mmode = MM_HEAL;
Monst->_mVar1 = Monst->_mmaxhp / (16 * (random(97, 5) + 4));
}
void __fastcall M_ChangeLightOffset(int monst)
{
if ((DWORD)monst >= MAXMONSTERS)
TermMsg("M_ChangeLightOffset: Invalid monster %d", monst);
int lx = monster[monst]._mxoff + 2 * monster[monst]._myoff;
int ly = 2 * monster[monst]._myoff - monster[monst]._mxoff;
int sign;
if (lx < 0) {
sign = -1;
lx = -lx;
} else {
sign = 1;
}
int _mxoff = sign * (lx >> 3);
int _myoff;
if (ly < 0) {
_myoff = -1;
ly = -ly;
} else {
_myoff = 1;
}
ChangeLightOff(monster[monst].mlid, _mxoff, _myoff * (ly >> 3));
}
int __fastcall M_DoStand(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoStand: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoStand: Monster %d \"%s\" MType NULL", i, monster[i].mName);
MonsterStruct *Monst = &monster[i];
if (Monst->MType->mtype == MT_GOLEM)
Monst->_mAnimData = Monst->MType->Anims[MA_WALK].Data[Monst->_mdir];
else
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir];
if (Monst->_mAnimFrame == Monst->_mAnimLen)
M_Enemy(i);
Monst->_mVar2++;
return FALSE;
}
BOOL __fastcall M_DoWalk(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoWalk: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoWalk: Monster %d \"%s\" MType NULL", i, monster[i].mName);
BOOL rv = FALSE;
if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) {
dMonster[monster[i]._mx][monster[i]._my] = 0;
monster[i]._mx += monster[i]._mVar1;
monster[i]._my += monster[i]._mVar2;
dMonster[monster[i]._mx][monster[i]._my] = i + 1;
if (monster[i]._uniqtype != 0)
ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my);
M_StartStand(i, monster[i]._mdir);
rv = TRUE;
} else if (!monster[i]._mAnimCnt) {
monster[i]._mVar8++;
monster[i]._mVar6 += monster[i]._mxvel;
monster[i]._mVar7 += monster[i]._myvel;
monster[i]._mxoff = monster[i]._mVar6 >> 4;
monster[i]._myoff = monster[i]._mVar7 >> 4;
}
if (monster[i]._uniqtype != 0)
M_ChangeLightOffset(i);
return rv;
}
BOOL __fastcall M_DoWalk2(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoWalk2: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoWalk2: Monster %d \"%s\" MType NULL", i, monster[i].mName);
BOOL rv;
if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) {
dMonster[monster[i]._mVar1][monster[i]._mVar2] = 0;
if (monster[i]._uniqtype != 0)
ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my);
M_StartStand(i, monster[i]._mdir);
rv = TRUE;
} else {
if (!monster[i]._mAnimCnt) {
monster[i]._mVar8++;
monster[i]._mVar6 += monster[i]._mxvel;
monster[i]._mVar7 += monster[i]._myvel;
monster[i]._mxoff = monster[i]._mVar6 >> 4;
monster[i]._myoff = monster[i]._mVar7 >> 4;
}
rv = FALSE;
}
if (monster[i]._uniqtype != 0)
M_ChangeLightOffset(i);
return rv;
}
BOOL __fastcall M_DoWalk3(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoWalk3: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoWalk3: Monster %d \"%s\" MType NULL", i, monster[i].mName);
BOOL rv;
if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) {
dMonster[monster[i]._mx][monster[i]._my] = 0;
monster[i]._mx = monster[i]._mVar1;
monster[i]._my = monster[i]._mVar2;
dFlags[monster[i]._mVar4][monster[i]._mVar5] &= ~DFLAG_MONSTER;
dMonster[monster[i]._mx][monster[i]._my] = i + 1;
if (monster[i]._uniqtype)
ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my);
M_StartStand(i, monster[i]._mdir);
rv = TRUE;
} else {
if (!monster[i]._mAnimCnt) {
monster[i]._mVar8++;
monster[i]._mVar6 += monster[i]._mxvel;
monster[i]._mVar7 += monster[i]._myvel;
monster[i]._mxoff = monster[i]._mVar6 >> 4;
monster[i]._myoff = monster[i]._mVar7 >> 4;
}
rv = FALSE;
}
if (monster[i]._uniqtype != 0)
M_ChangeLightOffset(i);
return rv;
}
void __fastcall M_TryM2MHit(int i, int mid, int hper, int mind, int maxd)
{
if ((DWORD)mid >= MAXMONSTERS) {
TermMsg("M_TryM2MHit: Invalid monster %d", mid);
}
if (monster[mid].MType == NULL)
TermMsg("M_TryM2MHit: Monster %d \"%s\" MType NULL", mid, monster[mid].mName);
if (monster[mid]._mhitpoints >> 6 > 0 && (monster[mid].MType->mtype != MT_ILLWEAV || monster[mid]._mgoal != MGOAL_RETREAT)) {
int hit = random(4, 100);
if (monster[mid]._mmode == MM_STONE)
hit = 0;
BOOL ret;
if (!CheckMonsterHit(mid, &ret) && hit < hper) {
int dam = (mind + random(5, maxd - mind + 1)) << 6;
monster[mid]._mhitpoints -= dam;
if (monster[mid]._mhitpoints >> 6 <= 0) {
if (monster[mid]._mmode == MM_STONE) {
M2MStartKill(i, mid);
monster[mid]._mmode = MM_STONE;
} else {
M2MStartKill(i, mid);
}
} else {
if (monster[mid]._mmode == MM_STONE) {
M2MStartHit(mid, i, dam);
monster[mid]._mmode = MM_STONE;
} else {
M2MStartHit(mid, i, dam);
}
}
}
}
}
void __fastcall M_TryH2HHit(int i, int pnum, int Hit, int MinDam, int MaxDam)
{
int v5; // esi
int v6; // ebx
int v7; // esi
int v8; // edi
int v9; // eax
//int v10; // ST08_4
int v12; // ecx
int v13; // edi
int v14; // eax
int v15; // eax
int *v16; // ecx
int v17; // eax
int v18; // edi
int v19; // edx
int v20; // eax
int v21; // eax
int v22; // edx
int v23; // eax
BOOLEAN v24; // zf
BOOLEAN v25; // sf
unsigned char v26; // of
int v27; // eax
int v29; // edi
int v30; // eax
int v31; // eax
int v32; // eax
int v33; // edi
int v34; // ebx
int v35; // edx
int v36; // [esp+Ch] [ebp-Ch]
int arglist; // [esp+10h] [ebp-8h]
int plr_num; // [esp+14h] [ebp-4h]
int hper; // [esp+20h] [ebp+8h]
v5 = i;
plr_num = pnum;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_TryH2HHit: Invalid monster %d", i);
v6 = v5;
if (monster[v5].MType == NULL)
TermMsg("M_TryH2HHit: Monster %d \"%s\" MType NULL", v5, monster[v6].mName);
if (monster[v6]._mFlags & MFLAG_TARGETS_MONSTER) {
M_TryM2MHit(v5, plr_num, Hit, MinDam, MaxDam);
return;
}
v7 = plr_num;
if (plr[plr_num]._pHitPoints >> 6 > 0 && !plr[v7]._pInvincible && !(plr[v7]._pSpellFlags & 1)) {
v8 = abs(monster[v6]._mx - plr[v7].WorldX);
v9 = abs(monster[v6]._my - plr[v7].WorldY);
//v11 = v10;
if (v8 < 2 && v9 < 2) {
v36 = random(98, 100);
#ifdef _DEBUG
if (debug_mode_dollar_sign || debug_mode_key_inverted_v)
v36 = 1000;
#endif
v12 = 5;
v13 = Hit
+ 2 * (SLOBYTE(monster[v6].mLevel) - plr[v7]._pLevel)
+ 30
- plr[v7]._pIBonusAC
- plr[v7]._pIAC
- plr[v7]._pDexterity / 5;
if (v13 < 15)
v13 = 15;
if (currlevel == 14) {
if (v13 >= 20)
goto LABEL_23;
v13 = 20;
}
if (currlevel != 15) {
LABEL_20:
if (currlevel == 16 && v13 < 30)
v13 = 30;
goto LABEL_23;
}
if (v13 < 25) {
v13 = 25;
goto LABEL_20;
}
LABEL_23:
v14 = plr[v7]._pmode;
if (v14 && v14 != 4 || !plr[v7]._pBlockFlag) {
v15 = 100;
} else {
v15 = random(98, 100);
}
v16 = (int *)(plr[v7]._pDexterity
+ plr[v7]._pBaseToBlk
- 2 * SLOBYTE(monster[v6].mLevel)
+ 2 * plr[v7]._pLevel);
if ((signed int)v16 < 0)
v16 = 0;
if ((signed int)v16 > 100)
v16 = (int *)100;
if (v36 < v13) {
if (v15 >= (signed int)v16) {
if (monster[v6].MType->mtype == MT_YZOMBIE && plr_num == myplr) {
v18 = -1;
v19 = 0;
for (hper = -1; v19 < nummissiles; ++v19) {
v20 = missileactive[v19];
if (missile[v20]._mitype == MIS_MANASHIELD) {
if (missile[v20]._misource == plr_num) {
v18 = missileactive[v19];
hper = missileactive[v19];
} else {
v18 = hper;
}
}
}
v16 = &plr[v7]._pMaxHP;
v21 = plr[v7]._pMaxHP;
if (v21 > 64) {
v22 = plr[v7]._pMaxHPBase;
if (v22 > 64) {
v23 = v21 - 64;
v26 = __OFSUB__(plr[v7]._pHitPoints, v23);
v24 = plr[v7]._pHitPoints == v23;
v25 = plr[v7]._pHitPoints - v23 < 0;
*v16 = v23;
if (!((unsigned char)(v25 ^ v26) | v24)) {
plr[v7]._pHitPoints = v23;
if (v18 >= 0)
missile[v18]._miVar1 = v23;
}
v16 = &plr[v7]._pHPBase;
v27 = v22 - 64;
plr[v7]._pMaxHPBase = v22 - 64;
if (plr[v7]._pHPBase > v22 - 64) {
*v16 = v27;
if (v18 >= 0)
missile[v18]._miVar2 = v27;
}
}
}
}
v29 = (plr[v7]._pIGetHit << 6) + (MinDam << 6) + random(99, (MaxDam - MinDam + 1) << 6);
if (v29 < 64)
v29 = 64;
if (plr_num == myplr) {
plr[v7]._pHitPoints -= v29;
plr[v7]._pHPBase -= v29;
}
if (plr[v7]._pIFlags & ISPL_FASTERRECOVER) {
v30 = (random(99, 3) + 1) << 6;
monster[v6]._mhitpoints -= v30;
if (monster[v6]._mhitpoints >> 6 > 0)
M_StartHit(arglist, plr_num, v30);
else
M_StartKill(arglist, plr_num);
}
if (!(monster[v6]._mFlags & MFLAG_NOLIFESTEAL) && monster[v6].MType->mtype == MT_SKING && gbMaxPlayers != 1)
monster[v6]._mhitpoints += v29;
v31 = plr[v7]._pMaxHP;
if (plr[v7]._pHitPoints > v31) {
plr[v7]._pHitPoints = v31;
plr[v7]._pHPBase = plr[v7]._pMaxHPBase;
}
if (plr[v7]._pHitPoints >> 6 > 0) {
StartPlrHit(plr_num, v29, 0);
if (monster[v6]._mFlags & MFLAG_KNOCKBACK) {
if (plr[v7]._pmode != PM_GOTHIT)
StartPlrHit(plr_num, 0, 1u);
v32 = monster[v6]._mdir;
v33 = plr[v7].WorldX + offset_x[v32];
v34 = plr[v7].WorldY + offset_y[v32];
if (PosOkPlayer(plr_num, v33, v34)) {
v35 = plr[v7]._pdir;
plr[v7].WorldX = v33;
plr[v7].WorldY = v34;
FixPlayerLocation(plr_num, v35);
FixPlrWalkTags(plr_num);
dPlayer[v33][v34] = plr_num + 1;
SetPlayerOld(plr_num);
}
}
} else {
SyncPlrKill(plr_num, 0);
}
} else {
v17 = GetDirection(plr[v7].WorldX, plr[v7].WorldY, monster[v6]._mx, monster[v6]._my);
StartPlrBlock(plr_num, v17);
}
}
return;
}
}
}
// 679660: using guessed type char gbMaxPlayers;
BOOL __fastcall M_DoAttack(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoAttack: Invalid monster %d", i);
MonsterStruct *Monst = &monster[i];
if (Monst->MType == NULL)
TermMsg("M_DoAttack: Monster %d \"%s\" MType NULL", i, Monst->mName);
if (Monst->MType == NULL) // BUGFIX: should check MData
TermMsg("M_DoAttack: Monster %d \"%s\" MData NULL", i, Monst->mName);
if (monster[i]._mAnimFrame == monster[i].MData->mAFNum) {
M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit, monster[i].mMinDamage, monster[i].mMaxDamage);
if (monster[i]._mAi != AI_SNAKE)
PlayEffect(i, 0);
}
if (monster[i].MType->mtype >= MT_NMAGMA && monster[i].MType->mtype <= MT_WMAGMA && monster[i]._mAnimFrame == 9) {
M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit + 10, monster[i].mMinDamage - 2, monster[i].mMaxDamage - 2);
PlayEffect(i, 0);
}
if (monster[i].MType->mtype >= MT_STORM && monster[i].MType->mtype <= MT_MAEL && monster[i]._mAnimFrame == 13) {
M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit - 20, monster[i].mMinDamage + 4, monster[i].mMaxDamage + 4);
PlayEffect(i, 0);
}
if (monster[i]._mAi == AI_SNAKE && monster[i]._mAnimFrame == 1)
PlayEffect(i, 0);
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_DoRAttack(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoRAttack: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoRAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName);
if (monster[i].MType == NULL) // BUGFIX: should check MData
TermMsg("M_DoRAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName);
if (monster[i]._mAnimFrame == monster[i].MData->mAFNum) {
if (monster[i]._mVar1 != -1) {
int multimissiles;
if (monster[i]._mVar1 != MIS_CBOLT)
multimissiles = 1;
else
multimissiles = 3;
for (int mi = 0; mi < multimissiles; mi++) {
AddMissile(
monster[i]._mx,
monster[i]._my,
monster[i]._menemyx,
monster[i]._menemyy,
monster[i]._mdir,
monster[i]._mVar1,
1,
i,
monster[i]._mVar2,
0);
}
}
PlayEffect(i, 0);
}
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
int __fastcall M_DoRSpAttack(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoRSpAttack: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoRSpAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName);
if (monster[i].MType == NULL) // BUGFIX: should check MData
TermMsg("M_DoRSpAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName);
if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2 && !monster[i]._mAnimCnt) {
AddMissile(
monster[i]._mx,
monster[i]._my,
monster[i]._menemyx,
monster[i]._menemyy,
monster[i]._mdir,
monster[i]._mVar1,
1,
i,
monster[i]._mVar3,
0);
PlayEffect(i, 3);
}
if (monster[i]._mAi == AI_MEGA && monster[i]._mAnimFrame == 3) {
int hadV2 = monster[i]._mVar2;
monster[i]._mVar2++;
if (hadV2 == 0) {
monster[i]._mFlags |= MFLAG_ALLOW_SPECIAL;
} else if (monster[i]._mVar2 == 15) {
monster[i]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
}
}
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_DoSAttack(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoSAttack: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoSAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName);
if (monster[i].MType == NULL) // BUGFIX: should check MData
TermMsg("M_DoSAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName);
if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2)
M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit2, monster[i].mMinDamage2, monster[i].mMaxDamage2);
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_DoFadein(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoFadein: Invalid monster %d", i);
if ((!(monster[i]._mFlags & MFLAG_LOCK_ANIMATION) || monster[i]._mAnimFrame != 1)
&& (monster[i]._mFlags & MFLAG_LOCK_ANIMATION || monster[i]._mAnimFrame != monster[i]._mAnimLen)) {
return FALSE;
}
M_StartStand(i, monster[i]._mdir);
monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION;
return TRUE;
}
BOOL __fastcall M_DoFadeout(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoFadeout: Invalid monster %d", i);
if ((!(monster[i]._mFlags & MFLAG_LOCK_ANIMATION) || monster[i]._mAnimFrame != 1)
&& (monster[i]._mFlags & MFLAG_LOCK_ANIMATION || monster[i]._mAnimFrame != monster[i]._mAnimLen)) {
return FALSE;
}
int mt = monster[i].MType->mtype;
if (mt < MT_INCIN || mt > MT_HELLBURN) {
monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION;
monster[i]._mFlags |= MFLAG_HIDDEN;
} else {
monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION;
}
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
int __fastcall M_DoHeal(int i)
{
int v1; // esi
int v2; // eax
int v3; // esi
int *v4; // edx
int v5; // ecx
int v6; // edi
int v7; // edi
int v8; // esi
v1 = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoHeal: Invalid monster %d", i);
v2 = v1;
if (monster[v1]._mFlags & MFLAG_NOHEAL) {
monster[v2]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
monster[v2]._mmode = MM_SATTACK;
} else if (monster[v2]._mAnimFrame == 1) {
v3 = monster[v2]._mVar1;
v4 = &monster[v2]._mhitpoints;
v5 = monster[v2]._mFlags & ~MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL;
v6 = monster[v2]._mhitpoints;
monster[v2]._mFlags = v5;
v7 = v3 + v6;
v8 = monster[v2]._mmaxhp;
if (v7 >= v8) {
*v4 = v8;
monster[v2]._mFlags = v5 & ~MFLAG_ALLOW_SPECIAL;
monster[v2]._mmode = MM_SATTACK;
} else {
*v4 = v7;
}
}
return 0;
}
int __fastcall M_DoTalk(int i)
{
int v1; // edi
int v2; // esi
//int v3; // eax
int v4; // eax
int v5; // edx
int v6; // ecx
char v7; // bl
int v8; // eax
char *v9; // eax
v1 = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoTalk: Invalid monster %d", i);
v2 = v1;
M_StartStand(v1, monster[v1]._mdir);
_LOBYTE(monster[v1]._mgoal) = MGOAL_TALKING;
//_LOBYTE(v3) = effect_is_playing(alltext[monster[v1].mtalkmsg].sfxnr);
if (!effect_is_playing(alltext[monster[v1].mtalkmsg].sfxnr)) {
InitQTextMsg(monster[v2].mtalkmsg);
if (monster[v2].mName == UniqMonst[0].mName) {
v4 = monster[v2].mtalkmsg;
if (v4 == QUEST_GARBUD1)
quests[QTYPE_GARB]._qactive = 2;
quests[QTYPE_GARB]._qlog = 1;
if (v4 == QUEST_GARBUD2 && !(monster[v2]._mFlags & MFLAG_QUEST_COMPLETE)) {
SpawnItem(v1, monster[v2]._mx + 1, monster[v2]._my + 1, 1u);
monster[v2]._mFlags |= MFLAG_QUEST_COMPLETE;
}
}
if (monster[v2].mName == UniqMonst[2].mName
&& monster[v2].mtalkmsg == QUEST_ZHAR1
&& !(monster[v2]._mFlags & MFLAG_QUEST_COMPLETE)) {
v5 = monster[v2]._my + 1;
v6 = monster[v2]._mx + 1;
quests[QTYPE_ZHAR]._qactive = 2;
quests[QTYPE_ZHAR]._qlog = 1;
CreateTypeItem(v6, v5, 0, 0, 24, 1, 0);
monster[v2]._mFlags |= MFLAG_QUEST_COMPLETE;
}
if (monster[v2].mName == UniqMonst[3].mName) {
if (monster[v2].mtalkmsg == QUEST_BANNER10 && !(monster[v2]._mFlags & MFLAG_QUEST_COMPLETE)) {
ObjChangeMap(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 2, (setpc_h >> 1) + setpc_y - 2);
v7 = TransVal;
TransVal = 9;
DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1));
TransVal = v7;
quests[QTYPE_BOL]._qvar1 = 2;
if (quests[QTYPE_BOL]._qactive == 1)
quests[QTYPE_BOL]._qactive = 2;
monster[v2]._mFlags |= MFLAG_QUEST_COMPLETE;
}
if (quests[QTYPE_BOL]._qvar1 < 2u) {
sprintf(tempstr, "SS Talk = %i, Flags = %i", monster[v2].mtalkmsg, monster[v2]._mFlags);
TermMsg(tempstr);
}
}
if (monster[v2].mName == UniqMonst[7].mName) {
v8 = monster[v2].mtalkmsg;
if (v8 == QUEST_VEIL9) {
quests[QTYPE_VEIL]._qactive = 2;
quests[QTYPE_VEIL]._qlog = 1;
}
if (v8 == QUEST_VEIL11 && !(monster[v2]._mFlags & MFLAG_QUEST_COMPLETE)) {
SpawnUnique(UITEM_STEELVEIL, monster[v2]._mx + 1, monster[v2]._my + 1);
monster[v2]._mFlags |= MFLAG_QUEST_COMPLETE;
}
}
v9 = monster[v2].mName;
if (v9 == UniqMonst[8].mName)
quests[QTYPE_WARLRD]._qvar1 = 2;
if (v9 == UniqMonst[4].mName && gbMaxPlayers != 1) {
monster[v2]._msquelch = -1;
monster[v2].mtalkmsg = 0;
quests[QTYPE_VB]._qvar1 = 6;
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
}
return 0;
}
// 4351F5: could not find valid save-restore pair for ebp
// 5A5590: using guessed type char TransVal;
// 5CF330: using guessed type int setpc_h;
// 5CF334: using guessed type int setpc_w;
// 679660: using guessed type char gbMaxPlayers;
void __fastcall M_Teleport(int i)
{
BOOL tren;
MonsterStruct *Monst;
int k, j, x, y, _mx, _my, rx, ry;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_Teleport: Invalid monster %d", i);
tren = FALSE;
Monst = &monster[i];
if (Monst->_mmode != MM_STONE) {
_mx = Monst->_menemyx;
_my = Monst->_menemyy;
rx = 2 * random(100, 2) - 1;
ry = 2 * random(100, 2) - 1;
for (j = -1; j <= 1 && !tren; j++) {
for (k = -1; k < 1 && !tren; k++) {
if (j != 0 || k != 0) {
x = _mx + rx * j;
y = _my + ry * k;
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && x != Monst->_mx && y != Monst->_my) {
if (PosOkMonst(i, x, y))
tren = TRUE;
}
}
}
}
}
if (tren) {
M_ClearSquares(i);
dMonster[Monst->_mx][Monst->_my] = 0;
dMonster[x][y] = i + 1;
Monst->_moldx = x;
Monst->_moldy = y;
Monst->_mdir = M_GetDir(i);
M_CheckEFlag(i);
}
}
BOOL __fastcall M_DoGotHit(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoGotHit: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoGotHit: Monster %d \"%s\" MType NULL", i, monster[i].mName);
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
void __fastcall M_UpdateLeader(int i)
{
int ma;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_UpdateLeader: Invalid monster %d", i);
for (int j = 0; j < nummonsters; j++) {
ma = monstactive[j];
if (monster[ma].leaderflag == 1 && monster[ma].leader == i)
monster[ma].leaderflag = 0;
}
if (monster[i].leaderflag == 1) {
monster[monster[i].leader].packsize--;
}
}
void __cdecl DoEnding()
{
if (gbMaxPlayers > 1) {
SNetLeaveGame(0x40000004);
}
music_stop();
if (gbMaxPlayers > 1) {
Sleep(1000);
}
if (plr[myplr]._pClass == PC_WARRIOR) {
play_movie("gendata\\DiabVic2.smk", 0);
} else if (plr[myplr]._pClass == PC_SORCERER) {
play_movie("gendata\\DiabVic1.smk", 0);
} else {
play_movie("gendata\\DiabVic3.smk", 0);
}
play_movie("gendata\\Diabend.smk", 0);
BOOL bMusicOn = gbMusicOn;
gbMusicOn = TRUE;
int musicVolume = sound_get_or_set_music_volume(1);
sound_get_or_set_music_volume(0);
music_start(2);
loop_movie = TRUE;
play_movie("gendata\\loopdend.smk", 1);
loop_movie = FALSE;
music_stop();
sound_get_or_set_music_volume(musicVolume);
gbMusicOn = bMusicOn;
}
// 679660: using guessed type char gbMaxPlayers;
void __cdecl PrepDoEnding()
{
gbSoundOn = sgbSaveSoundOn;
gbRunGame = FALSE;
deathflag = FALSE;
cineflag = TRUE;
DWORD *killLevel = &plr[myplr].pDiabloKillLevel;
int newKillLevel = gnDifficulty + 1;
if (*killLevel > newKillLevel)
newKillLevel = *killLevel;
plr[myplr].pDiabloKillLevel = newKillLevel;
for (int i = 0; i < MAX_PLRS; i++) {
plr[i]._pmode = PM_QUIT;
plr[i]._pBlockFlag = TRUE;
if (gbMaxPlayers > 1) {
if (plr[i]._pHitPoints >> 6 == 0)
plr[i]._pHitPoints = 64;
if (plr[i]._pMana >> 6 == 0)
plr[i]._pMana = 64;
}
}
}
// 525718: using guessed type char cineflag;
// 64D32C: using guessed type int sgbSaveSoundOn;
// 679660: using guessed type char gbMaxPlayers;
BOOL __fastcall M_DoDeath(int i)
{
int var1;
int x, y;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoDeath: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoDeath: Monster %d \"%s\" MType NULL", i, monster[i].mName);
monster[i]._mVar1++;
var1 = monster[i]._mVar1;
if (monster[i].MType->mtype == MT_DIABLO) {
x = monster[i]._mx - ViewX;
if (x < 0)
x = -1;
else
x = x > 0;
ViewX += x;
y = monster[i]._my - ViewY;
if (y < 0) {
y = -1;
} else {
y = y > 0;
}
ViewY += y;
if (var1 == 140)
PrepDoEnding();
} else if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
if (monster[i]._uniqtype == 0)
AddDead(monster[i]._mx, monster[i]._my, monster[i].MType->mdeadval, (direction)monster[i]._mdir);
else
AddDead(monster[i]._mx, monster[i]._my, monster[i]._udeadval, (direction)monster[i]._mdir);
monster[i]._mDelFlag = TRUE;
dMonster[monster[i]._mx][monster[i]._my] = 0;
M_UpdateLeader(i);
}
return FALSE;
}
BOOL __fastcall M_DoSpStand(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoSpStand: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoSpStand: Monster %d \"%s\" MType NULL", i, monster[i].mName);
if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2)
PlayEffect(i, 3);
if (monster[i]._mAnimFrame == monster[i]._mAnimLen) {
M_StartStand(i, monster[i]._mdir);
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_DoDelay(int i)
{
int mVar2;
int oFrame;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoDelay: Invalid monster %d", i);
if (monster[i].MType == NULL)
TermMsg("M_DoDelay: Monster %d \"%s\" MType NULL", i, monster[i].mName);
monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[M_GetDir(i)];
if (monster[i]._mAi == AI_LAZURUS) {
if (monster[i]._mVar2 > 8 || monster[i]._mVar2 < 0)
monster[i]._mVar2 = 8;
}
mVar2 = monster[i]._mVar2;
monster[i]._mVar2--;
if (!mVar2) {
oFrame = monster[i]._mAnimFrame;
M_StartStand(i, monster[i]._mdir);
monster[i]._mAnimFrame = oFrame;
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_DoStone(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_DoStone: Invalid monster %d", i);
if (!monster[i]._mhitpoints) {
dMonster[monster[i]._mx][monster[i]._my] = 0;
monster[i]._mDelFlag = TRUE;
}
return FALSE;
}
void __fastcall M_WalkDir(int i, int md)
{
int mwi;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_WalkDir: Invalid monster %d", i);
mwi = monster[i].MType->Anims[MA_WALK].Frames - 1;
switch (md) {
case DIR_N:
M_StartWalk(i, 0, -MWVel[mwi][1], -1, -1, DIR_N);
break;
case DIR_NE:
M_StartWalk(i, MWVel[mwi][1], -MWVel[mwi][0], 0, -1, DIR_NE);
break;
case DIR_E:
M_StartWalk3(i, MWVel[mwi][2], 0, -32, -16, 1, -1, 1, 0, DIR_E);
break;
case DIR_SE:
M_StartWalk2(i, MWVel[mwi][1], MWVel[mwi][0], -32, -16, 1, 0, DIR_SE);
break;
case DIR_S:
M_StartWalk2(i, 0, MWVel[mwi][1], 0, -32, 1, 1, DIR_S);
break;
case DIR_SW:
M_StartWalk2(i, -MWVel[mwi][1], MWVel[mwi][0], 32, -16, 0, 1, DIR_SW);
break;
case DIR_W:
M_StartWalk3(i, -MWVel[mwi][2], 0, 32, -16, -1, 1, 0, 1, DIR_W);
break;
case DIR_NW:
M_StartWalk(i, -MWVel[mwi][1], -MWVel[mwi][0], -1, 0, DIR_NW);
break;
}
}
void __fastcall GroupUnity(int i)
{
int v1; // ebx
int v2; // esi
int v3; // ebp
int v4; // edi
BOOLEAN v5; // eax
int v6; // eax
unsigned char v8; // al
int v9; // ebp
int j; // edi
int v11; // eax
v1 = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("GroupUnity: Invalid monster %d", i);
v2 = v1;
if (monster[v1].leaderflag) {
v3 = (unsigned char)monster[v2].leader;
v4 = v3;
v5 = LineClearF(
CheckNoSolid,
monster[v2]._mx,
monster[v2]._my,
monster[v4]._mfutx,
monster[v4]._mfuty);
if (v5) {
if (monster[v2].leaderflag == 2
&& abs(monster[v2]._mx - monster[v4]._mfutx) < 4
&& abs(monster[v2]._my - monster[v4]._mfuty) < 4) {
++monster[v4].packsize;
monster[v2].leaderflag = 1;
}
} else {
if (monster[v2].leaderflag != 1)
goto LABEL_18;
--monster[v4].packsize;
monster[v2].leaderflag = 2;
}
} else {
v3 = 0; /* v13 */
}
if (monster[v2].leaderflag == 1) {
v6 = v3;
if (monster[v2]._msquelch > monster[v3]._msquelch) {
monster[v6]._lastx = monster[v2]._mx;
monster[v6]._lasty = monster[v2]._my;
monster[v6]._msquelch = monster[v2]._msquelch - 1;
}
if (monster[v6]._mAi == AI_GARG) {
if (monster[v6]._mFlags & MFLAG_ALLOW_SPECIAL) {
monster[v6]._mmode = MM_SATTACK;
monster[v6]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
}
}
return;
}
LABEL_18:
v8 = monster[v2]._uniqtype;
if (v8 != 0) {
if (UniqMonst[v8 - 1].mUnqAttr & 2) {
v9 = nummonsters;
for (j = 0; j < v9; ++j) {
v11 = monstactive[j];
if (monster[v11].leaderflag == 1 && (unsigned char)monster[v11].leader == v1) {
if (monster[v2]._msquelch > monster[v11]._msquelch) {
monster[v11]._lastx = monster[v2]._mx;
monster[v11]._lasty = monster[v2]._my;
monster[v11]._msquelch = monster[v2]._msquelch - 1;
}
if (monster[v11]._mAi == AI_GARG) {
if (monster[v11]._mFlags & MFLAG_ALLOW_SPECIAL) {
monster[v11]._mmode = MM_SATTACK;
monster[v11]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
}
}
}
}
}
}
}
BOOL __fastcall M_CallWalk(int i, int md)
{
int v2; // esi
int v3; // edi
int v4; // ebp
//int v5; // eax
BOOLEAN v7; // ebx
int v9; // ebx
//int v10; // eax
int v11; // ebx
//int v12; // eax
//int v13; // eax
signed int v14; // ebx
//int v15; // eax
//int v16; // eax
//int v17; // eax
unsigned char v18; // bl
v2 = md;
v3 = i;
v4 = md;
//_LOBYTE(v5) = DirOK(i, md);
v7 = DirOK(i, md);
if (random(101, 2)) {
if (v7)
goto LABEL_10;
v9 = v2;
v2 = left[v2];
//_LOBYTE(v10) = DirOK(v3, v2);
if (DirOK(v3, v2))
goto LABEL_10;
v2 = right[v9];
} else {
if (v7)
goto LABEL_10;
v11 = v2;
v2 = right[v2];
//_LOBYTE(v12) = DirOK(v3, v2);
if (DirOK(v3, v2))
goto LABEL_10;
v2 = left[v11];
}
//_LOBYTE(v13) = DirOK(v3, v2);
if (!DirOK(v3, v2)) {
v14 = 0;
goto LABEL_11;
}
LABEL_10:
v14 = 1;
LABEL_11:
if (random(102, 2)) {
if (v14)
goto LABEL_20;
v2 = right[right[v4]];
//_LOBYTE(v15) = DirOK(v3, v2);
if (DirOK(v3, v2))
goto LABEL_20;
v2 = left[left[v4]];
} else {
if (v14)
goto LABEL_20;
v2 = left[left[v4]];
//_LOBYTE(v16) = DirOK(v3, v2);
if (DirOK(v3, v2))
goto LABEL_20;
v2 = right[right[v4]];
}
//_LOBYTE(v17) = DirOK(v3, v2);
if (DirOK(v3, v2)) {
LABEL_20:
v18 = 1;
M_WalkDir(v3, v2);
return v18;
}
return 0;
}
BOOL __fastcall M_PathWalk(int i)
{
char path[25];
BOOL(__fastcall * Check)
(int, int, int);
if ((DWORD)i >= MAXMONSTERS)
TermMsg("M_PathWalk: Invalid monster %d", i);
Check = PosOkMonst3;
if (!(monster[i]._mFlags & MFLAG_CAN_OPEN_DOOR))
Check = PosOkMonst;
if (FindPath(Check, i, monster[i]._mx, monster[i]._my, monster[i]._menemyx, monster[i]._menemyy, path)) {
M_CallWalk(i, plr2monst[path[0]]); /* plr2monst is local */
return TRUE;
}
return FALSE;
}
BOOL __fastcall M_CallWalk2(int i, int md)
{
BOOL ok;
int mdtemp;
mdtemp = md;
ok = DirOK(i, md); // Can we continue in the same direction
if (random(101, 2)) { // Randomly go left or right
ok = ok || (mdtemp = left[md], DirOK(i, left[md])) || (mdtemp = right[md], DirOK(i, right[md]));
} else {
ok = ok || (mdtemp = right[md], DirOK(i, right[md])) || (mdtemp = left[md], DirOK(i, left[md]));
}
if (ok)
M_WalkDir(i, mdtemp);
return ok;
}
BOOL __fastcall M_DumbWalk(int i, int md)
{
BOOL ok;
ok = DirOK(i, md);
if (ok)
M_WalkDir(i, md);
return ok;
}
BOOLEAN __fastcall M_RoundWalk(int i, int md, int *dir)
{
int *v3; // ebp
int v4; // ebx
int v5; // esi
//int v6; // eax
BOOLEAN v7; // di
int v8; // edi
//int v9; // eax
//int v10; // eax
int *v11; // ebp
//int v12; // eax
//int v13; // eax
v3 = dir;
v4 = i;
if (*dir)
v5 = left[left[md]];
else
v5 = right[right[md]];
//_LOBYTE(v6) = DirOK(i, v5);
v7 = DirOK(i, v5);
if (v7)
goto LABEL_12;
v8 = v5;
if (!*dir) {
v11 = &left[v8];
v5 = left[v8];
//_LOBYTE(v12) = DirOK(v4, left[v8]);
if (DirOK(v4, left[v8]))
goto LABEL_11;
v5 = left[*v11];
//_LOBYTE(v13) = DirOK(v4, left[*v11]);
if (DirOK(v4, left[*v11]))
goto LABEL_11;
v3 = dir;
LABEL_14:
*v3 = *v3 == 0;
return M_CallWalk(v4, opposite[v8]);
}
v5 = right[v8];
//_LOBYTE(v9) = DirOK(v4, right[v8]);
if (!DirOK(v4, right[v8])) {
v5 = right[right[v8]];
//_LOBYTE(v10) = DirOK(v4, v5);
if (!DirOK(v4, v5))
goto LABEL_14;
}
LABEL_11:
v7 = 1;
LABEL_12:
M_WalkDir(v4, v5);
return v7;
}
void __fastcall MAI_Zombie(int i)
{
int v1; // esi
//int v2; // ST04_4
MonsterStruct *v3; // esi
int v4; // edi
int v5; // ebx
int v6; // edi
int v7; // eax
int v8; // ecx
int v9; // eax
int v10; // eax
int v11; // eax
int v12; // ecx
int md; // [esp+Ch] [ebp-Ch]
int v14; // [esp+10h] [ebp-8h]
int arglist; // [esp+14h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("MAI_Zombie: Invalid monster %d", i);
//i = v2;
}
v3 = &monster[v1];
if (v3->_mmode == MM_STAND) {
v4 = v3->_my;
if (dFlags[v3->_mx][v4] & DFLAG_VISIBLE) {
v5 = v3->_mx - (unsigned char)v3->_menemyx;
v6 = v4 - (unsigned char)v3->_menemyy;
md = v3->_mdir;
v14 = random(103, 100);
if (abs(v5) >= 2 || abs(v6) >= 2) {
if (v14 < 2 * (unsigned char)v3->_mint + 10) {
v7 = abs(v5);
v8 = 2 * (unsigned char)v3->_mint + 4;
if (v7 >= v8 || (v9 = abs(v6), v8 = 2 * (unsigned char)v3->_mint + 4, v9 >= v8)) {
v11 = random(104, 100);
v12 = 2 * (unsigned char)v3->_mint + 20;
if (v11 < v12) {
md = random(104, 8);
}
M_DumbWalk(arglist, md);
} else {
v10 = M_GetDir(arglist);
M_CallWalk(arglist, v10);
}
}
} else if (v14 < 2 * (unsigned char)v3->_mint + 10) {
M_StartAttack(arglist);
}
if (v3->_mmode == MM_STAND)
v3->_mAnimData = v3->MType->Anims[MA_STAND].Data[v3->_mdir];
}
}
}
void __fastcall MAI_SkelSd(int i)
{
MonsterStruct *Monst;
int mx, my, x, y, md;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_SkelSd: Invalid monster %d", i);
Monst = &monster[i];
if (Monst->_mmode == MM_STAND && Monst->_msquelch) {
mx = Monst->_mx;
my = Monst->_my;
x = mx - Monst->_menemyx;
y = my - Monst->_menemyy;
md = GetDirection(mx, my, Monst->_lastx, Monst->_lasty);
Monst->_mdir = md;
if (abs(x) >= 2 || abs(y) >= 2) {
if (Monst->_mVar1 == 13 || (random(106, 100) >= 35 - 4 * Monst->_mint)) {
M_CallWalk(i, md);
} else {
M_StartDelay(i, 15 - 2 * Monst->_mint + random(106, 10));
}
} else {
if (Monst->_mVar1 == 13 || (random(105, 100) < 2 * Monst->_mint + 20)) {
M_StartAttack(i);
} else {
M_StartDelay(i, 2 * (5 - Monst->_mint) + random(105, 10));
}
}
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
}
BOOL __fastcall MAI_Path(int i)
{
MonsterStruct *Monst;
BOOL clear;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Path: Invalid monster %d", i);
Monst = &monster[i];
if (Monst->MType->mtype != MT_GOLEM) {
if (!Monst->_msquelch)
return FALSE;
if (Monst->_mmode != MM_STAND)
return FALSE;
if (Monst->_mgoal != MGOAL_NORMAL && Monst->_mgoal != MGOAL_MOVE && Monst->_mgoal != MGOAL_SHOOT)
return FALSE;
if (Monst->_mx == 1 && Monst->_my == 0)
return FALSE;
}
clear = LineClearF1(
PosOkMonst2,
i,
Monst->_mx,
Monst->_my,
Monst->_menemyx,
Monst->_menemyy);
if (!clear || Monst->_pathcount >= 5 && Monst->_pathcount < 8) {
if (Monst->_mFlags & MFLAG_CAN_OPEN_DOOR)
MonstCheckDoors(i);
Monst->_pathcount++;
if (Monst->_pathcount < 5)
return FALSE;
if (M_PathWalk(i))
return TRUE;
}
if (Monst->MType->mtype != MT_GOLEM)
Monst->_pathcount = 0;
return FALSE;
}
void __fastcall MAI_Snake(int i)
{
int esi1; // esi
MonsterStruct *esi3; // esi
BOOLEAN v3; // zf
int v4; // ecx
int v5; // eax
int v6; // ST1C_4
int v7; // edi
int v8; // edx
int v9; // ST18_4
int v10; // ebx
int v11; // eax
//int v12; // ST1C_4
int v14; // eax
int v15; // eax
int v16; // ecx
int v17; // edx
int v18; // ecx
int v19; // eax
//int v20; // ST1C_4
int v22; // eax
//int v23; // ST1C_4
int v24; // ebx
int v26; // ecx
int v27; // eax
int v28; // ecx
int v29; // ecx
int v30; // eax
int v31; // edx
int v32; // eax
int v33; // ecx
int v34; // ecx
int v35; // eax
char pattern[6]; // [esp+4h] [ebp-1Ch]
int micaster; // [esp+Ch] [ebp-14h]
int midir; // [esp+10h] [ebp-10h]
int v1; // [esp+14h] [ebp-Ch]
int v2; // [esp+18h] [ebp-8h]
int arglist; // [esp+1Ch] [ebp-4h]
esi1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Snake: Invalid monster %d", i);
pattern[2] = 0;
pattern[3] = -1;
pattern[4] = -1;
pattern[5] = 0;
esi3 = &monster[esi1];
pattern[0] = 1;
pattern[1] = 1;
v3 = esi3->_mmode == MM_STAND;
micaster = esi3->_menemy;
if (v3 && esi3->_msquelch) {
v4 = esi3->_mx;
v5 = (unsigned char)esi3->_menemyy;
v6 = esi3->_lasty;
v1 = (unsigned char)esi3->_menemyx;
v7 = v4 - v1;
v8 = esi3->_my;
v9 = esi3->_lastx;
v2 = v5;
v10 = v8 - v5;
midir = GetDirection(v4, v8, v9, v6);
esi3->_mdir = midir;
if (abs(v7) < 2) {
v11 = abs(v10);
//v13 = v12;
if (v11 < 2) {
v14 = esi3->_mVar1;
if (v14 == 13
|| v14 == 14
|| (v15 = random(105, 100), v16 = (unsigned char)esi3->_mint + 20, v15 < v16)) {
M_StartAttack(arglist);
LABEL_49:
if (esi3->_mmode == MM_STAND)
esi3->_mAnimData = esi3->MType->Anims[MA_STAND].Data[esi3->_mdir];
return;
}
v17 = 10 - (unsigned char)esi3->_mint + random(105, 10);
v18 = arglist;
LABEL_11:
M_StartDelay(v18, v17);
goto LABEL_49;
}
}
v19 = abs(v7);
//v21 = v20;
if (v19 >= 3 || (v22 = abs(v10), v22 >= 3)) /* v21 = v23, */
{
v24 = arglist;
} else {
v24 = arglist;
if (LineClearF1(PosOkMonst, arglist, esi3->_mx, esi3->_my, v1, v2) && esi3->_mVar1 != 14) {
if (AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, MIS_RHINO, micaster, arglist, 0, 0) != -1) {
PlayEffect(arglist, 0);
v26 = esi3->_my + 112 * esi3->_mx;
esi3->_mmode = MM_CHARGE;
dMonster[0][v26] = -1 - v24;
}
goto LABEL_49;
}
}
if (esi3->_mVar1 != 13) {
v27 = random(106, 100);
v28 = 2 * (unsigned char)esi3->_mint;
if (v27 < 35 - v28) {
v17 = 15 - (unsigned char)esi3->_mint + random(106, 10);
v18 = v24;
goto LABEL_11;
}
}
v29 = esi3->_mgoalvar1;
v30 = midir + pattern[v29];
if (v30 >= 0) {
v31 = v30 - 8;
if (v30 < 8)
v31 = midir + pattern[v29];
} else {
v31 = v30 + 8;
}
esi3->_mgoalvar1 = v29 + 1;
if (v29 + 1 > 5)
esi3->_mgoalvar1 = 0;
v32 = esi3->_mgoalvar2;
v33 = v31 - v32;
if (v31 - v32 >= 0) {
if (v33 >= 8)
v33 -= 8;
} else {
v33 += 8;
}
if (v33 <= 0) {
LABEL_47:
if (!M_DumbWalk(v24, esi3->_mgoalvar2))
M_CallWalk2(v24, esi3->_mdir);
goto LABEL_49;
}
if (v33 >= 4) {
if (v33 == 4) {
esi3->_mgoalvar2 = v31;
goto LABEL_47;
}
v34 = v32 - 1;
if (v32 - 1 < 0) {
v35 = v32 + 7;
goto LABEL_46;
}
if (v34 >= 8) {
v35 = v32 - 9;
goto LABEL_46;
}
} else {
v34 = v32 + 1;
if (v32 + 1 < 0) {
v35 = v32 + 9;
LABEL_46:
esi3->_mgoalvar2 = v35;
goto LABEL_47;
}
if (v34 >= 8) {
v35 = v32 - 7;
goto LABEL_46;
}
}
v35 = v34;
goto LABEL_46;
}
}
void __fastcall MAI_Bat(int i)
{
int esi1; // esi
MonsterStruct *esi3; // esi
int v3; // ecx
int v4; // edx
int v5; // edi
int v6; // ebx
int v7; // eax
int v10; // edx
BOOLEAN v11; // eax
int v12; // ecx
CMonster *v14; // eax
int v15; // edi
int v16; // eax
signed int v17; // ecx
int v18; // eax
int micaster; // [esp+Ch] [ebp-18h]
int v1; // [esp+10h] [ebp-14h]
int v2; // [esp+14h] [ebp-10h]
int v22; // [esp+18h] [ebp-Ch]
int midir; // [esp+1Ch] [ebp-8h]
int arglist; // [esp+20h] [ebp-4h]
esi1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Bat: Invalid monster %d", i);
esi3 = &monster[esi1];
micaster = esi3->_menemy;
if (esi3->_mmode == MM_STAND && esi3->_msquelch) {
v3 = esi3->_mx;
v4 = esi3->_my;
v5 = v3 - (unsigned char)esi3->_menemyx;
v6 = v4 - (unsigned char)esi3->_menemyy;
v7 = GetDirection(v3, v4, esi3->_lastx, esi3->_lasty);
midir = v7;
esi3->_mdir = v7;
v22 = random(107, 100);
if (_LOBYTE(esi3->_mgoal) == MGOAL_RETREAT) {
if (esi3->_mgoalvar1) {
if (random(108, 2))
v10 = left[midir];
else
v10 = right[midir];
M_CallWalk(arglist, v10);
_LOBYTE(esi3->_mgoal) = MGOAL_NORMAL;
} else {
M_CallWalk(arglist, opposite[midir]);
++esi3->_mgoalvar1;
}
} else {
v1 = (unsigned char)esi3->_menemyx;
v2 = (unsigned char)esi3->_menemyy;
if (esi3->MType->mtype == MT_GLOOM
&& (abs(v5) >= 5 || abs(v6) >= 5)
&& v22 < 4 * (unsigned char)esi3->_mint + 33
&& (v11 = LineClearF1(
PosOkMonst,
arglist,
esi3->_mx,
esi3->_my,
v1,
v2),
v11)) {
if (AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, MIS_RHINO, micaster, arglist, 0, 0) != -1) {
v12 = esi3->_my + 112 * esi3->_mx;
esi3->_mmode = MM_CHARGE;
dMonster[0][v12] = -1 - arglist;
}
} else if (abs(v5) >= 2 || abs(v6) >= 2) {
v17 = esi3->_mVar2;
if (v17 > 20 && v22 < (unsigned char)esi3->_mint + 13
|| ((v18 = esi3->_mVar1, v18 == 1) || v18 == 2 || v18 == 3)
&& !v17
&& v22 < (unsigned char)esi3->_mint + 63) {
M_CallWalk(arglist, midir);
}
} else if (v22 < 4 * (unsigned char)esi3->_mint + 8) {
M_StartAttack(arglist);
v14 = esi3->MType;
esi3->_mgoalvar1 = 0;
_LOBYTE(esi3->_mgoal) = MGOAL_RETREAT;
if (v14->mtype == MT_FAMILIAR) {
v15 = (unsigned char)esi3->_menemyx;
v16 = random(109, 10);
AddMissile(v15, (unsigned char)esi3->_menemyy, v15 + 1, 0, -1, MIS_LIGHTNING, 1, arglist, v16 + 1, 0);
}
}
if (esi3->_mmode == MM_STAND)
esi3->_mAnimData = esi3->MType->Anims[MA_STAND].Data[midir];
}
}
}
void __fastcall MAI_SkelBow(int i)
{
MonsterStruct *Monst;
int mx, my, md, v;
BOOL walking;
walking = FALSE;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_SkelBow: Invalid monster %d", i);
Monst = &monster[i];
if (Monst->_mmode == MM_STAND && Monst->_msquelch) {
mx = Monst->_mx - Monst->_menemyx;
my = Monst->_my - Monst->_menemyy;
md = M_GetDir(i);
Monst->_mdir = md;
v = random(110, 100);
if (abs(mx) < 4 && abs(my) < 4) {
if (Monst->_mVar2 > 20 && v < 2 * Monst->_mint + 13
|| (Monst->_mVar1 == 1 || Monst->_mVar1 == 2 || Monst->_mVar1 == 3)
&& !Monst->_mVar2
&& v < 2 * Monst->_mint + 63) {
walking = M_DumbWalk(i, opposite[md]);
}
}
mx = Monst->_menemyx;
my = Monst->_menemyy;
if (!walking) {
if (random(110, 100) < 2 * Monst->_mint + 3) {
if (LineClear(Monst->_mx, Monst->_my, mx, my))
M_StartRAttack(i, MIS_ARROW, 4);
}
}
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
}
void __fastcall MAI_Fat(int i)
{
MonsterStruct *Monst;
int mx, my, md, v;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Fat: Invalid monster %d", i);
Monst = &monster[i];
if (Monst->_mmode == MM_STAND && Monst->_msquelch) {
mx = Monst->_mx - Monst->_menemyx;
my = Monst->_my - Monst->_menemyy;
md = M_GetDir(i);
Monst->_mdir = md;
v = random(111, 100);
if (abs(mx) >= 2 || abs(my) >= 2) {
if (Monst->_mVar2 > 20 && v < 4 * Monst->_mint + 20
|| (Monst->_mVar1 == 1 || Monst->_mVar1 == 2 || Monst->_mVar1 == 3) && Monst->_mVar2 == 0 && v < 4 * Monst->_mint + 70) {
M_CallWalk(i, md);
}
} else if (v < 4 * Monst->_mint + 15) {
M_StartAttack(i);
} else if (v < 4 * Monst->_mint + 20) {
M_StartSpAttack(i);
}
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
}
void __fastcall MAI_Sneak(int i)
{
int v1; // edi
MonsterStruct *v2; // esi
int v3; // ebx
int v4; // ebx
int v6; // edi
int v7; // eax
//int v8; // ST04_4
int v9; // eax
//int v10; // ST04_4
int v11; // eax
int v12; // edi
signed int v13; // ecx
int v14; // eax
int v15; // [esp+Ch] [ebp-10h]
int arglist; // [esp+10h] [ebp-Ch]
int v17; // [esp+14h] [ebp-8h]
int md; // [esp+18h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("MAI_Sneak: Invalid monster %d", i);
}
v2 = &monster[v1];
if (v2->_mmode == MM_STAND) {
v3 = v2->_my;
if (dTransVal[v2->_mx][v3] != lightmax) {
v17 = v2->_mx - (unsigned char)v2->_menemyx;
v4 = v3 - (unsigned char)v2->_menemyy;
md = M_GetDir(v1);
v6 = 5 - (unsigned char)v2->_mint;
if (v2->_mVar1 == 5) {
v2->_mgoalvar1 = 0;
_LOBYTE(v2->_mgoal) = MGOAL_RETREAT;
} else {
v7 = abs(v17);
//v5 = v8;
if (v7 >= v6 + 3 || (v9 = abs(v4), v9 >= v6 + 3) || v2->_mgoalvar1 > 8) /* v5 = v10, */
{
v2->_mgoalvar1 = 0;
_LOBYTE(v2->_mgoal) = MGOAL_NORMAL;
}
}
if (_LOBYTE(v2->_mgoal) == MGOAL_RETREAT) {
if (v2->_mFlags & MFLAG_TARGETS_MONSTER)
md = GetDirection(v2->_mx, v2->_my, plr[v2->_menemy]._pownerx, plr[v2->_menemy]._pownery);
md = opposite[md];
if (v2->MType->mtype == MT_UNSEEN) {
if (random(112, 2))
v11 = left[md];
else
v11 = right[md];
md = v11;
}
}
v2->_mdir = md;
v15 = random(112, 100);
if (abs(v17) < v6 && abs(v4) < v6 && v2->_mFlags & MFLAG_HIDDEN) {
M_StartFadein(arglist, md, FALSE);
} else {
v12 = v6 + 1;
if (abs(v17) < v12 && abs(v4) < v12 || v2->_mFlags & MFLAG_HIDDEN) {
if (_LOBYTE(v2->_mgoal) == MGOAL_RETREAT
|| (abs(v17) >= 2 || abs(v4) >= 2)
&& ((v13 = v2->_mVar2, v13 > 20) && v15 < 4 * (unsigned char)v2->_mint + 14
|| ((v14 = v2->_mVar1, v14 == 1) || v14 == 2 || v14 == 3)
&& !v13
&& v15 < 4 * (unsigned char)v2->_mint + 64)) {
++v2->_mgoalvar1;
M_CallWalk(arglist, md);
}
} else {
M_StartFadeout(arglist, md, TRUE);
}
}
if (v2->_mmode == MM_STAND) {
if (abs(v17) >= 2 || abs(v4) >= 2 || v15 >= 4 * (unsigned char)v2->_mint + 10)
v2->_mAnimData = v2->MType->Anims[MA_STAND].Data[md];
else
M_StartAttack(arglist);
}
}
}
}
// 642A14: using guessed type char lightmax;
void __fastcall MAI_Fireman(int i)
{
int esi1; // esi
int esi3; // esi
int v3; // ecx
int v4; // eax
int v5; // ebx
int v6; // edi
int v7; // edx
char v9; // al
//int v10; // eax
//int v11; // eax
int v13; // eax
//int v14; // eax
int v15; // edx
//int v16; // eax
int v17; // eax
int micaster; // [esp+Ch] [ebp-14h]
int v1; // [esp+10h] [ebp-10h]
int v2; // [esp+14h] [ebp-Ch]
int midir; // [esp+18h] [ebp-8h]
int arglist; // [esp+1Ch] [ebp-4h]
esi1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Fireman: Invalid monster %d", i);
esi3 = esi1;
if (monster[esi3]._mmode || !monster[esi3]._msquelch)
return;
v3 = (unsigned char)monster[esi3]._menemyy;
micaster = monster[esi3]._menemy;
v4 = (unsigned char)monster[esi3]._menemyx;
v2 = v3;
v5 = monster[esi3]._my - v3;
v1 = v4;
v6 = monster[esi3]._mx - v4;
v7 = M_GetDir(arglist);
v9 = monster[esi3]._mgoal;
midir = v7;
switch (v9) {
case MGOAL_NORMAL:
//_LOBYTE(v10) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2);
if (!LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2)
|| AddMissile(monster[esi3]._mx, monster[esi3]._my, v1, v2, midir, MIS_FIREMAN, micaster, arglist, 0, 0) == -1) {
break;
}
monster[esi3]._mgoalvar1 = 0;
monster[esi3]._mmode = MM_CHARGE;
goto LABEL_18;
case MGOAL_SHOOT:
if (monster[esi3]._mgoalvar1 == 3) {
_LOBYTE(monster[esi3]._mgoal) = MGOAL_NORMAL;
M_StartFadeout(arglist, v7, TRUE);
} else {
//_LOBYTE(v11) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2);
if (LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2)) {
M_StartRAttack(arglist, MIS_KRULL, 4);
} else {
//_LOBYTE(v11) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2);
if (LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2)) {
M_StartRAttack(arglist, MIS_KRULL, 4);
} else {
v13 = random(112, 10);
M_StartDelay(arglist, v13 + 5);
}
++monster[esi3]._mgoalvar1;
}
++monster[esi3]._mgoalvar1;
}
break;
case MGOAL_RETREAT:
M_StartFadein(arglist, v7, FALSE);
LABEL_18:
_LOBYTE(monster[esi3]._mgoal) = MGOAL_SHOOT;
break;
}
monster[esi3]._mdir = midir;
random(112, 100);
if (monster[esi3]._mmode == MM_STAND)
return;
if (abs(v6) < 2 && abs(v5) < 2 && _LOBYTE(monster[esi3]._mgoal) == MGOAL_NORMAL) {
M_TryH2HHit(
arglist,
monster[esi3]._menemy,
(unsigned char)monster[esi3].mHit,
(unsigned char)monster[esi3].mMinDamage,
(unsigned char)monster[esi3].mMaxDamage);
_LOBYTE(monster[esi3]._mgoal) = MGOAL_RETREAT;
//_LOBYTE(v14) = M_CallWalk(arglist, opposite[midir]);
if (M_CallWalk(arglist, opposite[midir]))
return;
v15 = midir;
goto LABEL_29;
}
//_LOBYTE(v16) = M_CallWalk(arglist, midir);
if (!M_CallWalk(arglist, midir)) {
v17 = _LOBYTE(monster[esi3]._mgoal);
if ((_BYTE)v17 == MGOAL_NORMAL || (_BYTE)v17 == MGOAL_RETREAT) {
v15 = midir;
LABEL_29:
M_StartFadein(arglist, v15, FALSE);
_LOBYTE(monster[esi3]._mgoal) = MGOAL_SHOOT;
return;
}
}
}
void __fastcall MAI_Fallen(int i)
{
int v1; // edi
//int v2; // ST04_4
int v3; // esi
int v4; // eax
int v5; // ecx
int *v6; // eax
int v7; // edx
int v8; // edx
int j; // edi
int k; // ecx
int v11; // eax
int v12; // eax
char v13; // al
int v14; // edx
int v15; // eax
int v16; // esi
v1 = i;
if ((DWORD)i >= MAXMONSTERS) {
TermMsg("MAI_Fallen: Invalid monster %d", i);
//i = v2;
}
v3 = v1;
if (_LOBYTE(monster[v1]._mgoal) == MGOAL_SHOOT) {
i = monster[v3]._mgoalvar1;
if (i)
monster[v3]._mgoalvar1 = --i;
else
_LOBYTE(monster[v3]._mgoal) = MGOAL_NORMAL;
}
if (monster[v3]._mmode == MM_STAND && monster[v3]._msquelch) {
if (_LOBYTE(monster[v3]._mgoal) == MGOAL_RETREAT) {
i = monster[v3]._mgoalvar1;
monster[v3]._mgoalvar1 = i - 1;
if (!i) {
v4 = monster[v3]._mdir;
_LOBYTE(monster[v3]._mgoal) = MGOAL_NORMAL;
M_StartStand(v1, opposite[v4]);
}
}
if (monster[v3]._mAnimFrame != monster[v3]._mAnimLen) {
v13 = monster[v3]._mgoal;
if (v13 == MGOAL_RETREAT) {
v14 = monster[v3]._mdir;
} else {
if (v13 != MGOAL_SHOOT) {
MAI_SkelSd(v1);
return;
}
v15 = monster[v3]._mx - (unsigned char)monster[v3]._menemyx;
v16 = monster[v3]._my - (unsigned char)monster[v3]._menemyy;
if (abs(v15) < 2 && abs(v16) < 2) {
M_StartAttack(v1);
return;
}
v14 = M_GetDir(v1);
}
M_CallWalk(v1, v14);
return;
}
if (!random(113, 4)) {
if (!(monster[v3]._mFlags & MFLAG_NOHEAL)) {
M_StartSpStand(v1, monster[v3]._mdir);
v5 = 2 * (unsigned char)monster[v3]._mint + 2;
v6 = &monster[v3]._mhitpoints;
v7 = monster[v3]._mhitpoints;
if (monster[v3]._mmaxhp - v5 < v7)
*v6 = monster[v3]._mmaxhp;
else
*v6 = v5 + v7;
}
v8 = 2 * (unsigned char)monster[v3]._mint + 4;
for (j = -v8; j <= v8; ++j) {
for (k = -v8; k <= v8; ++k) {
if (j >= 0 && j < MAXDUNY && k >= 0 && k < MAXDUNX) {
v11 = dMonster[k + monster[v3]._mx][j + monster[v3]._my];
if (v11 > 0) {
v12 = v11 - 1;
if (monster[v12]._mAi == AI_FALLEN) {
_LOBYTE(monster[v12]._mgoal) = MGOAL_SHOOT;
monster[v12]._mgoalvar1 = 30 * (unsigned char)monster[v3]._mint + 105;
}
}
}
}
}
}
}
}
void __fastcall MAI_Cleaver(int i)
{
MonsterStruct *Monst;
int x, y, mx, my, md;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Cleaver: Invalid monster %d", i);
Monst = &monster[i];
if (Monst->_mmode == MM_STAND && Monst->_msquelch) {
mx = Monst->_mx;
my = Monst->_my;
x = mx - Monst->_menemyx;
y = my - Monst->_menemyy;
md = GetDirection(mx, my, Monst->_lastx, Monst->_lasty);
Monst->_mdir = md;
if (abs(x) >= 2 || abs(y) >= 2)
M_CallWalk(i, md);
else
M_StartAttack(i);
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
}
void __fastcall MAI_Round(int i, BOOL special)
{
int v2; // esi
MonsterStruct *v3; // esi
int v4; // edx
int v5; // ecx
int v6; // edi
int v7; // ebx
int v9; // eax
//int v10; // ST04_4
int v12; // eax
//int v13; // ST04_4
int v15; // edi
int v16; // eax
int v17; // ecx
BOOLEAN v18; // eax
//int v19; // eax
int v21; // eax
int v22; // eax
//int v23; // ST04_4
signed int v25; // ecx
int v26; // eax
int v27; // [esp+4h] [ebp-18h]
int v28; // [esp+8h] [ebp-14h]
char *v29; // [esp+8h] [ebp-14h]
int v30; // [esp+Ch] [ebp-10h]
int md; // [esp+10h] [ebp-Ch]
int v32; // [esp+14h] [ebp-8h]
int arglist; // [esp+18h] [ebp-4h]
v2 = i;
v27 = special;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Round: Invalid monster %d", i);
v3 = &monster[v2];
if (v3->_mmode == MM_STAND && v3->_msquelch) {
v4 = v3->_my;
v5 = v3->_mx;
v28 = (unsigned char)v3->_menemyy;
v6 = (unsigned char)v3->_menemyx;
v7 = v5 - v6;
v32 = v4 - v28;
md = GetDirection(v5, v4, v3->_lastx, v3->_lasty);
if (v3->_msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
v30 = random(114, 100);
if ((abs(v7) >= 2 || abs(v32) >= 2) && v3->_msquelch == -1) {
v29 = &dung_map[v6][v28];
if (dung_map[v3->_mx][v3->_my] == *v29) {
if (_LOBYTE(v3->_mgoal) != MGOAL_MOVE) {
v9 = abs(v7);
//v11 = v10;
if (v9 < 4) {
v12 = abs(v32);
//v11 = v13;
if (v12 < 4)
goto LABEL_26;
}
if (random(115, 4))
goto LABEL_26;
if (_LOBYTE(v3->_mgoal) != MGOAL_MOVE) {
v3->_mgoalvar1 = 0;
v3->_mgoalvar2 = random(116, 2);
}
}
_LOBYTE(v3->_mgoal) = MGOAL_MOVE;
v15 = abs(v32);
if (abs(v7) <= v15)
v16 = abs(v32);
else
v16 = abs(v7);
v17 = v3->_mgoalvar1;
v3->_mgoalvar1 = v17 + 1;
if (v17 < 2 * v16 || (v18 = DirOK(arglist, md), !v18)) {
if (dung_map[v3->_mx][v3->_my] == *v29) {
//_LOBYTE(v19) = M_RoundWalk(arglist, md, &v3->_mgoalvar2);
if (!M_RoundWalk(arglist, md, &v3->_mgoalvar2)) {
v21 = random(125, 10);
M_StartDelay(arglist, v21 + 10);
}
goto LABEL_26;
}
}
}
}
_LOBYTE(v3->_mgoal) = MGOAL_NORMAL;
LABEL_26:
if (_LOBYTE(v3->_mgoal) == MGOAL_NORMAL) {
if (abs(v7) >= 2 || (v22 = abs(v32), v22 >= 2)) /* v24 = v23, */
{
v25 = v3->_mVar2;
if (v25 > 20 && v30 < 2 * (unsigned char)v3->_mint + 28
|| ((v26 = v3->_mVar1, v26 == 1) || v26 == 2 || v26 == 3)
&& !v25
&& v30 < 2 * (unsigned char)v3->_mint + 78) {
M_CallWalk(arglist, md);
}
} else if (v30 < 2 * (unsigned char)v3->_mint + 23) {
v3->_mdir = md;
if (v27 && v3->_mhitpoints<v3->_mmaxhp>> 1 && random(117, 2))
M_StartSpAttack(arglist);
else
M_StartAttack(arglist);
}
}
if (v3->_mmode == MM_STAND)
v3->_mAnimData = v3->MType->Anims[MA_STAND].Data[md];
}
}
void __fastcall MAI_GoatMc(int i)
{
MAI_Round(i, 1u);
}
void __fastcall MAI_Ranged(int i, int missile_type, unsigned char special)
{
int v3; // edi
int v4; // esi
char v5; // al
int v6; // eax
int v7; // ecx
int v8; // ebx
int v9; // edi
BOOLEAN v11; // zf
int v12; // eax
int v13; // eax
//int v14; // ST00_4
//int v16; // eax
int x2; // [esp+8h] [ebp-14h]
int y2; // [esp+Ch] [ebp-10h]
int missile_typea; // [esp+10h] [ebp-Ch]
int v20; // [esp+14h] [ebp-8h]
int arglist; // [esp+18h] [ebp-4h]
v3 = i;
missile_typea = missile_type;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Ranged: Invalid monster %d", i);
v4 = v3;
if (monster[v3]._mmode == MM_STAND) {
v5 = monster[v4]._msquelch;
if (v5 == -1 || monster[v4]._mFlags & MFLAG_TARGETS_MONSTER) {
v7 = (unsigned char)monster[v4]._menemyy;
y2 = v7;
v8 = monster[v4]._my - v7;
x2 = (unsigned char)monster[v4]._menemyx;
v9 = monster[v4]._mx - x2;
v20 = M_GetDir(arglist);
if (monster[v4]._msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
v11 = monster[v4]._mVar1 == 10;
monster[v4]._mdir = v20;
if (v11) {
v12 = random(118, 20);
M_StartDelay(arglist, v12);
} else if (abs(v9) < 4) {
v13 = abs(v8);
//v15 = v14;
if (v13 < 4) {
if (random(119, 100) < 10 * ((unsigned char)monster[v4]._mint + 7))
M_CallWalk(arglist, opposite[v20]);
}
}
if (monster[v4]._mmode == MM_STAND) {
//_LOBYTE(v16) = LineClear(monster[v4]._mx, monster[v4]._my, x2, y2);
if (LineClear(monster[v4]._mx, monster[v4]._my, x2, y2)) {
if (special)
M_StartRSpAttack(arglist, missile_typea, 4);
else
M_StartRAttack(arglist, missile_typea, 4);
} else {
monster[v4]._mAnimData = monster[v4].MType->Anims[MA_STAND].Data[v20];
}
}
} else if (v5) {
v6 = GetDirection(monster[v4]._mx, monster[v4]._my, monster[v4]._lastx, monster[v4]._lasty);
M_CallWalk(v3, v6);
}
}
}
void __fastcall MAI_GoatBow(int i)
{
MAI_Ranged(i, MIS_ARROW, 0);
}
void __fastcall MAI_Succ(int i)
{
MAI_Ranged(i, MIS_FLARE, 0);
}
void __fastcall MAI_AcidUniq(int i)
{
MAI_Ranged(i, MIS_ACID, 1u);
}
void __fastcall MAI_Scav(int i)
{
int v1; // edi
int v2; // esi
unsigned char *v3; // eax
int v4; // ecx
int v5; // ecx
signed int v6; // ebx
signed int v7; // edi
int v8; // edx
int v9; // eax
BOOLEAN v10; // eax
int v11; // ebx
int v12; // edi
signed int v13; // edi
int v14; // edx
int v15; // eax
BOOLEAN v16; // eax
int v17; // eax
int v18; // eax
int arglist; // [esp+Ch] [ebp-8h]
BOOL v20; // [esp+10h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Scav: Invalid monster %d", i);
v2 = v1;
v20 = 0;
if (monster[v1]._mmode == MM_STAND) {
if (monster[v2]._mhitpoints<monster[v2]._mmaxhp>> 1) {
if (_LOBYTE(monster[v2]._mgoal) == MGOAL_HEALING)
goto LABEL_10;
if (monster[v2].leaderflag) {
v3 = &monster[(unsigned char)monster[v2].leader].packsize;
--*v3;
monster[v2].leaderflag = 0;
}
_LOBYTE(monster[v2]._mgoal) = MGOAL_HEALING;
monster[v2]._mgoalvar3 = 10;
}
if (_LOBYTE(monster[v2]._mgoal) != MGOAL_HEALING) {
LABEL_52:
if (monster[v2]._mmode == MM_STAND)
MAI_SkelSd(arglist);
return;
}
LABEL_10:
v4 = monster[v2]._mgoalvar3;
if (v4) {
monster[v2]._mgoalvar3 = v4 - 1;
v5 = monster[v2]._my;
if (dDead[monster[v2]._mx][v5]) {
M_StartEat(v1);
if (!(monster[v2]._mFlags & MFLAG_NOHEAL))
monster[v2]._mhitpoints += 64;
if (monster[v2]._mhitpoints >= (monster[v2]._mmaxhp >> 1) + (monster[v2]._mmaxhp >> 2)) {
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
monster[v2]._mgoalvar1 = 0;
monster[v2]._mgoalvar2 = 0;
}
} else {
if (!monster[v2]._mgoalvar1) {
v6 = arglist;
if (random(120, 2)) {
v7 = -4;
do {
if (v20)
break;
v6 = -4;
do {
if (v20)
break;
if (v7 >= 0 && v7 < MAXDUNY && v6 >= 0 && v6 < MAXDUNX) {
v8 = monster[v2]._mx;
v9 = monster[v2]._my;
v20 = dDead[v8 + v6][v9 + v7]
&& (v10 = LineClearF(
CheckNoSolid,
v8,
v9,
v8 + v6,
v9 + v7),
v10);
}
++v6;
} while (v6 <= 4);
++v7;
} while (v7 <= 4);
v11 = v6 - 1;
v12 = v7 - 1;
} else {
v13 = 4;
do {
if (v20)
break;
v6 = 4;
do {
if (v20)
break;
if (v13 >= 0 && v13 < MAXDUNY && v6 >= 0 && v6 < MAXDUNX) {
v14 = monster[v2]._mx;
v15 = monster[v2]._my;
v20 = dDead[v14 + v6][v15 + v13]
&& (v16 = LineClearF(
CheckNoSolid,
v14,
v15,
v14 + v6,
v15 + v13),
v16);
}
--v6;
} while (v6 >= -4);
--v13;
} while (v13 >= -4);
v11 = v6 + 1;
v12 = v13 + 1;
}
if (v20) {
monster[v2]._mgoalvar1 = monster[v2]._mx + v11 + 1;
monster[v2]._mgoalvar2 = monster[v2]._my + v12 + 1;
}
}
v17 = monster[v2]._mgoalvar1;
if (v17) {
v18 = GetDirection(monster[v2]._mx, monster[v2]._my, v17 - 1, monster[v2]._mgoalvar2 - 1);
monster[v2]._mdir = v18;
M_CallWalk(arglist, v18);
}
}
}
goto LABEL_52;
}
}
void __fastcall MAI_Garg(int i)
{
MonsterStruct *Monst;
int mx, my, dx, dy, md;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Garg: Invalid monster %d", i);
Monst = &monster[i];
dx = Monst->_mx - Monst->_lastx;
dy = Monst->_my - Monst->_lasty;
md = M_GetDir(i);
if (Monst->_msquelch && Monst->_mFlags & MFLAG_ALLOW_SPECIAL) {
M_Enemy(i);
mx = Monst->_mx - Monst->_menemyx;
my = Monst->_my - Monst->_menemyy;
if (abs(mx) < Monst->_mint + 2 && abs(my) < Monst->_mint + 2) {
Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL;
}
} else if (Monst->_mmode == MM_STAND && Monst->_msquelch) {
if (Monst->_mhitpoints<Monst->_mmaxhp>> 1 && !(Monst->_mFlags & MFLAG_NOHEAL))
Monst->_mgoal = MGOAL_RETREAT;
if (Monst->_mgoal == MGOAL_RETREAT) {
if (abs(dx) >= Monst->_mint + 2 || abs(dy) >= Monst->_mint + 2) {
Monst->_mgoal = MGOAL_NORMAL;
M_StartHeal(i);
} else if (!M_CallWalk(i, opposite[md])) {
Monst->_mgoal = MGOAL_NORMAL;
}
}
MAI_Round(i, 0);
}
}
void __fastcall MAI_RoundRanged(int i, int missile_type, unsigned char checkdoors, int dam, int lessmissiles)
{
int v5; // esi
MonsterStruct *v6; // esi
int v7; // edx
int v8; // ebx
int v9; // edi
int v11; // eax
//int v12; // ST04_4
int v13; // ecx
int v14; // eax
//int v15; // ST04_4
int v16; // eax
//int v17; // ST04_4
int v18; // ecx
int v19; // ebx
int v20; // eax
int v21; // ecx
BOOLEAN v22; // eax
BOOLEAN v23; // eax
BOOLEAN v24; // eax
int v25; // eax
//int v26; // ST04_4
int v27; // eax
//int v28; // ST04_4
int v29; // eax
int v30; // edx
int v31; // eax
int missile_typea; // [esp+4h] [ebp-18h]
int v33; // [esp+8h] [ebp-14h]
int x2; // [esp+Ch] [ebp-10h]
int md; // [esp+10h] [ebp-Ch]
int y2; // [esp+14h] [ebp-8h]
int arglist; // [esp+18h] [ebp-4h]
int checkdoorsa; // [esp+24h] [ebp+8h]
v5 = i;
missile_typea = missile_type;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_RoundRanged: Invalid monster %d", i);
v6 = &monster[v5];
if (v6->_mmode == MM_STAND && v6->_msquelch) {
v7 = v6->_my;
y2 = (unsigned char)v6->_menemyy;
v8 = v7 - y2;
x2 = (unsigned char)v6->_menemyx;
v9 = v6->_mx - x2;
v33 = v7 - y2;
md = GetDirection(v6->_mx, v7, v6->_lastx, v6->_lasty);
if (checkdoors && v6->_msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
checkdoorsa = random(121, 10000);
v11 = abs(v9);
//v13 = v12;
if (v11 < 2) {
v14 = abs(v8);
//v13 = v15;
if (v14 < 2)
goto LABEL_50;
}
if (v6->_msquelch != -1)
goto LABEL_50;
//v13 = y2;
if (dung_map[v6->_mx][v6->_my] != dung_map[x2][y2])
goto LABEL_50;
if (_LOBYTE(v6->_mgoal) != MGOAL_MOVE) {
if (abs(v9) < 3) {
v16 = abs(v8);
//v13 = v17;
if (v16 < 3)
goto LABEL_28;
}
v18 = lessmissiles;
if (random(122, 4 << lessmissiles))
goto LABEL_28;
if (_LOBYTE(v6->_mgoal) != MGOAL_MOVE) {
v6->_mgoalvar1 = 0;
v6->_mgoalvar2 = random(123, 2);
}
}
_LOBYTE(v6->_mgoal) = MGOAL_MOVE;
v19 = abs(v8);
if (abs(v9) <= v19) {
v8 = v33;
v20 = abs(v33);
} else {
v20 = abs(v9);
v8 = v33;
}
v21 = v6->_mgoalvar1;
v6->_mgoalvar1 = v21 + 1;
if (v21 >= 2 * v20 && (v22 = DirOK(arglist, md), v22)) {
LABEL_50:
_LOBYTE(v6->_mgoal) = MGOAL_NORMAL;
} else if (checkdoorsa<500 * ((unsigned char)v6->_mint + 1)>> lessmissiles
&& (v23 = LineClear(v6->_mx, v6->_my, x2, y2), v23)) {
M_StartRSpAttack(arglist, missile_typea, dam);
} else {
M_RoundWalk(arglist, md, &v6->_mgoalvar2);
}
LABEL_28:
if (_LOBYTE(v6->_mgoal) == MGOAL_NORMAL) {
if (((abs(v9) >= 3 || abs(v8) >= 3) && checkdoorsa<500 * ((unsigned char)v6->_mint + 2)>> lessmissiles
|| checkdoorsa<500 * ((unsigned char)v6->_mint + 1)>> lessmissiles)
&& (v24 = LineClear(v6->_mx, v6->_my, x2, y2), v24)) {
M_StartRSpAttack(arglist, missile_typea, dam);
} else {
v25 = abs(v9);
//v13 = v26;
if (v25 >= 2 || (v27 = abs(v8), v27 >= 2)) /* v13 = v28, */
{
v29 = random(124, 100);
v30 = (unsigned char)v6->_mint;
if (v29 < 1000 * (v30 + 5)
|| ((v13 = v6->_mVar1, v13 == 1) || v13 == 2 || v13 == 3) && !v6->_mVar2 && v29 < 1000 * (v30 + 8)) {
M_CallWalk(arglist, md);
}
} else if (checkdoorsa < 1000 * ((unsigned char)v6->_mint + 6)) {
v6->_mdir = md;
M_StartAttack(arglist);
}
}
}
if (v6->_mmode == MM_STAND) {
v31 = random(125, 10);
M_StartDelay(arglist, v31 + 5);
}
}
}
void __fastcall MAI_Magma(int i)
{
MAI_RoundRanged(i, MIS_MAGMABALL, 1u, 4, 0);
}
void __fastcall MAI_Storm(int i)
{
MAI_RoundRanged(i, MIS_LIGHTCTRL2, 1u, 4, 0);
}
void __fastcall MAI_Acid(int i)
{
MAI_RoundRanged(i, MIS_ACID, 0, 4, 1);
}
void __fastcall MAI_Diablo(int i)
{
MAI_RoundRanged(i, MIS_DIABAPOCA, 0, 40, 0);
}
void __fastcall MAI_RR2(int i, int mistype, int dam)
{
int v3; // ebx
MonsterStruct *v4; // esi
int v5; // edi
int v6; // edx
int v7; // ebx
int v8; // edi
int v10; // eax
//int v11; // ST04_4
int v12; // ecx
int v13; // eax
//int v14; // ST04_4
int v15; // eax
//int v16; // ST04_4
int v17; // eax
//int v18; // ST04_4
int v19; // ebx
int v20; // eax
BOOLEAN v21; // eax
BOOLEAN v22; // eax
int v23; // ecx
int v24; // eax
//int v25; // ST04_4
int v27; // eax
//int v28; // ST04_4
int v29; // eax
int v30; // eax
int v31; // eax
int v32; // edx
int v33; // eax
int missile_type; // [esp+Ch] [ebp-1Ch]
int x2; // [esp+10h] [ebp-18h]
int v36; // [esp+14h] [ebp-14h]
int y2; // [esp+18h] [ebp-10h]
int v38; // [esp+1Ch] [ebp-Ch]
int md; // [esp+20h] [ebp-8h]
int arglist; // [esp+24h] [ebp-4h]
v3 = i;
missile_type = mistype;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_RR2: Invalid monster %d", i);
v4 = &monster[v3];
v5 = v4->_my - (unsigned char)v4->_menemyy;
if (abs(v4->_mx - (unsigned char)v4->_menemyx) >= 5 || abs(v5) >= 5) {
MAI_SkelSd(v3);
return;
}
if (v4->_mmode == MM_STAND && v4->_msquelch) {
v6 = v4->_my;
y2 = (unsigned char)v4->_menemyy;
v7 = v6 - y2;
x2 = (unsigned char)v4->_menemyx;
v8 = v4->_mx - x2;
v36 = v6 - y2;
md = GetDirection(v4->_mx, v6, v4->_lastx, v4->_lasty);
if (v4->_msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
v38 = random(121, 100);
v10 = abs(v8);
//v12 = v11;
if (v10 >= 2 || (v13 = abs(v7), v13 >= 2)) /* v12 = v14, */
{
if (v4->_msquelch == -1) {
//v12 = y2;
if (dung_map[v4->_mx][v4->_my] == dung_map[x2][y2]) {
if (_LOBYTE(v4->_mgoal) != MGOAL_MOVE) {
v15 = abs(v8);
//v12 = v16;
if (v15 < 3) {
v17 = abs(v7);
//v12 = v18;
if (v17 < 3)
goto LABEL_26;
}
if (_LOBYTE(v4->_mgoal) != MGOAL_MOVE) {
v4->_mgoalvar1 = 0;
v4->_mgoalvar2 = random(123, 2);
}
}
_LOBYTE(v4->_mgoal) = MGOAL_MOVE;
v4->_mgoalvar3 = 4;
v19 = abs(v7);
if (abs(v8) <= v19) {
v7 = v36;
v20 = abs(v36);
} else {
v20 = abs(v8);
v7 = v36;
}
v12 = v4->_mgoalvar1;
v4->_mgoalvar1 = v12 + 1;
if (v12 < 2 * v20 || (v21 = DirOK(arglist, md), !v21)) {
if (v38 < 5 * ((unsigned char)v4->_mint + 16))
M_RoundWalk(arglist, md, &v4->_mgoalvar2);
LABEL_26:
if (_LOBYTE(v4->_mgoal) != MGOAL_NORMAL)
goto LABEL_48;
if (((abs(v8) >= 3 || abs(v7) >= 3) && v38 < 5 * ((unsigned char)v4->_mint + 2)
|| v38 < 5 * ((unsigned char)v4->_mint + 1)
|| v4->_mgoalvar3 == 4)
&& (v22 = LineClear(v4->_mx, v4->_my, x2, y2), v22)) {
v23 = arglist;
} else {
v24 = abs(v8);
//v26 = v25;
if (v24 >= 2 || (v27 = abs(v7), v27 >= 2)) /* v26 = v28, */
{
v31 = random(124, 100);
v12 = (unsigned char)v4->_mint;
if (v31 < 2 * (5 * v12 + 25)
|| ((v32 = v4->_mVar1, v32 == 1) || v32 == 2 || v32 == 3)
&& !v4->_mVar2
&& (v12 = 2 * (5 * v12 + 40), v31 < v12)) {
M_CallWalk(arglist, md);
}
goto LABEL_47;
}
v29 = random(124, 100);
v12 = 10 * ((unsigned char)v4->_mint + 4);
if (v29 >= v12) {
LABEL_47:
v4->_mgoalvar3 = 1;
LABEL_48:
if (v4->_mmode == MM_STAND) {
v33 = random(125, 10);
M_StartDelay(arglist, v33 + 5);
}
return;
}
v4->_mdir = md;
v30 = random(124, 2);
v23 = arglist;
if (v30) {
M_StartAttack(arglist);
goto LABEL_47;
}
}
M_StartRSpAttack(v23, missile_type, dam);
goto LABEL_47;
}
}
}
}
_LOBYTE(v4->_mgoal) = MGOAL_NORMAL;
goto LABEL_26;
}
}
void __fastcall MAI_Mega(int i)
{
MAI_RR2(i, MIS_FLAMEC, 0);
}
void __fastcall MAI_Golum(int i)
{
int j, k;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Golum: Invalid monster %d", i);
MonsterStruct *Monst = &monster[i];
if (Monst->_mx == 1 && Monst->_my == 0) {
return;
}
if (Monst->_mmode == MM_DEATH
|| Monst->_mmode == MM_SPSTAND
|| (Monst->_mmode >= MM_WALK && Monst->_mmode <= MM_WALK3)) {
return;
}
if (!(Monst->_mFlags & MFLAG_TARGETS_MONSTER))
M_Enemy(i);
BOOL have_enemy = !(monster[i]._mFlags & MFLAG_NO_ENEMY);
if (Monst->_mmode == MM_ATTACK) {
return;
}
int _menemy = monster[i]._menemy;
int mx = monster[i]._mx;
int my = monster[i]._my;
int _mex = mx - monster[_menemy]._mfutx;
int _mey = my - monster[_menemy]._mfuty;
int md = GetDirection(mx, my, monster[_menemy]._mx, monster[_menemy]._my);
monster[i]._mdir = md;
if (abs(_mex) >= 2 || abs(_mey) >= 2) {
if (have_enemy && MAI_Path(i))
return;
} else if (have_enemy) {
_menemy = monster[i]._menemy;
monster[i]._menemyx = monster[_menemy]._mx;
monster[i]._menemyy = monster[_menemy]._my;
if (!monster[_menemy]._msquelch) {
monster[_menemy]._msquelch = -1;
monster[monster[i]._menemy]._lastx = monster[i]._mx;
monster[monster[i]._menemy]._lasty = monster[i]._my;
for (j = 0; j < 5; j++) {
for (k = 0; k < 5; k++) {
_menemy = dMonster[monster[i]._mx + k - 2][monster[i]._my + j - 2];
if (_menemy > 0)
monster[_menemy]._msquelch = -1;
}
}
}
M_StartAttack(i);
return;
}
monster[i]._pathcount++;
if (monster[i]._pathcount > 8)
monster[i]._pathcount = 5;
BOOL ok = M_CallWalk(i, plr[i]._pdir);
if (!ok) {
md = (md - 1) & 7;
for (j = 0; j < 8 && !ok; j++) {
md = (md + 1) & 7;
ok = DirOK(i, md);
}
if (!ok) {
return;
}
M_WalkDir(i, md);
}
}
void __fastcall MAI_SkelKing(int i)
{
int v1; // esi
MonsterStruct *v2; // esi
int v3; // edx
int v4; // ebx
int v5; // edi
int v7; // eax
//int v8; // ST04_4
int v10; // eax
//int v11; // ST04_4
int v13; // ebx
int v14; // eax
int v15; // ecx
BOOLEAN v16; // eax
//int v17; // eax
int v19; // eax
BOOLEAN v20; // eax
int v21; // edi
int v22; // ebx
int v23; // eax
//int v24; // ST04_4
int v26; // eax
//int v27; // ST04_4
int v28; // eax
int v29; // ecx
int v30; // edx
int v31; // eax
char *v32; // [esp+4h] [ebp-1Ch]
int x2; // [esp+8h] [ebp-18h]
int v34; // [esp+Ch] [ebp-14h]
int v35; // [esp+10h] [ebp-10h]
int y2; // [esp+14h] [ebp-Ch]
int md; // [esp+18h] [ebp-8h]
int arglist; // [esp+1Ch] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_SkelKing: Invalid monster %d", i);
v2 = &monster[v1];
if (v2->_mmode == MM_STAND && v2->_msquelch) {
v3 = v2->_my;
y2 = (unsigned char)v2->_menemyy;
v4 = v3 - y2;
x2 = (unsigned char)v2->_menemyx;
v5 = v2->_mx - x2;
v34 = v3 - y2;
md = GetDirection(v2->_mx, v3, v2->_lastx, v2->_lasty);
if (v2->_msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
v35 = random(126, 100);
if ((abs(v5) >= 2 || abs(v4) >= 2) && v2->_msquelch == -1) {
v32 = &dung_map[x2][y2];
if (dung_map[v2->_mx][v2->_my] == *v32) {
if (_LOBYTE(v2->_mgoal) != MGOAL_MOVE) {
v7 = abs(v5);
//v9 = v8;
if (v7 < 3) {
v10 = abs(v4);
//v9 = v11;
if (v10 < 3)
goto LABEL_26;
}
if (random(127, 4))
goto LABEL_26;
if (_LOBYTE(v2->_mgoal) != MGOAL_MOVE) {
v2->_mgoalvar1 = 0;
v2->_mgoalvar2 = random(128, 2);
}
}
_LOBYTE(v2->_mgoal) = MGOAL_MOVE;
v13 = abs(v4);
if (abs(v5) <= v13) {
v4 = v34;
v14 = abs(v34);
} else {
v14 = abs(v5);
v4 = v34;
}
v15 = v2->_mgoalvar1;
v2->_mgoalvar1 = v15 + 1;
if (v15 < 2 * v14 || (v16 = DirOK(arglist, md), !v16)) {
if (dung_map[v2->_mx][v2->_my] == *v32) {
//_LOBYTE(v17) = M_RoundWalk(arglist, md, &v2->_mgoalvar2);
if (!M_RoundWalk(arglist, md, &v2->_mgoalvar2)) {
v19 = random(125, 10);
M_StartDelay(arglist, v19 + 10);
}
goto LABEL_26;
}
}
}
}
_LOBYTE(v2->_mgoal) = MGOAL_NORMAL;
LABEL_26:
if (_LOBYTE(v2->_mgoal) == MGOAL_NORMAL) {
if (gbMaxPlayers == 1
&& ((abs(v5) >= 3 || abs(v4) >= 3) && v35 < 4 * (unsigned char)v2->_mint + 35 || v35 < 6)
&& (v20 = LineClear(v2->_mx, v2->_my, x2, y2), v20)) {
v21 = v2->_mx + offset_x[md];
v22 = v2->_my + offset_y[md];
if (PosOkMonst(arglist, v21, v22) && nummonsters < MAXMONSTERS) {
M_SpawnSkel(v21, v22, md);
M_StartSpStand(arglist, md);
}
} else {
v23 = abs(v5);
//v25 = v24;
if (v23 >= 2 || (v26 = abs(v4), v26 >= 2)) /* v25 = v27, */
{
v28 = random(129, 100);
v29 = (unsigned char)v2->_mint;
if (v28 >= v29 + 25
&& ((v30 = v2->_mVar1, v30 != 1) && v30 != 2 && v30 != 3 || v2->_mVar2 || (v29 += 75, v28 >= v29))) {
v31 = random(130, 10);
M_StartDelay(arglist, v31 + 10);
} else {
M_CallWalk(arglist, md);
}
} else if (v35 < (unsigned char)v2->_mint + 20) {
v2->_mdir = md;
M_StartAttack(arglist);
}
}
}
if (v2->_mmode == MM_STAND)
v2->_mAnimData = v2->MType->Anims[MA_STAND].Data[md];
}
}
// 679660: using guessed type char gbMaxPlayers;
void __fastcall MAI_Rhino(int i)
{
int esi1; // esi
MonsterStruct *esi3; // esi
int v3; // edx
int v4; // ebx
int v5; // edi
int v7; // eax
//int v8; // ST1C_4
int v10; // eax
//int v11; // ST1C_4
int v13; // ebx
int v14; // eax
int v15; // ecx
//int v16; // eax
int v18; // eax
BOOLEAN v19; // eax
int v20; // ecx
int v21; // eax
//int v22; // ST1C_4
int v24; // eax
//int v25; // ST1C_4
int v26; // eax
int v27; // ecx
int v28; // edx
int v29; // eax
int v30; // [esp+4h] [ebp-18h]
int v31; // [esp+8h] [ebp-14h]
int v1; // [esp+Ch] [ebp-10h]
int midir; // [esp+10h] [ebp-Ch]
int v2; // [esp+14h] [ebp-8h]
int arglist; // [esp+18h] [ebp-4h]
esi1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Rhino: Invalid monster %d", i);
esi3 = &monster[esi1];
if (esi3->_mmode == MM_STAND && esi3->_msquelch) {
v3 = esi3->_my;
v2 = (unsigned char)esi3->_menemyy;
v4 = v3 - v2;
v1 = (unsigned char)esi3->_menemyx;
v5 = esi3->_mx - v1;
v31 = v3 - v2;
midir = GetDirection(esi3->_mx, v3, esi3->_lastx, esi3->_lasty);
if (esi3->_msquelch < 0xFFu) /* check sign */
MonstCheckDoors(arglist);
v30 = random(131, 100);
if (abs(v5) >= 2 || abs(v4) >= 2) {
if (_LOBYTE(esi3->_mgoal) != MGOAL_MOVE) {
v7 = abs(v5);
//v9 = v8;
if (v7 < 5) {
v10 = abs(v4);
//v9 = v11;
if (v10 < 5)
goto LABEL_23;
}
if (!random(132, 4))
goto LABEL_23;
if (_LOBYTE(esi3->_mgoal) != MGOAL_MOVE) {
esi3->_mgoalvar1 = 0;
esi3->_mgoalvar2 = random(133, 2);
}
}
_LOBYTE(esi3->_mgoal) = 4;
v13 = abs(v4);
if (abs(v5) <= v13) {
v4 = v31;
v14 = abs(v31);
} else {
v14 = abs(v5);
v4 = v31;
}
v15 = esi3->_mgoalvar1;
esi3->_mgoalvar1 = v15 + 1;
if (v15 < 2 * v14 && dung_map[esi3->_mx][esi3->_my] == dung_map[v1][v2]) {
//_LOBYTE(v16) = M_RoundWalk(arglist, midir, &esi3->_mgoalvar2);
if (!M_RoundWalk(arglist, midir, &esi3->_mgoalvar2)) {
v18 = random(125, 10);
M_StartDelay(arglist, v18 + 10);
}
goto LABEL_23;
}
}
_LOBYTE(esi3->_mgoal) = MGOAL_NORMAL;
LABEL_23:
if (_LOBYTE(esi3->_mgoal) == MGOAL_NORMAL) {
if ((abs(v5) >= 5 || abs(v4) >= 5)
&& v30 < 2 * (unsigned char)esi3->_mint + 43
&& (v19 = LineClearF1(
PosOkMonst,
arglist,
esi3->_mx,
esi3->_my,
v1,
v2),
v19)) {
if (AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, MIS_RHINO, esi3->_menemy, arglist, 0, 0) != -1) {
if (esi3->MData->snd_special)
PlayEffect(arglist, 3);
v20 = esi3->_my + 112 * esi3->_mx;
esi3->_mmode = MM_CHARGE;
dMonster[0][v20] = -1 - arglist;
}
} else {
v21 = abs(v5);
//v23 = v22;
if (v21 >= 2 || (v24 = abs(v4), v24 >= 2)) /* v23 = v25, */
{
v26 = random(134, 100);
v27 = 2 * (unsigned char)esi3->_mint;
if (v26 >= v27 + 33
&& ((v28 = esi3->_mVar1, v28 != 1) && v28 != 2 && v28 != 3
|| esi3->_mVar2
|| (v27 += 83, v26 >= v27))) {
v29 = random(135, 10);
M_StartDelay(arglist, v29 + 10);
} else {
M_CallWalk(arglist, midir);
}
} else if (v30 < 2 * (unsigned char)esi3->_mint + 28) {
esi3->_mdir = midir;
M_StartAttack(arglist);
}
}
}
if (esi3->_mmode == MM_STAND)
esi3->_mAnimData = esi3->MType->Anims[MA_STAND].Data[esi3->_mdir];
}
}
void __fastcall MAI_Counselor(int i)
{
int v1; // ebx
int v2; // esi
int v3; // ecx
int v4; // edi
int v5; // edx
int v6; // ebp
char v9; // al
int v10; // ecx
BOOLEAN v11; // zf
BOOLEAN v12; // sf
unsigned char v13; // of
int v14; // edx
int v15; // ecx
int v16; // ebx
int v17; // eax
int v18; // ebx
int v19; // edx
int v20; // ecx
//int v21; // eax
int v22; // eax
//int v23; // ST1C_4
int v25; // eax
//int v26; // ST1C_4
int v27; // edx
int v28; // eax
int v29; // eax
int v30; // ecx
//int v31; // eax
int v32; // eax
int v33; // eax
int v34; // eax
int md; // [esp+8h] [ebp-14h]
int arglist; // [esp+Ch] [ebp-10h]
int y2; // [esp+10h] [ebp-Ch]
int x2; // [esp+14h] [ebp-8h]
int v39; // [esp+18h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Counselor: Invalid monster %d", i);
v2 = v1;
if (monster[v1]._mmode == MM_STAND && monster[v2]._msquelch) {
v3 = monster[v2]._mx;
x2 = (unsigned char)monster[v2]._menemyx;
v4 = v3 - x2;
v5 = monster[v2]._my;
y2 = (unsigned char)monster[v2]._menemyy;
v6 = v5 - y2;
md = GetDirection(v3, v5, monster[v2]._lastx, monster[v2]._lasty);
if (monster[v2]._msquelch < 0xFFu) /* check sign */
MonstCheckDoors(v1);
v39 = random(121, 100);
v9 = monster[v2]._mgoal;
if (v9 == MGOAL_RETREAT) {
v10 = monster[v2]._mgoalvar1;
v13 = __OFSUB__(v10, 3);
v11 = v10 == 3;
v12 = v10 - 3 < 0;
v14 = v10 + 1;
v15 = v1;
monster[v2]._mgoalvar1 = v14;
if ((unsigned char)(v12 ^ v13) | v11) {
M_CallWalk(v1, opposite[md]);
goto LABEL_39;
}
goto LABEL_21;
}
if (v9 == MGOAL_MOVE) {
v16 = abs(v6);
if (abs(v4) <= v16)
v17 = abs(v6);
else
v17 = abs(v4);
v18 = v17;
if (abs(v4) < 2 && abs(v6) < 2
|| monster[v2]._msquelch != -1
|| dung_map[monster[v2]._mx][monster[v2]._my] != dung_map[x2][y2]) {
v1 = arglist;
LABEL_20:
v15 = v1;
LABEL_21:
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
M_StartFadein(v15, md, TRUE);
goto LABEL_39;
}
v19 = 2 * v18;
v1 = arglist;
v20 = monster[v2]._mgoalvar1;
monster[v2]._mgoalvar1 = v20 + 1;
if (v20 >= v19) {
//_LOBYTE(v21) = DirOK(arglist, md);
if (DirOK(arglist, md))
goto LABEL_20;
}
M_RoundWalk(arglist, md, &monster[v2]._mgoalvar2);
LABEL_39:
if (monster[v2]._mmode == MM_STAND) {
v34 = random(125, 10);
M_StartDelay(v1, v34 + 5);
}
return;
}
if (v9 != MGOAL_NORMAL)
goto LABEL_39;
v22 = abs(v4);
//v24 = v23;
if (v22 >= 2 || (v25 = abs(v6), v25 >= 2)) /* v24 = v26, */
{
if (v39 < 5 * ((unsigned char)monster[v2]._mint + 10)) {
//_LOBYTE(v31) = LineClear(monster[v2]._mx, monster[v2]._my, x2, y2);
if (LineClear(monster[v2]._mx, monster[v2]._my, x2, y2)) {
v32 = random(
77,
(unsigned char)monster[v2].mMaxDamage - (unsigned char)monster[v2].mMinDamage + 1);
M_StartRAttack(
v1,
(unsigned char)counsmiss[(unsigned char)monster[v2]._mint], /* counsmiss is local */
(unsigned char)monster[v2].mMinDamage + v32);
goto LABEL_39;
}
}
if (random(124, 100) < 30) {
v27 = md;
_LOBYTE(monster[v2]._mgoal) = MGOAL_MOVE;
goto LABEL_29;
}
} else {
v27 = md;
v28 = monster[v2]._mmaxhp >> 1;
v13 = __OFSUB__(monster[v2]._mhitpoints, v28);
v12 = monster[v2]._mhitpoints - v28 < 0;
monster[v2]._mdir = md;
if (v12 ^ v13) {
_LOBYTE(monster[v2]._mgoal) = MGOAL_RETREAT;
LABEL_29:
monster[v2]._mgoalvar1 = 0;
M_StartFadeout(v1, v27, FALSE);
goto LABEL_39;
}
if (monster[v2]._mVar1 == 13
|| (v29 = random(105, 100),
v30 = 2 * (unsigned char)monster[v2]._mint + 20,
v29 < v30)) {
M_StartRAttack(v1, -1, 0);
AddMissile(monster[v2]._mx, monster[v2]._my, 0, 0, monster[v2]._mdir, MIS_FLASH, 1, v1, 4, 0);
AddMissile(monster[v2]._mx, monster[v2]._my, 0, 0, monster[v2]._mdir, MIS_FLASH2, 1, v1, 4, 0);
goto LABEL_39;
}
}
v33 = random(105, 10);
M_StartDelay(v1, v33 + 2 * (5 - (unsigned char)monster[v2]._mint));
goto LABEL_39;
}
}
void __fastcall MAI_Garbud(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Garbud: Invalid monster %d", i);
MonsterStruct *Monst = &monster[i];
if (Monst->_mmode != MM_STAND) {
return;
}
int _mx = Monst->_mx;
int _my = Monst->_my;
int md = M_GetDir(i);
if (Monst->mtalkmsg < QUEST_GARBUD4
&& Monst->mtalkmsg > QUEST_DOOM10
&& !(dFlags[_mx][_my] & DFLAG_VISIBLE)
&& Monst->_mgoal == MGOAL_TALKING) {
Monst->_mgoal = MGOAL_INQUIRING;
Monst->mtalkmsg++;
}
if (dFlags[_mx][_my] & DFLAG_VISIBLE) {
if (Monst->mtalkmsg == QUEST_GARBUD4) {
if (!effect_is_playing(USFX_GARBUD4) && Monst->_mgoal == MGOAL_TALKING) {
Monst->_mgoal = MGOAL_NORMAL;
Monst->_msquelch = -1;
Monst->mtalkmsg = 0;
}
}
}
if (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_MOVE)
MAI_Round(i, TRUE);
monster[i]._mdir = md;
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
void __fastcall MAI_Zhar(int i)
{
int v1; // ebp
int v2; // esi
int v3; // ebx
int v4; // edi
int v5; // edi
int v6; // ebx
int v7; // ebp
//int v8; // eax
char v9; // al
int arglist; // [esp+8h] [ebp-8h]
int v11; // [esp+Ch] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Zhar: Invalid monster %d", i);
v2 = v1;
if (monster[v1]._mmode == MM_STAND) {
v3 = monster[v2]._my;
v4 = monster[v2]._mx;
v11 = M_GetDir(v1);
if (monster[v2].mtalkmsg == QUEST_ZHAR1 && !(dFlags[v4][v3] & DFLAG_VISIBLE) && _LOBYTE(monster[v2]._mgoal) == MGOAL_TALKING) {
monster[v2].mtalkmsg = QUEST_ZHAR2;
_LOBYTE(monster[v2]._mgoal) = MGOAL_INQUIRING;
}
if (dFlags[v4][v3] & DFLAG_VISIBLE) {
v5 = monster[v2]._mx - (unsigned char)monster[v2]._menemyx;
v6 = monster[v2]._my - (unsigned char)monster[v2]._menemyy;
v7 = abs(v6);
if (abs(v5) <= v7)
abs(v6);
else
abs(v5);
if (monster[v2].mtalkmsg == QUEST_ZHAR2) {
//_LOBYTE(v8) = effect_is_playing(USFX_ZHAR2);
if (!effect_is_playing(USFX_ZHAR2) && _LOBYTE(monster[v2]._mgoal) == MGOAL_TALKING) {
monster[v2]._msquelch = -1;
monster[v2].mtalkmsg = 0;
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
}
}
v9 = monster[v2]._mgoal;
if (v9 == MGOAL_NORMAL || v9 == MGOAL_RETREAT || v9 == MGOAL_MOVE)
MAI_Counselor(arglist);
monster[v2]._mdir = v11;
if (monster[v2]._mmode == MM_STAND)
monster[v2]._mAnimData = monster[v2].MType->Anims[MA_STAND].Data[v11];
}
}
void __fastcall MAI_SnotSpil(int i)
{
int v1; // ebp
int v2; // esi
int v3; // ebx
int v4; // edi
int v5; // ebp
//int v6; // eax
char v7; // al
int arglist; // [esp+8h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_SnotSpil: Invalid monster %d", i);
v2 = v1;
if (monster[v1]._mmode == MM_STAND) {
v3 = monster[v2]._my;
v4 = monster[v2]._mx;
v5 = M_GetDir(v1);
if (monster[v2].mtalkmsg == QUEST_BANNER10 && !(dFlags[v4][v3] & DFLAG_VISIBLE) && _LOBYTE(monster[v2]._mgoal) == 7) {
monster[v2].mtalkmsg = QUEST_BANNER11;
_LOBYTE(monster[v2]._mgoal) = MGOAL_INQUIRING;
}
if (monster[v2].mtalkmsg == QUEST_BANNER11 && quests[QTYPE_BOL]._qvar1 == 3) {
monster[v2].mtalkmsg = 0;
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
if (dFlags[v4][v3] & DFLAG_VISIBLE) {
if (monster[v2].mtalkmsg == QUEST_BANNER12) {
//_LOBYTE(v6) = effect_is_playing(USFX_SNOT3);
if (!effect_is_playing(USFX_SNOT3) && _LOBYTE(monster[v2]._mgoal) == MGOAL_TALKING) {
ObjChangeMap(setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1);
quests[QTYPE_BOL]._qvar1 = 3;
RedoPlayerVision();
monster[v2]._msquelch = -1;
monster[v2].mtalkmsg = 0;
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
}
if (quests[QTYPE_BOL]._qvar1 == 3) {
v7 = monster[v2]._mgoal;
if (v7 == MGOAL_NORMAL || v7 == MGOAL_SHOOT)
MAI_Fallen(arglist);
}
}
monster[v2]._mdir = v5;
if (monster[v2]._mmode == MM_STAND)
monster[v2]._mAnimData = monster[v2].MType->Anims[MA_STAND].Data[v5];
}
}
// 5CF330: using guessed type int setpc_h;
// 5CF334: using guessed type int setpc_w;
void __fastcall MAI_Lazurus(int i)
{
int v1; // ebx
int v2; // esi
int v3; // ebp
int v4; // edi
int v5; // ebx
//int v6; // eax
char v7; // al
int v8; // eax
int arglist; // [esp+8h] [ebp-4h]
v1 = i;
arglist = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Lazurus: Invalid monster %d", i);
v2 = v1;
if (monster[v1]._mmode == MM_STAND) {
v3 = monster[v2]._my;
v4 = monster[v2]._mx;
v5 = M_GetDir(v1);
if (dFlags[v4][v3] & DFLAG_VISIBLE) {
if (gbMaxPlayers != 1)
goto LABEL_29;
if (monster[v2].mtalkmsg == QUEST_VILE13) {
if (_LOBYTE(monster[v2]._mgoal) == MGOAL_INQUIRING && plr[myplr].WorldX == QUEST_VILE13 && plr[myplr].WorldY == 46) {
PlayInGameMovie("gendata\\fprst3.smk");
monster[v2]._mmode = MM_TALK;
quests[QTYPE_VB]._qvar1 = 5;
}
if (monster[v2].mtalkmsg == QUEST_VILE13) {
//_LOBYTE(v6) = effect_is_playing(USFX_LAZ1);
if (!effect_is_playing(USFX_LAZ1) && _LOBYTE(monster[v2]._mgoal) == MGOAL_TALKING) {
ObjChangeMapResync(1, 18, 20, 24);
RedoPlayerVision();
monster[v2]._msquelch = -1;
monster[v2].mtalkmsg = 0;
quests[QTYPE_VB]._qvar1 = 6;
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
}
}
if (gbMaxPlayers != 1) {
LABEL_29:
if (monster[v2].mtalkmsg == QUEST_VILE13 && _LOBYTE(monster[v2]._mgoal) == MGOAL_INQUIRING && quests[QTYPE_VB]._qvar1 <= 3u)
monster[v2]._mmode = MM_TALK;
}
}
v7 = monster[v2]._mgoal;
if (v7 == MGOAL_NORMAL || v7 == MGOAL_RETREAT || v7 == MGOAL_MOVE) {
monster[v2].mtalkmsg = 0;
MAI_Counselor(arglist);
}
monster[v2]._mdir = v5;
v8 = monster[v2]._mmode;
if (v8 == MM_STAND || v8 == MM_TALK)
monster[v2]._mAnimData = monster[v2].MType->Anims[MA_STAND].Data[v5];
}
}
// 679660: using guessed type char gbMaxPlayers;
void __fastcall MAI_Lazhelp(int i)
{
int v1; // esi
int v2; // esi
int v3; // ebx
int v4; // edi
int v5; // [esp+4h] [ebp-8h]
int ia; // [esp+8h] [ebp-4h]
v1 = i;
ia = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Lazhelp: Invalid monster %d", i);
v2 = v1;
if (monster[v2]._mmode == MM_STAND) {
v3 = monster[v2]._my;
v4 = monster[v2]._mx;
v5 = M_GetDir(ia);
if (dFlags[v4][v3] & DFLAG_VISIBLE) {
if (gbMaxPlayers == 1) {
if (quests[QTYPE_VB]._qvar1 <= 5u) {
_LOBYTE(monster[v2]._mgoal) = MGOAL_INQUIRING;
goto LABEL_10;
}
monster[v2].mtalkmsg = 0;
}
_LOBYTE(monster[v2]._mgoal) = MGOAL_NORMAL;
}
LABEL_10:
if (_LOBYTE(monster[v2]._mgoal) == MGOAL_NORMAL)
MAI_Succ(ia);
monster[v2]._mdir = v5;
if (monster[v2]._mmode == MM_STAND)
monster[v2]._mAnimData = monster[v2].MType->Anims[MA_STAND].Data[v5];
}
}
// 679660: using guessed type char gbMaxPlayers;
void __fastcall MAI_Lachdanan(int i)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Lachdanan: Invalid monster %d", i);
MonsterStruct *Monst = &monster[i];
if (Monst->_mmode != MM_STAND) {
return;
}
int _mx = Monst->_mx;
int _my = Monst->_my;
int md = M_GetDir(i);
if (Monst->mtalkmsg == QUEST_VEIL9 && !(dFlags[_mx][_my] & DFLAG_VISIBLE) && Monst->_mgoal == MGOAL_TALKING) {
Monst->mtalkmsg = QUEST_VEIL10;
Monst->_mgoal = MGOAL_INQUIRING;
}
if (dFlags[_mx][_my] & DFLAG_VISIBLE) {
if (Monst->mtalkmsg == QUEST_VEIL11) {
if (!effect_is_playing(USFX_LACH3) && Monst->_mgoal == MGOAL_TALKING) {
Monst->mtalkmsg = 0;
quests[QTYPE_VEIL]._qactive = 3;
M_StartKill(i, -1);
}
}
}
monster[i]._mdir = md;
if (Monst->_mmode == MM_STAND)
Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md];
}
void __fastcall MAI_Warlord(int i)
{
int mx, my, md;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("MAI_Warlord: Invalid monster %d", i);
if (monster[i]._mmode == MM_STAND) {
mx = monster[i]._mx;
my = monster[i]._my;
md = M_GetDir(i);
if (dFlags[mx][my] & DFLAG_VISIBLE) {
if (monster[i].mtalkmsg == QUEST_WARLRD9 && monster[i]._mgoal == MGOAL_INQUIRING)
monster[i]._mmode = MM_TALK;
if (monster[i].mtalkmsg == QUEST_WARLRD9 && !effect_is_playing(USFX_WARLRD1) && monster[i]._mgoal == MGOAL_TALKING) {
monster[i]._msquelch = -1;
monster[i].mtalkmsg = 0;
monster[i]._mgoal = MGOAL_NORMAL;
}
}
if (monster[i]._mgoal == MGOAL_NORMAL)
MAI_SkelSd(i);
monster[i]._mdir = md;
if (monster[i]._mmode == MM_STAND || monster[i]._mmode == MM_TALK)
monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[md];
}
}
void __cdecl DeleteMonsterList()
{
int i;
for (i = 0; i < 4; i++) {
if (monster[i]._mDelFlag) {
monster[i]._mx = 1;
monster[i]._my = 0;
monster[i]._mfutx = 0;
monster[i]._mfuty = 0;
monster[i]._moldx = 0;
monster[i]._moldy = 0;
monster[i]._mDelFlag = FALSE;
}
}
i = 4;
while (i < nummonsters) {
if (monster[monstactive[i]]._mDelFlag) {
DeleteMonster(i);
i = 0; // TODO: check if this should be i=4.
} else {
i++;
}
}
}
void __cdecl ProcessMonsters()
{
int v0; // edi
int v1; // esi
int v2; // ecx
int v3; // eax
char *v4; // ebx
unsigned int v5; // eax
int v6; // eax
int v7; // edx
int v8; // eax
unsigned int v9; // eax
int v10; // eax
BOOLEAN v11; // zf
char *v12; // ecx
char *v13; // eax
int v14; // ecx
int v15; // eax
char v16; // al
int v17; // ecx
BOOLEAN v18; // eax
int v19; // eax
int v20; // ecx
int *v21; // eax
int *v22; // eax
int v23; // [esp+0h] [ebp-Ch]
int v24; // [esp+4h] [ebp-8h]
int v25; // [esp+8h] [ebp-4h]
DeleteMonsterList();
v24 = 0;
if (nummonsters <= 0)
goto LABEL_60;
do {
v25 = 0;
v23 = monstactive[v24];
v0 = v23;
v1 = v23;
if ((unsigned char)gbMaxPlayers > 1u) {
SetRndSeed(monster[v1]._mAISeed);
monster[v1]._mAISeed = GetRndSeed();
}
if (!(monster[v1]._mFlags & MFLAG_NOHEAL)) {
v2 = monster[v1]._mhitpoints;
if (v2 < monster[v1]._mmaxhp && v2 >> 6 > 0) {
v3 = SLOBYTE(monster[v1].mLevel);
if ((char)v3 > 1)
v3 = (char)v3 >> 1;
monster[v1]._mhitpoints = v2 + v3;
}
}
v4 = &dFlags[monster[v1]._mx][monster[v1]._my];
if (*v4 & DFLAG_VISIBLE && !monster[v1]._msquelch && monster[v1].MType->mtype == MT_CLEAVER)
PlaySFX(USFX_CLEAVER);
if (monster[v1]._mFlags & MFLAG_TARGETS_MONSTER) {
v5 = monster[v1]._menemy;
if (v5 >= MAXMONSTERS)
TermMsg("Illegal enemy monster %d for monster \"%s\"", v5, monster[v1].mName);
v6 = monster[v1]._menemy;
v7 = monster[v6]._mfutx;
monster[v1]._lastx = v7;
monster[v1]._menemyx = v7;
v8 = monster[v6]._mfuty;
monster[v1]._menemyy = v8;
monster[v1]._lasty = v8;
} else {
v9 = monster[v1]._menemy;
if (v9 >= MAX_PLRS)
TermMsg("Illegal enemy player %d for monster \"%s\"", v9, monster[v1].mName);
v10 = monster[v1]._menemy;
v11 = (*v4 & DFLAG_VISIBLE) == 0;
v12 = (char *)&plr[v10]._px;
v13 = (char *)&plr[v10]._py;
monster[v1]._menemyx = *v12;
monster[v1]._menemyy = *v13;
if (v11) {
v16 = monster[v1]._msquelch;
if (v16 && monster[v1]._mAi != MT_DIABLO) /// BUGFIX: test `MT_DIABLO` with 'MType->mtype' instead of '_mAi'
monster[v1]._msquelch = v16 - 1;
} else {
v14 = *(_DWORD *)v12;
v15 = *(_DWORD *)v13;
monster[v1]._msquelch = -1;
monster[v1]._lastx = v14;
monster[v1]._lasty = v15;
}
v0 = v23;
}
while (1) {
v17 = v0;
if (monster[v1]._mFlags & MFLAG_SEARCH) {
v18 = MAI_Path(v0);
if (v18)
goto LABEL_30;
v17 = v0;
}
AiProc[(unsigned char)monster[v1]._mAi](v17);
LABEL_30:
switch (monster[v1]._mmode) {
case MM_STAND:
v19 = M_DoStand(v0);
goto LABEL_48;
case MM_WALK:
v19 = M_DoWalk(v0);
goto LABEL_48;
case MM_WALK2:
v19 = M_DoWalk2(v0);
goto LABEL_48;
case MM_WALK3:
v19 = M_DoWalk3(v0);
goto LABEL_48;
case MM_ATTACK:
v19 = M_DoAttack(v0);
goto LABEL_48;
case MM_GOTHIT:
v19 = M_DoGotHit(v0);
goto LABEL_48;
case MM_DEATH:
v19 = M_DoDeath(v0);
goto LABEL_48;
case MM_SATTACK:
v19 = M_DoSAttack(v0);
goto LABEL_48;
case MM_FADEIN:
v19 = M_DoFadein(v0);
goto LABEL_48;
case MM_FADEOUT:
v19 = M_DoFadeout(v0);
goto LABEL_48;
case MM_RATTACK:
v19 = M_DoRAttack(v0);
goto LABEL_48;
case MM_SPSTAND:
v19 = M_DoSpStand(v0);
goto LABEL_48;
case MM_RSPATTACK:
v19 = M_DoRSpAttack(v0);
goto LABEL_48;
case MM_DELAY:
v19 = M_DoDelay(v0);
goto LABEL_48;
case MM_CHARGE:
goto LABEL_51;
case MM_STONE:
v19 = M_DoStone(v0);
goto LABEL_48;
case MM_HEAL:
v19 = M_DoHeal(v0);
goto LABEL_48;
case MM_TALK:
v19 = M_DoTalk(v0);
LABEL_48:
v25 = v19;
break;
default:
break;
}
if (!v25)
break;
GroupUnity(v0);
}
LABEL_51:
if (monster[v1]._mmode != MM_STONE) {
v20 = monster[v1]._mFlags;
v21 = &monster[v1]._mAnimCnt;
++*v21;
if (!(v20 & MFLAG_ALLOW_SPECIAL) && monster[v1]._mAnimCnt >= monster[v1]._mAnimDelay) {
*v21 = 0;
v22 = &monster[v1]._mAnimFrame;
if (v20 & MFLAG_LOCK_ANIMATION) {
v11 = (*v22)-- == 1;
if (v11)
*v22 = monster[v1]._mAnimLen;
} else if (++*v22 > monster[v1]._mAnimLen) {
*v22 = 1;
}
}
}
++v24;
} while (v24 < nummonsters);
LABEL_60:
DeleteMonsterList();
}
// 679660: using guessed type char gbMaxPlayers;
void __cdecl FreeMonsters()
{
int mtype;
int i, j;
void *ptr;
for (i = 0; i < nummtypes; i++) {
mtype = Monsters[i].mtype;
for (j = 0; j < 6; j++) {
if (animletter[j] != 's' || monsterdata[mtype].has_special) {
ptr = Monsters[i].Anims[j].CMem;
Monsters[i].Anims[j].CMem = NULL;
mem_free_dbg(ptr);
}
}
}
FreeMissiles2();
}
BOOL __fastcall DirOK(int i, int mdir)
{
int v2; // ebx
int v3; // esi
int v4; // ebx
int v5; // edi
int v6; // esi
int v7; // edi
BOOLEAN v8; // zf
int v9; // edx
unsigned char *v11; // ebx
unsigned char v12; // al
int v13; // edx
int v14; // eax
int v15; // edi
int v16; // ecx
signed int j; // esi
int v18; // eax
BOOLEAN v19; // zf
int v20; // eax
int v21; // [esp+Ch] [ebp-14h]
int v22; // [esp+10h] [ebp-10h]
int v23; // [esp+14h] [ebp-Ch]
int a1; // [esp+18h] [ebp-8h]
int v25; // [esp+1Ch] [ebp-4h]
int v26; // [esp+1Ch] [ebp-4h]
v2 = i;
v3 = mdir;
v25 = mdir;
a1 = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("DirOK: Invalid monster %d", i);
v4 = v2;
v5 = offset_y[v3];
v6 = monster[v4]._mx + offset_x[v3];
v7 = monster[v4]._my + v5;
if (v7 < 0 || v7 >= MAXDUNY || v6 < 0 || v6 >= MAXDUNX || !PosOkMonst(a1, v6, v7))
return 0;
if (v25 == DIR_E) {
if (!SolidLoc(v6, v7 + 1)) {
v8 = (dFlags[v6][v7 + 1] & DFLAG_MONSTER) == 0;
goto LABEL_18;
}
return 0;
}
if (v25 == DIR_W) {
if (SolidLoc(v6 + 1, v7))
return 0;
v8 = (dFlags[v6 + 1][v7] & DFLAG_MONSTER) == 0;
} else {
if (v25 == DIR_N) {
if (SolidLoc(v6 + 1, v7))
return 0;
v9 = v7 + 1;
} else {
if (v25)
goto LABEL_24;
if (SolidLoc(v6 - 1, v7))
return 0;
v9 = v7 - 1;
}
v8 = SolidLoc(v6, v9) == 0;
}
LABEL_18:
if (!v8)
return 0;
LABEL_24:
if (monster[v4].leaderflag == 1) {
v11 = &monster[v4].leader;
if (abs(v6 - monster[(unsigned char)*v11]._mfutx) >= 4
|| abs(v7 - monster[(unsigned char)*v11]._mfuty) >= 4) {
return 0;
}
return 1;
}
v12 = monster[v4]._uniqtype;
if (v12 == 0 || !(UniqMonst[v12 - 1].mUnqAttr & 2))
return 1;
v26 = 0;
v13 = v6 - 3;
v21 = v6 + 3;
if (v6 - 3 <= v6 + 3) {
v14 = v7 - 3;
v15 = v7 + 3;
v23 = v14;
v22 = v15;
v16 = 112 * v13;
do {
for (j = v23; j <= v15; ++j) {
if (j >= 0 && j < MAXDUNY && v16 >= 0 && v16 < MAXDUNX * 112) {
v18 = dMonster[0][v16 + j];
v19 = v18 == 0;
if (v18 < 0) {
v18 = -v18;
v19 = v18 == 0;
}
if (!v19)
--v18;
v20 = v18;
if (monster[v20].leaderflag == 1
&& (unsigned char)monster[v20].leader == a1
&& monster[v20]._mfutx == v13
&& monster[v20]._mfuty == j) {
++v26;
}
}
v15 = v22;
}
++v13;
v16 += 112;
} while (v13 <= v21);
}
return v26 == (unsigned char)monster[v4].packsize;
}
BOOL __fastcall PosOkMissile(int x, int y)
{
return !nMissileTable[dPiece[x][y]] && !(dFlags[x][y] & DFLAG_MONSTER);
}
BOOL __fastcall CheckNoSolid(int x, int y)
{
return nSolidTable[dPiece[x][y]] == 0;
}
BOOL __fastcall LineClearF(BOOL(__fastcall *Clear)(int, int), int x1, int y1, int x2, int y2)
{
int v5; // esi
int v6; // edi
int v7; // ebx
int v8; // eax
int v9; // eax
int v10; // eax
int v11; // ebx
int v12; // esi
signed int v13; // edi
int v14; // edx
int v15; // ecx
int v16; // eax
int v17; // eax
int v18; // eax
int v19; // ebx
int v20; // edi
signed int v21; // esi
int v22; // ecx
int v25; // [esp+10h] [ebp-10h]
int v26; // [esp+14h] [ebp-Ch]
int v27; // [esp+18h] [ebp-8h]
int v28; // [esp+18h] [ebp-8h]
int v29; // [esp+1Ch] [ebp-4h]
v5 = y2 - y1;
v29 = x1;
v25 = x1;
v26 = y1;
v6 = x2 - x1;
v7 = abs(y2 - y1);
if (abs(v6) <= v7) {
if (v5 < 0) {
v16 = y1;
y1 = y2;
y2 = v16;
v17 = v29;
v5 = -v5;
v29 = x2;
x2 = v17;
v6 = -v6;
}
v18 = 2 * v6;
v28 = 2 * v6;
if (v6 <= 0) {
v19 = v18 + v5;
v20 = 2 * (v5 + v6);
v21 = -1;
} else {
v19 = v18 - v5;
v20 = 2 * (v6 - v5);
v21 = 1;
}
while (1) {
v22 = v29;
if (y1 == y2 && v29 == x2)
break;
if (v19 <= 0 == v21 < 0) {
v19 += v20;
v22 = v21 + v29;
v29 += v21;
} else {
v19 += v28;
}
if ((++y1 != v26 || v22 != v25) && !Clear(v22, y1)) /* check args */
goto LABEL_29;
}
} else {
if (v6 < 0) {
v8 = v29;
v29 = x2;
x2 = v8;
v9 = y1;
v6 = -v6;
y1 = y2;
y2 = v9;
v5 = -v5;
}
v10 = 2 * v5;
v27 = 2 * v5;
if (v5 <= 0) {
v11 = v10 + v6;
v12 = 2 * (v6 + v5);
v13 = -1;
} else {
v11 = v10 - v6;
v12 = 2 * (v5 - v6);
v13 = 1;
}
do {
v14 = y1;
if (v29 == x2 && y1 == y2)
break;
if (v11 <= 0 == v13 < 0) {
v11 += v12;
v14 = v13 + y1;
y1 += v13;
} else {
v11 += v27;
}
v15 = v29 + 1;
} while (++v29 == v25 && v14 == v26 || Clear(v15, v14));
LABEL_29:
if (v29 != x2)
return 0;
}
if (y1 == y2)
return 1;
return 0;
}
BOOL __fastcall LineClear(int x1, int y1, int x2, int y2)
{
return LineClearF(PosOkMissile, x1, y1, x2, y2);
}
BOOL __fastcall LineClearF1(BOOL(__fastcall *Clear)(int, int, int), int monst, int x1, int y1, int x2, int y2)
{
int v6; // esi
int v7; // edi
int v8; // ebx
int v9; // eax
int v10; // eax
int v11; // eax
int v12; // ebx
int v13; // esi
signed int v14; // edi
int v15; // eax
int v16; // eax
int v17; // eax
int v18; // eax
int v19; // ebx
int v20; // edi
signed int v21; // esi
int v22; // edx
int v25; // [esp+10h] [ebp-10h]
int v26; // [esp+14h] [ebp-Ch]
int v27; // [esp+18h] [ebp-8h]
int v28; // [esp+1Ch] [ebp-4h]
int v29; // [esp+1Ch] [ebp-4h]
v6 = y2 - y1;
v25 = monst;
v26 = x1;
v27 = y1;
v7 = x2 - x1;
v8 = abs(y2 - y1);
if (abs(x2 - x1) <= v8) {
if (v6 < 0) {
v16 = y1;
y1 = y2;
y2 = v16;
v17 = x1;
v6 = -v6;
x1 = x2;
x2 = v17;
v7 = -v7;
}
v18 = 2 * v7;
v29 = 2 * v7;
if (v7 <= 0) {
v19 = v18 + v6;
v20 = 2 * (v6 + v7);
v21 = -1;
} else {
v19 = v18 - v6;
v20 = 2 * (v7 - v6);
v21 = 1;
}
while (1) {
v22 = x1;
if (y1 == y2 && x1 == x2)
break;
if (v19 <= 0 == v21 < 0) {
v19 += v20;
v22 = v21 + x1;
x1 += v21;
} else {
v19 += v29;
}
if ((++y1 != v27 || v22 != v26) && !Clear(v25, v22, y1))
goto LABEL_29;
}
} else {
if (v7 < 0) {
v9 = x1;
x1 = x2;
x2 = v9;
v10 = y1;
v7 = -v7;
y1 = y2;
y2 = v10;
v6 = -v6;
}
v11 = 2 * v6;
v28 = 2 * v6;
if (v6 <= 0) {
v12 = v11 + v7;
v13 = 2 * (v7 + v6);
v14 = -1;
} else {
v12 = v11 - v7;
v13 = 2 * (v6 - v7);
v14 = 1;
}
do {
v15 = y1;
if (x1 == x2 && y1 == y2)
break;
if (v12 <= 0 == v14 < 0) {
v12 += v13;
v15 = v14 + y1;
y1 += v14;
} else {
v12 += v28;
}
} while (++x1 == v26 && v15 == v27 || Clear(v25, x1, v15)); /* check args */
LABEL_29:
if (x1 != x2)
return 0;
}
if (y1 == y2)
return 1;
return 0;
}
void __fastcall SyncMonsterAnim(int i)
{
int v1; // esi
int v2; // eax
int v3; // edx
MonsterData *v4; // esi
CMonster *v5; // ecx
unsigned char v6; // dl
char *v7; // edx
int v8; // esi
int v9; // edx
unsigned char *v10; // ecx
unsigned char *v11; // edx
int v12; // ecx
unsigned char *v13; // edx
v1 = i;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("SyncMonsterAnim: Invalid monster %d", i);
v2 = v1;
v3 = monster[v1]._mMTidx;
v4 = Monsters[v3].MData;
v5 = &Monsters[v3];
v6 = monster[v2]._uniqtype;
monster[v2].MType = v5;
monster[v2].MData = v4;
if (v6 != 0)
v7 = UniqMonst[v6 - 1].mName;
else
v7 = v4->mName;
v8 = monster[v2]._mmode;
monster[v2].mName = v7;
v9 = monster[v2]._mdir;
switch (v8) {
case MM_STAND:
case MM_DELAY:
case MM_TALK:
v10 = v5->Anims[MA_STAND].Data[v9];
goto LABEL_13;
case MM_WALK:
case MM_WALK2:
case MM_WALK3:
v10 = v5->Anims[MA_WALK].Data[v9];
goto LABEL_13;
case MM_ATTACK:
case MM_RATTACK:
v10 = v5->Anims[MA_ATTACK].Data[v9];
goto LABEL_13;
case MM_GOTHIT:
v10 = v5->Anims[MA_GOTHIT].Data[v9];
goto LABEL_13;
case MM_DEATH:
v10 = v5->Anims[MA_DEATH].Data[v9];
goto LABEL_13;
case MM_SATTACK:
case MM_FADEIN:
case MM_FADEOUT:
case MM_SPSTAND:
case MM_RSPATTACK:
case MM_HEAL:
v10 = v5->Anims[MA_SPECIAL].Data[v9];
LABEL_13:
monster[v2]._mAnimData = v10;
return;
case MM_CHARGE:
v11 = v5->Anims[MA_ATTACK].Data[v9];
monster[v2]._mAnimFrame = 1;
monster[v2]._mAnimData = v11;
v12 = v5->Anims[MA_ATTACK].Frames;
break;
default:
v13 = v5->Anims[MA_STAND].Data[v9];
monster[v2]._mAnimFrame = 1;
monster[v2]._mAnimData = v13;
v12 = v5->Anims[MA_STAND].Frames;
break;
}
monster[v2]._mAnimLen = v12;
}
void __fastcall M_FallenFear(int x, int y)
{
int v2; // eax
int *v3; // ebx
int v4; // edi
int v5; // esi
signed int v6; // eax
int v7; // eax
BOOLEAN v8; // zf
int v9; // eax
int v10; // eax
signed int v11; // [esp-10h] [ebp-1Ch]
int v12; // [esp+0h] [ebp-Ch]
int x1; // [esp+4h] [ebp-8h]
int y1; // [esp+8h] [ebp-4h]
v2 = 0;
y1 = y;
x1 = x;
v12 = 0;
if (nummonsters > 0) {
v3 = &monster[0]._mx;
do {
v4 = 0;
v5 = monstactive[v2];
v6 = monster[v5].MType->mtype;
if (v6 > MT_RFALLSD) {
v9 = v6 - 13;
v8 = v9 == 0;
} else {
if (v6 == MT_RFALLSD || (v7 = v6 - 4) == 0) {
v11 = 7;
goto LABEL_15;
}
v9 = v7 - 1;
v8 = v9 == 0;
}
if (v8) {
v11 = 5;
} else {
v10 = v9 - 1;
if (v10) {
if (v10 != 1)
goto LABEL_16;
v11 = 2;
} else {
v11 = 3;
}
}
LABEL_15:
v4 = v11;
LABEL_16:
if (monster[v5]._mAi == AI_FALLEN
&& v4
&& abs(x1 - monster[v5]._mx) < 5
&& abs(y1 - monster[v5]._my) < 5
&& monster[v5]._mhitpoints >> 6 > 0) {
_LOBYTE(monster[v5]._mgoal) = MGOAL_RETREAT;
monster[v5]._mgoalvar1 = v4;
monster[v5]._mdir = GetDirection(x1, y1, *v3, v3[1]);
}
v3 += 57;
v2 = v12++ + 1;
} while (v12 < nummonsters);
}
}
void __fastcall PrintMonstHistory(int mt)
{
int v1; // edi
int *v2; // ebx
int v3; // ecx
int v4; // eax
int v5; // edi
short v6; // bx
int v7; // ebx
v1 = mt;
v2 = &monstkills[mt];
sprintf(tempstr, "Total kills : %i", *v2);
AddPanelString(tempstr, 1);
if (*v2 >= 30) {
v3 = monsterdata[v1].mMinHP;
v4 = monsterdata[v1].mMaxHP;
if (gbMaxPlayers == 1) {
v3 = monsterdata[v1].mMinHP >> 1;
v4 = monsterdata[v1].mMaxHP >> 1;
}
if (v3 < 1)
v3 = 1;
if (v4 < 1)
v4 = 1;
if (gnDifficulty == DIFF_NIGHTMARE) {
v3 = 3 * v3 + 1;
v4 = 3 * v4 + 1;
}
if (gnDifficulty == DIFF_HELL) {
v3 = 4 * v3 + 3;
v4 = 4 * v4 + 3;
}
sprintf(tempstr, "Hit Points : %i-%i", v3, v4);
AddPanelString(tempstr, 1);
}
if (*v2 >= 15) {
v5 = v1 << 7;
if (gnDifficulty == DIFF_HELL)
v6 = *(short *)((char *)&monsterdata[0].mMagicRes2 + v5);
else
v6 = *(short *)((char *)&monsterdata[0].mMagicRes + v5);
v7 = v6 & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING);
if (v7) {
if (v7 & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING)) {
strcpy(tempstr, "Resists : ");
if (v7 & RESIST_MAGIC)
strcat(tempstr, "Magic ");
if (v7 & RESIST_FIRE)
strcat(tempstr, "Fire ");
if (v7 & RESIST_LIGHTNING)
strcat(tempstr, "Lightning ");
tempstr[strlen(tempstr) - 1] = '\0';
AddPanelString(tempstr, 1);
}
if (v7 & (IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING)) {
strcpy(tempstr, "Immune : ");
if (v7 & IMUNE_MAGIC)
strcat(tempstr, "Magic ");
if (v7 & IMUNE_FIRE)
strcat(tempstr, "Fire ");
if (v7 & IMUNE_LIGHTNING)
strcat(tempstr, "Lightning ");
tempstr[strlen(tempstr) - 1] = '\0';
AddPanelString(tempstr, 1);
}
} else {
strcpy(tempstr, "No magic resistance");
AddPanelString(tempstr, 1);
}
}
pinfoflag = 1;
}
// 4B8824: using guessed type int pinfoflag;
// 679660: using guessed type char gbMaxPlayers;
void __cdecl PrintUniqueHistory()
{
char v0; // bl
v0 = monster[pcursmonst].mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING);
if (v0) {
if (monster[pcursmonst].mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING))
strcpy(tempstr, "Some Magic Resistances");
else
strcpy(tempstr, "No resistances");
AddPanelString(tempstr, 1);
if (v0 & (IMUNE_MAGIC | IMUNE_FIRE | IMUNE_LIGHTNING)) {
strcpy(tempstr, "Some Magic Immunities");
goto LABEL_4;
}
} else {
strcpy(tempstr, "No resistances");
AddPanelString(tempstr, 1);
}
strcpy(tempstr, "No Immunities");
LABEL_4:
AddPanelString(tempstr, 1);
pinfoflag = 1;
}
// 4B8824: using guessed type int pinfoflag;
void __fastcall MissToMonst(int i, int x, int y)
{
int v3; // edi
MissileStruct *v4; // edi
unsigned int v5; // ebx
MonsterStruct *v6; // esi
int v7; // edx
char v8; // al
int v9; // eax
char *v10; // edi
int v11; // eax
int v12; // edx
char v13; // al
char v14; // al
int v15; // ebx
int v16; // eax
int v17; // esi
int v18; // edi
int v19; // esi
int v20; // edx
int *v21; // ebx
char v22; // cl
char v23; // al
int v24; // esi
int v25; // edi
int v26; // esi
int v27; // eax
int v28; // eax
int ia; // [esp+Ch] [ebp-10h]
int v30; // [esp+10h] [ebp-Ch]
int v31; // [esp+14h] [ebp-8h]
int v32; // [esp+18h] [ebp-4h]
int arglist; // [esp+24h] [ebp+8h]
v3 = i;
v30 = x;
if ((DWORD)i >= MAXMISSILES)
TermMsg("MissToMonst: Invalid missile %d", i);
v4 = &missile[v3];
v5 = v4->_misource;
ia = v4->_misource;
if (v5 >= MAXMONSTERS)
TermMsg("MissToMonst: Invalid monster %d", v5);
v32 = v4->_mix;
v31 = v4->_miy;
v6 = &monster[v5];
v6->_mx = v30;
dMonster[v30][y] = v5 + 1;
v7 = v4->_mimfnum;
v6->_mdir = v7;
v6->_my = y;
M_StartStand(v5, v7);
v8 = v6->MType->mtype;
if (v8 < MT_INCIN || v8 > MT_HELLBURN) {
if (v6->_mFlags & MFLAG_TARGETS_MONSTER)
M2MStartHit(v5, -1, 0);
else
M_StartHit(v5, -1, 0);
} else {
M_StartFadein(v5, v6->_mdir, FALSE);
}
v9 = v32;
if (v6->_mFlags & MFLAG_TARGETS_MONSTER) {
v21 = (int *)((char *)dMonster + 4 * (v31 + v9 * 112));
if (*v21 > 0) {
v22 = v6->MType->mtype;
if (v22 != MT_GLOOM && (v22 < MT_INCIN || v22 > MT_HELLBURN)) {
M_TryM2MHit(ia, *v21 - 1, 500, (unsigned char)v6->mMinDamage2, (unsigned char)v6->mMaxDamage2);
v23 = v6->MType->mtype;
if (v23 < MT_NSNAKE || v23 > MT_GSNAKE) {
v24 = v6->_mdir;
v25 = v32 + offset_x[v24];
v26 = v31 + offset_y[v24];
if (PosOkMonst(*v21 - 1, v25, v26)) {
v27 = *v21;
dMonster[v25][v26] = *v21;
*v21 = 0;
v28 = v27 - 1;
monster[v28]._mx = v25;
monster[v28]._mfutx = v25;
monster[v28]._my = v26;
monster[v28]._mfuty = v26;
}
}
}
}
} else {
v10 = &dPlayer[v9][v31];
v11 = *v10;
v12 = v11 - 1;
arglist = v11 - 1;
if (*v10 > 0) {
v13 = v6->MType->mtype;
if (v13 != MT_GLOOM && (v13 < MT_INCIN || v13 > MT_HELLBURN)) {
M_TryH2HHit(v5, v12, 500, (unsigned char)v6->mMinDamage2, (unsigned char)v6->mMaxDamage2);
if (arglist == *v10 - 1) {
v14 = v6->MType->mtype;
if (v14 < MT_NSNAKE || v14 > MT_GSNAKE) {
v15 = arglist;
v16 = plr[arglist]._pmode;
if (v16 != 7 && v16 != 8)
StartPlrHit(arglist, 0, 1u);
v17 = v6->_mdir;
v18 = v32 + offset_x[v17];
v19 = v31 + offset_y[v17];
if (PosOkPlayer(arglist, v18, v19)) {
v20 = plr[v15]._pdir;
plr[v15].WorldX = v18;
plr[v15].WorldY = v19;
FixPlayerLocation(arglist, v20);
FixPlrWalkTags(arglist);
dPlayer[v18][v19] = arglist + 1;
SetPlayerOld(arglist);
}
}
}
}
}
}
}
BOOL __fastcall PosOkMonst(int i, int x, int y)
{
int oi, mi, j;
BOOL ret, fire;
fire = FALSE;
ret = !SolidLoc(x, y) && !dPlayer[x][y] && !dMonster[x][y];
if (ret && dObject[x][y]) {
oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1);
if (object[oi]._oSolidFlag)
ret = FALSE;
}
if (ret && dMissile[x][y] && i >= 0) {
mi = dMissile[x][y];
if (mi > 0) {
if (missile[mi]._mitype == MIS_FIREWALL) {
fire = TRUE;
} else {
for (j = 0; j < nummissiles; j++) {
if (missile[missileactive[j]]._mitype == MIS_FIREWALL)
fire = TRUE;
}
}
}
if (fire && (!(monster[i].mMagicRes & IMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO))
ret = FALSE;
}
return ret;
}
BOOL __fastcall PosOkMonst2(int i, int x, int y)
{
int oi, mi, j;
BOOL ret, fire;
fire = FALSE;
ret = !SolidLoc(x, y); //12-15
if (ret && dObject[x][y]) {
oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1);
if (object[oi]._oSolidFlag)
ret = FALSE;
}
if (ret && dMissile[x][y] && i >= 0) { //37
mi = dMissile[x][y];
if (mi > 0) {
if (missile[mi]._mitype == MIS_FIREWALL) {
fire = TRUE;
} else {
for (j = 0; j < nummissiles; j++) {
if (missile[missileactive[j]]._mitype == MIS_FIREWALL)
fire = TRUE;
}
}
}
if (fire && (!(monster[i].mMagicRes & IMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO))
ret = FALSE;
}
return ret;
}
BOOL __fastcall PosOkMonst3(int i, int x, int y)
{
int oi, mi, j, objtype;
BOOL ret, fire, isdoor;
fire = FALSE;
isdoor = FALSE;
if (dObject[x][y]) {
oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1);
objtype = object[oi]._otype;
isdoor = TRUE;
if (objtype != OBJ_L1LDOOR
&& objtype != OBJ_L1RDOOR
&& objtype != OBJ_L2LDOOR
&& objtype != OBJ_L2RDOOR
&& objtype != OBJ_L3LDOOR
&& objtype != OBJ_L3RDOOR) {
isdoor = FALSE;
}
if (object[oi]._oSolidFlag && !isdoor)
return FALSE;
}
if (SolidLoc(x, y) && !isdoor || dPlayer[x][y] || dMonster[x][y])
return FALSE;
ret = TRUE;
if (dMissile[x][y] && i >= 0) {
mi = dMissile[x][y];
if (mi > 0) {
if (missile[mi]._mitype == MIS_FIREWALL) {
fire = TRUE;
} else {
for (j = 0; j < nummissiles; j++) {
if (missile[missileactive[j]]._mitype == MIS_FIREWALL)
fire = TRUE;
}
}
}
if (fire && (!(monster[i].mMagicRes & IMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO))
ret = FALSE;
}
return ret;
}
BOOL __fastcall IsSkel(int mt)
{
return mt >= MT_WSKELAX && mt <= MT_XSKELAX
|| mt >= MT_WSKELBW && mt <= MT_XSKELBW
|| mt >= MT_WSKELSD && mt <= MT_XSKELSD;
}
BOOL __fastcall IsGoat(int mt)
{
return mt >= MT_NGOATMC && mt <= MT_GGOATMC
|| mt >= MT_NGOATBW && mt <= MT_GGOATBW;
}
int __fastcall M_SpawnSkel(int x, int y, int dir)
{
int i, j, skeltypes, skel;
j = 0;
for (i = 0; i < nummtypes; i++) {
if (IsSkel(Monsters[i].mtype))
j++;
}
if (j) {
skeltypes = random(136, j);
j = 0;
for (i = 0; i < nummtypes && j <= skeltypes; i++) {
if (IsSkel(Monsters[i].mtype))
j++;
}
skel = AddMonster(x, y, dir, i - 1, 1);
if (skel != -1)
M_StartSpStand(skel, dir);
return skel;
}
return -1;
}
void __fastcall ActivateSpawn(int i, int x, int y, int dir)
{
dMonster[x][y] = i + 1;
monster[i]._mx = x;
monster[i]._my = y;
monster[i]._mfutx = x;
monster[i]._mfuty = y;
monster[i]._moldx = x;
monster[i]._moldy = y;
M_StartSpStand(i, dir);
}
BOOL __fastcall SpawnSkeleton(int ii, int x, int y)
{
int dx, dy, xx, yy, dir, j, k, rs;
BOOL savail;
int monstok[3][3];
if (ii == -1)
return FALSE;
if (PosOkMonst(-1, x, y)) {
dir = GetDirection(x, y, x, y);
ActivateSpawn(ii, x, y, dir);
return TRUE;
}
savail = FALSE;
yy = 0;
for (j = y - 1; j <= y + 1; j++) {
xx = 0;
for (k = x - 1; k <= x + 1; k++) {
monstok[xx][yy] = PosOkMonst(-1, k, j);
savail |= monstok[xx][yy];
xx++;
}
yy++;
}
if (!savail) {
return FALSE;
}
rs = random(137, 15) + 1;
xx = 0;
yy = 0;
while (rs > 0) {
if (monstok[xx][yy])
rs--;
if (rs > 0) {
xx++;
if (xx == 3) {
xx = 0;
yy++;
if (yy == 3)
yy = 0;
}
}
}
dx = x - 1 + xx;
dy = y - 1 + yy;
dir = GetDirection(dx, dy, x, y);
ActivateSpawn(ii, dx, dy, dir);
return TRUE;
}
int __cdecl PreSpawnSkeleton()
{
int i, j, skeltypes, skel;
j = 0;
if (nummtypes <= 0)
return -1;
for (i = 0; i < nummtypes; i++) {
if (IsSkel(Monsters[i].mtype))
j++;
}
if (j) {
skeltypes = random(136, j);
j = 0;
for (i = 0; i < nummtypes && j <= skeltypes; i++) {
if (IsSkel(Monsters[i].mtype))
j++;
}
skel = AddMonster(0, 0, 0, i - 1, 0);
if (skel != -1)
M_StartStand(skel, 0);
return skel;
}
return -1;
}
void __fastcall TalktoMonster(int i)
{
MonsterStruct *Monst;
int pnum, itm;
if ((DWORD)i >= MAXMONSTERS)
TermMsg("TalktoMonster: Invalid monster %d", i);
Monst = &monster[i];
pnum = Monst->_menemy;
Monst->_mmode = MM_TALK;
if (Monst->_mAi == AI_SNOTSPIL || Monst->_mAi == AI_LACHDAN) {
if (QuestStatus(QTYPE_BOL) && quests[QTYPE_BOL]._qvar1 == 2 && PlrHasItem(pnum, IDI_BANNER, &itm)) {
RemoveInvItem(pnum, itm);
quests[QTYPE_BOL]._qactive = 3;
Monst->mtalkmsg = QUEST_BANNER12;
Monst->_mgoal = MGOAL_INQUIRING;
}
if (QuestStatus(QTYPE_VEIL) && Monst->mtalkmsg >= QUEST_VEIL9) {
if (PlrHasItem(pnum, IDI_GLDNELIX, &itm)) {
RemoveInvItem(pnum, itm);
Monst->mtalkmsg = QUEST_VEIL11;
Monst->_mgoal = MGOAL_INQUIRING;
}
}
}
}
void __fastcall SpawnGolum(int i, int x, int y, int mi)
{
if ((DWORD)i >= MAXMONSTERS)
TermMsg("SpawnGolum: Invalid monster %d", i);
dMonster[x][y] = i + 1;
monster[i]._mx = x;
monster[i]._my = y;
monster[i]._mfutx = x;
monster[i]._mfuty = y;
monster[i]._moldx = x;
monster[i]._moldy = y;
monster[i]._pathcount = 0;
monster[i]._mFlags |= MFLAG_GOLEM;
monster[i].mArmorClass = 25;
monster[i]._mmaxhp = 2 * (320 * missile[mi]._mispllvl + plr[i]._pMaxMana / 3);
monster[i]._mhitpoints = monster[i]._mmaxhp;
monster[i].mHit = 5 * (missile[mi]._mispllvl + 8) + 2 * plr[i]._pLevel;
monster[i].mMinDamage = 2 * (missile[mi]._mispllvl + 4);
monster[i].mMaxDamage = 2 * (missile[mi]._mispllvl + 8);
M_StartSpStand(i, 0);
M_Enemy(i);
if (i == myplr) {
NetSendCmdGolem(
monster[i]._mx,
monster[i]._my,
monster[i]._mdir,
monster[i]._menemy,
monster[i]._mhitpoints,
currlevel);
}
}
BOOL __fastcall CanTalkToMonst(int m)
{
if ((DWORD)m >= MAXMONSTERS) {
TermMsg("CanTalkToMonst: Invalid monster %d", m);
}
if (monster[m]._mgoal == MGOAL_INQUIRING) {
return TRUE;
}
return monster[m]._mgoal == MGOAL_TALKING;
}
BOOL __fastcall CheckMonsterHit(int m, BOOL *ret)
{
if ((DWORD)m >= MAXMONSTERS) {
TermMsg("CheckMonsterHit: Invalid monster %d", m);
}
if (monster[m]._mAi == AI_GARG && monster[m]._mFlags & MFLAG_ALLOW_SPECIAL) {
monster[m]._mmode = MM_SATTACK;
monster[m]._mFlags &= ~MFLAG_ALLOW_SPECIAL;
*ret = TRUE;
return TRUE;
}
if (monster[m].MType->mtype < MT_COUNSLR || monster[m].MType->mtype > MT_ADVOCATE || monster[m]._mgoal == MGOAL_NORMAL) {
return FALSE;
} else {
*ret = FALSE;
}
return TRUE;
}
int __fastcall encode_enemy(int m)
{
int enemy;
enemy = monster[m]._menemy;
if (monster[m]._mFlags & MFLAG_TARGETS_MONSTER)
enemy += 4;
return enemy;
}
void __fastcall decode_enemy(int m, int enemy)
{
if (enemy < 4) {
monster[m]._mFlags &= ~MFLAG_TARGETS_MONSTER;
monster[m]._menemy = enemy;
monster[m]._menemyx = plr[enemy]._px;
monster[m]._menemyy = plr[enemy]._py;
} else {
monster[m]._mFlags |= MFLAG_TARGETS_MONSTER;
enemy -= 4;
monster[m]._menemy = enemy;
monster[m]._menemyx = monster[enemy]._mfutx;
monster[m]._menemyy = monster[enemy]._mfuty;
}
}