d2skills.c
4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
129
#include "d2skills.h"
#include "d2stat.h"
#include <stdio.h>
#include <stdlib.h>
const char* getSkillName(D2S_SKILL skillID) {
if(skillID > D2S_SKILL_NUMSKILLS || skillID < 0) {
fprintf(stderr,"libd2char error: skillID %d doesn't exist\n",skillID);
return NULL;
}
return skillNames[skillID];
}
const D2S_SKILL* _getCharSkillTree(D2S_CHARCLASS class) {
switch(class) {
case D2S_CHARCLASS_AMAZON:
return amazonSkills;
break;
case D2S_CHARCLASS_SORCERESS:
return sorceressSkills;
break;
case D2S_CHARCLASS_NECROMANCER:
return necromancerSkills;
break;
case D2S_CHARCLASS_PALADIN:
return paladinSkills;
break;
case D2S_CHARCLASS_BARBARIAN:
return barbarianSkills;
break;
case D2S_CHARCLASS_DRUID:
return druidSkills;
break;
case D2S_CHARCLASS_ASSASSIN:
return assassinSkills;
break;
case D2S_CHARCLASS_UNKNOWN:
default:
return NULL;
break;
}
}
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;
}