Blame view

d2skills.c 4.37 KB
1
#include "d2skills.h"
2
#include "d2stat.h"
3
4
5
6
7

#include <stdio.h>
#include <stdlib.h>

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