All times are UTC - 5 hours

It is currently Fri Jan 19, 2018 12:19 pm

Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: Easier Monster Skill-Damage Adjustment
PostPosted: Tue Jun 25, 2013 1:57 pm 
User avatar

Joined: Mon Aug 31, 2009 11:28 am
Posts: 1091
Location: Vancouver, BC
Warning: If you decide to try the changes I'm describing, then note that it's a pretty big project with lots of potential for bugs. A big benefit is that later changes to monster skills and damage become trivial (you just need to worry about which pretty graphic to select and what elemental damage you want it to do). Since one of the changes I wanted to play with was big leaps in monster level across difficulties (Norm is lvl 1 to 85, NM = 85-95, Hell = 95), there was no other obvious or simpler solution.

Easier Monster Skill-Damage Adjustment

When I was making adjustments to HU's files last year, I found a nice way of setting monster skill damage to a formula using their monster level (mLvl). This was the best way I could find to allow my A1 Norm monster (mLvl=1) to do decent damage in A1 Hell (mLvl=95) without time consuming micromanagement of monprops (i.e. giving monsters +%ElemMastery). D2 normally improves monster skills across difficulty levels by increasing the skill level by a set number, but in cases where the levels of monsters do not change by a consistent amount (e.g. Between Norm and NM, the mLvl in HU can change by about 60 (A1) to around 20 (A5)), it's nearly impossible to balance their skills with a +Skills mod shared by all of them. Many skills (e.g. FireArrow) can base their damage on the monster's attack damage, which is determined by mLvl in one of the text files. Making skill damage somehow determined by mLvl is a nice method of balancing when the mLvl changes greatly. The method I describe below extends that benefit to all monster skills.

The hardest but quickest part of the method is determining which formula will match monster damage across all monster levels. A good approach is to make a graph of the damage at each level, and then graph a formula that you can change until they match pretty closely. In D2, the file monlvl.txt contains the base Defense, ARating, HP, Damage, and XP for all monster levels (1-110). Copy the columns for Level and Damage into a spreadsheet program like MS-Excel or OO-Calc, and then it's pretty easy to make a graph or line chart of Damage vs Level. In a column beside the Damage, start a new column to contain your formula-damage. Your goal is to think of a formula that will result in the correct damage across all levels, and then copy it down the column to prove that it works as expected. If you don't want to mess around with graphs or charts, then you could simply make a new column that subtracts the actual damage from your formula damage, copy that for every level, and try to make that column's values as close to zero has you can. Your damage formula will probably use mLvl*mLvl since D2 Damage is usually exponential. For me, the formula was (Level+8)/2 + Level*Level/50. That formula made monsters do a little too much damage in early levels (<20) and around level 80, too little damage around level 60, but was within 3 points for the rest of the game. Since NM and Hell difficulties are probably where players spend most of their time, try to make the formula quite accurate for those mLvls.

With a formula determined, it's time investigate skill editing. Skill damage is determined in skills.txt using the SrcDmg field (e.g. Fire Arrow), or the fields to the right of that (i.e. MinDam to ELen). Note that to the left of SrcDmg is HitShift, which divides the Damages entered into the fields to the right of SrcDmg (e.g. HitShift=8 divides by 1 (2^0), HitShift=7 divides by 2 (2^1), HitShift 0 divides by 256 (2^8)). We will be focusing on the fields EMinDam, EMaxDam, and EDmgSymPerCalc. Our method of determining damage will be to give the skill a very low damage, and then applying a massive synergy based on monster level. For example, if we set EMinDam=1, EMaxDam=2, and EDmgSymPerCalc=10000, then the skill damage would be 101-202. Unfortunately, D2 appears to ignore EMinDam less than 1, even if you set it to 1 and use the HitShift field to divide it (although that seemed to work for Damage Per Second type skills like poison). This makes it harder to give a skill a smaller damage spread (e.g. 100-150). The most precise method I've found to overcome this is to set HitShift=0, EMinDam=256 (i.e. 1 damage), EMaxDam=384 (i.e. 1.5 damage), and EDmgSymPerCalc=10000, so the skill damage would be 101-151.5. Here are some example EMinDam and EMaxDam I found useful, along with the EDmgSymPerCalc formula set so that the average damage for all examples is the same.
Let mDmg be the formula I determined earlier, i.e. ((mLvl+8)/2 + mLvl*mLvl/50)
At about mLvl=58, mDmg=100, so the examples show an average damage of 100.
EMinDam EMaxDam EDmgSymPerCalc  Example
256     256     mDmg*100        100-100   
256     313     mDmg*90          90-110    I use this for cold and magic damage
256     475     mDmg*70          70-130    I use this for fire and physical damage
256     768     mDmg*50          50-150    I use this for lightning damage
  1       1     mDmg*100*256/25 100-100DPS For skill damage per frame (25/sec)

