Open wheybags opened 4 years ago
ping @AJenbo I know it's probably a bunch of work, but given your involvement with the devilution project, is there any chance you would be interested in gathering some data for this? No pressure :)
To start with just some values for a level 1 warrior in default gear hitting a zombie would be enough.
warrior in default gear hitting a zombie
RNG locked to 0 (because zero is normally success)
INFO: MonsterTrapHit: monster -64
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Zombie
--- At this point I got stunlocked by the zombies because they always hit
INFO: M_TryH2HHit: player -35
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -29
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -27
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -29
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -35
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -27
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -32765
INFO: M_TryH2HHit: player -31
INFO: M_TryH2HHit: player -8
--- palyer dead
Note that health is health << 6
internally so that you can take fractional damage.
Some fighting with RNG enabled:
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton Captain
INFO: PlrHitMonst: monster -64
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -448
INFO: M_StartKill: Scavenger
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -576
INFO: M_StartKill: Fallen One
INFO: PlrHitMonst: monster -64
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -64
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -64
INFO: M_TryH2HHit: player -35
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Zombie
INFO: PlrHitMonst: monster -448
INFO: M_StartKill: Fallen One
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Skeleton
INFO: MonsterTrapHit: monster -128
INFO: M_StartKill: Fallen One
INFO: PlayerMHit: player -728
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Scavenger
INFO: PlrHitMonst: monster -128
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Fallen One
INFO: PlrHitMonst: monster -448
INFO: M_StartKill: Fallen One
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton Captain
INFO: M_TryH2HHit: player -28
INFO: M_TryH2HHit: player -28
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Scavenger
INFO: PlrHitMonst: monster -192
INFO: M_StartKill: Skeleton
INFO: PlrHitMonst: monster -256
INFO: M_StartKill: Scavenger
INFO: PlrHitMonst: monster -256
INFO: M_StartKill: Fallen One
I'm making sure to only fight one monster at a time, all the hits will be on the monster that subsequently appears with the M_StartKill
line.
I do at times get attacked by more than one mosnter so you won't be able to see exactly who dealt the damage to the player.
*: player -d
The player was hit
*: monster -d
A monter was hit
M_StartKill: *
A monter played it death animation
Also note that RNG in Diablo is biased.
Nice, thanks a lot! When you say the RNG is biased, do you mean they do the modulo trick for generating a number in a range? (so, eg, rand(100) = rand() % 101) Or is it something deeper in their RNG implementation? I'm hoping we can just not replicate that defect, do you think it's significant to gameplay?
It does affect gameplay a bit, but mostly in a negative way (streaks are more common then they should). If you aim to have comparability with save game files you will need to implement the RNG from Diablo (Borland C/C++) or items will not be regenerated correctly, but you could limit it's use to just the item loading code.
I probably won't bother with that level of import, but a character stats / inventory importer is definitely on the todo list.
Well you will need it for inventory
Oh, are items stored as an rng seed or something?
Ok, so I did some tests with damage: We are currently handling damage as ints, so issue # 1 is that we need some fractional support. Apart from that, I tried running the algorithms from Jarulf's guide in a python interpreter, and didn't get results that match the data you posted:
>>> strength = 30
>>> player_level = 1
>>> weapon_dmg = (2,6)
>>> weapon_type_modifier = 0.5 # zombie is undead and weapon is sword https://wheybags.gitlab.io/jarulfs-guide/#how-to-calculate-monster-data
>>>
>>> def rand_in_range(lo, hi):
... return lo # hack for testing
...
...
>>> base_damage = (strength * player_level) / 100 # https://wheybags.gitlab.io/jarulfs-guide/#damage-done
>>> base_damage
0.3
>>>
>>> damage_calc = base_damage + rand_in_range(weapon_dmg[0], weapon_dmg[1]) # https://wheybags.gitlab.io/jarulfs-guide/#player-versus-monster
>>> damage_calc
2.3
>>>
>>> final_dmg = damage_calc * weapon_type_modifier
>>> final_dmg
1.15
Final damage calculation is 1.15, whereas your data indicates it should be 128 / (1 << 6) = 2.
Any idea what's wrong here?
Sorry, no clue about how to handle damage.
The first int in the item struct is it's seed value.
Fair enough, thanks a lot for your help anyway!
Ok, I did some more digging around, and it seems that while the hp variable for enemies is a fixedpoint value << 6, the damage calculations for melee attacks are actually done in unscaled ints anyway. Some samples, of a warrior in default gear attacking an undead: str 30, level 1: 2/128 str 50, level 4: 4/256
It seems freeablo is actually correct after all :p Still, it would be nice to get some tests in for this, I plan to add that soon.
We need some sample data from the original game to verify our combat calculatiosn against. I have implemented melee combat in accordance with the formulae from Jarulfs' guide, and from what I can tell they should be correct. However, it still feels to me like there is something off when attacking monsters in the first dungeon level, sometimes they seem to survive too long.
It would be useful to have some test data from the original game (ie, with this gear, hit this enemy, and then measure the damage dealt). Ideally we could rig the RNG to always do the max damage in range, never miss etc, to make it easier to compare.
We could use this sample data for automated tests.