Commit 24639c0433774cae725aceaaffbeb7962acd7084
1 parent
f8fab420
Added character skill parsing
Showing
2 changed files
with
100 additions
and
13 deletions
d2skills.c
1 | 1 | #include "d2skills.h" |
2 | +#include "d2stat.h" | |
2 | 3 | |
3 | 4 | #include <stdio.h> |
4 | 5 | #include <stdlib.h> |
... | ... | @@ -11,36 +12,118 @@ const char* getSkillName(D2S_SKILL skillID) { |
11 | 12 | return skillNames[skillID]; |
12 | 13 | } |
13 | 14 | |
14 | -D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset) { | |
15 | - if(offset < 0 || offset > D2S_SKILL_MAXSKILLS_PER_CHAR) { | |
16 | - fprintf(stderr,"libd2char error: Invalid character skill offset: %d\n",offset); | |
17 | - return D2S_SKILL_UNKNOWN; | |
18 | - } | |
15 | +const D2S_SKILL* _getCharSkillTree(D2S_CHARCLASS class) { | |
19 | 16 | switch(class) { |
20 | 17 | case D2S_CHARCLASS_AMAZON: |
21 | - return amazonSkills[offset]; | |
18 | + return amazonSkills; | |
22 | 19 | break; |
23 | 20 | case D2S_CHARCLASS_SORCERESS: |
24 | - return sorceressSkills[offset]; | |
21 | + return sorceressSkills; | |
25 | 22 | break; |
26 | 23 | case D2S_CHARCLASS_NECROMANCER: |
27 | - return necromancerSkills[offset]; | |
24 | + return necromancerSkills; | |
28 | 25 | break; |
29 | 26 | case D2S_CHARCLASS_PALADIN: |
30 | - return paladinSkills[offset]; | |
27 | + return paladinSkills; | |
31 | 28 | break; |
32 | 29 | case D2S_CHARCLASS_BARBARIAN: |
33 | - return barbarianSkills[offset]; | |
30 | + return barbarianSkills; | |
34 | 31 | break; |
35 | 32 | case D2S_CHARCLASS_DRUID: |
36 | - return druidSkills[offset]; | |
33 | + return druidSkills; | |
37 | 34 | break; |
38 | 35 | case D2S_CHARCLASS_ASSASSIN: |
39 | - return assassinSkills[offset]; | |
36 | + return assassinSkills; | |
40 | 37 | break; |
41 | 38 | case D2S_CHARCLASS_UNKNOWN: |
42 | 39 | default: |
43 | - return D2S_SKILL_UNKNOWN; | |
40 | + return NULL; | |
44 | 41 | break; |
45 | 42 | } |
43 | +} | |
44 | + | |
45 | +D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset) { | |
46 | + if(offset < 0 || offset > D2S_SKILL_MAXSKILLS_PER_CHAR) { | |
47 | + fprintf(stderr,"libd2char error: Invalid character skill offset: %d\n",offset); | |
48 | + return D2S_SKILL_UNKNOWN; | |
49 | + } | |
50 | + const D2S_SKILL* skillTree = _getCharSkillTree(class); | |
51 | + if(!skillTree) { | |
52 | + fprintf(stderr,"libd2char error: Invalid character class: %d\n",class); | |
53 | + return D2S_SKILL_UNKNOWN; | |
54 | + } | |
55 | + return skillTree[offset]; | |
56 | +} | |
57 | + | |
58 | +void* _getCharSkillsOffset(void* charData, size_t dataLen) { | |
59 | + // Find skill header and look for previous 2 bytes | |
60 | + // possible good candidates: | |
61 | + // | |
62 | + // 0b0000000111111111 | |
63 | + // 0b000000111111111x | |
64 | + // 0b00000111111111xx | |
65 | + // 0b0000111111111xxx | |
66 | + // 0b000111111111xxxx | |
67 | + // 0b00111111111xxxxx | |
68 | + // 0b0111111111xxxxxx | |
69 | + // 0b111111111xxxxxxx | |
70 | + unsigned int offset = 0; | |
71 | + while(offset < dataLen) { | |
72 | + void* offsetAddr = charData + (offset++); | |
73 | + if(!memcmp(offsetAddr, D2S_SKILL_HEADER, D2S_SKILL_HEADER_LENGTH)) { | |
74 | + uint16_t prevBytes = 0; | |
75 | + memcpy(&prevBytes, offsetAddr, sizeof(prevBytes)); | |
76 | + // Shift a maximum of 7 positions, and check if at some point the candidate | |
77 | + // turns into the 9 bit D2S_STAT_FOOTER value | |
78 | + for(int i = 0; i < 7; ++i) { | |
79 | + if(prevBytes == D2S_STAT_FOOTER) { | |
80 | + return offsetAddr; | |
81 | + } | |
82 | + prevBytes >>= 1; | |
83 | + } | |
84 | + // If we reach here, candidate was not viable, let's find a new candidate | |
85 | + } | |
86 | + } | |
87 | + return NULL; | |
88 | +} | |
89 | + | |
90 | +int getSkillLevel(D2CharHeader* c, D2S_SKILL skillID, void* charData, size_t dataLen) { | |
91 | + const D2S_SKILL* skillTree = _getCharSkillTree(c->charClass); | |
92 | + if(!skillTree) { | |
93 | + fprintf(stderr,"libd2char error: Invalid character class: %d\n",c->charClass); | |
94 | + return D2S_SKILL_UNKNOWN; | |
95 | + } | |
96 | + for(int i = 0; i < D2S_SKILL_MAXSKILLS_PER_CHAR; ++i) { | |
97 | + if(skillTree[i] == skillID) { | |
98 | + void* skillOffset = _getCharSkillsOffset(charData, dataLen); | |
99 | + if(!skillOffset) { | |
100 | + fprintf(stderr,"libd2char error: Unable to find skill data offset in charData\n"); | |
101 | + return -1; | |
102 | + } | |
103 | + return ((uint8_t*)skillOffset)[i + D2S_SKILL_HEADER_LENGTH]; | |
104 | + } | |
105 | + } | |
106 | + fprintf(stderr,"libd2char error: The specified skillID is not in your class's skill tree\n"); | |
107 | + return -1; | |
108 | +} | |
109 | + | |
110 | +int setSkillLevel(D2CharHeader* c, D2S_SKILL skillID, unsigned int level, void* charData, size_t dataLen) { | |
111 | + const D2S_SKILL* skillTree = _getCharSkillTree(c->charClass); | |
112 | + if(!skillTree) { | |
113 | + fprintf(stderr,"libd2char error: Invalid character class: %d\n",c->charClass); | |
114 | + return D2S_SKILL_UNKNOWN; | |
115 | + } | |
116 | + for(int i = 0; i < D2S_SKILL_MAXSKILLS_PER_CHAR; ++i) { | |
117 | + if(skillTree[i] == skillID) { | |
118 | + void* skillOffset = _getCharSkillsOffset(charData, dataLen); | |
119 | + if(!skillOffset) { | |
120 | + fprintf(stderr,"libd2char error: Unable to find skill data offset in charData\n"); | |
121 | + return -1; | |
122 | + } | |
123 | + ((uint8_t*)skillOffset)[i + D2S_SKILL_HEADER_LENGTH] = (uint8_t)level; | |
124 | + return 0; | |
125 | + } | |
126 | + } | |
127 | + fprintf(stderr,"libd2char error: The specified skillID is not in your class's skill tree\n"); | |
128 | + return -1; | |
46 | 129 | } |
47 | 130 | \ No newline at end of file | ... | ... |
d2skills.h
... | ... | @@ -8,6 +8,8 @@ |
8 | 8 | |
9 | 9 | #define D2S_SKILL_NUMSKILLS 357 |
10 | 10 | #define D2S_SKILL_MAXSKILLS_PER_CHAR 30 |
11 | +#define D2S_SKILL_HEADER "if" | |
12 | +#define D2S_SKILL_HEADER_LENGTH 2 | |
11 | 13 | |
12 | 14 | typedef enum D2S_SKILL { |
13 | 15 | D2S_SKILL_UNKNOWN = -1, |
... | ... | @@ -964,5 +966,7 @@ const char* const skillNames[] = { |
964 | 966 | // Returns static string from library memory, no need to free |
965 | 967 | const char* getSkillName(D2S_SKILL skillID); |
966 | 968 | D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset); |
969 | +int getSkillLevel(D2CharHeader* c, D2S_SKILL skillID, void* charData, size_t dataLen); | |
970 | +int setSkillLevel(D2CharHeader* c, D2S_SKILL skillID, unsigned int level, void* charData, size_t dataLen); | |
967 | 971 | |
968 | 972 | #endif |
969 | 973 | \ No newline at end of file | ... | ... |