- Hammercake
- Registered User
-
Member for 14 years, 3 months, and 15 days
Last active Sat, Sep, 3 2016 13:44:19
- 7 Followers
- 277 Total Posts
- 8 Thanks
-
1
DryingPole posted a message on Prayer Synergy ExceptionHello, I'm new here. I registered to tell you that Prayer is an exception to the synergy rule, +skills benefits the healing on Cleansing and Meditation. See you on ladder reset.Posted in: Diablo Tools -
1
Matt.J posted a message on A bit of help from code expertsYou can contact me if you're in need of help with parsing .D2S files (or any other technical information regarding Diablo II for that matter)Posted in: Diablo Tools
In regards to your specific issue, the bulk of the file is static except for the stats section and the items. The stats section is very straight-forward to parse; each entry begins with a 9-bit identifier followed by the value (of which's length can be gleamed from d2_patch.mpq/global/excel/ItemStatCost.txt)
Below is taken from a project of mine that you may find helpful.
/* * D2SDecode.cpp * ============= * Version: 1.0 * Author: Matt.J * * * Description: * Provides an interface for dealing with Diablo II save-files (.D2S) * * *********************************************************************************************************************/ #include "D2SDecode.h" using namespace D2S; ///////////////////////////////////////////////////////////////////// // Internal Functions ///////////////////////////////////////////////////////////////////// Dword STDCALL ReadBits(Void* pStream, Dword dwOffset, Dword dwSize); /////////////////////////////////////////////////////////////////////////////////////////////////// // // General Routines // /////////////////////////////////////////////////////////////////////////////////////////////////// Void FASTCALL D2S::Decode(Game::Player* pPlayer, Byte* pD2S) { Dword dwOffset = 0; Dword dwStatId; Dword dwStatVal; // Save class. pPlayer->Character.wClass = ((D2SBase*) pD2S)->Class; pPlayer->Character.wLevel = ((D2SBase*) pD2S)->Level; // Traverse to the start of player stats. pD2S += sizeof(D2SBase); pD2S += ((D2SQuest*) pD2S)->wSize; pD2S += sizeof(D2SWaypoints); pD2S += ((D2SNPC*) pD2S)->wSize; pD2S += 2; // Skip 'gf' // Reset total stat count. pPlayer->Character.wStatsUsed = 0; // Decode stats and store in the given Player. while((dwStatId = ReadBits(pD2S, dwOffset, 9)) != 511) { // Read the stat value. dwStatVal = ReadBits(pD2S, (dwOffset += 9), SIT[dwStatId].Size); dwOffset += SIT[dwStatId].Size; // Adjust for Diablo II's bullshit. dwStatVal = (SIT[dwStatId].Div ? (dwStatVal / SIT[dwStatId].Div) : dwStatVal); // Save. switch(dwStatId) { case 0: pPlayer->Character.wStr = (Word) dwStatVal; break; case 1: pPlayer->Character.wNrg = (Word) dwStatVal; break; case 2: pPlayer->Character.wDex = (Word) dwStatVal; break; case 3: pPlayer->Character.wVit = (Word) dwStatVal; break; case 4: pPlayer->Character.wStats = (Word) dwStatVal; break; case 5: pPlayer->Character.wSkills = (Word) dwStatVal; break; case 6: pPlayer->Character.dwCurLife = dwStatVal; break; case 7: pPlayer->Character.dwMaxLife = dwStatVal; break; case 8: pPlayer->Character.dwCurMana = dwStatVal; break; case 9: pPlayer->Character.dwMaxMana = dwStatVal; break; } // Total stat counter. if(dwStatId < 4) pPlayer->Character.wStatsUsed += ((Word) dwStatVal); } dwOffset += 9; // Traverse to skills, stats assumed to be padded to the next byte. pD2S += (dwOffset / 8) + ((dwOffset % 8) ? 1 : 0); // Verify header integrity. if(((D2SSkills*) pD2S)->strTag[0] != 'i' || ((D2SSkills*) pD2S)->strTag[1] != 'f') { // ERROR: Out("[ERROR] Failed to find 'if' header."); return; } // Count total skill points used. pPlayer->Character.wSkillsUsed = 0; pPlayer->Character.wHighestSkill = 0; for(Int i = 0; i < 30; i++) { pPlayer->Character.wSkillsUsed += ((D2SSkills*) pD2S)->Level[i]; pPlayer->Character.wHighestSkill = (((D2SSkills*) pD2S)->Level[i] > pPlayer->Character.wHighestSkill ? ((D2SSkills*) pD2S)->Level[i] : pPlayer->Character.wHighestSkill); } // Offset based on class. dwOffset = (BST[pPlayer->Character.wClass].Str + BST[pPlayer->Character.wClass].Dex + BST[pPlayer->Character.wClass].Vit + BST[pPlayer->Character.wClass].Nrg); pPlayer->Character.wStatsUsed = (Word) (pPlayer->Character.wStatsUsed > dwOffset ? (pPlayer->Character.wStatsUsed - dwOffset) : 0); } /////////////////////////////////////////////////////////////////////////////////////////////////// // // Helper Functions // /////////////////////////////////////////////////////////////////////////////////////////////////// NAKED Dword STDCALL ReadBits(Void* pStream, Dword dwOffset, Dword dwSize) { __asm { // PROLOGUE: push ebx // Calculate the bytewise offset, and remainder. mov eax, [esp+8] mov edx, [esp+12] mov ecx, 7 and ecx, edx shr edx, 3 // Read in the containing dword. mov ebx, [eax + edx] // Compensate for the offset. shr ebx, cl // Generate a mask for the significant bits of the desired sequence. mov ecx, [esp+16] mov eax, 1 shl eax, cl sub eax, 1 // Extract the result. and eax, ebx // EPILOGUE: pop ebx ret 12 } }
/* * D2SDecode.h * =========== * Version: 1.0 * Author: Matt.J * * * Description: * D2SDecode module interface. * * *********************************************************************************************************************/ #ifndef D2SDECODE_H #define D2SDECODE_H #include "Master.h" ///////////////////////////////////////////////////////////////////// // D2SDecode Module ///////////////////////////////////////////////////////////////////// namespace D2S { ///////////////////////////////////////////////////////////////////// // D2S Structures ///////////////////////////////////////////////////////////////////// struct D2SBase { Dword dwTag; /* 0x55AA55AA */ Dword dwVersion; Dword dwSize; Dword dwCRC; Dword dwWeaponSet; Char strName[16]; Byte Type; Byte Title; Word wUnknown1; Byte Class; Word wUnknown2; Byte Level; Dword dwUnknown3; Dword dwTimeStamp; Dword dwUnknown4; Dword dwHotkey[16]; Dword dwLeftSkill1; Dword dwRightSkill1; Dword dwLeftSkill2; Dword dwRightSkill2; Byte Outfit[16]; Byte Colors[16]; Byte NTown; Byte MTown; Byte HTown; Dword dwMapSeed; Word wUnknown5; Byte bDeadMerc; Byte Unknown6; Dword dwMercSeed; Word wMercName; Word wMercClass; Dword dwMercExp; Byte Unknown[0x90]; }; struct D2SQuest { Char strTag[4]; /* Woo! */ Dword dwActs; Word wSize; }; struct D2SWaypoints { Char strTag[2]; /* WS */ Byte Unknown[6]; Dword dwData[3*6]; }; struct D2SNPC { Char strTag[2]; /* w4 */ Word wSize; }; struct D2SSkills { Char strTag[2]; /* if */ Byte Level[30]; }; struct D2SItems { Char strTag[2]; /* JM */ Word wItems; }; ///////////////////////////////////////////////////////////////////// // Stat Information Table ///////////////////////////////////////////////////////////////////// CONST struct { Byte Size; Word Div; Char* pstrName; } SIT[] = { 10, 0, "Str", 10, 0, "Nrg", 10, 0, "Dex", 10, 0, "Vit", 10, 0, "Stat Points", 8, 0, "Skill Points", 21, 256, "CurLife", 21, 256, "MaxLife", 21, 256, "CurMana", 21, 256, "MaxMana", 21, 256, "CurStamina", 21, 256, "MaxStamina", 7, 0, "Level", 32, 0, "Experience", 25, 0, "Invo Gold", 25, 0, "Stash Gold", }; ///////////////////////////////////////////////////////////////////// // Base Stat Table ///////////////////////////////////////////////////////////////////// CONST struct _BST { Char* pstrClass; Byte Str; Byte Dex; Byte Vit; Byte Nrg; Byte Life; Byte Mana; Byte LifePerLvl; Byte ManaPerLvl; Byte LifePerVit; Byte ManaPerNrg; } BST[] = { /* Ama */ "Amazon", 20, 25, 20, 15, 50, 15, 8, 6, 12, 6, /* Sor */ "Sorceress", 10, 25, 10, 35, 40, 35, 4, 8, 8, 8, /* Nec */ "Necromancer", 15, 25, 15, 25, 45, 25, 6, 8, 8, 8, /* Pal */ "Paladin", 25, 20, 25, 15, 55, 15, 8, 6, 12, 6, /* Bar */ "Barbarian", 30, 20, 25, 10, 55, 10, 8, 2, 16, 4, /* Dru */ "Druid", 15, 20, 25, 20, 55, 20, 6, 8, 8, 8, /* Ass */ "Assassin", 20, 20, 20, 25, 50, 25, 8, 6, 12, 7, }; ///////////////////////////////////////////////////////////////////// // Exposed Routines ///////////////////////////////////////////////////////////////////// EXTERN Void FASTCALL Decode(Game::Player* pPlayer, Byte* pD2S); } #endif
-
1
Shatterer posted a message on Skill calculator - todo listSo I went and tried the skill calculator to create a Bonemancer. But then i saw that the damage for Bone Spirit had a + in front. After a long and winding road I'm going to nitpick pretty much every little detail!Posted in: Diablo Tools
Incorrect Mana cost
<input type='button' class='bbc_spoiler_show' value='Show <strong>Amazon</strong><br/> Fend:<br/> Now - Mana_Cost = Skill_Lvl<br/> Should be - Mana_Cost = 5<br/> <br/> Lightning Strike:<br/> Now - Mana_Cost = 5<br/> Should be - Mana_Cost = 9<br/> <br/> Decoy:<br/> Now - Mana_Cost = 1<br/> Should be - <a href="This" rel="noopener nofollow" target="_blank">http://classic.battle.net/diablo2exp/skills/amazon-passive.shtml#Decoy">This might be a good start</a><br/> Maybe someone can check the 20+ mana costs on the PTR.<br/> <br/> Exploding Arrow:<br/> Now - Mana_Cost_Array = 5|5|6|6|7|7<br/> Should be - Mana_Cost_Array = 5|5.5|6|6.5|7|7.5<br/> <br/> <strong>Assassin:</strong><br/> Cloak of Shadows:<br/> Now - Isn't shownDamage siplayed with an extra + in front
Should be - Mana_Cost = 13
Barbarian:
Bash:
Now - not displayed
Should be - Mana_Cost = 2
Double Swing:
Now - Mana_cost_Array = 2|1.7|1.5|1.2|1|0.7|0.5|0.2|0
Should be - Mana_Cost_Array = 1|0.8|0.7|0.6|0.5|0.3|0.2|0.1|0
I'm not sure about this data, but this is what it says on the Arreat Summit. I guess that their data is for each hit, but your data (and thus the displayed data) is for the complete move.
Stun:
Now - Mana_Cost = 4
Should be - Mana_Cost = 2
Druid
Arctic Freeze:
Now - Mana_Cost = 4
Should be - Mana_Cost_Array = A bit more complicated
Paladin
Prayer:
Now - Mana_Cost is in integers
Should be - Here is a proper path until lvl 20
' />Amazon
Fend:
Now - Mana_Cost = Skill_Lvl
Should be - Mana_Cost = 5
Lightning Strike:
Now - Mana_Cost = 5
Should be - Mana_Cost = 9
Decoy:
Now - Mana_Cost = 1
Should be - This might be a good start
Maybe someone can check the 20+ mana costs on the PTR.
Exploding Arrow:
Now - Mana_Cost_Array = 5|5|6|6|7|7
Should be - Mana_Cost_Array = 5|5.5|6|6.5|7|7.5
Assassin:
Cloak of Shadows:
Now - Isn't shown
Should be - Mana_Cost = 13
Barbarian:
Bash:
Now - not displayed
Should be - Mana_Cost = 2
Double Swing:
Now - Mana_cost_Array = 2|1.7|1.5|1.2|1|0.7|0.5|0.2|0
Should be - Mana_Cost_Array = 1|0.8|0.7|0.6|0.5|0.3|0.2|0.1|0
I'm not sure about this data, but this is what it says on the Arreat Summit. I guess that their data is for each hit, but your data (and thus the displayed data) is for the complete move.
Stun:
Now - Mana_Cost = 4
Should be - Mana_Cost = 2
Druid
Arctic Freeze:
Now - Mana_Cost = 4
Should be - Mana_Cost_Array = A bit more complicated
Paladin
Prayer:
Now - Mana_Cost is in integers
Should be - Here is a proper path until lvl 20
<input type='button' class='bbc_spoiler_show' value='Show <strong>Amazon:</strong><br/> Poison Javelin<br/> <br/> <strong>Druid:</strong><br/> Arctic Freeze<br/> Hurricane<br/> Fire Claws<br/> <br/> <strong>Necromancer</strong><br/> Poison Dagger<br/> Poison Explosion<br/> Poison Nova<br/> Bone Spirit<br/> <br/> <strong>Paladin:</strong><br/> Holy Fire<br/> <br/> <strong>Sorceress</strong><br/> Every skill that inflicts damage except for:<br/> Charged Bolt<br/> Lightning<br/> Blaze<br/> Fire Wall<br/> Enchant<br/> Meteor<br/> Hydra<br/> ' />Other display errorsAmazon:
Poison Javelin
Druid:
Arctic Freeze
Hurricane
Fire Claws
Necromancer
Poison Dagger
Poison Explosion
Poison Nova
Bone Spirit
Paladin:
Holy Fire
Sorceress
Every skill that inflicts damage except for:
Charged Bolt
Lightning
Blaze
Fire Wall
Enchant
Meteor
Hydra
<input type='button' class='bbc_spoiler_show' value='Show <br/> <strong>Assassin:</strong><br/> Death Sentry:<br/> Now - Lightning_Damage%<br/> Should be - Lightning_Damage<br/> <br/> Cloak of Shadows:<br/> Now - Range isn't shownRandom Stuff
Should be - Range = 20 yards
Barbarian:
Battle Cry:
Now - Duration is shown in integers
Should be - Duration is given with one decimal as seen here
Druid:
Rabies:
Now - No space at poison_duration
Should be - Yah...
Necromancer
Corpse Explosion:
Now - Range_Array = 3|3|3|4|4|4
Should be - Range_Array = 2.6|3|3.3|3.6|4|4.3 (once again integers -> decimals)
The duration of some curses at certain skill levels is, well, ugly. They've got infinite decimals. A small list:
Weaken 3/8/9
Iron Maiden 2/3/8/9
Life Tap 3/9
Decripify 3/9
I only went to Skill_Lvl 20, but there are probably more.
Paladin:
Sacrifice:
Now - Damage to Self isn't shown
Should be - Damage_Self = 8%
Vengeance:
Now - Cold_Damage%
Should be - +Cold_Damage%
Sorceress
Frozen/Shiver Armor:
Now - +Defence_Bonus%
Should be - Defence_Bonus% (A bonus implies that it's added. Ingame there also is no plus-sign)
Shiver Armor:
Now - +Armor_Duration
Should be - Armor_Duration
Energy Shield:
Now - +Duration
Should be - Duration
Inferno:
Now - +Range
Should be - Range
Blaze:
Now - +Fire_Duration
Should be - Fire_Duration
' />
Assassin:
Death Sentry:
Now - Lightning_Damage%
Should be - Lightning_Damage
Cloak of Shadows:
Now - Range isn't shown
Should be - Range = 20 yards
Barbarian:
Battle Cry:
Now - Duration is shown in integers
Should be - Duration is given with one decimal as seen here
Druid:
Rabies:
Now - No space at poison_duration
Should be - Yah...
Necromancer
Corpse Explosion:
Now - Range_Array = 3|3|3|4|4|4
Should be - Range_Array = 2.6|3|3.3|3.6|4|4.3 (once again integers -> decimals)
The duration of some curses at certain skill levels is, well, ugly. They've got infinite decimals. A small list:
Weaken 3/8/9
Iron Maiden 2/3/8/9
Life Tap 3/9
Decripify 3/9
I only went to Skill_Lvl 20, but there are probably more.
Paladin:
Sacrifice:
Now - Damage to Self isn't shown
Should be - Damage_Self = 8%
Vengeance:
Now - Cold_Damage%
Should be - +Cold_Damage%
Sorceress
Frozen/Shiver Armor:
Now - +Defence_Bonus%
Should be - Defence_Bonus% (A bonus implies that it's added. Ingame there also is no plus-sign)
Shiver Armor:
Now - +Armor_Duration
Should be - Armor_Duration
Energy Shield:
Now - +Duration
Should be - Duration
Inferno:
Now - +Range
Should be - Range
Blaze:
Now - +Fire_Duration
Should be - Fire_Duration
<input type='button' class='bbc_spoiler_show' value='Show <br/> <strong>Barbarian:</strong><br/> Bash:<br/> Now - Only has the '+% damage' part
Should be - Bash also adds Damage = Skill_Lvl (this is not effected by the synergies)
Druid:
Fire Claws:
Now - Attack_Bonus_Array = 60|75|90
Should be - Attack_Bonus_Array = 50|65|80 (just -10%)
Paladin:
Vigor:
Now - Radius_Array = 10|12|14
Should be - Radius_Array = 10.6|12.6|14.6 (Just add 0.6 yards)
Meditation:
Now - Radius_Array = 6.6|8|9.3
Should be - I'm not sure here. Ingame it says Radius_Array = 10.6|12|13.3 (the same as pretty much every other aura) but here it says something completely different.
Holy Fire:
Now - Fire_Damage_Array = 1-3|1-3|2-4|2-4
Should be - Lookies
The following offensive auras have incorrect radii:
Holy Fire
Holy Freeze
Holy Shock
Sanctuary
Fanaticism
Those on the Arreat Summit correspond with at least the first 3 levels ingame. I guess the other levels are pretty easy to deduct.
Sorceress
Frost Nova:
Now - Cold_Damage_Array = 4-4|6-6|8-9
Should be - Cold_Damage_Array = 2-4|4-6|6-9 (min_Cold_Damage should be reduced by 2)
Glacial Spike:
Now - When all cold spells are at lvl 1, then Cold_Damage = 20-29
Should be - Cold_Damage = 18-27
The odd thing is that this difference seems to change at different skill levels. Sometimes it's 2-2, then it's 1-2 and so forth. If you tried setting the Base_Cold_Damage = 16-24, then the problem should be gone. Now the base damage is 17-26, which is the same as on the Arreat Summit. The problem with the Arreat Summit is that 17-26 includes the synergies from the prerequisites (so +5% from ice bolt and +5% from ice blast.)
Static Field:
Now - Radius_Array = 3|3.6|4.3|5 (i.e. 3|3 2/3|4 1/3|5)
Should be - Radius_Array = 3.3|4|4.6|5 (simply + 1/3 yard)
Chain Lightning:
Simply the same problem as Glacial Spike - your base damage is actually base damage plus some synergies. Setting the base damage 1-37 will solve this (37*1.08=40 lightning and charged bolt synergy)' />
Barbarian:
Bash:
Now - Only has the '+% damage' part
Should be - Bash also adds Damage = Skill_Lvl (this is not effected by the synergies)
Druid:
Fire Claws:
Now - Attack_Bonus_Array = 60|75|90
Should be - Attack_Bonus_Array = 50|65|80 (just -10%)
Paladin:
Vigor:
Now - Radius_Array = 10|12|14
Should be - Radius_Array = 10.6|12.6|14.6 (Just add 0.6 yards)
Meditation:
Now - Radius_Array = 6.6|8|9.3
Should be - I'm not sure here. Ingame it says Radius_Array = 10.6|12|13.3 (the same as pretty much every other aura) but here it says something completely different.
Holy Fire:
Now - Fire_Damage_Array = 1-3|1-3|2-4|2-4
Should be - Lookies
The following offensive auras have incorrect radii:
Holy Fire
Holy Freeze
Holy Shock
Sanctuary
Fanaticism
Those on the Arreat Summit correspond with at least the first 3 levels ingame. I guess the other levels are pretty easy to deduct.
Sorceress
Frost Nova:
Now - Cold_Damage_Array = 4-4|6-6|8-9
Should be - Cold_Damage_Array = 2-4|4-6|6-9 (min_Cold_Damage should be reduced by 2)
Glacial Spike:
Now - When all cold spells are at lvl 1, then Cold_Damage = 20-29
Should be - Cold_Damage = 18-27
The odd thing is that this difference seems to change at different skill levels. Sometimes it's 2-2, then it's 1-2 and so forth. If you tried setting the Base_Cold_Damage = 16-24, then the problem should be gone. Now the base damage is 17-26, which is the same as on the Arreat Summit. The problem with the Arreat Summit is that 17-26 includes the synergies from the prerequisites (so +5% from ice bolt and +5% from ice blast.)
Static Field:
Now - Radius_Array = 3|3.6|4.3|5 (i.e. 3|3 2/3|4 1/3|5)
Should be - Radius_Array = 3.3|4|4.6|5 (simply + 1/3 yard)
Chain Lightning:
Simply the same problem as Glacial Spike - your base damage is actually base damage plus some synergies. Setting the base damage 1-37 will solve this (37*1.08=40 lightning and charged bolt synergy)
I should note that these things have been detected in Chrome 4.0.
I checked pretty much everything ingame with help of the -act5 shortcut modifier. -
1
ScyberDragon posted a message on Skill calculator - todo listAs of now, there is no level requirement for any of the skills. Also the level required under the stat points does not revert back when subtracting points.Posted in: Diablo Tools - To post a comment, please login or register a new account.
1
He tried repairing the game and re-installing but it didn't help...
1
Version 1.5.3
(soon online)
Data
1
Interface
1
1
Awesome, you didn't use your skills from quests though!
Yes we talked about that already (here) and we plan on adding it when the higher priority work is done. The Calculator is in Javascript.
1
The TODO list is now in the sticky post, here.
1
Hope you enjoy the Skill Calculator! It's in beta phase so report the bugs you find in the Diablo Tools Discussion so I can fix them asap.
Enjoy!
1
Je me plais déjà, merci!