Commit 24639c0433774cae725aceaaffbeb7962acd7084

Authored by Imanol-Mikel Barba Sabariego
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
... ...