|
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
}
D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset) {
if(offset < 0 || offset > D2S_SKILL_MAXSKILLS_PER_CHAR) {
fprintf(stderr,"libd2char error: Invalid character skill offset: %d\n",offset);
return D2S_SKILL_UNKNOWN;
}
const D2S_SKILL* skillTree = _getCharSkillTree(class);
if(!skillTree) {
fprintf(stderr,"libd2char error: Invalid character class: %d\n",class);
return D2S_SKILL_UNKNOWN;
}
return skillTree[offset];
}
void* _getCharSkillsOffset(void* charData, size_t dataLen) {
// Find skill header and look for previous 2 bytes
// possible good candidates:
//
// 0b0000000111111111
// 0b000000111111111x
// 0b00000111111111xx
// 0b0000111111111xxx
// 0b000111111111xxxx
// 0b00111111111xxxxx
// 0b0111111111xxxxxx
// 0b111111111xxxxxxx
unsigned int offset = 0;
while(offset < dataLen) {
void* offsetAddr = charData + (offset++);
if(!memcmp(offsetAddr, D2S_SKILL_HEADER, D2S_SKILL_HEADER_LENGTH)) {
uint16_t prevBytes = 0;
memcpy(&prevBytes, offsetAddr, sizeof(prevBytes));
// Shift a maximum of 7 positions, and check if at some point the candidate
// turns into the 9 bit D2S_STAT_FOOTER value
for(int i = 0; i < 7; ++i) {
if(prevBytes == D2S_STAT_FOOTER) {
return offsetAddr;
}
prevBytes >>= 1;
}
// If we reach here, candidate was not viable, let's find a new candidate
}
}
return NULL;
}
int getSkillLevel(D2CharHeader* c, D2S_SKILL skillID, void* charData, size_t dataLen) {
const D2S_SKILL* skillTree = _getCharSkillTree(c->charClass);
if(!skillTree) {
fprintf(stderr,"libd2char error: Invalid character class: %d\n",c->charClass);
return D2S_SKILL_UNKNOWN;
}
for(int i = 0; i < D2S_SKILL_MAXSKILLS_PER_CHAR; ++i) {
if(skillTree[i] == skillID) {
void* skillOffset = _getCharSkillsOffset(charData, dataLen);
if(!skillOffset) {
fprintf(stderr,"libd2char error: Unable to find skill data offset in charData\n");
return -1;
}
return ((uint8_t*)skillOffset)[i + D2S_SKILL_HEADER_LENGTH];
}
}
fprintf(stderr,"libd2char error: The specified skillID is not in your class's skill tree\n");
return -1;
}
int setSkillLevel(D2CharHeader* c, D2S_SKILL skillID, unsigned int level, void* charData, size_t dataLen) {
const D2S_SKILL* skillTree = _getCharSkillTree(c->charClass);
if(!skillTree) {
fprintf(stderr,"libd2char error: Invalid character class: %d\n",c->charClass);
return D2S_SKILL_UNKNOWN;
}
for(int i = 0; i < D2S_SKILL_MAXSKILLS_PER_CHAR; ++i) {
if(skillTree[i] == skillID) {
void* skillOffset = _getCharSkillsOffset(charData, dataLen);
if(!skillOffset) {
fprintf(stderr,"libd2char error: Unable to find skill data offset in charData\n");
return -1;
}
((uint8_t*)skillOffset)[i + D2S_SKILL_HEADER_LENGTH] = (uint8_t)level;
return 0;
}
}
fprintf(stderr,"libd2char error: The specified skillID is not in your class's skill tree\n");
return -1;
|