Since the monster's skill level ("lvl" in the text files) is no longer relevant to the damage, it can be used in other ways. For example, I use it to determine if the monster is a sub-boss (double damage) or act-boss (triple damage). This is the formula I am using, where Act-Bosses have skills around level 40, and sub-bosses have skills around level 20:
( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) )
I place that formula into one of the unused calc fields for the skill. The main benefit is that it can be referenced in missiles.txt by those few skills that launch a missile that launches yet another missle (e.g. Meteor's flames). The main penalty is that some skills actually use their "unused" calc fields without any documentation. Sometimes you just have to test to know if it will work (assigning the skill as a 100% onStruck Zombie monprop makes the testing pretty easy). If the formula were placed into the calc4 field, then the EDmgSymPerCalc formula would be changed to:

Although it's possible to copy-paste the damage formula into each EDmgSymPerCalc field, I chose to copy it only into the calc4 field of the "Attack" skill. All other uses of the formula reference that field, so I can change the skill damage of all monsters by just changing the formula in that field. I consider this handy, as I've already needed to change my formula a couple times. D2 formulas use 'ulvl' to refer to a Unit's Level, so the formula I'm using is actually:
(ulvl+8)/2 + ulvl*ulvl/50
This means that the EDmgSymPerCalc formula I'm using is generally one of these:
skill('Attack'.clc4)*100*( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) )

Once you've standardized the damage that spells do, examine the missiles launched by that spell in the srvmissile field. Find that missile in Missiles.txt and confirm that one of the following is done:
1) The Skill field is set to a skill that you've already set the damage for.
2) The SrcDamage field is set to 128 for missiles that are simple and should simply do damage equal to the monster's regular attack (e.g. bighead1 to bighead5 are the lightning-balls launched by the Tainted-type demons numbered 1 through 5).
3) The damage columns to the right of SrcDamage are set just like you were doing in Skills.txt.
With option 2, the damage will automatically be buffed for bosses and sub-bosses if their damage was buffed in monstats.txt.
With option 3, the damage should to be buffed by referencing the clc4 field of the parent skill because I don't think 'lvl' will reference the skill's level.
IE: EDmgSymPerCalc = skill('Attack'.clc4)*100*skill('ParentSkill'.clc4)
When you come across missiles with the same name except for an ending number, that seems to be a clue that the parent skill is hardcoded to a particular monster. For example, missile unholybolt1 is launched by skill UnHolyBolt, and modifying that missile's damage will affect unraveler1 monsters (HollowOne), but not unraveler3 (Unraveler). Even though unraveler3 uses the same skill, which claims to launch missile unholybolt1, it will launch missile unholybolt3 instead. Similarly necromage1 to necromage4 are the missiles launched by the Necromancer's Raise Skeleton Mage skill. I haven't tried it, but it's likely that if you changed the element of necromage1 from poison to cold, then your summon would shoot green poison balls that chilled the enemy. Also note that the level of the necromage missiles is simply the level assigned in skills.txt.

