diff --git a/d2common/d2data/d2datadict/d2datadict.go b/d2common/d2data/d2datadict/d2datadict.go new file mode 100644 index 00000000..629121bd --- /dev/null +++ b/d2common/d2data/d2datadict/d2datadict.go @@ -0,0 +1,3 @@ +// Package d2datadict parses txt files as data dictionaries and exports records arrays +// For the Diablo II MPQ's, data dictionaries are the tab-separated value txt files found in `data/global/excel` +package d2datadict diff --git a/d2common/d2data/d2datadict/monstats.go b/d2common/d2data/d2datadict/monstats.go index a04c03e5..13ea7ece 100644 --- a/d2common/d2data/d2datadict/monstats.go +++ b/d2common/d2data/d2datadict/monstats.go @@ -4,794 +4,683 @@ package d2datadict import ( "log" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) // https://d2mods.info/forum/kb/viewarticle?a=360 -// TODO: these types are described in the notes below, but they aren't used yet -type MonsterCombatType int +type ( + // MonStatsRecord represents a single row from `data/global/excel/monstats.txt` in the MPQ files. + // These records are used for creating monsters. + MonStatsRecord struct { -const ( - // see notes on column `rangedtype` - MonsterMelee MonsterCombatType = iota - MonsterRanged + // Key contains the pointer that will be used in other txt files + // such as levels.txt and superuniques.txt. + Key string // called `Id` in monstats.txt + + // Id is the actual internal ID of the unit (this is what the ID pointer + // actually points at) remember that no two units can have the same ID, + // this will result in lots of unpredictable behavior and crashes so please + // don’t do it. This 'HarcCodedInDeX' is used for several things, such as + // determining whenever the unit uses DCC or DC6 graphics (like mephisto + // and the death animations of Diablo, the Maggoc Queen etc.), the hcIdx + // column also links other hardcoded effects to the units, such as the + // transparency on necro summons and the name-color change on unique boss + // units (thanks to Kingpin for the info) + Id string // called `hcIdx` in monstats.txt + + // BaseKey is an ID pointer of the “base” unit for this specific + // monster type (ex. There are five types of “Fallen”; all of them have + // fallen1 as their “base” unit). + BaseKey string // called `BaseId` in monstats.txt + + // NextKey is the ID of the next unit in the chain. (fallen1 has the ID pointer of fallen2 in here). + // The game uses this for “map generated” monsters such as the fallen in the fallen camps, + // which get picked based on area level. + NextKey string // called `NextInClass` in monstats.txt + + // NameStringTableKey the string-key used in the TBL (string.tbl, + // expansionstring.tbl and patchstring.tbl) files to make this monsters + // name appear when you highlight it. + NameStringTableKey string // called `NameStr` in monstats.txt + + // ExtraDataKey the ID pointer to an entry in MonStats2.txt. + ExtraDataKey string // called `MonStatsEx` in monstats.txt + + // PropertiesKey contains the ID pointer to an entry in MonProp.txt which + // controls what special modifiers are appended to the unit + PropertiesKey string // called `MonProp` in monstats.txt + + // MonsterGroup contains the group ID of the “super group” this monster + // belongs to, IE all skeletons belong to the "super group" skeleton. The + MonsterGroup string // called `MonType` in monstats.txt + + // AiKey tells the game which AI to use for this monster. Every AI + // needs a specific set of animation modes (GH, A1, A2, S1, WL, RN etc). + AiKey string // called `AI` in monstats.txt + + // DescriptionStringTableKey contains the string-key used in the TBL (string.tbl, + // expansionstring.tbl and patchstring.tbl) files for the monsters + // description (leave it blank for no description). + // NOTE: ever wondered how to make it say something below the monster + // name (such as “Drains Mana and Stamina etc), well this is how you do it. + // Just put the string-key of the string you want to display below the + // monsters name in here. + DescriptionStringTableKey string // called `DescStr` in monstats.txt + + // AnimationDirectoryToken controls which token (IE name of a folder that + // contains animations) the game uses for this monster. + AnimationDirectoryToken string // called `Code` in monstats.txt + + // SpawnKey contains the key of the unit to spawn. + SpawnKey string // called `spawn` in monstats.txt + + // SpawnAnimationKey + // which animation mode will the spawned monster be spawned in. + SpawnAnimationKey string // called `spawnmode` in monstats.txt + + // MinionId1 is an Id of a minion that spawns when this monster is created + MinionId1 string // called `minion1` in monstats.txt + + // MinionId2 is an Id of a minion that spawns when this monster is created + MinionId2 string // called `minion2` in monstats.txt + + // SoundKeyNormal, SoundKeySpecial + // specifies the ID pointer to this monsters “Sound Bank” in MonSound.txt + // when this monster is normal. + SoundKeyNormal string // called `MonSound` in monstats.txt + SoundKeySpecial string // called `UMonSound` in monstats.txt + + // MissileA1 -- MissileSQ + // these columns control “non-skill-related” missiles used by the monster. + // For example if you enter a missile ID pointer (from Missiles.txt) in + // MissA1 then, whenever the monster uses its A1 mode, it will shoot a + // missile, this however will successfully prevent it from dealing any damage + // with the swing of A1. + // NOTE: for the beginners, A1=Attack1, A2=Attack2, S1=Skill1, S2=Skill2, + // S3=Skill3, S4=Skill4, C=Cast, SQ=Sequence. + MissileA1 string // called `MissA1` in monstats.txt + MissileA2 string // called `MissA2` in monstats.txt + MissileS1 string // called `MissS1` in monstats.txt + MissileS2 string // called `MissS2` in monstats.txt + MissileS3 string // called `MissS3` in monstats.txt + MissileS4 string // called `MissS4` in monstats.txt + MissileC string // called `MissC` in monstats.txt + MissileSQ string // called `MissSQ` in monstats.txt + + // SkillId1 -- SkillId8 + // the ID Pointer to the skill (from Skills.txt) the monster will cast when + // this specific slot is accessed by the AI. Which slots are used is + // determined by the units AI. + SkillId1 string // called `Skill1` in monstats.txt + SkillId2 string // called `Skill2` in monstats.txt + SkillId3 string // called `Skill3` in monstats.txt + SkillId4 string // called `Skill4` in monstats.txt + SkillId5 string // called `Skill5` in monstats.txt + SkillId6 string // called `Skill6` in monstats.txt + SkillId7 string // called `Skill7` in monstats.txt + SkillId8 string // called `Skill8` in monstats.txt + + // SkillAnimation1 -- SkillAnimation8 + // the graphical MODE (or SEQUENCE) this unit uses when it uses this skill. + SkillAnimation1 string // called `Sk1mode` in monstats.txt + SkillAnimation2 string // called `Sk2mode` in monstats.txt + SkillAnimation3 string // called `Sk3mode` in monstats.txt + SkillAnimation4 string // called `Sk4mode` in monstats.txt + SkillAnimation5 string // called `Sk5mode` in monstats.txt + SkillAnimation6 string // called `Sk6mode` in monstats.txt + SkillAnimation7 string // called `Sk7mode` in monstats.txt + SkillAnimation8 string // called `Sk8mode` in monstats.txt + + // DamageSkillId + // ID Pointer to the skill that controls this units damage. This is used for + // the druids summons. IE their damage is specified solely by Skills.txt and + // not by MonStats.txt. + DamageSkillId string // called `SkillDamage` in monstats.txt + + // ElementAttackMode1 -- ElementAttackMode3 + // the mode to which the elemental damage is appended. The modes to which + // you would usually attack elemental damage are A1, A2, S1, S2, S3, S4, SQ + // or C as these are the only ones that naturally contain trigger bytes. + ElementAttackMode1 string // called `El1Mode` in monstats.txt + ElementAttackMode2 string // called `El2Mode` in monstats.txt + ElementAttackMode3 string // called `El3Mode` in monstats.txt + + // ElementType1 -- ElementType3 + // the type of the elemental damage appended to an attack. There are several + // elements: fire=Fire Damage, ltng=Lightning Damage, cold=Cold Damage + // (uses duration), pois = Poison Damage (uses duration), mag=Magic Damage, + // life=Life Drain (the monster heals the specified amount when it hits + // you), mana=Mana Drain (the monster steals the specified amount of mana + // when it hits you), stam=Stamina Drain (the monster steals the specified + // amount of stamina when it hits you), stun=Stun Damage (uses duration, + // damage is not used, this only effects pets and mercs, players will not + // get immobilized but they will get thrown into hit recovery whenever they + // get hit by an attack, no matter what type of attack it is, thanks to + // Brother Laz clearing this one up), rand=Random Damage (uses duration, + // either does Poison, Cold, Fire or Lightning damage, randomly picked for + // every attack), burn=Burning Damage (uses duration, this damage type + // cannot be resisted or reduced in any way), frze=Freezing Damage (uses + // duration, this will effect players like normal cold damage but will + // freeze and shatter pets). If you want to give your monster knockback use + // MonProp.txt. + ElementType1 string // called `El1Type` in monstats.txt + ElementType2 string // called `El2Type` in monstats.txt + ElementType3 string // called `El3Type` in monstats.txt + + // TreasureClassNormal + // Treasure class for normal monsters, champions, uniques, and quests + // on the respective difficulties. + TreasureClassNormal string // called `TreasureClass1` in monstats.txt + TreasureClassNightmare string // called `TreasureClass1(N)` in monstats.txt + TreasureClassHell string // called `TreasureClass1(H)` in monstats.txt + TreasureClassChampionNormal string // called `TreasureClass2` in monstats.txt + TreasureClassChampionNightmare string // called `TreasureClass2(N)` in monstats.txt + TreasureClassChampionHell string // called `TreasureClass2(H)` in monstats.txt + TreasureClass3UniqueNormal string // called `TreasureClass3` in monstats.txt + TreasureClass3UniqueNightmare string // called `TreasureClass3(N)` in monstats.txt + TreasureClass3UniqueHell string // called `TreasureClass3(H)` in monstats.txt + TreasureClassQuestNormal string // called `TreasureClass4` in monstats.txt + TreasureClassQuestNightmare string // called `TreasureClass4(N)` in monstats.txt + TreasureClassQuestHell string // called `TreasureClass4(H)` in monstats.txt + + // TreasureClassQuestTriggerId + // the ID of the Quest that triggers the Quest Treasureclass drop. + TreasureClassQuestTriggerId string // called `TCQuestId` in monstats.txt + + // TreasureClassQuestCompleteId + // the ID of the Quest State that you need to complete to trigger the Quest + // Treasureclass trop. + TreasureClassQuestCompleteId string // called `TCQuestCP` in monstats.txt + + // PaletteId indicates which palette (color) entry the unit will use, most + // monsters have a palshift.dat file in their COF folder, this file + // contains 8 palettes, starting from index 0. These palettes are used by + // the game to make the various monster sub-types appear with color + // variations. The game with use the palette from the palettes file + // corresponding to the value in this column plus 2; eg: translvl = 0 will + // use the third palette in the file. + // NOTE: some tokens (token = IE name of a folder that contains animations) + // such as FC do not accept their palettes. + // NOTE no 2: some monsters got unused palettes, ZM (zombie) for example + // will turn light-rotten-green with palette nr 5 and pink-creamy with 6. + PaletteId int // called `TransLvl` in monstats.txt + + // SpawnOffsetX, SpawnOffsetY + // are the x/y offsets at which spawned monsters are placed. IE this prevents + // the spawned monsters from being created at the same x/y coordinates as + // the spawner itself. + SpawnOffsetX int // called `spawnx` in monstats.txt + SpawnOffsetY int // called `spawny` in monstats.txt + + // MinionPartyMin, MinionPartyMax controls how many minions are spawned together with this unit. + MinionPartyMin int // called `PartyMin` in monstats.txt + MinionPartyMax int // called `PartyMax` in monstats.txt + + // MinionGroupMin, MinionGroupMax + // controls how many units of the base unit to spawn. + MinionGroupMin int // called `MinGrp` in monstats.txt + MinionGroupMax int // called `MaxGrp` in monstats.txt + + // PopulationReductionPercent controls the overall chance something will spawn in + // percentages. Blank entries are the same as 100%. + PopulationReductionPercent int // called `sparsePopulate` in monstats.txt + + // SpeedBase, SpeedRun + // controls the walking and running speed of this monster respectively. + // NOTE: RUN is only used if the monster has a RN mode and its AI uses that + // mode. + SpeedBase int // called `Velocity` in monstats.txt + SpeedRun int // called `Run` in monstats.txt + + // Rarity controls the overall odds that this monster will be spawned. + // IE Lets say in Levels.txt you have two monsters set to spawn - Monster A + // has rarity of 10 whereas Monster B has rarity of 1 and the level in + // question is limited to 1 monster type. First the game sums up the + // chances (11) and then calculates the odds of the monster spawning. Which + // would be 1/11 (9% chance) for Monster B and 10/11 (91% chance) for + // Monster A, thus Monster A is a lot more common than monster B. If you set + // this column to 0 then the monster will never be selected by Levels.txt + // for obvious reasons. + Rarity int // called `Rarity` in monstats.txt + + // LevelNormal, LevelNightmare, LevelHell + // controls the monsters level on the specified difficulty. This setting is + // only used on normal. On nightmare and hell the monsters level is + // identical with the area level from Levels.txt, unless your monster has + // BOSS column set to 1, in this case its level will be always taken from + // these 3 columns. + LevelNormal int // called `Level` in monstats.txt + LevelNightmare int // called `Level(N)` in monstats.txt + LevelHell int // called `Level(H)` in monstats.txt + + // used by the game to tell AIs which unit to target first. The higher this + // is the higher the threat level. Setting this to 25 or so on Maggot Eggs + // would make your Mercenary NPC try to destroy those first. + ThreatLevel int // called `threat` in monstats.txt + + // AiDelayNormal, AiDelayNightmare, AiDelayHell + // this controls delays between AI ticks (on normal, nightmare and hell). + // The lower the number, the faster the AI's will attack thanks to reduced + // delay between swings, casting spells, throwing missiles etc. Please + // remember that some AI's got individual delays between attacks, this will + // still make them faster and seemingly more deadly though. + AiDelayNormal int // called `aidel` in monstats.txt + AiDelayNightmare int // called `aidel(N)` in monstats.txt + AiDelayHell int // called `aidel(H)` in monstats.txt + + // AiDistanceNormal, AiDistanceNightmare, AiDistanceHell + // the distance in cells from which AI is activated. Most AI"s have base + // hardcoded activation radius of 35 which stands for a distamnce of about + // 1 screen, thus leaving these fields blank sets this to 35 automatically. + AiDistanceNormal int // called `aidist` in monstats.txt + AiDistanceNightmare int // called `aidist(N)` in monstats.txt + AiDistanceHell int // called `aidist(H)` in monstats.txt + + // AiParameterNormal1, AiParameterNightmare1, AiParameterHell1 + // these cells are very important, they pass on parameters (in percentage) + // to the AI code. For descriptions about what all these AI's do, check + // The AI Compendium. https://d2mods.info/forum/viewtopic.php?t=36230 + // Warning: many people have trouble with the AI of the Imps, this AI is + // special and uses multiple rows. + AiParameterNormal1 int // called `aip1` in monstats.txt + AiParameterNormal2 int // called `aip2` in monstats.txt + AiParameterNormal3 int // called `aip3` in monstats.txt + AiParameterNormal4 int // called `aip4` in monstats.txt + AiParameterNormal5 int // called `aip5` in monstats.txt + AiParameterNormal6 int // called `aip6` in monstats.txt + AiParameterNormal7 int // called `aip7` in monstats.txt + AiParameterNormal8 int // called `aip8` in monstats.txt + AiParameterNightmare1 int // called `aip1(N)` in monstats.txt + AiParameterNightmare2 int // called `aip2(N)` in monstats.txt + AiParameterNightmare3 int // called `aip3(N)` in monstats.txt + AiParameterNightmare4 int // called `aip4(N)` in monstats.txt + AiParameterNightmare5 int // called `aip5(N)` in monstats.txt + AiParameterNightmare6 int // called `aip6(N)` in monstats.txt + AiParameterNightmare7 int // called `aip7(N)` in monstats.txt + AiParameterNightmare8 int // called `aip8(N)` in monstats.txt + AiParameterHell1 int // called `aip1(H)` in monstats.txt + AiParameterHell2 int // called `aip2(H)` in monstats.txt + AiParameterHell3 int // called `aip3(H)` in monstats.txt + AiParameterHell4 int // called `aip4(H)` in monstats.txt + AiParameterHell5 int // called `aip5(H)` in monstats.txt + AiParameterHell6 int // called `aip6(H)` in monstats.txt + AiParameterHell7 int // called `aip7(H)` in monstats.txt + AiParameterHell8 int // called `aip8(H)` in monstats.txt + + // Alignment controls whenever the monster fights on your side or + // fights against you (or if it just walks around, IE a critter). + // If you want to turn some obsolete NPCs into enemies, this is + // one of the settings you will need to modify. Setting it to 2 + // without adjusting other settings (related to AI and also some + // in MonStats2) it will simply attack everything. + Alignment d2enum.MonsterAlignmentType // called `Align` in monstats.txt + + // SkillLevel1 -- SkillLevel8 + // the skill level of the skill in question. This gets a bonus on nightmare + // and hell which you can modify in DifficultyLevels.txt. + SkillLevel1 int // called `Sk1lvl` in monstats.txt + SkillLevel2 int // called `Sk2lvl` in monstats.txt + SkillLevel3 int // called `Sk3lvl` in monstats.txt + SkillLevel4 int // called `Sk4lvl` in monstats.txt + SkillLevel5 int // called `Sk5lvl` in monstats.txt + SkillLevel6 int // called `Sk6lvl` in monstats.txt + SkillLevel7 int // called `Sk7lvl` in monstats.txt + SkillLevel8 int // called `Sk8lvl` in monstats.txt + + // LeechSensitivityNormal / Nightmare / Hell + // controls the effectiveness of Life and Mana steal from equipment on this + // unit on the respective difficulties. 0=Can’t leech at all. Remember that + // besides this, Life and Mana Steal is further limited by DifficultyLevels.txt. + LeechSensitivityNormal int // called `Drain` in monstats.txt + LeechSensitivityNightmare int // called `Drain(N)` in monstats.txt + LeechSensitivityHell int // called `Drain(H)` in monstats.txt + + // ColdSensitivityNormal / Nightmare / Hell + // controls the effectiveness of cold effect and its duration and freeze + // duration on this unit. The lower this value is, the more speed this unit + // looses when its under the effect of cold, also freezing/cold effect will + // stay for longer. Positive values will make the unit faster (thanks to + // Brother Laz for confirming my assumption), and 0 will make it + // unfreezeable. Besides this, cold length and freeze length settings are + // also set in DifficultyLevels.txt. + ColdSensitivityNormal int // called `coldeffect` in monstats.txt + ColdSensitivityNightmare int // called `coldeffect(N)` in monstats.txt + ColdSensitivityHell int // called `coldeffect(H)` in monstats.txt + + // ResistancePhysicalNormal + // Damage resistance on the respective difficulties. Negative values mean + // that the unit takes more damage from this element, values at or above 100 + // will result in immunity. + ResistancePhysicalNormal int // called `ResDm` in monstats.txt + ResistancePhysicalNightmare int // called `ResDm(N)` in monstats.txt + ResistancePhysicalHell int // called `ResDm(H)` in monstats.txt + ResistanceMagicNormal int // called `ResMa` in monstats.txt + ResistanceMagicNightmare int // called `ResMa(N)` in monstats.txt + ResistanceMagicHell int // called `ResMa(H)` in monstats.txt + ResistanceFireNormal int // called `ResFi` in monstats.txt + ResistanceFireNightmare int // called `ResFi(N)` in monstats.txt + ResistanceFireHell int // called `ResFi(H)` in monstats.txt + ResistanceLightningNormal int // called `ResLi` in monstats.txt + ResistanceLightningNightmare int // called `ResLi(N)` in monstats.txt + ResistanceLightningHell int // called `ResLi(H)` in monstats.txt + ResistanceColdNormal int // called `ResCo` in monstats.txt + ResistanceColdNightmare int // called `ResCo(N)` in monstats.txt + ResistanceColdHell int // called `ResCo(H)` in monstats.txt + ResistancePoisonNormal int // called `ResPo` in monstats.txt + ResistancePoisonNightmare int // called `ResPo(N)` in monstats.txt + ResistancePoisonHell int // called `ResPo(H)` in monstats.txt + + // HealthRegenPerFrame + // this controls how much health this unit regenerates per frame. Sometimes + // this is altered by the units AI. The formula is (REGEN * HP) / 4096. So + // a monster with 200 hp and a regen rate of 10 would regenerate ~0,5 HP + // (~12 per second) every frame (1 second = 25 frames). + HealthRegenPerFrame int // called `DamageRegen` in monstats.txt + + // ChanceToBlockNormal / Nightmare / Hell + // this units chance to block. See the above column for details when this + // applies or not. Monsters are capped at 75% block as players are AFAIK. + ChanceToBlockNormal int // called `ToBlock` in monstats.txt + ChanceToBlockNightmare int // called `ToBlock(N)` in monstats.txt + ChanceToBlockHell int // called `ToBlock(H)` in monstats.txt + + // ChanceDeadlyStrike + // this units chance of scoring a critical hit (dealing double the damage). + ChanceDeadlyStrike int // called `Crit` in monstats.txt + + // MinHPNormal -- MaxHPHell + // minHp, maxHp, minHp(N), maxHp(N), minHp(H), maxHp(H): this units minimum + // and maximum HP on the respective difficulties. + // NOTE: Monster HitPoints are calculated as the following: (minHp * Hp from + // MonLvl.txt)/100 for minimal hp and (maxHp * Hp from MonLvl.txt)/100 for + // maximum hp. + // To make this guide idiot-proof, we will calculate the hit points of a + // Hungry Dead from vanilla on Normal difficulty and Single Player mode. + // It has minHp = 101 and maxHp = 186 and level 2. Hp for level 2 in + // MonLvl.txt = 9 + // It means Hungry Dead has (101*9)/100 ~ 9 of minimum hp and + // (186*9)/100 ~ 17 maximum hit points. You have to remember monsters on + // nightmare and hell take their level (unless Boss = 1) from area level of + // Levels.txt instead of Level column of MonStats.txt. I hope this is clear. + MinHPNormal int // called `minHP` in monstats.txt + MinHPNightmare int // called `MinHP(N)` in monstats.txt + MinHPHell int // called `MinHP(H)` in monstats.txt + MaxHPNormal int // called `maxHP` in monstats.txt + MaxHPNightmare int // called `MaxHP(N)` in monstats.txt + MaxHPHell int // called `MaxHP(H)` in monstats.txt + + // ArmorClassNormal -- Hell + // this units Armor Class on the respective difficulties. The calculation is + // the same (analogical) as for hit points. + ArmorClassNormal int // called `AC` in monstats.txt + ArmorClassNightmare int // called `AC(N)` in monstats.txt + ArmorClassHell int // called `AC(H)` in monstats.txt + + // ExperienceNormal -- Hell + // the experience you get when killing this unit on the respective + // difficulty. The calculation is the same (analogical) as for hit points. + ExperienceNormal int // called `Exp` in monstats.txt + ExperienceNightmare int // called `Exp(N)` in monstats.txt + ExperienceHell int // called `Exp(H)` in monstats.txt + + // DamageMinA1Normal / Nightmare / Hell + // DamageMaxA1Normal / Nightmare /Hell + // this units minimum and maximum damage when it uses A1/A2/S1 mode. + // The calculation is the same (analogical) as for hit points. + DamageMinA1Normal int // called `A1MinD` in monstats.txt + DamageMinA1Nightmare int // called `A1MinD(N)` in monstats.txt + DamageMinA1Hell int // called `A1MinD(H)` in monstats.txt + DamageMaxA1Normal int // called `A1MaxD` in monstats.txt + DamageMaxA1Nightmare int // called `A1MaxD(N)` in monstats.txt + DamageMaxA1Hell int // called `A1MaxD(H)` in monstats.txt + DamageMinA2Normal int // called `A2MinD` in monstats.txt + DamageMinA2Nightmare int // called `A2MinD(N)` in monstats.txt + DamageMinA2Hell int // called `A2MinD(H)` in monstats.txt + DamageMaxA2Normal int // called `A2MaxD` in monstats.txt + DamageMaxA2Nightmare int // called `A2MaxD(N)` in monstats.txt + DamageMaxA2Hell int // called `A2MaxD(H)` in monstats.txt + DamageMinS1Normal int // called `S1MinD` in monstats.txt + DamageMinS1Nightmare int // called `S1MinD(N)` in monstats.txt + DamageMinS1Hell int // called `S1MinD(H)` in monstats.txt + DamageMaxS1Normal int // called `S1MaxD` in monstats.txt + DamageMaxS1Nightmare int // called `S1MaxD(N)` in monstats.txt + DamageMaxS1Hell int // called `S1MaxD(H)` in monstats.txt + + // AttackRatingA1Normal AttackRatingS1Hell + // this units attack rating for A1/A2/S1 mode on the respective difficulties + // The calculation is the same (analogical) as for hit points. + AttackRatingA1Normal int // called `A1TH` in monstats.txt + AttackRatingA1Nightmare int // called `A1TH(N)` in monstats.txt + AttackRatingA1Hell int // called `A1TH(H)` in monstats.txt + AttackRatingA2Normal int // called `A2TH` in monstats.txt + AttackRatingA2Nightmare int // called `A2TH(N)` in monstats.txt + AttackRatingA2Hell int // called `A2TH(H)` in monstats.txt + AttackRatingS1Normal int // called `S1TH` in monstats.txt + AttackRatingS1Nightmare int // called `S1TH(N)` in monstats.txt + AttackRatingS1Hell int // called `S1TH(H)` in monstats.txt + + // ElementChance1Normal -- ElementChance3Hell + // chance to append elemental damage to an attack on the respective + // difficulties. 0=Never append, 100=Always append. + ElementChance1Normal int // called `El1Pct` in monstats.txt + ElementChance1Nightmare int // called `El1Pct(N)` in monstats.txt + ElementChance1Hell int // called `El1Pct(H)` in monstats.txt + ElementChance2Normal int // called `El2Pct` in monstats.txt + ElementChance2Nightmare int // called `El2Pct(N)` in monstats.txt + ElementChance2Hell int // called `El2Pct(H)` in monstats.txt + ElementChance3Normal int // called `El3Pct` in monstats.txt + ElementChance3Nightmare int // called `El3Pct(N)` in monstats.txt + ElementChance3Hell int // called `El3Pct(H)` in monstats.txt + + // ElementDamageMin1Normal -- ElementDamageMax3Hell + // minimum and Maximum elemental damage to append to the attack on the + // respective difficulties. Note that you should only append elemental + // damage to those missiles that don’t have any set in Missiles.txt. The + // calculation is the same (analogical) as for hit points. + ElementDamageMin1Normal int // called `El1MinD` in monstats.txt + ElementDamageMin1Nightmare int // called `El1MinD(N)` in monstats.txt + ElementDamageMin1Hell int // called `El1MinD(H)` in monstats.txt + ElementDamageMin2Normal int // called `El2MinD` in monstats.txt + ElementDamageMin2Nightmare int // called `El2MinD(N)` in monstats.txt + ElementDamageMin2Hell int // called `El2MinD(H)` in monstats.txt + ElementDamageMin3Normal int // called `El3MinD` in monstats.txt + ElementDamageMin3Nightmare int // called `El3MinD(N)` in monstats.txt + ElementDamageMin3Hell int // called `El3MinD(H)` in monstats.txt + ElementDamageMax1Normal int // called `El1MaxD` in monstats.txt + ElementDamageMax1Nightmare int // called `El1MaxD(N)` in monstats.txt + ElementDamageMax1Hell int // called `El1MaxD(H)` in monstats.txt + ElementDamageMax2Normal int // called `El2MaxD` in monstats.txt + ElementDamageMax2Nightmare int // called `El2MaxD(N)` in monstats.txt + ElementDamageMax2Hell int // called `El2MaxD(H)` in monstats.txt + ElementDamageMax3Normal int // called `El3MaxD` in monstats.txt + ElementDamageMax3Nightmare int // called `El3MaxD(N)` in monstats.txt + ElementDamageMax3Hell int // called `El3MaxD(H)` in monstats.txt + + // ElementDuration1Normal -- ElementDuration3Hell + // duration of the elemental effect (for freeze, burn, cold, poison and + // stun) on the respective difficulties. + ElementDuration1Normal int // called `El1Dur` in monstats.txt + ElementDuration1Nightmare int // called `El1Dur(N)` in monstats.txt + ElementDuration1Hell int // called `El1Dur(H)` in monstats.txt + ElementDuration2Normal int // called `El2Dur` in monstats.txt + ElementDuration2Nightmare int // called `El2Dur(N)` in monstats.txt + ElementDuration2Hell int // called `El2Dur(H)` in monstats.txt + ElementDuration3Normal int // called `El3Dur` in monstats.txt + ElementDuration3Nightmare int // called `El3Dur(N)` in monstats.txt + ElementDuration3Hell int // called `El3Dur(H)` in monstats.txt + + // SpecialEndDeath + // 0 == no special death + // 1 == spawn minion1 on death + // 2 == kill mounted minion on death (ie the guard tower) + SpecialEndDeath int // called `SplEndDeath` in monstats.txt + + // Enabled controls whenever the unit can be + // used at all for any purpose whatsoever. This is not the only setting + // that controls this; there are some other things that can also disable + // the unit (Rarity and isSpawn columns see those for description). + Enabled bool // called `enabled` in monstats.txt + + // SpawnsMinions tells the game whenever this + // unit is a “nest”. IE, monsters that spawn new monsters have this set to + // 1. Note that you can make any monster spawn new monsters, irregardless of + // its AI, all you need to do is adjust spawn related columns and make sure + // one of its skills is either “Nest” or “Minion Spawner”. + SpawnsMinions bool // called `placespawn` in monstats.txt + + // IsLeader controls if a monster is the leader of minions it spawns + // a leadercan order "raid on target" it causes group members to use + // SK1 instead of A1 and A2 modes while raiding. + IsLeader bool // called `SetBoss` in monstats.txt + + // TransferLeadership is connected with the previous one, + // when "boss of the group" is killed, the "leadership" is passed to one of + // his minions. + TransferLeadership bool // called `BossXfer` in monstats.txt + + // Boolean, 1=spawnable, 0=not spawnable. This controls whenever this unit + // can be spawned via Levels.txt. + IsLevelSpawnable bool // called `isSpawn` in monstats.txt + + // IsMelee controls whenever + // this unit can spawn with boss modifiers such as multiple shot or not. + IsMelee bool // called `isMelee` in monstats.txt + + // IsNPC controls whenever the unit is a NPC or not. + IsNpc bool // called `npc` in monstats.txt + + // IsInteractable + // controls whenever you can interact with this unit. IE this controls + // whenever it opens a speech-box or menu when you click on the unit. To + // turn units like Kaeleen or Flavie into enemies you will need to set this + // to 0 (you will also need to set NPC to 0 for that). + IsInteractable bool // called `interact` in monstats.txt + + // IsRanged tells the game whenever this is a ranged attacker. It will make it possible for + // monsters to spawn with multiple shot modifier. + IsRanged bool // called `rangedtype` in monstats.txt + + // HasInventory Controls whenever this + // NPC or UNIT can carry items with it. For NPCs this means that you can + // access their Inventory and buy items (if you disable this and then try to + // access this feature it will cause a crash so don’t do it unless you know + // what you’re doing). For Monsters this means that they can access their + // equipment data in MonEquip.txt. + HasInventory bool // called `inventory` in monstats.txt + + // CanEnterTown + // controls whenever enemies can follow you into a town or not. This should be set to + // 1 for everything that spawns in a town for obvious reasons. According to + // informations from Ogodei, it also disables/enables collision in + // singleplayer and allows pets to walk/not walk in city in multiplayer. + // In multiplayer collision is always set to 0 for pets. + CanEnterTown bool // called `inTown` in monstats.txt + + // IsUndeadLow, IsUndeadHigh + // Blizzard used this to differentiate High and Low Undead (IE low + // undead like Zombies, Skeletons etc are set to 1 here), both this and + // HUNDEAD will make the unit be considered undead. Low undeads can be + // resurrected by high undeads. High undeads can't resurrect eachother. + IsUndeadLow bool // called `lUndead` in monstats.txt + IsUndeadHigh bool // called `hUndead` in monstats.txt + + // IsDemon makes the game consider this unit a demon. + IsDemon bool // called `demon` in monstats.txt + + // IsFlying If you set this to 1 the monster will be able to move fly over + // obstacles such as puddles and rivers. + IsFlying bool // called `flying` in monstats.txt + + // CanOpenDoors controls whether monsters can open doors or not + CanOpenDoors bool // called `opendoors` in monstats.txt + + // IsSpecialBoss controls whenever this unit + // is a special boss, as mentioned already, monsters set as boss IGNORE the + // level settings, IE they will always spawn with the levels specified in + // MonStats.txt. Boss will gain some special resistances, such as immunity + // to being stunned (!!!), also it will not be affected by things like + // deadly strike the way normal monsters are. + IsSpecialBoss bool // called `boss` in monstats.txt + + // IsActBoss + // Setting this to 1 will give your monsters huge (300% IIRC) damage bonus + // against hirelings and summons. Ever wondered why Diablo destroys your + // skeletons with 1 fire nova while barely doing anything to you? Here is + // your answer. + IsActBoss bool // called `primeevil` in monstats.txt + + // IsKillable will make the monster absolutely unkillable. + IsKillable bool // called `killable` in monstats.txt + + // IsAiSwitchable Gives controls if this units mind may + // be altered by “mind altering skills” like Attract, Conversion, Revive + IsAiSwitchable bool // called `switchai` in monstats.txt + + // DisableAura Monsters set to 0 here + // will not be effected by friendly auras + DisableAura bool // called `noAura` in monstats.txt + + // DisableMultiShot + // This is another layer of security to prevent this modifier from spawning, + // besides the ISMELEE layer. + DisableMultiShot bool // called `nomultishot` in monstats.txt + + // DisableCounting + // prevents your pets from being counted as population in said area, for + // example thanks to this you can finish The Den Of Evil quest while having + // pets summoned. + DisableCounting bool // called `neverCount` in monstats.txt + + // IgnorePets + // Summons and hirelings are ignored by this unit, 0=Summons and + // hirelings are noticed by this unit. If you set this to 1 you will the + // monsters going directly for the player. + IgnorePets bool // called `petIgnore` in monstats.txt + + // DealsDamageOnDeath This works similar to corpse explosion (its based on + // hitpoints) and damages the surrounding players when the unit dies. (Ever + // wanted to prevent those undead stygian dolls from doing damage when they + // die, this is all there is to it) + DealsDamageOnDeath bool // called `deathDmg` in monstats.txt + + // GenericSpawn Has to do + // something is with minions being transformed into suicide minions, the + // exact purpose of this is a mystery. + GenericSpawn bool // called `genericSpawn` in monstats.txt + + // IgnoreMonLevelTxt Does this unit use + // MonLevel.txt or does it use the stats listed in MonStats.txt as is. + // Setting this to 1 will result in an array of problems, such as the + // appended elemental damage being completely ignored, irregardless of the + // values in it. + IgnoreMonLevelTxt bool // called `noRatio` in monstats.txt + + // CanBlockWithoutShield in order for a unit to + // block it needs the BL mode, if this is set to 1 then it will block + // irregardless of what modes it has. + CanBlockWithoutShield bool // called `NoShldBlock` in monstats.txt + + // SpecialGetModeChart + // Unknown but could be telling the game to look at some internal table. + // This is used for some Act Bosses and monsters like Putrid Defilers. + SpecialGetModeChart bool // called `SplGetModeChar` in monstats.txt + + // SpecialEndGeneric Works in conjunction with SPLCLIENTEND, this + // makes the unit untargetable when it is first spawned (used for those monsters that are under water, under ground or fly above you) + SpecialEndGeneric bool // called `SplEndGeneric` in monstats.txt + + // SpecialClientEnd Works in conjunction with SPLENDGENERIC, this + // makes the unit invisible when it is first spawned (used for those + // monsters that are under water, under ground or fly above you), this is + // also used for units that have other special drawing setups. + SpecialClientEnd bool // called `SplClientEnd` in monstats.txt + + } ) -type MonsterAlignmentType int - -const ( - MonsterEnemy MonsterAlignmentType = iota - MonsterFriend - MonsterNeutral -) - -// i've tried to choose better field names instead of what's inside of the txt -// file. after the definition, if there is a comment after the type, it will -// be the original column name corresponding to that field. -// i've tried to preserve the order of the columns, as well. -type MonStatsRecord struct { - - // this column contains the pointer that will be used in other txt files - // such as levels.txt and superuniques.txt. - Key string // Id <-- this is the original field name - - // this is the actual internal ID of the unit (this is what the ID pointer - // actually points at) remember that no two units can have the same ID, - // this will result in lots of unpredictable behavior and crashes so please - // don’t do it. This 'HarcCodedInDeX' is used for several things, such as - // determining whenever the unit uses DCC or DC6 graphics (like mephisto - // and the death animations of Diablo, the Maggoc Queen etc.), the hcIdx - // column also links other hardcoded effects to the units, such as the - // transparency on necro summons and the name-color change on unique boss - // units (thanks to Kingpin for the info) - Id string // hcIdx - - // this column contains the ID pointer of the “base” unit for this specific - // monster type (ex. There are five types of “Fallen”; all of them have - // fallen1 as their “base” unit). The baseID is responsible for some - // hardcoded behaviors, for example moving thru walls (ghosts), knowing - // what units to resurrect, create etc (putrid defilers, shamans etc), the - // explosion appended to suicide minions (either cold, fire or ice). Thanks - // to Kingpin for additional info on this column. - BaseKey string // BaseId - - // this column contains the ID of the next unit in the chain. (Continuing - // on the above example, fallen1 has the ID pointer of fallen2 in here). - // If you want to make a monster subtype less you should simply leave this - // blank and make BaseId point at itself (its ID pointer). The game uses - // this for “map generated” monsters such as the fallen in the fallen camps, - // which get picked based on area level (the same camp, that in the cold - // plains contains normal fallen will contain carvers and devilkin - // elsewhere, read Levels.txt to check how to adjust area level). - NextKey string // NextInClass - - // this indicates which palette (color) entry the unit will use, most - // monsters have a palshift.dat file in their COF folder, this file - // contains 8 palettes, starting from index 0. These palettes are used by - // the game to make the various monster sub-types appear with color - // variations. The game with use the palette from the palettes file - // corresponding to the value in this column plus 2; eg: translvl = 0 will - // use the third palette in the file. - // NOTE: some tokens (token = IE name of a folder that contains animations) - // such as FC do not accept their palettes. - // NOTE no 2: some monsters got unused palettes, ZM (zombie) for example - // will turn light-rotten-green with palette nr 5 and pink-creamy with 6. - PaletteId int // TransLvl - - // this column contains the string-key used in the TBL (string.tbl, - // expansionstring.tbl and patchstring.tbl) files to make this monsters - // name appear when you highlight it. Without that your monster will be - // displayed as "not used - tell ken" or "an evil force". - // Warning: string keys are case sensitive, so if you enter a key like “Foo” - // in monstats.txt you must enter exactly that in the TBL file! (IE if you - // enter “foo” or “fOO” you will get "not used - tell ken" or "an evil force"). - NameStringTableKey string // NameStr - - // this column contains the ID pointer to an entry in MonStats2.txt. - // In 1.10 Blizzard has moved all the graphical aspects (light radius, - // bleeding etc) to a new file to conserve space (MonStats.txt is one column - // short of 256, the maximum MS Excel can handle, and that’s what they - // probably used for their files). - ExtraDataKey string // MonStatsEx - - // this column contains the ID pointer to an entry in MonProp.txt which - // controls what special modifiers are appended to the unit, for example - // you can use it to give your monsters auras, states, random resistances - // or immunities, give them “get hit skills” and almost anything else. - PropertiesKey string // MonProp - - // this column contains the group ID of the “super group” this monster - // belongs to, IE all skeletons belong to the "super group" skeleton. The - // 1.10 MonType.txt works exactly like ItemTypes.txt, furthermore this file - // is used for special modifiers such as additional damage vs. monster-class. - MonsterGroup string // MonType - - // this column tells the game which AI to use for this monster. Every AI - // needs a specific set of animation modes (GH, A1, A2, S1, WL, RN etc). - // Most of AI's require a configuration in aip columns (read about them - // below), without that they (most of them) will do absolutely nothing. - AiKey string // AI - - // this column contains the string-key used in the TBL (string.tbl, - // expansionstring.tbl and patchstring.tbl) files for the monsters - // description (leave it blank for no description). - // NOTE: ever wondered how to make it say something below the monster - // name (such as “Drains Mana and Stamina etc), well this is how you do it. - // Just put the string-key of the string you want to display below the - // monsters name in here. - DescriptionStringTableKey string // DescStr - - // this is the only graphical setting (besides TransLvl) left in - // MonStats.txt, this controls which token (IE name of a folder that - // contains animations) the game uses for this monster. - AnimationDirectoryToken string // Code - - // Boolean, 1=enabled, 0=disabled. This controls whenever the unit can be - // used at all for any purpose whatsoever. This is not the only setting - // that controls this; there are some other things that can also disable - // the unit (Rarity and isSpawn columns see those for description). - Enabled bool // enabled - - // Boolean, 1=ranged attacker, 0=melee attacker. This tells the game - // whenever this is a ranged attacker. It will make it possible for - // monsters to spawn with multiple shot modifier. Also, I suspect this has - // to do with the RANGEDSPAWN column in Levels.txt. (Could it be the game - // uses this for preference settings when spawning monsters to avoid areas - // being populated only with melee monsters, IE the game picks a set amount - // of monsters for every level, randomly, only based on their rarity values, - // from those specified in Levels.txt, now I assume that it could pick 4 - // melee monsters, however in 1.10 Blizzard added a check to prevent this - // from happening AFAIK and this could be how they control it.) - IsRanged int // rangedtype - - // Boolean, 1=spawner, 0=not a spawner. This tells the game whenever this - // unit is a “nest”. IE, monsters that spawn new monsters have this set to - // 1. Note that you can make any monster spawn new monsters, irregardless of - // its AI, all you need to do is adjust spawn related columns and make sure - // one of its skills is either “Nest” or “Minion Spawner”. - SpawnsMinions bool // placespawn - - // this column contains the ID pointer of the unit to spawn. (in case it is - // a spawner that is), so if you want to make a new monster that generates - // Balrogs this is where you would put the Balrog ID pointer. - SpawnId string // spawn - - // the x/y offsets at which spawned monsters are placed. IE this prevents - // the spawned monsters from being created at the same x/y coordinates as - // the spawner itself, albeit its not needed, Blizzards collision detection - // system is good enough to prevent them from getting stuck. - SpawnOffsetX int // spawnx - SpawnOffsetY int // spawny - - // which animation mode will the spawned monster be spawned in. IE. If you - // make a golem summoner (yes I know, “very original”) you could put S1 in - // here to make it look as if the golems are really summoned (otherwise they - // would just appear), in most cases you will probably want to use NU mode - // or a sequence though. - SpawnAnimationKey string // spawnmode - - // these columns contain the ID pointers to the minions that spawn around - // this unit when it is created. - // NOTE + MINI TUTORIAL: lets say you want your super-strong boss to spawn - // with 5 Oblivion Knights. To do this you would simply enter the Oblivion - // Knights ID pointer in the MINION1 column. And set PARTYMIN and PARTYMAX - // both to 5. MINION1/2 are used for several other things. If the monster - // spawns as unique or superunique then it will have the unit from MINION1/2 - // set as its minion instead of monsters of its own type. That’s why - // Lord De Seis doesn’t spawn with other oblivion knights anymore. To - // semi-circumvent this I suggest you simply put the monsters ID pointer in - // the MINION2 column (I.E. if you give the Oblivion Knights their own ID - // pointer in MINION2, Lord De Seis should spawn with both Doom Knights and - // Oblivion Knights again). The other use controls what monster is created - // when this unit dies. For example Flayer Shamans will spawn a regular - // Flayer when they are killed. To enable this you must set SPLENDDEATH to - // 1, make sure the unit you spawn this was has a raise or resurrect - // sequence otherwise it will look weird (but it works). - // NOTE: THESE ARE SPAWNED ON MONSTER CREATION, NOTHING TO DO WITH ABOVE - MinionId1 string // minion1 - MinionId2 string // minion2 - - // Boolean, 1=set unit as boss, 0=don’t set unit as boss. This is related to - // hardcoded behavior of some of the AI's. IE Scarabs are spawned a bit - // different than most of other monsters. There are 1 or 2 with minions of - // own kind. Thanks to this colums, the "bosses" of a group can have - // ('can" because you may set the chance in percentages ia aip5 column of - // Scarab AI) a chance to order "raid on tagret", what does it change is - // they will always use SK1 instead of A1 and A2 modes while raiding. - IsLeader bool // SetBoss - - // Boolean, 1=true, 0=false. This field is connected with the previous one, - // when "boss of the group" is killed, his "leadership" is passed to one of - // his minions. - TransferLeadership bool // BossXfer - - // how many minions are spawned together with this unit. As mentioned above - // in the MINION1/2 columns, this controls the quantity of minions this - // unit has. - MinionPartyMin int // PartyMin - MinionPartyMax int // PartyMax - - // exactly like the previous two columns, just that this controls how many - // units of the base unit to spawn. In versions 1.00-1.06, setting the - // minimum to more then 99 would crash the game. - MinionGroupMin int // MinGrp - MinionGroupMax int // MaxGrp - - // this column controls the overall chance something will spawn in - // percentages, leaving it blank is the same as 100%. If you enter "80" in - // this column then whenever the game chooses to spawn this unit it will - // first roll out the chances. So in 2 out of 10 cases the monster will not - // be spawned and other one may take its place. If you use some low number - // there can be a situation when the game doesn't roll out the monster and - // if this monster has units specified in minion1/minion2 columns it will - // only spawn those minions without the "main" unit. - PopulationReductionPercent int // sparsePopulate - - // controls the walking and running speed of this monster respectively. - // NOTE: RUN is only used if the monster has a RN mode and its AI uses that - // mode. - SpeedBase int // Velocity - SpeedRun int // Run - - // this column controls the overall odds that this monster will be spawned. - // IE Lets say in Levels.txt you have two monsters set to spawn - Monster A - // has rarity of 10 whereas Monster B has rarity of 1 and the level in - // question is limited to 1 monster type. First the game sums up the - // chances (11) and then calculates the odds of the monster spawning. Which - // would be 1/11 (9% chance) for Monster B and 10/11 (91% chance) for - // Monster A, thus Monster A is a lot more common than monster B. If you set - // this column to 0 then the monster will never be selected by Levels.txt - // for obvious reasons. - Rarity int // Rarity - - // controls the monsters level on the specified difficulty. This setting is - // only used on normal. On nightmare and hell the monsters level is - // identical with the area level from Levels.txt, unless your monster has - // BOSS column set to 1, in this case its level will be always taken from - // these 3 columns. - LevelNormal int // Level - LevelNightmare int // Level(N) - LevelHell int // Level(H) - - // specifies the ID pointer to this monsters “Sound Bank” in MonSound.txt - // when this monster is normal. - SoundKeyNormal string // MonSound - SoundKeySpecial string // UMonSound - - // used by the game to tell AIs which unit to target first. The higher this - // is the higher the threat level. Setting this to 25 or so on Maggot Eggs - // would make your Merc try to destroy those first. - ThreatLevel int // threat - - // this controls delays between AI ticks (on normal, nightmare and hell). - // The lower the number, the faster the AI's will attack thanks to reduced - // delay between swings, casting spells, throwing missiles etc. Please - // remember that some AI's got individual delays between attacks, this will - // still make them faster and seemingly more deadly though. - AiDelayNormal int // aidel - AiDelayNightmare int // aidel(N) - AiDelayHell int // aidel(H) - - // the distance in cells from which AI is activated. Most AI"s have base - // hardcoded activation radius of 35 which stands for a distamnce of about - // 1 screen, thus leaving these fields blank sets this to 35 automatically. - AiDistanceNormal int // aidist - AiDistanceNightmare int // aidist(N) - AiDistanceHell int // aidist(H) - - // these cells are very important, they pass on parameters (in percentage) - // to the AI code. For descriptions about what all these AI's do, check - // The AI Compendium. https://d2mods.info/forum/viewtopic.php?t=36230 - // Warning: many people have trouble with the AI of the Imps, this AI is - // special and uses multiple rows. - AiParameterNormal1 int // aip1 - AiParameterNormal2 int // aip2 - AiParameterNormal3 int // aip3 - AiParameterNormal4 int // aip4 - AiParameterNormal5 int // aip5 - AiParameterNormal6 int // aip6 - AiParameterNormal7 int // aip7 - AiParameterNormal8 int // aip8 - AiParameterNightmare1 int // aip1 - AiParameterNightmare2 int // aip2 - AiParameterNightmare3 int // aip3 - AiParameterNightmare4 int // aip4 - AiParameterNightmare5 int // aip5 - AiParameterNightmare6 int // aip6 - AiParameterNightmare7 int // aip7 - AiParameterNightmare8 int // aip8 - AiParameterHell1 int // aip1 - AiParameterHell2 int // aip2 - AiParameterHell3 int // aip3 - AiParameterHell4 int // aip4 - AiParameterHell5 int // aip5 - AiParameterHell6 int // aip6 - AiParameterHell7 int // aip7 - AiParameterHell8 int // aip8 - - // these columns control “non-skill-related” missiles used by the monster. - // For example if you enter a missile ID pointer (from Missiles.txt) in - // MissA1 then, whenever the monster uses its A1 mode, it will shoot a - // missile, this however will successfully prevent it from dealing any damage - // with the swing of A1. - // NOTE: for the beginners, A1=Attack1, A2=Attack2, S1=Skill1, S2=Skill2, - // S3=Skill3, S4=Skill4, C=Cast, SQ=Sequence. - MissileA1 string // MissA1 - MissileA2 string // MissA2 - MissileS1 string // MissS1 - MissileS2 string // MissS2 - MissileS3 string // MissS3 - MissileS4 string // MissS4 - MissileC string // MissC - MissileSQ string // MissSQ - - // Switch, 0=enemy, 1=aligned, 2=neutral. This setting controls whenever the - // monster fights on your side or fights against you (or if it just walks - // around, IE a critter). If you want to turn some obsolete NPCs into - // enemies, this is one of the settings you will need to modify. Setting it - // to 2 without adjusting other settings (related to AI and also some in - // MonStats2) it will simply attack everything. - Alignment int // Align - - // Boolean, 1=spawnable, 0=not spawnable. This controls whenever this unit - // can be spawned via Levels.txt. - IsLevelSpawnable bool // isSpawn - - // Boolean, 1=melee attacker, 0=not a melee attacker. This controls whenever - // this unit can spawn with boss modifiers such as multiple shot or not. - // IE melee monsters will never spawn with multiple shot. - IsMelee bool // isMelee - - // Boolean, 1=I’m a NPC, 0=I’m not. This controls whenever the unit is a NPC - // or not. - IsNpc bool // npc - - // Boolean, 1=Special NPC features enabled, 0=No special NPC features. This - // controls whenever you can interact with this unit. IE this controls - // whenever it opens a speech-box or menu when you click on the unit. To - // turn units like Kaeleen or Flavie into enemies you will need to set this - // to 0 (you will also need to set NPC to 0 for that). - IsInteractable bool // interact - - // Boolean, 1=Has an inventory, 0=Has no inventory. Controls whenever this - // NPC or UNIT can carry items with it. For NPCs this means that you can - // access their Inventory and buy items (if you disable this and then try to - // access this feature it will cause a crash so don’t do it unless you know - // what you’re doing). For Monsters this means that they can access their - // equipment data in MonEquip.txt. - HasInventory bool // inventory - - // Boolean, 1=I can enter towns, 0=I can’t enter towns. This controls - // whenever enemies can follow you into a town or not. This should be set to - // 1 for everything that spawns in a town for obvious reasons. According to - // informations from Ogodei, it also disables/enables collision in - // singleplayer and allows pets to walk/not walk in city in multiplayer. - // In multiplayer collision is always set to 0 for pets. - CanEnterTown bool // inTown - - // Boolean. Blizzard used this to differentiate High and Low Undead (IE low - // undead like Zombies, Skeletons etc are set to 1 here), both this and - // HUNDEAD will make the unit be considered undead. Low undeads can be - // resurrected by high undeads. High undeads can't resurrect eachother. - IsUndeadLow bool // lUndead - IsUndeadHigh bool // hUndead - - // Boolean, This makes the game consider this unit a demon. - IsDemon bool // demon - - // Boolean, If you set this to 1 the monster will be able to move fly over - // obstacles such as puddles and rivers. - // TIP: Setting this to 1 for Mephisto will prevent the possibility of - // making him stuck and being slaughtered by blizzard or other ranged spells - // easily. - IsFlying bool // flying - - // Boolean, 1=I can open doors, 0=I’m too damn retarded to open doors. Ever - // wanted to make the game more like D1 (where closing doors could actually - // protect you), then this column is all you need. By setting this to 0 you - // will successfully lobotomize the monster, thus he will not be able to open - // doors any more. - CanOpenDoors bool // opendoors - - // Boolean, 1=I’m a boss, 0=I’m not a boss. This controls whenever this unit - // is a special boss, as mentioned already, monsters set as boss IGNORE the - // level settings, IE they will always spawn with the levels specified in - // MonStats.txt. Boss will gain some special resistances, such as immunity - // to being stunned (!!!), also it will not be affected by things like - // deadly strike the way normal monsters are. - IsSpecialBoss bool // boss - - // Boolean, 1=I’m a prime evil, 0=I’m not a prime evil. (=Act Boss). - // Setting this to 1 will give your monsters huge (300% IIRC) damage bonus - // against hirelings and summons. Ever wondered why Diablo destroys your - // skeletons with 1 fire nova while barely doing anything to you? Here is - // your answer. - IsActBoss bool // primeevil - - // Setting this to 0 will make the monster absolutely unkillable. - IsKillable bool // killable - - // Boolean, 1=Can change sides, 0=Cannot change sides. Gives your monster - // something what I call "Strong Mind", it decides if this units mind may - // be altered by “mind altering skills” like Attract, Conversion, Revive - // etc or not. - IsAiSwitchable bool // switchai - - // Boolean, 1=Can’t get an aura, 0=Can get an aura. Monsters set to 0 here - // will not be effected by friendly auras - DisableAura bool // noAura - - // Boolean, 1=Can’t get multishot modifier, 0=Can get multishot modifier. - // This is another layer of security to prevent this modifier from spawning, - // besides the ISMELEE layer. - DisableMultiShot bool // nomultishot - - // Boolean, 1=Never accounted for, 0=Accounted for. Setting this to 1 - // prevents your pets from being counted as population in said area, for - // example thanks to this you can finish The Den Of Evil quest while having - // pets summoned. - DisableCounting bool // neverCount - - // Boolean 1=Summons and hirelings are ignored by this unit, 0=Summons and - // hirelings are noticed by this unit. If you set this to 1 you will the - // monsters going directly for the player. - IgnorePets bool // petIgnore - - // Boolean, 1=Damage players colliding with my death animation, 0=Don’t - // damage anything. This works similar to corpse explosion (its based on - // hitpoints) and damages the surrounding players when the unit dies. (Ever - // wanted to prevent those undead stygian dolls from doing damage when they - // die, this is all there is to it) - DealsDamageOnDeath bool // deathDmg - - // Boolean, 1=Use generic spawning, 0=Don’t use generic spawning. Has to do - // something is with minions being transformed into suicide minions, the - // exact purpose of this is a mystery to me though. - GenericSpawn bool // genericSpawn - - // Boolean, 1=true, 0=false. Unused. - // zoo - - // Switch, 1=Unknown, 2=Used for assassin traps, 0=Don’t send skills. This - // is only used by two of the Assassin traps, however it doesn't serve any - // purpose anymore. - // SendSkills - - // the ID Pointer to the skill (from Skills.txt) the monster will cast when - // this specific slot is accessed by the AI. Which slots are used is - // determined by the units AI. - SkillId1 string // Skill1 - SkillId2 string // Skill2 - SkillId3 string // Skill3 - SkillId4 string // Skill4 - SkillId5 string // Skill5 - SkillId6 string // Skill6 - SkillId7 string // Skill7 - SkillId8 string // Skill8 - - // the graphical MODE (or SEQUENCE) this unit uses when it uses this skill. - SkillAnimation1 string // Sk1mode - SkillAnimation2 string // Sk2mode - SkillAnimation3 string // Sk3mode - SkillAnimation4 string // Sk4mode - SkillAnimation5 string // Sk5mode - SkillAnimation6 string // Sk6mode - SkillAnimation7 string // Sk7mode - SkillAnimation8 string // Sk8mode - - // the skill level of the skill in question. This gets a bonus on nightmare - // and hell which you can modify in DifficultyLevels.txt. - SkillLevel1 int // Sk1lvl - SkillLevel2 int // Sk2lvl - SkillLevel3 int // Sk3lvl - SkillLevel4 int // Sk4lvl - SkillLevel5 int // Sk5lvl - SkillLevel6 int // Sk6lvl - SkillLevel7 int // Sk7lvl - SkillLevel8 int // Sk8lvl - - // controls the effectiveness of Life and Mana steal from equipment on this - // unit on the respective difficulties. 0=Can’t leech at all. (negative - // values don't damage you, thanks to Doombreed-x for testing this), setting - // it to more then 100 would make LL and ML more effective. Remember that - // besides this, Life and Mana Steal is further limited by - // DifficultyLevels.txt. - LeechSensitivityNormal int // Drain - LeechSensitivityNightmare int // Drain(N) - LeechSensitivityHell int // Drain(H) - - // controls the effectiveness of cold effect and its duration and freeze - // duration on this unit. The lower this value is, the more speed this unit - // looses when its under the effect of cold, also freezing/cold effect will - // stay for longer. Positive values will make the unit faster (thanks to - // Brother Laz for confirming my assumption), and 0 will make it - // unfreezeable. Besides this, cold length and freeze length settings are - // also set in DifficultyLevels.txt. - ColdSensitivityNormal int // coldeffect - ColdSensitivityNightmare int // coldeffect(N) - ColdSensitivityHell int // coldeffect(H) - - // damage resistance on the respective difficulties. Negative values mean - // that the unit takes more damage from this element, values at or above 100 - // will result in immunity. - // NOTE: even though it may be quite obvious, I already met many people who - // do not know about it. Each point of resistance means 1% of reduction (or - // increase if the value is <0) of damage from said source. The same stands - // for player characters. Same stands for all other resistances. 81% of fire - // resist means 81% of incoming fire damage reduction. - // NOTE 2: when resistance is >100 (immunity), you need 5 points of - // resistance reducing stat applied DIRECTLY to the unit to reduce 1% of - // immunity. It means if you want to break 105% immunity, you will need at - // least 30 resist reduction stat (105 - 6 = 99 and 6 * 5 = 30). - // NOTE 3: yes, yes, indeed, "damage reduced by x%" stat that may spawn on - // items such as The Crown Of Ages or Ber rune is nothing else than physical - // resistance. - ResistancePhysicalNormal int // ResDm - ResistancePhysicalNightmare int // ResDm(N) - ResistancePhysicalHell int // ResDm(H) - - ResistanceMagicNormal int // ResMa - ResistanceMagicNightmare int // ResMa(N) - ResistanceMagicHell int // ResMa(H) - - ResistanceFireNormal int // ResFi - ResistanceFireNightmare int // ResFi(N) - ResistanceFireHell int // ResFi(H) - - ResistanceLightningNormal int // ResLi - ResistanceLightningNightmare int // ResLi(N) - ResistanceLightningHell int // ResLi(H) - - ResistanceColdNormal int // ResCo - ResistanceColdNightmare int // ResCo(N) - ResistanceColdHell int // ResCo(H) - - ResistancePoisonNormal int // ResPo - ResistancePoisonNightmare int // ResPo(N) - ResistancePoisonHell int // ResPo(H) - - // this controls how much health this unit regenerates per frame. Sometimes - // this is altered by the units AI. The formula is (REGEN * HP) / 4096. So - // a monster with 200 hp and a regen rate of 10 would regenerate ~0,5 HP - // (~12 per second) every frame (1 second = 25 frames). - HealthRegenPerFrame int // DamageRegen - - // ID Pointer to the skill that controls this units damage. This is used for - // the druids summons. IE their damage is specified solely by Skills.txt and - // not by MonStats.txt. - DamageSkillId string // SkillDamage - - // Boolean, 1=Don’t use MonLevel.txt, 0=Use MonLevel.txt. Does this unit use - // MonLevel.txt or does it use the stats listed in MonStats.txt as is. - // Setting this to 1 will result in an array of problems, such as the - // appended elemental damage being completely ignored, irregardless of the - // values in it. - IgnoreMonLevelTxt bool // noRatio - - // Boolean, 1=Can block without a blocking animation, 0=Can’t block without - // a blocking animation. Quite self explanatory, in order for a unit to - // block it needs the BL mode, if this is set to 1 then it will block - // irregardless of what modes it has. - CanBlockWithoutShield bool // NoShldBlock - - // this units chance to block. See the above column for details when this - // applies or not. Monsters are capped at 75% block as players are AFAIK. - ChanceToBlockNormal int // ToBlock - ChanceToBlockNightmare int // ToBlock(N) - ChanceToBlockHell int // ToBlock(H) - - // this units chance of scoring a critical hit (dealing double the damage). - ChanceDeadlyStrike int // Crit - - // minHp, maxHp, minHp(N), maxHp(N), minHp(H), maxHp(H): this units minimum - // and maximum HP on the respective difficulties. - // NOTE: Monster HitPoints are calculated as the following: (minHp * Hp from - // MonLvl.txt)/100 for minimal hp and (maxHp * Hp from MonLvl.txt)/100 for - // maximum hp. - // To make this guide idiot-proof, we will calculate the hit points of a - // Hungry Dead from vanilla on Normal difficulty and Single Player mode. - // It has minHp = 101 and maxHp = 186 and level 2. Hp for level 2 in - // MonLvl.txt = 9 - // It means Hungry Dead has (101*9)/100 ~ 9 of minimum hp and - // (186*9)/100 ~ 17 maximum hit points. You have to remember monsters on - // nightmare and hell take their level (unless Boss = 1) from area level of - // Levels.txt instead of Level column of MonStats.txt. I hope this is clear. - MinHPNormal int // minHP - MinHPNightmare int // MinHP(N) - MinHPHell int // MinHP(H) - - MaxHPNormal int // maxHP - MaxHPNightmare int // MaxHP(N) - MaxHPHell int // MaxHP(H) - - // this units Armor Class on the respective difficulties. The calculation is - // the same (analogical) as for hit points. - ArmorClassNormal int // AC - ArmorClassNightmare int // AC(N) - ArmorClassHell int // AC(H) - - // the experience you get when killing this unit on the respective - // difficulty. The calculation is the same (analogical) as for hit points. - ExperienceNormal int // Exp - ExperienceNightmare int // Exp(N) - ExperienceHell int // Exp(H) - - // this units minimum and maximum damage when it uses A1/A2/S1 mode. - // The calculation is the same (analogical) as for hit points. - DamageMinA1Normal int // A1MinD - DamageMinA1Nightmare int // A1MinD(N) - DamageMinA1Hell int // A1MinD(H) - - DamageMaxA1Normal int // A1MaxD - DamageMaxA1Nightmare int // A1MaxD(N) - DamageMaxA1Hell int // A1MaxD(H) - - DamageMinA2Normal int // A2MinD - DamageMinA2Nightmare int // A2MinD(N) - DamageMinA2Hell int // A2MinD(H) - - DamageMaxA2Normal int // A2MaxD - DamageMaxA2Nightmare int // A2MaxD(N) - DamageMaxA2Hell int // A2MaxD(H) - - DamageMinS1Normal int // S1MinD - DamageMinS1Nightmare int // S1MinD(N) - DamageMinS1Hell int // S1MinD(H) - - DamageMaxS1Normal int // S1MaxD - DamageMaxS1Nightmare int // S1MaxD(N) - DamageMaxS1Hell int // S1MaxD(H) - - // this units attack rating for A1/A2/S1 mode on the respective difficulties - // The calculation is the same (analogical) as for hit points. - AttackRatingA1Normal int // A1TH - AttackRatingA1Nightmare int // A1TH(N) - AttackRatingA1Hell int // A1TH(H) - - AttackRatingA2Normal int // A2TH - AttackRatingA2Nightmare int // A2TH(N) - AttackRatingA2Hell int // A2TH(H) - - AttackRatingS1Normal int // S1TH - AttackRatingS1Nightmare int // S1TH(N) - AttackRatingS1Hell int // S1TH(H) - - // the mode to which the elemental damage is appended. The modes to which - // you would usually attack elemental damage are A1, A2, S1, S2, S3, S4, SQ - // or C as these are the only ones that naturally contain trigger bytes. - ElementAttackMode1 string // El1Mode - ElementAttackMode2 string // El2Mode - ElementAttackMode3 string // El3Mode - - // the type of the elemental damage appended to an attack. There are several - // elements: fire=Fire Damage, ltng=Lightning Damage, cold=Cold Damage - // (uses duration), pois = Poison Damage (uses duration), mag=Magic Damage, - // life=Life Drain (the monster heals the specified amount when it hits - // you), mana=Mana Drain (the monster steals the specified amount of mana - // when it hits you), stam=Stamina Drain (the monster steals the specified - // amount of stamina when it hits you), stun=Stun Damage (uses duration, - // damage is not used, this only effects pets and mercs, players will not - // get immobilized but they will get thrown into hit recovery whenever they - // get hit by an attack, no matter what type of attack it is, thanks to - // Brother Laz clearing this one up), rand=Random Damage (uses duration, - // either does Poison, Cold, Fire or Lightning damage, randomly picked for - // every attack), burn=Burning Damage (uses duration, this damage type - // cannot be resisted or reduced in any way), frze=Freezing Damage (uses - // duration, this will effect players like normal cold damage but will - // freeze and shatter pets). If you want to give your monster knockback use - // MonProp.txt. - ElementType1 string // El1Type - ElementType2 string // El2Type - ElementType3 string // El3Type - - // chance to append elemental damage to an attack on the respective - // difficulties. 0=Never append, 100=Always append. - ElementChance1Normal int // El1Pct - ElementChance1Nightmare int // El1Pct(N) - ElementChance1Hell int // El1Pct(H) - - ElementChance2Normal int // El2Pct - ElementChance2Nightmare int // El2Pct(N) - ElementChance2Hell int // El2Pct(H) - - ElementChance3Normal int // El3Pct - ElementChance3Nightmare int // El3Pct(N) - ElementChance3Hell int // El3Pct(H) - - // minimum and Maximum elemental damage to append to the attack on the - // respective difficulties. Note that you should only append elemental - // damage to those missiles that don’t have any set in Missiles.txt. The - // calculation is the same (analogical) as for hit points. - ElementDamageMin1Normal int // El1MinD - ElementDamageMin1Nightmare int // El1MinD(N) - ElementDamageMin1Hell int // El1MinD(H) - - ElementDamageMin2Normal int // El2MinD - ElementDamageMin2Nightmare int // El2MinD(N) - ElementDamageMin2Hell int // El2MinD(H) - - ElementDamageMin3Normal int // El3MinD - ElementDamageMin3Nightmare int // El3MinD(N) - ElementDamageMin3Hell int // El3MinD(H) - - ElementDamageMax1Normal int // El1MaxD - ElementDamageMax1Nightmare int // El1MaxD(N) - ElementDamageMax1Hell int // El1MaxD(H) - - ElementDamageMax2Normal int // El2MaxD - ElementDamageMax2Nightmare int // El2MaxD(N) - ElementDamageMax2Hell int // El2MaxD(H) - - ElementDamageMax3Normal int // El3MaxD - ElementDamageMax3Nightmare int // El3MaxD(N) - ElementDamageMax3Hell int // El3MaxD(H) - - // duration of the elemental effect (for freeze, burn, cold, poison and - // stun) on the respective difficulties. - ElementDuration1Normal int // El1Dur - ElementDuration1Nightmare int // El1Dur(N) - ElementDuration1Hell int // El1Dur(H) - - ElementDuration2Normal int // El2Dur - ElementDuration2Nightmare int // El2Dur(N) - ElementDuration2Hell int // El2Dur(H) - - ElementDuration3Normal int // El3Dur - ElementDuration3Nightmare int // El3Dur(N) - ElementDuration3Hell int // El3Dur(H) - - // the TreasureClass used by this unit as a normal monster on the respective - // difficulties. - // NOTE: because of the new TreasureClass system introduced in 1.10 and - // later patches, TC entries are only of minor influence regarding what TC - // is being selected unless you change the system by editing - // TreasureClassEX.txt. - TreasureClassNormal string // TreasureClass1 - TreasureClassNightmare string // TreasureClass1(N) - TreasureClassHell string // TreasureClass1(H) - - TreasureClassChampionNormal string // TreasureClass2 - TreasureClassChampionNightmare string // TreasureClass2(N) - TreasureClassChampionHell string // TreasureClass2(H) - - TreasureClass3UniqueNormal string // TreasureClass3 - TreasureClass3UniqueNightmare string // TreasureClass3(N) - TreasureClass3UniqueHell string // TreasureClass3(H) - - TreasureClassQuestNormal string // TreasureClass4 - TreasureClassQuestNightmare string // TreasureClass4(N) - TreasureClassQuestHell string // TreasureClass4(H) - - // the ID of the Quest that triggers the Quest Treasureclass drop. - TreasureClassQuestTriggerId string // TCQuestId - - // the ID of the Quest State that you need to complete to trigger the Quest - // Treasureclass trop. - TreasureClassQuestComleteId string // TCQuestCP - - // TODO: fix these last 4 field names, they're fucking ridiculous - // Switch, 0=no special death, 1=spawn the monster in the MINION1 column - // when I die, 2=kill whatever monster is mounted to me when I die (used by - // guard towers that kill the imps that are on top of them when they die). - SpecialEndDeath int // SplEndDeath - - // Boolean, 1=Get Special Mode Chart, 0=Don’t get special mode chart. - // Unknown but could be telling the game to look at some internal table. - // This is used for some Act Bosses and monsters like Putrid Defilers. - SpecialGetModeChart bool // SplGetModeChart - - // Boolean, 1=true, 0=false. Works in conjunction with SPLCLIENTEND, this - // makes the unit untargetable when it is first spawned (used for those monsters that are under water, under ground or fly above you) - SpecialEndGeneric bool // SplEndGeneric - - // Boolean, 1=true, 0=false. Works in conjunction with SPLENDGENERIC, this - // makes the unit invisible when it is first spawned (used for those - // monsters that are under water, under ground or fly above you), this is - // also used for units that have other special drawing setups. - SpecialClientEnd bool // SplClientEnd -} - var MonStats map[string]*MonStatsRecord //nolint:funlen // Makes no sense to split @@ -815,9 +704,9 @@ func LoadMonStats(file []byte) { DescriptionStringTableKey: dict.GetString("DescStr", idx), AnimationDirectoryToken: dict.GetString("Code", idx), Enabled: dict.GetNumber("enabled", idx) > 0, - IsRanged: dict.GetNumber("rangedtype", idx), + IsRanged: dict.GetNumber("rangedtype", idx) > 0, SpawnsMinions: dict.GetNumber("placespawn", idx) > 0, - SpawnId: dict.GetString("spawn", idx), + SpawnKey: dict.GetString("spawn", idx), SpawnOffsetX: dict.GetNumber("spawnx", idx), SpawnOffsetY: dict.GetNumber("spawny", idx), SpawnAnimationKey: dict.GetString("spawnmode", idx), @@ -853,22 +742,22 @@ func LoadMonStats(file []byte) { AiParameterNormal6: dict.GetNumber("aip6", idx), AiParameterNormal7: dict.GetNumber("aip7", idx), AiParameterNormal8: dict.GetNumber("aip8", idx), - AiParameterNightmare1: dict.GetNumber("aip1", idx), - AiParameterNightmare2: dict.GetNumber("aip2", idx), - AiParameterNightmare3: dict.GetNumber("aip3", idx), - AiParameterNightmare4: dict.GetNumber("aip4", idx), - AiParameterNightmare5: dict.GetNumber("aip5", idx), - AiParameterNightmare6: dict.GetNumber("aip6", idx), - AiParameterNightmare7: dict.GetNumber("aip7", idx), - AiParameterNightmare8: dict.GetNumber("aip8", idx), - AiParameterHell1: dict.GetNumber("aip1", idx), - AiParameterHell2: dict.GetNumber("aip2", idx), - AiParameterHell3: dict.GetNumber("aip3", idx), - AiParameterHell4: dict.GetNumber("aip4", idx), - AiParameterHell5: dict.GetNumber("aip5", idx), - AiParameterHell6: dict.GetNumber("aip6", idx), - AiParameterHell7: dict.GetNumber("aip7", idx), - AiParameterHell8: dict.GetNumber("aip8", idx), + AiParameterNightmare1: dict.GetNumber("aip1(N)", idx), + AiParameterNightmare2: dict.GetNumber("aip2(N)", idx), + AiParameterNightmare3: dict.GetNumber("aip3(N)", idx), + AiParameterNightmare4: dict.GetNumber("aip4(N)", idx), + AiParameterNightmare5: dict.GetNumber("aip5(N)", idx), + AiParameterNightmare6: dict.GetNumber("aip6(N)", idx), + AiParameterNightmare7: dict.GetNumber("aip7(N)", idx), + AiParameterNightmare8: dict.GetNumber("aip8(N)", idx), + AiParameterHell1: dict.GetNumber("aip1(H)", idx), + AiParameterHell2: dict.GetNumber("aip2(H)", idx), + AiParameterHell3: dict.GetNumber("aip3(H)", idx), + AiParameterHell4: dict.GetNumber("aip4(H)", idx), + AiParameterHell5: dict.GetNumber("aip5(H)", idx), + AiParameterHell6: dict.GetNumber("aip6(H)", idx), + AiParameterHell7: dict.GetNumber("aip7(H)", idx), + AiParameterHell8: dict.GetNumber("aip8(H)", idx), MissileA1: dict.GetString("MissA1", idx), MissileA2: dict.GetString("MissA2", idx), MissileS1: dict.GetString("MissS1", idx), @@ -877,7 +766,7 @@ func LoadMonStats(file []byte) { MissileS4: dict.GetString("MissS4", idx), MissileC: dict.GetString("MissC", idx), MissileSQ: dict.GetString("MissSQ", idx), - Alignment: dict.GetNumber("Align", idx), + Alignment: d2enum.MonsterAlignmentType(dict.GetNumber("Align", idx)), IsLevelSpawnable: dict.GetNumber("isSpawn", idx) > 0, IsMelee: dict.GetNumber("isMelee", idx) > 0, IsNpc: dict.GetNumber("npc", idx) > 0, @@ -1049,7 +938,7 @@ func LoadMonStats(file []byte) { TreasureClassQuestNightmare: dict.GetString("TreasureClass4(N)", idx), TreasureClassQuestHell: dict.GetString("TreasureClass4(H)", idx), TreasureClassQuestTriggerId: dict.GetString("TCQuestId", idx), - TreasureClassQuestComleteId: dict.GetString("TCQuestCP", idx), + TreasureClassQuestCompleteId: dict.GetString("TCQuestCP", idx), SpecialEndDeath: dict.GetNumber("SplEndDeath", idx), SpecialGetModeChart: dict.GetNumber("SplGetModeChart", idx) > 0, SpecialEndGeneric: dict.GetNumber("SplEndGeneric", idx) > 0, diff --git a/d2common/d2enum/monster_alignment_type.go b/d2common/d2enum/monster_alignment_type.go new file mode 100644 index 00000000..b4d4a30a --- /dev/null +++ b/d2common/d2enum/monster_alignment_type.go @@ -0,0 +1,17 @@ +package d2enum + +// MonsterAlignmentType determines the hostility of the monster towards players +type MonsterAlignmentType int + +const ( + // MonsterEnemy flag will make monsters hostile towards players + MonsterEnemy MonsterAlignmentType = iota + + // MonsterFriend will make monsters friendly towards players + // this is likely used by NPC's and summons + MonsterFriend + + // MonsterNeutral will make monsters not care about players or monsters + // this flag is used for `critter` type monsters + MonsterNeutral +) diff --git a/d2common/d2enum/monster_combat_type.go b/d2common/d2enum/monster_combat_type.go new file mode 100644 index 00000000..9127f750 --- /dev/null +++ b/d2common/d2enum/monster_combat_type.go @@ -0,0 +1,12 @@ +package d2enum + +// MonsterCombatType is used for setting the monster as melee or ranged +type MonsterCombatType int + +const ( + // MonsterMelee is a flag that sets the monster as melee-only + MonsterMelee MonsterCombatType = iota + + // MonsterRanged is a flag that sets the monster as ranged-only + MonsterRanged +)