diff --git a/d2char.c b/d2char.c index c3ef6f9..0fa9dd0 100644 --- a/d2char.c +++ b/d2char.c @@ -28,39 +28,47 @@ int isHardcore(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_HARDCORE; } -void setHardcore(D2CharHeader* c) { - +void setHardcore(D2CharHeader* c, int bool) { + if(bool) { + c->charProgress |= D2S_CHARSTATUS_HARDCORE; + } else { + c->charProgress &= ~D2S_CHARSTATUS_HARDCORE; + } } int hasDied(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_DIED; } -void setDied(D2CharHeader* c) { - +void setDied(D2CharHeader* c, int bool) { + if(bool) { + c->charProgress |= D2S_CHARSTATUS_DIED; + } else { + c->charProgress &= ~D2S_CHARSTATUS_DIED; + } } int isExpansion(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_EXPANSION; } -void setExpansion(D2CharHeader* c) { - +void setExpansion(D2CharHeader* c, int bool) { + if(bool) { + c->charProgress |= D2S_CHARSTATUS_EXPANSION; + } else { + c->charProgress &= ~D2S_CHARSTATUS_EXPANSION; + } } int isLadder(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_LADDER; } -void setLadder(D2CharHeader* c) { - -} - -D2S_ACT getCurrentAct(D2CharHeader* c) { - if(isExpansion(c)) { - return c->charProgress % 5; +void setLadder(D2CharHeader* c, int bool) { + if(bool) { + c->charProgress |= D2S_CHARSTATUS_LADDER; } else { - return c->charProgress % 4; + c->charProgress &= ~D2S_CHARSTATUS_LADDER; } } @@ -71,33 +79,34 @@ int isFemale(D2CharHeader* c) { } const char* getCharacterTitle(D2CharHeader* c) { - int tier; + D2S_DIFFICULTY hardestCleared; + D2S_ACT act; // We don't care, but need to provide it + getProgress(c,&act,&hardestCleared); if(isExpansion(c)) { // Expansion - tier = c->charProgress / 5; if(isHardcore(c)) { // Expansion Hardcore - switch(tier) { - case 1: + switch(hardestCleared) { + case D2S_DIFFICULTY_NORMAL: return D2S_CHARPROGRESS_EXPANSION_TIER1_NAME_HARDCORE; break; - case 2: + case D2S_DIFFICULTY_NIGHTMARE: return D2S_CHARPROGRESS_EXPANSION_TIER2_NAME_HARDCORE; break; - case 3: + case D2S_DIFFICULTY_HELL: return D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE; break; } } else { // Expansion Softcore - switch(tier) { - case 1: + switch(hardestCleared) { + case D2S_DIFFICULTY_NORMAL: return D2S_CHARPROGRESS_EXPANSION_TIER1_NAME; break; - case 2: + case D2S_DIFFICULTY_NIGHTMARE: return D2S_CHARPROGRESS_EXPANSION_TIER2_NAME; break; - case 3: + case D2S_DIFFICULTY_HELL: return isFemale(c) ? D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_F : D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_M; break; } @@ -106,27 +115,27 @@ const char* getCharacterTitle(D2CharHeader* c) { // Classic if(isHardcore(c)) { // Classic Hardcore - switch(tier) { - case 1: + switch(hardestCleared) { + case D2S_DIFFICULTY_NORMAL: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_HARDCORE_M; break; - case 2: + case D2S_DIFFICULTY_NIGHTMARE: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_HARDCORE_M; break; - case 3: + case D2S_DIFFICULTY_HELL: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_HARDCORE_M; break; } } else { // Classic Softcore - switch(tier) { - case 1: + switch(hardestCleared) { + case D2S_DIFFICULTY_NORMAL: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_M; break; - case 2: + case D2S_DIFFICULTY_NIGHTMARE: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_M; break; - case 3: + case D2S_DIFFICULTY_HELL: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_M; break; } @@ -160,18 +169,72 @@ D2S_DIFFICULTY getCurrentDifficulty(D2CharHeader* c) { return D2S_DIFFICULTY_UNKNOWN; } -int setProgress(D2S_ACT act, D2S_DIFFICULTY difficulty) { - // TODO - // set c->difficulty and c->progress? +D2S_ACT getCurrentAct(D2CharHeader* c) { + for(int i = D2S_DIFFICULTY_NORMAL; i <= D2S_DIFFICULTY_HELL; ++i) { + if(c->difficulty[i] & D2S_DIFFICULTY_ACTIVE) { + return (D2S_ACT)(c->difficulty[i] & 0x07); + } + } + return D2S_ACT_UNKNOWN; +} + +void getProgress(D2CharHeader* c, D2S_ACT* act, D2S_DIFFICULTY* difficulty) { + if(isExpansion(c)) { + *difficulty = c->charProgress / 5; + *act = c->charProgress % 5; + // Unfortunately, this won't distinguish between act IV and act V, because + // the game does not increment the charProgress when you kill Diablo, so + // the only way to know is check whether or not you started the act on the + // quest data + // NB: This doesn't happen in Classic + if(*act == D2S_ACT4) { + if(c->questData.quests[*difficulty].expansionAct.actStarted) { + ++*act; + } + } + } else { + *difficulty = c->charProgress / 4; + *act = c->charProgress % 4; + } +} + +int setProgress(D2CharHeader* c, D2S_ACT act, D2S_DIFFICULTY difficulty) { + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: Invalid difficulty specified: %d\n", difficulty); + return -1; + } + if(act != D2S_ACT1 || + act != D2S_ACT2 || + act != D2S_ACT3 || + act != D2S_ACT4 || + act != D2S_ACT5) { + fprintf(stderr,"libd2char error: Invalid act specified: %d\n", act); + return -1; + } + uint8_t progress = 0; + if(isExpansion(c)) { + progress += difficulty * 5; + progress += act; + if(act == D2S_ACT5) { + // See comment above + --progress; + c->questData.quests[difficulty].expansionAct.actStarted = 1; + } + } else { + progress = (difficulty * 4) + act; + } + c->charProgress = progress; return 0; } int getAttribute(D2S_STAT attr) { - // TODO + // TODO implement return 0; } int setAttribute(D2S_STAT attr, unsigned int value) { - // TODO + // TODO implement return 0; } \ No newline at end of file diff --git a/d2char.h b/d2char.h index 82a8d02..af617d5 100644 --- a/d2char.h +++ b/d2char.h @@ -45,6 +45,7 @@ typedef enum D2S_VERSION { } D2S_VERSION; typedef enum D2S_CHARCLASS { + D2S_CHARCLASS_UNKNOWN = -1, D2S_CHARCLASS_AMAZON = 0, D2S_CHARCLASS_SORCERESS = 1, D2S_CHARCLASS_NECROMANCER = 2, @@ -74,6 +75,7 @@ typedef enum D2S_STAT { } D2S_STAT; typedef enum D2S_ACT { + D2S_ACT_UNKNOWN = -1, D2S_ACT1 = 0, D2S_ACT2, D2S_ACT3, @@ -132,16 +134,13 @@ typedef struct __attribute__((packed)){ uint32_t calcChecksum(D2CharHeader* c, void* charData); int checkChecksum(D2CharHeader* c, void* charData); int isHardcore(D2CharHeader* c); -void setHardcore(D2CharHeader* c); +void setHardcore(D2CharHeader* c, int bool); int hasDied(D2CharHeader* c); -void setDied(D2CharHeader* c); +void setDied(D2CharHeader* c, int bool); int isExpansion(D2CharHeader* c); -void setExpansion(D2CharHeader* c); +void setExpansion(D2CharHeader* c, int bool); int isLadder(D2CharHeader* c); -void setLadder(D2CharHeader* c); - -// 0 = Act I, 4 = Act V (Expansion) -D2S_ACT getCurrentAct(D2CharHeader* c); +void setLadder(D2CharHeader* c, int bool); int isFemale(D2CharHeader* c); @@ -151,10 +150,16 @@ const char* getCharacterTitle(D2CharHeader* c); // Writes to user-allocated string. Format is default locale's time representation size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen); +// This is the last difficulty played, not the highest available. For that, use getProgress() // 0 = Normal, 2 = Hell D2S_DIFFICULTY getCurrentDifficulty(D2CharHeader* c); -int setProgress(D2S_ACT act, D2S_DIFFICULTY difficulty); +// This is the last act played, not the highest available. For that, use getProgress() +// 0 = Act I, 4 = Act V (Expansion) +D2S_ACT getCurrentAct(D2CharHeader* c); + +void getProgress(D2CharHeader* c, D2S_ACT* act, D2S_DIFFICULTY* difficulty); +int setProgress(D2CharHeader* c, D2S_ACT act, D2S_DIFFICULTY difficulty); int getAttribute(D2S_STAT attr); int setAttribute(D2S_STAT attr, unsigned int value); diff --git a/d2mercs.c b/d2mercs.c index 789e8c9..c9c427d 100644 --- a/d2mercs.c +++ b/d2mercs.c @@ -27,13 +27,224 @@ D2S_MERCTYPE getMercType(uint16_t mercID) { } D2S_MERCSUBTYPE getMercSubType(uint16_t mercID) { - // TODO + D2S_MERCSUBTYPE subtype; + switch(getMercType(mercID)) { + case D2S_MERCTYPE_ROGUE: + if(mercID == 0 || mercID == 2 || mercID == 4) { + subtype = D2S_MERCSUBTYPE_FIRE_ARROW; + } else { + subtype = D2S_MERCSUBTYPE_COLD_ARROW; + } + break; + case D2S_MERCTYPE_DESERT: + if(mercID == 6 || mercID == 9 || mercID == 12) { + subtype = D2S_MERCSUBTYPE_COMBAT; + } if(mercID == 7 || mercID == 10 || mercID == 13) { + subtype = D2S_MERCSUBTYPE_DEFENSIVE; + } else { + subtype = D2S_MERCSUBTYPE_OFFENSIVE; + } + break; + case D2S_MERCTYPE_SORCEROR: + if(mercID == 15 || mercID == 18 || mercID == 21) { + subtype = D2S_MERCSUBTYPE_FIRE; + } if(mercID == 16 || mercID == 19 || mercID == 22) { + subtype = D2S_MERCSUBTYPE_COLD; + } else { + subtype = D2S_MERCSUBTYPE_LIGHTNING; + } + break; + case D2S_MERCTYPE_BARBARIAN: + case D2S_MERCTYPE_UNKNOWN: + subtype = D2S_MERCSUBTYPE_NONE; + break; + } + return subtype; } D2S_DIFFICULTY getMercDifficulty(uint16_t mercID) { - // TODO + if(mercID == 0 || mercID == 1 || + mercID == 6 || mercID == 7 || mercID == 8 || + mercID == 15 || mercID == 16 || mercID == 17 || + mercID == 24 || mercID == 25) { + return D2S_DIFFICULTY_NORMAL; + } else if (mercID == 2 || mercID == 3 || + mercID == 9 || mercID == 10 || mercID == 11 || + mercID == 18 || mercID == 19 || mercID == 20 || + mercID == 26 || mercID == 27) { + return D2S_DIFFICULTY_NIGHTMARE; + } else if (mercID == 4 || mercID == 5 || + mercID == 12 || mercID == 13 || mercID == 14 || + mercID == 21 || mercID == 22 || mercID == 23 || + mercID == 28 || mercID == 29) { + return D2S_DIFFICULTY_HELL; + } + return D2S_DIFFICULTY_UNKNOWN; } -int setMerc(D2S_MERCTYPE type, D2S_MERCSUBTYPE subtype, D2S_DIFFICULTY difficulty) { - // TODO +int setMerc(D2CharHeader* c, D2S_MERCTYPE type, D2S_MERCSUBTYPE subtype, D2S_DIFFICULTY difficulty) { + switch(type) { + case D2S_MERCTYPE_ROGUE: + switch(subtype) { + case D2S_MERCSUBTYPE_FIRE_ARROW: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 0; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 2; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 4; + return 0; + break; + } + break; + case D2S_MERCSUBTYPE_COLD_ARROW: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 1; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 3; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 5; + return 0; + break; + } + break; + } + break; + case D2S_MERCTYPE_DESERT: + switch(subtype) { + case D2S_MERCSUBTYPE_COMBAT: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 6; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 9; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 12; + return 0; + break; + } + break; + case D2S_MERCSUBTYPE_DEFENSIVE: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 7; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 10; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 13; + return 0; + break; + } + break; + case D2S_MERCSUBTYPE_OFFENSIVE: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 8; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 11; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 14; + return 0; + break; + } + break; + } + break; + case D2S_MERCTYPE_SORCEROR: + switch(subtype) { + case D2S_MERCSUBTYPE_FIRE: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 15; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 18; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 21; + return 0; + break; + } + break; + case D2S_MERCSUBTYPE_COLD: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 16; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 19; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 22; + return 0; + break; + } + break; + case D2S_MERCSUBTYPE_LIGHTNING: + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 17; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 20; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 23; + return 0; + break; + } + break; + } + break; + case D2S_MERCTYPE_BARBARIAN: + // There's actually 2 identifiers for barbarians in each difficulty, they don't seem to have + // noticeable effect in game, so I'm considering only one of them. If you want to specifcially + // change to the other type, you probably know already what the mercID is so change it directly + // in the header instead of using this function + switch(difficulty) { + case D2S_DIFFICULTY_NORMAL: + c->mercenaryType = 24; + return 0; + break; + case D2S_DIFFICULTY_NIGHTMARE: + c->mercenaryType = 26; + return 0; + break; + case D2S_DIFFICULTY_HELL: + c->mercenaryType = 28; + return 0; + break; + } + break; + } + fprintf(stderr,"libd2char error: invalid combination of parameters for setMerc()\n"); + return -1; } \ No newline at end of file diff --git a/d2mercs.h b/d2mercs.h index 4f1be82..3c8013b 100644 --- a/d2mercs.h +++ b/d2mercs.h @@ -186,6 +186,6 @@ const char* getMercName(uint16_t mercID, uint16_t mercNameID); D2S_MERCTYPE getMercType(uint16_t mercID); D2S_MERCSUBTYPE getMercSubType(uint16_t mercID); D2S_DIFFICULTY getMercDifficulty(uint16_t mercID); -int setMerc(D2S_MERCTYPE type, D2S_MERCSUBTYPE subtype, D2S_DIFFICULTY difficulty); +int setMerc(D2CharHeader* c, D2S_MERCTYPE type, D2S_MERCSUBTYPE subtype, D2S_DIFFICULTY difficulty); #endif \ No newline at end of file diff --git a/d2quest.c b/d2quest.c index 621bac9..31e9360 100644 --- a/d2quest.c +++ b/d2quest.c @@ -17,10 +17,16 @@ int getCheckpointDescriptions(D2S_QUEST quest, const char* *descriptions[16]) { return -1; } memcpy(descriptions,(&checkpointDescriptions) + (quest * 16 * sizeof(const char*)), 16 * sizeof(const char*)); + return 0; } int getQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t* data) { - // TODO sanity check diff and quest + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); + return -1; + } if(quest >= D2S_QUEST_DEN_OF_EVIL && quest <= D2S_QUEST_SISTERS_TO_THE_SLAUGHTER) { *data = d->quests[difficulty].actData[D2S_ACT1].questCheckpoints[quest]; } else if(quest >= D2S_QUEST_RADAMENT_LAIR && quest <= D2S_QUEST_SEVEN_TOMBS) { @@ -39,7 +45,12 @@ int getQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, u } int setQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t questData) { - // TODO sanity check diff and quest + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); + return -1; + } if(quest >= D2S_QUEST_DEN_OF_EVIL && quest <= D2S_QUEST_SISTERS_TO_THE_SLAUGHTER) { d->quests[difficulty].actData[D2S_ACT1].questCheckpoints[quest] = questData; } else if(quest >= D2S_QUEST_RADAMENT_LAIR && quest <= D2S_QUEST_SEVEN_TOMBS) { @@ -133,22 +144,34 @@ int setQuestCompleted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty return setQuestStatus(d,quest,difficulty,questData); } -int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, D2S_DIFFICULTY difficulty) { +int getSpecialQuestStatus(D2QuestData* d, D2S_SPECIALQUEST specialQuestState, D2S_DIFFICULTY difficulty) { + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); + return -1; + } int ret = 0; switch(specialQuestState) { case D2S_SPECIALQUEST_AKARA_RESPEC: ret = d->quests[difficulty].akaraRespecData & D2S_QUEST_STATUS_REWARD_AVAILABLE; break; + default: + fprintf(stderr,"libd2char error: invalid special quest %d\n",specialQuestState); + ret = -1; + break; } return ret; } -int setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, D2S_DIFFICULTY difficulty, int bool) { +int setSpecialQuestStatus(D2QuestData* d, D2S_SPECIALQUEST specialQuestState, D2S_DIFFICULTY difficulty, int bool) { if(difficulty != D2S_DIFFICULTY_NORMAL || difficulty != D2S_DIFFICULTY_NIGHTMARE || difficulty != D2S_DIFFICULTY_HELL) { fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); + return -1; } + int ret = 0; switch(specialQuestState) { case D2S_SPECIALQUEST_AKARA_RESPEC: // This operation only makes sense if the quest is actually completed, otherwise ignore request @@ -160,5 +183,10 @@ int setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, D2S_DI } } break; + default: + fprintf(stderr,"libd2char error: invalid special quest %d\n",specialQuestState); + ret = -1; + break; } + return ret; } \ No newline at end of file diff --git a/d2skills.c b/d2skills.c index 3302233..d275dfd 100644 --- a/d2skills.c +++ b/d2skills.c @@ -1,17 +1,46 @@ -#include "d2char.h" #include "d2skills.h" #include #include -D2S_CHARCLASS getSkillClass(D2S_SKILL skillID) { - // TODO -} - const char* getSkillName(D2S_SKILL skillID) { - if(skillID > D2S_SKILL_NUMSKILLS) { + if(skillID > D2S_SKILL_NUMSKILLS || skillID < 0) { fprintf(stderr,"libd2char error: skillID %d doesn't exist\n",skillID); return NULL; } - return skills[skillID]; + return skillNames[skillID]; +} + +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; + } + switch(class) { + case D2S_CHARCLASS_AMAZON: + return amazonSkills[offset]; + break; + case D2S_CHARCLASS_SORCERESS: + return sorceressSkills[offset]; + break; + case D2S_CHARCLASS_NECROMANCER: + return necromancerSkills[offset]; + break; + case D2S_CHARCLASS_PALADIN: + return paladinSkills[offset]; + break; + case D2S_CHARCLASS_BARBARIAN: + return barbarianSkills[offset]; + break; + case D2S_CHARCLASS_DRUID: + return druidSkills[offset]; + break; + case D2S_CHARCLASS_ASSASSIN: + return assassinSkills[offset]; + break; + case D2S_CHARCLASS_UNKNOWN: + default: + return D2S_SKILL_UNKNOWN; + break; + } } \ No newline at end of file diff --git a/d2skills.h b/d2skills.h index 74415d3..117e197 100644 --- a/d2skills.h +++ b/d2skills.h @@ -3,14 +3,605 @@ #include +#include "d2char.h" #include "d2strings.h" #define D2S_SKILL_NUMSKILLS 357 +#define D2S_SKILL_MAXSKILLS_PER_CHAR 30 -// TODO skill class trees -typedef int D2S_SKILL; +typedef enum D2S_SKILL { + D2S_SKILL_UNKNOWN = -1, + D2S_SKILL_ATTACK = 0, + D2S_SKILL_KICK, + D2S_SKILL_THROW_ITEM, + D2S_SKILL_UNSUMMON, + D2S_SKILL_LEFT_HAND_THROW, + D2S_SKILL_LEFT_HAND_SWING, + D2S_SKILL_MAGIC_ARROW, + D2S_SKILL_FIRE_ARROW, + D2S_SKILL_INNER_SIGHT, + D2S_SKILL_CRITICAL_STRIKE, + D2S_SKILL_JAB, + D2S_SKILL_COLD_ARROW, + D2S_SKILL_MULTIPLE_SHOT, + D2S_SKILL_DODGE, + D2S_SKILL_POWER_STRIKE, + D2S_SKILL_POISON_JAVELIN, + D2S_SKILL_EXPLODING_ARROW, + D2S_SKILL_SLOW_MISSILES, + D2S_SKILL_AVOID, + D2S_SKILL_IMPALE, + D2S_SKILL_LIGHTNING_BOLT, + D2S_SKILL_ICE_ARROW, + D2S_SKILL_GUIDED_ARROW, + D2S_SKILL_PENETRATE, + D2S_SKILL_CHARGED_STRIKE, + D2S_SKILL_PLAGUE_JAVELIN, + D2S_SKILL_STRAFE, + D2S_SKILL_IMMOLATION_ARROW, + D2S_SKILL_DOPPLEZON, + D2S_SKILL_EVADE, + D2S_SKILL_FEND, + D2S_SKILL_FREEZING_ARROW, + D2S_SKILL_VALKYRIE, + D2S_SKILL_PIERCE, + D2S_SKILL_LIGHTNING_STRIKE, + D2S_SKILL_LIGHTNING_FURY, + D2S_SKILL_FIRE_BOLT, + D2S_SKILL_WARMTH, + D2S_SKILL_CHARGED_BOLT, + D2S_SKILL_ICE_BOLT, + D2S_SKILL_FROZEN_ARMOR, + D2S_SKILL_INFERNO, + D2S_SKILL_STATIC_FIELD, + D2S_SKILL_TELEKINESIS, + D2S_SKILL_FROST_NOVA, + D2S_SKILL_ICE_BLAST, + D2S_SKILL_BLAZE, + D2S_SKILL_FIRE_BALL, + D2S_SKILL_NOVA, + D2S_SKILL_LIGHTNING, + D2S_SKILL_SHIVER_ARMOR, + D2S_SKILL_FIRE_WALL, + D2S_SKILL_ENCHANT, + D2S_SKILL_CHAIN_LIGHTNING, + D2S_SKILL_TELEPORT, + D2S_SKILL_GLACIAL_SPIKE, + D2S_SKILL_METEOR, + D2S_SKILL_THUNDER_STORM, + D2S_SKILL_ENERGY_SHIELD, + D2S_SKILL_BLIZZARD, + D2S_SKILL_CHILLING_ARMOR, + D2S_SKILL_FIRE_MASTERY, + D2S_SKILL_HYDRA, + D2S_SKILL_LIGHTNING_MASTERY, + D2S_SKILL_FROZEN_ORB, + D2S_SKILL_COLD_MASTERY, + D2S_SKILL_AMPLIFY_DAMAGE, + D2S_SKILL_TEETH, + D2S_SKILL_BONE_ARMOR, + D2S_SKILL_SKELETON_MASTERY, + D2S_SKILL_RAISE_SKELETON, + D2S_SKILL_DIM_VISION, + D2S_SKILL_WEAKEN, + D2S_SKILL_POISON_DAGGER, + D2S_SKILL_CORPSE_EXPLOSION, + D2S_SKILL_CLAY_GOLEM, + D2S_SKILL_IRON_MAIDEN, + D2S_SKILL_TERROR, + D2S_SKILL_BONE_WALL, + D2S_SKILL_GOLEM_MASTERY, + D2S_SKILL_RAISE_SKELETAL_MAGE, + D2S_SKILL_CONFUSE, + D2S_SKILL_LIFE_TAP, + D2S_SKILL_POISON_EXPLOSION, + D2S_SKILL_BONE_SPEAR, + D2S_SKILL_BLOOD_GOLEM, + D2S_SKILL_ATTRACT, + D2S_SKILL_DECREPIFY, + D2S_SKILL_BONE_PRISON, + D2S_SKILL_SUMMON_RESIST, + D2S_SKILL_IRON_GOLEM, + D2S_SKILL_LOWER_RESIST, + D2S_SKILL_POISON_NOVA, + D2S_SKILL_BONE_SPIRIT, + D2S_SKILL_FIRE_GOLEM, + D2S_SKILL_REVIVE, + D2S_SKILL_SACRIFICE, + D2S_SKILL_SMITE, + D2S_SKILL_MIGHT, + D2S_SKILL_PRAYER, + D2S_SKILL_RESIST_FIRE, + D2S_SKILL_HOLY_BOLT, + D2S_SKILL_HOLY_FIRE, + D2S_SKILL_THORNS, + D2S_SKILL_DEFIANCE, + D2S_SKILL_RESIST_COLD, + D2S_SKILL_ZEAL, + D2S_SKILL_CHARGE, + D2S_SKILL_BLESSED_AIM, + D2S_SKILL_CLEANSING, + D2S_SKILL_RESIST_LIGHTNING, + D2S_SKILL_VENGEANCE, + D2S_SKILL_BLESSED_HAMMER, + D2S_SKILL_CONCENTRATION, + D2S_SKILL_HOLY_FREEZE, + D2S_SKILL_VIGOR, + D2S_SKILL_CONVERSION, + D2S_SKILL_HOLY_SHIELD, + D2S_SKILL_HOLY_SHOCK, + D2S_SKILL_SANCTUARY, + D2S_SKILL_MEDITATION, + D2S_SKILL_FIST_OF_THE_HEAVENS, + D2S_SKILL_FANATICISM, + D2S_SKILL_CONVICTION, + D2S_SKILL_REDEMPTION, + D2S_SKILL_SALVATION, + D2S_SKILL_BASH, + D2S_SKILL_SWORD_MASTERY, + D2S_SKILL_AXE_MASTERY, + D2S_SKILL_MACE_MASTERY, + D2S_SKILL_HOWL, + D2S_SKILL_FIND_POTION, + D2S_SKILL_LEAP, + D2S_SKILL_DOUBLE_SWING, + D2S_SKILL_POLE_ARM_MASTERY, + D2S_SKILL_THROWING_MASTERY, + D2S_SKILL_SPEAR_MASTERY, + D2S_SKILL_TAUNT, + D2S_SKILL_SHOUT, + D2S_SKILL_STUN, + D2S_SKILL_DOUBLE_THROW, + D2S_SKILL_INCREASED_STAMINA, + D2S_SKILL_FIND_ITEM, + D2S_SKILL_LEAP_ATTACK, + D2S_SKILL_CONCENTRATE, + D2S_SKILL_IRON_SKIN, + D2S_SKILL_BATTLE_CRY, + D2S_SKILL_FRENZY, + D2S_SKILL_INCREASED_SPEED, + D2S_SKILL_BATTLE_ORDERS, + D2S_SKILL_GRIM_WARD, + D2S_SKILL_WHIRLWIND, + D2S_SKILL_BERSERK, + D2S_SKILL_NATURAL_RESISTANCE, + D2S_SKILL_WAR_CRY, + D2S_SKILL_BATTLE_COMMAND, + D2S_SKILL_FIRE_HIT, + D2S_SKILL_UNHOLY_BOLT, + D2S_SKILL_SKELETON_RAISE, + D2S_SKILL_MAGGOT_EGG, + D2S_SKILL_SHAMAN_FIRE, + D2S_SKILL_MAGOTTUP, + D2S_SKILL_MAGOTTDOWN, + D2S_SKILL_MAGOTTLAY, + D2S_SKILL_ANDRIAL_SPRAY, + D2S_SKILL_JUMP, + D2S_SKILL_SWARM_MOVE, + D2S_SKILL_NEST, + D2S_SKILL_QUICK_STRIKE, + D2S_SKILL_VAMPIRE_FIREBALL, + D2S_SKILL_VAMPIRE_FIREWALL, + D2S_SKILL_VAMPIRE_METEOR, + D2S_SKILL_GARGOYLE_TRAP, + D2S_SKILL_SPIDER_LAY, + D2S_SKILL_VAMPIRE_HEAL, + D2S_SKILL_VAMPIRE_RAISE, + D2S_SKILL_SUBMERGE, + D2S_SKILL_FETISH_AURA, + D2S_SKILL_FETISH_INFERNO, + D2S_SKILL_ZAKARUM_HEAL, + D2S_SKILL_EMERGE, + D2S_SKILL_RESURRECT, + D2S_SKILL_BESTOW, + D2S_SKILL_MISSILE_SKILL1, + D2S_SKILL_MON_TELEPORT, + D2S_SKILL_PRIME_LIGHTNING, + D2S_SKILL_PRIME_BOLT, + D2S_SKILL_PRIME_BLAZE, + D2S_SKILL_PRIME_FIREWALL, + D2S_SKILL_PRIME_SPIKE, + D2S_SKILL_PRIME_ICE_NOVA, + D2S_SKILL_PRIME_POISON_BALL, + D2S_SKILL_PRIME_POISON_NOVA, + D2S_SKILL_DIABLIGHT, + D2S_SKILL_DIABCOLD, + D2S_SKILL_DIABFIRE, + D2S_SKILL_FINGERMAGESPIDER, + D2S_SKILL_DIABWALL, + D2S_SKILL_DIABRUN, + D2S_SKILL_DIABPRISON, + D2S_SKILL_POISON_BALL_TRAP, + D2S_SKILL_ANDY_POISON_BOLT, + D2S_SKILL_HIREABLE_MISSILE, + D2S_SKILL_DESERT_TURRET, + D2S_SKILL_ARCANE_TOWER, + D2S_SKILL_MONBLIZZARD, + D2S_SKILL_MOSQUITO, + D2S_SKILL_CURSED_BALL_TRAP_RIGHT, + D2S_SKILL_CURSED_BALL_TRAP_LEFT, + D2S_SKILL_MONFROZENARMOR, + D2S_SKILL_MONBONEARMOR, + D2S_SKILL_MONBONESPIRIT, + D2S_SKILL_MONCURSECAST, + D2S_SKILL_HELLMETEOR, + D2S_SKILL_REGURGITATOREAT, + D2S_SKILL_MONFRENZY, + D2S_SKILL_QUEENDEATH, + D2S_SKILL_SCROLL_OF_IDENTIFY, + D2S_SKILL_BOOK_OF_IDENTIFY, + D2S_SKILL_SCROLL_OF_TOWNPORTAL, + D2S_SKILL_BOOK_OF_TOWNPORTAL, + D2S_SKILL_RAVEN, + D2S_SKILL_POISON_CREEPER, + D2S_SKILL_WEARWOLF, + D2S_SKILL_SHAPE_SHIFTING, + D2S_SKILL_FIRESTORM, + D2S_SKILL_OAK_SAGE, + D2S_SKILL_SUMMON_SPIRIT_WOLF, + D2S_SKILL_WEARBEAR, + D2S_SKILL_MOLTEN_BOULDER, + D2S_SKILL_ARCTIC_BLAST, + D2S_SKILL_CYCLE_OF_LIFE, + D2S_SKILL_FERAL_RAGE, + D2S_SKILL_MAUL, + D2S_SKILL_ERUPTION, + D2S_SKILL_CYCLONE_ARMOR, + D2S_SKILL_HEART_OF_WOLVERINE, + D2S_SKILL_SUMMON_FENRIS, + D2S_SKILL_RABIES, + D2S_SKILL_FIRE_CLAWS, + D2S_SKILL_TWISTER, + D2S_SKILL_VINES, + D2S_SKILL_HUNGER, + D2S_SKILL_SHOCK_WAVE, + D2S_SKILL_VOLCANO, + D2S_SKILL_TORNADO, + D2S_SKILL_SPIRIT_OF_BARBS, + D2S_SKILL_SUMMON_GRIZZLY, + D2S_SKILL_FURY, + D2S_SKILL_ARMAGEDDON, + D2S_SKILL_HURRICANE, + D2S_SKILL_FIRE_BLAST, + D2S_SKILL_CLAW_MASTERY, + D2S_SKILL_PSYCHIC_HAMMER, + D2S_SKILL_TIGER_STRIKE, + D2S_SKILL_DRAGON_TALON, + D2S_SKILL_SHOCK_FIELD, + D2S_SKILL_BLADE_SENTINEL, + D2S_SKILL_QUICKNESS, + D2S_SKILL_FISTS_OF_FIRE, + D2S_SKILL_DRAGON_CLAW, + D2S_SKILL_CHARGED_BOLT_SENTRY, + D2S_SKILL_WAKE_OF_FIRE_SENTRY, + D2S_SKILL_WEAPON_BLOCK, + D2S_SKILL_CLOAK_OF_SHADOWS, + D2S_SKILL_COBRA_STRIKE, + D2S_SKILL_BLADE_FURY, + D2S_SKILL_FADE, + D2S_SKILL_SHADOW_WARRIOR, + D2S_SKILL_CLAWS_OF_THUNDER, + D2S_SKILL_DRAGON_TAIL, + D2S_SKILL_LIGHTNING_SENTRY, + D2S_SKILL_INFERNO_SENTRY, + D2S_SKILL_MIND_BLAST, + D2S_SKILL_BLADES_OF_ICE, + D2S_SKILL_DRAGON_FLIGHT, + D2S_SKILL_DEATH_SENTRY, + D2S_SKILL_BLADE_SHIELD, + D2S_SKILL_VENOM, + D2S_SKILL_SHADOW_MASTER, + D2S_SKILL_ROYAL_STRIKE, + D2S_SKILL_WAKE_OF_DESTRUCTION_SENTRY, + D2S_SKILL_IMP_INFERNO, + D2S_SKILL_IMP_FIREBALL, + D2S_SKILL_BAAL_TAUNT, + D2S_SKILL_BAAL_CORPSE_EXPLODE, + D2S_SKILL_BAAL_MONSTER_SPAWN, + D2S_SKILL_CATAPULT_CHARGED_BALL, + D2S_SKILL_CATAPULT_SPIKE_BALL, + D2S_SKILL_SUCK_BLOOD, + D2S_SKILL_CRY_HELP, + D2S_SKILL_HEALING_VORTEX, + D2S_SKILL_TELEPORT_2, + D2S_SKILL_SELF_RESURRECT, + D2S_SKILL_VINE_ATTACK, + D2S_SKILL_OVERSEER_WHIP, + D2S_SKILL_BARBS_AURA, + D2S_SKILL_WOLVERINE_AURA, + D2S_SKILL_OAK_SAGE_AURA, + D2S_SKILL_IMP_FIRE_MISSILE, + D2S_SKILL_IMPREGNATE, + D2S_SKILL_SIEGE_BEAST_STOMP, + D2S_SKILL_MINIONSPAWNER, + D2S_SKILL_CATAPULTBLIZZARD, + D2S_SKILL_CATAPULTPLAGUE, + D2S_SKILL_CATAPULTMETEOR, + D2S_SKILL_BOLTSENTRY, + D2S_SKILL_CORPSECYCLER, + D2S_SKILL_DEATHMAUL, + D2S_SKILL_DEFENSE_CURSE, + D2S_SKILL_BLOOD_MANA, + D2S_SKILL_MON_INFERNO_SENTRY, + D2S_SKILL_MON_DEATH_SENTRY, + D2S_SKILL_SENTRY_LIGHTNING, + D2S_SKILL_FENRIS_RAGE, + D2S_SKILL_BAAL_TENTACLE, + D2S_SKILL_BAAL_NOVA, + D2S_SKILL_BAAL_INFERNO, + D2S_SKILL_BAAL_COLD_MISSILES, + D2S_SKILL_MEGA_DEMON_INFERNO, + D2S_SKILL_EVIL_HUT_SPAWNER, + D2S_SKILL_COUNTESS_FIREWALL, + D2S_SKILL_IMPBOLT, + D2S_SKILL_HORROR_ARCTIC_BLAST, + D2S_SKILL_DEATH_SENTRY_LTNG, + D2S_SKILL_VINECYCLER, + D2S_SKILL_BEARSMITE, + D2S_SKILL_RESURRECT2, + D2S_SKILL_BLOODLORD_FRENZY, + D2S_SKILL_BAAL_TELEPORT, + D2S_SKILL_IMP_TELEPORT, + D2S_SKILL_BAAL_CLONE_TELEPORT, + D2S_SKILL_ZAKARUM_LIGHTNING, + D2S_SKILL_VAMPIRE_MISSILE, + D2S_SKILL_MEPHISTO_MISSILE, + D2S_SKILL_DOOM_KNIGHT_MISSILE, + D2S_SKILL_ROGUE_MISSILE, + D2S_SKILL_HYDRA_MISSILE, + D2S_SKILL_NECRO_MAGE_MISSILE, + D2S_SKILL_MONBOW, + D2S_SKILL_MONFIREARROW, + D2S_SKILL_MONCOLDARROW, + D2S_SKILL_MONEXPLODINGARROW, + D2S_SKILL_MONFREEZINGARROW, + D2S_SKILL_MONPOWERSTRIKE, + D2S_SKILL_SUCCUBUSBOLT, + D2S_SKILL_MEPHFROSTNOVA, + D2S_SKILL_MONICESPEAR, + D2S_SKILL_SHAMAN_ICE, + D2S_SKILL_DIABLOGEDDON, + D2S_SKILL_DELERIUM_CHANGE, + D2S_SKILL_NIHLATHAK_CORPSE_EXPLOSION, + D2S_SKILL_SERPENT_CHARGE, + D2S_SKILL_TRAP_NOVA, + D2S_SKILL_UNHOLY_BOLTEX, + D2S_SKILL_SHAMAN_FIREEX, + D2S_SKILL_IMP_FIRE_MISSILE_EX, +} D2S_SKILL; -const char* const skills[] = { +const D2S_SKILL amazonSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_MAGIC_ARROW, + D2S_SKILL_FIRE_ARROW, + D2S_SKILL_INNER_SIGHT, + D2S_SKILL_CRITICAL_STRIKE, + D2S_SKILL_JAB, + D2S_SKILL_COLD_ARROW, + D2S_SKILL_MULTIPLE_SHOT, + D2S_SKILL_DODGE, + D2S_SKILL_POWER_STRIKE, + D2S_SKILL_POISON_JAVELIN, + D2S_SKILL_EXPLODING_ARROW, + D2S_SKILL_SLOW_MISSILES, + D2S_SKILL_AVOID, + D2S_SKILL_IMPALE, + D2S_SKILL_LIGHTNING_BOLT, + D2S_SKILL_ICE_ARROW, + D2S_SKILL_GUIDED_ARROW, + D2S_SKILL_PENETRATE, + D2S_SKILL_CHARGED_STRIKE, + D2S_SKILL_PLAGUE_JAVELIN, + D2S_SKILL_STRAFE, + D2S_SKILL_IMMOLATION_ARROW, + D2S_SKILL_DOPPLEZON, + D2S_SKILL_EVADE, + D2S_SKILL_FEND, + D2S_SKILL_FREEZING_ARROW, + D2S_SKILL_VALKYRIE, + D2S_SKILL_PIERCE, + D2S_SKILL_LIGHTNING_STRIKE, + D2S_SKILL_LIGHTNING_FURY +}; + +const D2S_SKILL sorceressSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_FIRE_BOLT, + D2S_SKILL_WARMTH, + D2S_SKILL_CHARGED_BOLT, + D2S_SKILL_ICE_BOLT, + D2S_SKILL_FROZEN_ARMOR, + D2S_SKILL_INFERNO, + D2S_SKILL_STATIC_FIELD, + D2S_SKILL_TELEKINESIS, + D2S_SKILL_FROST_NOVA, + D2S_SKILL_ICE_BLAST, + D2S_SKILL_BLAZE, + D2S_SKILL_FIRE_BALL, + D2S_SKILL_NOVA, + D2S_SKILL_LIGHTNING, + D2S_SKILL_SHIVER_ARMOR, + D2S_SKILL_FIRE_WALL, + D2S_SKILL_ENCHANT, + D2S_SKILL_CHAIN_LIGHTNING, + D2S_SKILL_TELEPORT, + D2S_SKILL_GLACIAL_SPIKE, + D2S_SKILL_METEOR, + D2S_SKILL_THUNDER_STORM, + D2S_SKILL_ENERGY_SHIELD, + D2S_SKILL_BLIZZARD, + D2S_SKILL_CHILLING_ARMOR, + D2S_SKILL_FIRE_MASTERY, + D2S_SKILL_HYDRA, + D2S_SKILL_LIGHTNING_MASTERY, + D2S_SKILL_FROZEN_ORB, + D2S_SKILL_COLD_MASTERY +}; + +const D2S_SKILL necromancerSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_AMPLIFY_DAMAGE, + D2S_SKILL_TEETH, + D2S_SKILL_BONE_ARMOR, + D2S_SKILL_SKELETON_MASTERY, + D2S_SKILL_RAISE_SKELETON, + D2S_SKILL_DIM_VISION, + D2S_SKILL_WEAKEN, + D2S_SKILL_POISON_DAGGER, + D2S_SKILL_CORPSE_EXPLOSION, + D2S_SKILL_CLAY_GOLEM, + D2S_SKILL_IRON_MAIDEN, + D2S_SKILL_TERROR, + D2S_SKILL_BONE_WALL, + D2S_SKILL_GOLEM_MASTERY, + D2S_SKILL_RAISE_SKELETAL_MAGE, + D2S_SKILL_CONFUSE, + D2S_SKILL_LIFE_TAP, + D2S_SKILL_POISON_EXPLOSION, + D2S_SKILL_BONE_SPEAR, + D2S_SKILL_BLOOD_GOLEM, + D2S_SKILL_ATTRACT, + D2S_SKILL_DECREPIFY, + D2S_SKILL_BONE_PRISON, + D2S_SKILL_SUMMON_RESIST, + D2S_SKILL_IRON_GOLEM, + D2S_SKILL_LOWER_RESIST, + D2S_SKILL_POISON_NOVA, + D2S_SKILL_BONE_SPIRIT, + D2S_SKILL_FIRE_GOLEM, + D2S_SKILL_REVIVE +}; + +const D2S_SKILL paladinSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_SACRIFICE, + D2S_SKILL_SMITE, + D2S_SKILL_MIGHT, + D2S_SKILL_PRAYER, + D2S_SKILL_RESIST_FIRE, + D2S_SKILL_HOLY_BOLT, + D2S_SKILL_HOLY_FIRE, + D2S_SKILL_THORNS, + D2S_SKILL_DEFIANCE, + D2S_SKILL_RESIST_COLD, + D2S_SKILL_ZEAL, + D2S_SKILL_CHARGE, + D2S_SKILL_BLESSED_AIM, + D2S_SKILL_CLEANSING, + D2S_SKILL_RESIST_LIGHTNING, + D2S_SKILL_VENGEANCE, + D2S_SKILL_BLESSED_HAMMER, + D2S_SKILL_CONCENTRATION, + D2S_SKILL_HOLY_FREEZE, + D2S_SKILL_VIGOR, + D2S_SKILL_CONVERSION, + D2S_SKILL_HOLY_SHIELD, + D2S_SKILL_HOLY_SHOCK, + D2S_SKILL_SANCTUARY, + D2S_SKILL_MEDITATION, + D2S_SKILL_FIST_OF_THE_HEAVENS, + D2S_SKILL_FANATICISM, + D2S_SKILL_CONVICTION, + D2S_SKILL_REDEMPTION, + D2S_SKILL_SALVATION +}; + +const D2S_SKILL barbarianSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_BASH, + D2S_SKILL_SWORD_MASTERY, + D2S_SKILL_AXE_MASTERY, + D2S_SKILL_MACE_MASTERY, + D2S_SKILL_HOWL, + D2S_SKILL_FIND_POTION, + D2S_SKILL_LEAP, + D2S_SKILL_DOUBLE_SWING, + D2S_SKILL_POLE_ARM_MASTERY, + D2S_SKILL_THROWING_MASTERY, + D2S_SKILL_SPEAR_MASTERY, + D2S_SKILL_TAUNT, + D2S_SKILL_SHOUT, + D2S_SKILL_STUN, + D2S_SKILL_DOUBLE_THROW, + D2S_SKILL_INCREASED_STAMINA, + D2S_SKILL_FIND_ITEM, + D2S_SKILL_LEAP_ATTACK, + D2S_SKILL_CONCENTRATE, + D2S_SKILL_IRON_SKIN, + D2S_SKILL_BATTLE_CRY, + D2S_SKILL_FRENZY, + D2S_SKILL_INCREASED_SPEED, + D2S_SKILL_BATTLE_ORDERS, + D2S_SKILL_GRIM_WARD, + D2S_SKILL_WHIRLWIND, + D2S_SKILL_BERSERK, + D2S_SKILL_NATURAL_RESISTANCE, + D2S_SKILL_WAR_CRY, + D2S_SKILL_BATTLE_COMMAND +}; + +const D2S_SKILL druidSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_RAVEN, + D2S_SKILL_POISON_CREEPER, + D2S_SKILL_WEARWOLF, + D2S_SKILL_SHAPE_SHIFTING, + D2S_SKILL_FIRESTORM, + D2S_SKILL_OAK_SAGE, + D2S_SKILL_SUMMON_SPIRIT_WOLF, + D2S_SKILL_WEARBEAR, + D2S_SKILL_MOLTEN_BOULDER, + D2S_SKILL_ARCTIC_BLAST, + D2S_SKILL_CYCLE_OF_LIFE, + D2S_SKILL_FERAL_RAGE, + D2S_SKILL_MAUL, + D2S_SKILL_ERUPTION, + D2S_SKILL_CYCLONE_ARMOR, + D2S_SKILL_HEART_OF_WOLVERINE, + D2S_SKILL_SUMMON_FENRIS, + D2S_SKILL_RABIES, + D2S_SKILL_FIRE_CLAWS, + D2S_SKILL_TWISTER, + D2S_SKILL_VINES, + D2S_SKILL_HUNGER, + D2S_SKILL_SHOCK_WAVE, + D2S_SKILL_VOLCANO, + D2S_SKILL_TORNADO, + D2S_SKILL_SPIRIT_OF_BARBS, + D2S_SKILL_SUMMON_GRIZZLY, + D2S_SKILL_FURY, + D2S_SKILL_ARMAGEDDON, + D2S_SKILL_HURRICANE +}; + +const D2S_SKILL assassinSkills[D2S_SKILL_MAXSKILLS_PER_CHAR] = { + D2S_SKILL_FIRE_BLAST, + D2S_SKILL_CLAW_MASTERY, + D2S_SKILL_PSYCHIC_HAMMER, + D2S_SKILL_TIGER_STRIKE, + D2S_SKILL_DRAGON_TALON, + D2S_SKILL_SHOCK_FIELD, + D2S_SKILL_BLADE_SENTINEL, + D2S_SKILL_QUICKNESS, + D2S_SKILL_FISTS_OF_FIRE, + D2S_SKILL_DRAGON_CLAW, + D2S_SKILL_CHARGED_BOLT_SENTRY, + D2S_SKILL_WAKE_OF_FIRE_SENTRY, + D2S_SKILL_WEAPON_BLOCK, + D2S_SKILL_CLOAK_OF_SHADOWS, + D2S_SKILL_COBRA_STRIKE, + D2S_SKILL_BLADE_FURY, + D2S_SKILL_FADE, + D2S_SKILL_SHADOW_WARRIOR, + D2S_SKILL_CLAWS_OF_THUNDER, + D2S_SKILL_DRAGON_TAIL, + D2S_SKILL_LIGHTNING_SENTRY, + D2S_SKILL_INFERNO_SENTRY, + D2S_SKILL_MIND_BLAST, + D2S_SKILL_BLADES_OF_ICE, + D2S_SKILL_DRAGON_FLIGHT, + D2S_SKILL_DEATH_SENTRY, + D2S_SKILL_BLADE_SHIELD, + D2S_SKILL_VENOM, + D2S_SKILL_SHADOW_MASTER, + D2S_SKILL_ROYAL_STRIKE +}; + +const char* const skillNames[] = { D2S_SKILL_0, D2S_SKILL_1, D2S_SKILL_2, @@ -372,6 +963,6 @@ const char* const skills[] = { // Returns static string from library memory, no need to free const char* getSkillName(D2S_SKILL skillID); -D2S_CHARCLASS getSkillClass(D2S_SKILL skillID); +D2S_SKILL getSkillIDFromCharOffset(D2S_CHARCLASS class, unsigned int offset); #endif \ No newline at end of file diff --git a/d2waypoints.c b/d2waypoints.c index 7e9fd81..b82bade 100644 --- a/d2waypoints.c +++ b/d2waypoints.c @@ -1,8 +1,25 @@ #include "d2waypoints.h" #include "d2char.h" +#include + +const char* getWaypointName(D2S_WAYPOINT waypoint) { + if(waypoint > D2S_WAYPOINTSDATA_NUMWAYPOINTS) { + fprintf(stderr,"libd2char error: waypoint %d doesn't exist\n",waypoint); + return NULL; + } + return waypoints[waypoint]; +} + int isWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty) { if(waypoint > D2S_WAYPOINTSDATA_NUMWAYPOINTS) { + fprintf(stderr,"libd2char error: waypoint %d doesn't exist\n",waypoint); + return -1; + } + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); return -1; } unsigned int byte = waypoint / 8; @@ -10,12 +27,19 @@ int isWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULT return (d->waypoints[difficulty].waypointData[byte] & (1 << offset)) >> offset; } -// TODO: Return success -void setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated) { +int setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated) { if(waypoint > D2S_WAYPOINTSDATA_NUMWAYPOINTS) { - return; + fprintf(stderr,"libd2char error: waypoint %d doesn't exist\n",waypoint); + return -1; + } + if(difficulty != D2S_DIFFICULTY_NORMAL || + difficulty != D2S_DIFFICULTY_NIGHTMARE || + difficulty != D2S_DIFFICULTY_HELL) { + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); + return -1; } unsigned int byte = waypoint / 8; unsigned int offset = waypoint % 8; d->waypoints[difficulty].waypointData[byte] |= (1 << offset); + return 0; } \ No newline at end of file diff --git a/d2waypoints.h b/d2waypoints.h index 7eeb2bc..4b47575 100644 --- a/d2waypoints.h +++ b/d2waypoints.h @@ -13,7 +13,46 @@ typedef enum D2S_DIFFICULTY D2S_DIFFICULTY; #define D2S_WAYPOINTSDATA_NUMWAYPOINTS 39 typedef enum D2S_WAYPOINT { -asd + D2S_WAYPOINT_UNKNOWN = -1, + D2S_WAYPOINT_ROGUE_ENCAMPMENT = 0, + D2S_WAYPOINT_COLD_PLAINS, + D2S_WAYPOINT_STONY_FIELD, + D2S_WAYPOINT_DARK_WOOD, + D2S_WAYPOINT_BLACK_MARSH, + D2S_WAYPOINT_OUTER_CLOISTER, + D2S_WAYPOINT_JAIL, + D2S_WAYPOINT_INNER_CLOISTER, + D2S_WAYPOINT_CATACOMBS, + D2S_WAYPOINT_LUT_GHOLEIN, + D2S_WAYPOINT_SEWERS, + D2S_WAYPOINT_DRY_HILLS, + D2S_WAYPOINT_HALLS_OF_THE_DEAD, + D2S_WAYPOINT_FAR_OASIS, + D2S_WAYPOINT_LOST_CITY, + D2S_WAYPOINT_PALACE_CELLAR, + D2S_WAYPOINT_ARCANE_SANCTUARY, + D2S_WAYPOINT_CANYON_OF_THE_MAGI, + D2S_WAYPOINT_KURAST_DOCS, + D2S_WAYPOINT_SPIDER_FOREST, + D2S_WAYPOINT_GREAT_MARSH, + D2S_WAYPOINT_FLAYER_JUNGLE, + D2S_WAYPOINT_LOWER_KURAST, + D2S_WAYPOINT_KURAST_BAZAAR, + D2S_WAYPOINT_UPPER_KURAST, + D2S_WAYPOINT_TRAVINCAL, + D2S_WAYPOINT_DURANCE_OF_HATE, + D2S_WAYPOINT_PANDEMONIUM_FORTRESS, + D2S_WAYPOINT_CITY_OF_THE_DAMNED, + D2S_WAYPOINT_RIVER_OF_FLAMES, + D2S_WAYPOINT_HARROGATH, + D2S_WAYPOINT_FRIGID_HIGHLANDS, + D2S_WAYPOINT_ARREAT_PLATEAU, + D2S_WAYPOINT_CRYSTALLINE_PASSAGE, + D2S_WAYPOINT_HALLS_OF_PAIN, + D2S_WAYPOINT_GLACIAL_TRAIL, + D2S_WAYPOINT_FROZEN_TUNDRA, + D2S_WAYPOINT_ANCIENTS_WAY, + D2S_WAYPOINT_WORLDSTONE_KEEP } D2S_WAYPOINT; const char* const waypoints[] = { @@ -71,7 +110,9 @@ typedef struct __attribute__((packed)) { D2Waypoints waypoints[3]; // 1 set for each difficulty } D2WaypointsData; +// Returns static string from library memory, no need to free +const char* getWaypointName(D2S_WAYPOINT waypoint); int isWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty); -void setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated); +int setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated); #endif \ No newline at end of file