The next thing to do is go through monstats.txt and consider all skills used by monsters. You will need to set the levels of skills so that the calc4 field results in damage-doubling or tripling or whatever you had in mind. Consider the following:
1) If the skill doesn't do damage, like curses and some auras, then maybe ignore it
2) If this is a trash monster and the skill level is less than 20, then you can ignore it. If the level is more than 20, then reduce it. I set it to 1 in either case so that I can quickly see which monsters were trash and which were bosses.
3) If this is a sub-boss, then make it's damage skills level 20 so that your calc4 formula will double the damage.
4) If this is an act-boss, then make it's damage skills level 40 so that your calc4 formula will triple the damage.

Now that you're finished with monstats.txt, standardize the skill levels used in monprops.txt for properties like onStrike, onStruck, etc. Luckily many of the monprops for bosses are named after the boss.

Note that there are many cases where monsters use player skills. I decided to clone those skills (copy their row, assign a new name, assign new missiles that are clones of the original missiles). You don't have to clone more than maybe 12, since you are mainly concerned with capturing the unique and pretty graphic of a particular skill (like FrozenOrb), or it's element (there is already a fire and magic clone of FrozenOrb). I read somewhere that skillID's higher than 512 can't be used with onStrike or related procs. Another thing to consider is that now a monIceBolt does the same damage as the monIceBolts launched by monFrozenOrb, but you can expect a player to be hit more than once by monFrozenOrb. Consider reducing the damage of FrozenOrb clones as well as skills with small nextHit Delays like DeathMaul (the underground tentacle attack of DeathMauler demons).

Some of the bugs I've found
1) Inferno-type skills use their calc1 and calc4 fields. They only worked when I put the entire formula into EDmgSymPerCalc, and even then their damage was a bit hard to configure. This formula seemed to output the expected damage per second:
EDmgSymPerCalc= 100* skill('Attack'.clc4)*( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) ) *256 /3
(the *256 is because EMinDam=1 with HitShift=0, the /3 was arbitrary but seems to work well)
2) Volcano seems to use all of its calc fields (the game crashed when I tried to use these). This formula worked well:
DmgSymPerCalc = 70 * skill('Attack'.clc4)*( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) ) /2 /2
EDmgSymPerCalc= 70 * skill('Attack'.clc4)*( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) ) /2 /2
(the /2/2 at the end is just to remind myself that the damage is split between 2 elements, and hits about 2 times per second)

1) You want to do this if your monster levels change a lot between difficulties, you don't want to mess around with exact skill levels in order to tweak monster skill damage, or you want to be able to quickly change the damage of all monster skills.
2) Create a formula for monster damage given monster level.
EG: (ulvl+8)/2 + ulvl*ulvl/50
3) Put the formula into the calc 4 field of skill Attack.
4) For each monster skill, set EMinDam and EMaxDam to values you like while considering the HitShift divider.
EG: HitShift=0, EMinDam=256, EMaxDam=475
5) Set EDmgSymPerCalc to a formula that uses skill('Attack'.clc4), considers the element's damage range (determined in step(3)), considers the skill level, and considers the number of hits per second for that skill.
EG: 70*skill('Attack'.clc4)*( (lvl>=40) ? 3 : ((lvl>=20) ? 2 : 1) )
6) Standardize the skill levels of skills used by monsters in monstats.txt and monprop.txt
EG: Act Bosses use level 40 skills, Sub Bosses use level 20 skills, Trash uses level 1 skills.
7) Clone player skills and assign them to monsters if you like the graphics of that skill.

 Offline Profile  
Reply with quote  
 Post subject: Re: Easier Monster Skill-Damage Adjustment
PostPosted: Tue Dec 27, 2016 3:07 pm 
Game Server Host
User avatar

Joined: Mon Aug 31, 2009 12:33 am
Posts: 4286

Bron wrote:
There's no cure for being a cunt.

 Offline Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC - 5 hours

Who is online

Users browsing this forum: No registered users and 3 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: