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 #include "d2skills.h" 1 #include "d2skills.h"
  2 +#include "d2stat.h"
2 3
3 #include <stdio.h> 4 #include <stdio.h>
4 #include <stdlib.h> 5 #include <stdlib.h>
@@ -11,36 +12,118 @@ const char* getSkillName(D2S_SKILL skillID) { @@ -11,36 +12,118 @@ const char* getSkillName(D2S_SKILL skillID) {
11 return skillNames[skillID]; 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 switch(class) { 16 switch(class) {
20 case D2S_CHARCLASS_AMAZON: 17 case D2S_CHARCLASS_AMAZON:
21 - return amazonSkills[offset]; 18 + return amazonSkills;
22 break; 19 break;
23 case D2S_CHARCLASS_SORCERESS: 20 case D2S_CHARCLASS_SORCERESS:
24 - return sorceressSkills[offset]; 21 + return sorceressSkills;
25 break; 22 break;
26 case D2S_CHARCLASS_NECROMANCER: 23 case D2S_CHARCLASS_NECROMANCER:
27 - return necromancerSkills[offset]; 24 + return necromancerSkills;
28 break; 25 break;
29 case D2S_CHARCLASS_PALADIN: 26 case D2S_CHARCLASS_PALADIN:
30 - return paladinSkills[offset]; 27 + return paladinSkills;
31 break; 28 break;
32 case D2S_CHARCLASS_BARBARIAN: 29 case D2S_CHARCLASS_BARBARIAN:
33 - return barbarianSkills[offset]; 30 + return barbarianSkills;
34 break; 31 break;
35 case D2S_CHARCLASS_DRUID: 32 case D2S_CHARCLASS_DRUID:
36 - return druidSkills[offset]; 33 + return druidSkills;
37 break; 34 break;
38 case D2S_CHARCLASS_ASSASSIN: 35 case D2S_CHARCLASS_ASSASSIN:
39 - return assassinSkills[offset]; 36 + return assassinSkills;
40 break; 37 break;
41 case D2S_CHARCLASS_UNKNOWN: 38 case D2S_CHARCLASS_UNKNOWN:
42 default: 39 default:
43 - return D2S_SKILL_UNKNOWN; 40 + return NULL;
44 break; 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 \ No newline at end of file 130 \ No newline at end of file
d2skills.h
@@ -8,6 +8,8 @@ @@ -8,6 +8,8 @@
8 8
9 #define D2S_SKILL_NUMSKILLS 357 9 #define D2S_SKILL_NUMSKILLS 357
10 #define D2S_SKILL_MAXSKILLS_PER_CHAR 30 10 #define D2S_SKILL_MAXSKILLS_PER_CHAR 30
  11 +#define D2S_SKILL_HEADER "if"
  12 +#define D2S_SKILL_HEADER_LENGTH 2
11 13
12 typedef enum D2S_SKILL { 14 typedef enum D2S_SKILL {
13 D2S_SKILL_UNKNOWN = -1, 15 D2S_SKILL_UNKNOWN = -1,
@@ -964,5 +966,7 @@ const char* const skillNames[] = { @@ -964,5 +966,7 @@ const char* const skillNames[] = {
964 // Returns static string from library memory, no need to free 966 // Returns static string from library memory, no need to free
965 const char* getSkillName(D2S_SKILL skillID); 967 const char* getSkillName(D2S_SKILL skillID);
966 D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset); 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 #endif 972 #endif
969 \ No newline at end of file 973 \ No newline at end of file