diff --git a/TODO b/TODO new file mode 100644 index 0000000..5dda435 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +// TODO: Error codes +// TODO: Func documentation \ No newline at end of file diff --git a/d2char.c b/d2char.c index 174aedf..c3ef6f9 100644 --- a/d2char.c +++ b/d2char.c @@ -28,19 +28,35 @@ int isHardcore(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_HARDCORE; } +void setHardcore(D2CharHeader* c) { + +} + int hasDied(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_DIED; } +void setDied(D2CharHeader* c) { + +} + int isExpansion(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_EXPANSION; } +void setExpansion(D2CharHeader* c) { + +} + int isLadder(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_LADDER; } -int getCurrentAct(D2CharHeader* c) { +void setLadder(D2CharHeader* c) { + +} + +D2S_ACT getCurrentAct(D2CharHeader* c) { if(isExpansion(c)) { return c->charProgress % 5; } else { @@ -135,15 +151,7 @@ size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen) { return ret; } -const char* getSkillName(int skillID) { - if(skillID > D2S_SKILL_NUMSKILLS) { - fprintf(stderr,"libd2char error: skillID %d doesn't exist\n",skillID); - return NULL; - } - return skills[skillID]; -} - -int getCurrentDifficulty(D2CharHeader* c) { +D2S_DIFFICULTY getCurrentDifficulty(D2CharHeader* c) { for(int i = D2S_DIFFICULTY_NORMAL; i <= D2S_DIFFICULTY_HELL; ++i) { if(c->difficulty[i] & D2S_DIFFICULTY_ACTIVE) { return i; @@ -152,10 +160,18 @@ int getCurrentDifficulty(D2CharHeader* c) { return D2S_DIFFICULTY_UNKNOWN; } -const char* getMercName(D2CharHeader* c) { - return _getMercName(c->mercenaryType, c->mercenaryNameID); +int setProgress(D2S_ACT act, D2S_DIFFICULTY difficulty) { + // TODO + // set c->difficulty and c->progress? + return 0; +} + +int getAttribute(D2S_STAT attr) { + // TODO + return 0; } -const char* getMercType(D2CharHeader* c) { - return mercTypes[c->mercenaryType]; +int setAttribute(D2S_STAT attr, unsigned int value) { + // TODO + return 0; } \ No newline at end of file diff --git a/d2char.h b/d2char.h index 562345b..82a8d02 100644 --- a/d2char.h +++ b/d2char.h @@ -8,6 +8,7 @@ #include "d2quest.h" #include "d2strings.h" +#include "d2waypoints.h" #define D2S_HEADER_LENGTH 765 #define D2S_SIGNATURE 0xAA55AA55 @@ -26,21 +27,24 @@ #define D2S_CHARSTATUS_LADDER 0x40 #define D2S_DIFFICULTY_ACTIVE 0x80 -#define D2S_DIFFICULTY_NORMAL 0 -#define D2S_DIFFICULTY_NIGHTMARE 1 -#define D2S_DIFFICULTY_HELL 2 -#define D2S_DIFFICULTY_UNKNOWN -1 -enum D2S_VERSION { +typedef enum D2S_DIFFICULTY { + D2S_DIFFICULTY_UNKNOWN = -1, + D2S_DIFFICULTY_NORMAL = 0, + D2S_DIFFICULTY_NIGHTMARE = 1, + D2S_DIFFICULTY_HELL = 2 +} D2S_DIFFICULTY; + +typedef enum D2S_VERSION { VER_106 = 71, VER_107 = 87, VER_108XP = 87, VER_108 = 89, VER_109 = 92, VER_110 = 96 -}; +} D2S_VERSION; -enum D2S_CHARCLASS { +typedef enum D2S_CHARCLASS { D2S_CHARCLASS_AMAZON = 0, D2S_CHARCLASS_SORCERESS = 1, D2S_CHARCLASS_NECROMANCER = 2, @@ -48,15 +52,34 @@ enum D2S_CHARCLASS { D2S_CHARCLASS_BARBARIAN = 4, D2S_CHARCLASS_DRUID = 5, D2S_CHARCLASS_ASSASSIN = 6 -}; - -enum D2S_ACT { +} D2S_CHARCLASS; + +typedef enum D2S_STAT { + D2S_STAT_STRENGTH = 0x00, + D2S_STAT_ENERGY = 0x01, + D2S_STAT_DEXTERITY = 0x02, + D2S_STAT_VITALITY = 0x03, + D2S_STAT_STATPTS = 0x04, + D2S_STAT_SKILLPTS = 0x05, + D2S_STAT_LIFE = 0x06, + D2S_STAT_MAXLIFE = 0x07, + D2S_STAT_MANA = 0x08, + D2S_STAT_MAXMANA = 0x09, + D2S_STAT_STAMINA = 0x0a, + D2S_STAT_MAXSTAMINA = 0x0b, + D2S_STAT_LEVEL = 0x0c, + D2S_STAT_EXPERIENCE = 0x0d, + D2S_STAT_GOLD = 0x0e, + D2S_STAT_GOLDSTASH = 0x0f, +} D2S_STAT; + +typedef enum D2S_ACT { D2S_ACT1 = 0, D2S_ACT2, D2S_ACT3, D2S_ACT4, D2S_ACT5 -}; +} D2S_ACT; // TODO: Add file hex offsets for each field typedef struct __attribute__((packed)){ @@ -91,12 +114,14 @@ typedef struct __attribute__((packed)){ uint32_t mercenaryExp; uint8_t unknown6[144]; // TODO D2QuestData questData; - uint8_t waypointData[D2S_WAYPOINTS_LENGTH]; + D2WaypointsData waypointsData; uint8_t unknown7; // TODO. Apparently this is always 0x01 uint8_t NPCIntroductions[D2S_NPCDATA_LENGTH]; // TODO: Not implemented + // TODO Add stats + // TODO Add skills } D2CharHeader; -// TODO: All setX functions + // TODO: Load from file. // int loadD2CharFromFile(const char* file, D2CharHeader** header, void** data); @@ -107,12 +132,16 @@ 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); int hasDied(D2CharHeader* c); +void setDied(D2CharHeader* c); int isExpansion(D2CharHeader* c); +void setExpansion(D2CharHeader* c); int isLadder(D2CharHeader* c); +void setLadder(D2CharHeader* c); // 0 = Act I, 4 = Act V (Expansion) -int getCurrentAct(D2CharHeader* c); +D2S_ACT getCurrentAct(D2CharHeader* c); int isFemale(D2CharHeader* c); @@ -122,16 +151,12 @@ 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); -// Returns static string from library memory, no need to free -const char* getSkillName(int skillID); - // 0 = Normal, 2 = Hell -int getCurrentDifficulty(D2CharHeader* c); +D2S_DIFFICULTY getCurrentDifficulty(D2CharHeader* c); -// Returns static string from library memory, no need to free -const char* getMercName(D2CharHeader* c); +int setProgress(D2S_ACT act, D2S_DIFFICULTY difficulty); -// Returns static string from library memory, no need to free -const char* getMercType(D2CharHeader* c); +int getAttribute(D2S_STAT attr); +int setAttribute(D2S_STAT attr, unsigned int value); #endif \ No newline at end of file diff --git a/d2mercs.c b/d2mercs.c index 79b019f..789e8c9 100644 --- a/d2mercs.c +++ b/d2mercs.c @@ -1,8 +1,18 @@ #include "d2mercs.h" +#include #include -int _getMercType(int mercID) { +const char* getMercName(uint16_t mercID, uint16_t mercNameID) { + int offset = getMercType(mercID); + if(offset == D2S_MERCTYPE_UNKNOWN) { + fprintf(stderr,"libd2char error: Unable to retrieve name for mercID %d, mercNameID %d\n",mercID, mercNameID); + return NULL; + } + return mercNames[mercNameID + offset]; +} + +D2S_MERCTYPE getMercType(uint16_t mercID) { if(mercID >= 0 && mercID <= 5) { return D2S_MERCTYPE_ROGUE; } else if(mercID >= 6 && mercID <= 14) { @@ -16,10 +26,14 @@ int _getMercType(int mercID) { } } -const char* _getMercName(int mercID, int mercNameID) { - int offset = _getMercType(mercID); - if(offset == D2S_MERCTYPE_UNKNOWN) { - return NULL; - } - return mercNames[mercNameID + offset]; +D2S_MERCSUBTYPE getMercSubType(uint16_t mercID) { + // TODO +} + +D2S_DIFFICULTY getMercDifficulty(uint16_t mercID) { + // TODO +} + +int setMerc(D2S_MERCTYPE type, D2S_MERCSUBTYPE subtype, D2S_DIFFICULTY difficulty) { + // TODO } \ No newline at end of file diff --git a/d2mercs.h b/d2mercs.h index bf0cb67..4f1be82 100644 --- a/d2mercs.h +++ b/d2mercs.h @@ -1,54 +1,32 @@ #ifndef D2MERCS_H #define D2MERCS_H +#include "d2char.h" #include "d2strings.h" -// TODO: return compound data (type, subtype, difficulty, not just a string) - // The values here are the offsets of each merc's names in the table. // i.e: Merc names from pos 41 to 61 are Desert mercs // // We use these values as offsets later to get the correct name using the relative ID the game provides -enum D2S_MERCTYPES { +typedef enum D2S_MERCTYPE { D2S_MERCTYPE_UNKNOWN = -1, D2S_MERCTYPE_ROGUE = 0, D2S_MERCTYPE_DESERT = 41, D2S_MERCTYPE_SORCEROR = 62, D2S_MERCTYPE_BARBARIAN = 82 -}; +} D2S_MERCTYPE; -const char* const mercTypes[] = { - D2S_MERC_ID_0, - D2S_MERC_ID_1, - D2S_MERC_ID_2, - D2S_MERC_ID_3, - D2S_MERC_ID_4, - D2S_MERC_ID_5, - D2S_MERC_ID_6, - D2S_MERC_ID_7, - D2S_MERC_ID_8, - D2S_MERC_ID_9, - D2S_MERC_ID_10, - D2S_MERC_ID_11, - D2S_MERC_ID_12, - D2S_MERC_ID_13, - D2S_MERC_ID_14, - D2S_MERC_ID_15, - D2S_MERC_ID_16, - D2S_MERC_ID_17, - D2S_MERC_ID_18, - D2S_MERC_ID_19, - D2S_MERC_ID_20, - D2S_MERC_ID_21, - D2S_MERC_ID_22, - D2S_MERC_ID_23, - D2S_MERC_ID_24, - D2S_MERC_ID_25, - D2S_MERC_ID_26, - D2S_MERC_ID_27, - D2S_MERC_ID_28, - D2S_MERC_ID_29 -}; +typedef enum D2S_MERCSUBTYPE { + D2S_MERCSUBTYPE_NONE = 0, + D2S_MERCSUBTYPE_FIRE_ARROW = 1, + D2S_MERCSUBTYPE_COLD_ARROW = 2, + D2S_MERCSUBTYPE_COMBAT = 3, + D2S_MERCSUBTYPE_DEFENSIVE = 4, + D2S_MERCSUBTYPE_OFFENSIVE = 5, + D2S_MERCSUBTYPE_FIRE = 6, + D2S_MERCSUBTYPE_COLD = 7, + D2S_MERCSUBTYPE_LIGHTNING = 8 +} D2S_MERCSUBTYPE; const char* const mercNames[] = { D2S_MERC_NAME_0, @@ -202,7 +180,12 @@ const char* const mercNames[] = { D2S_MERC_NAME_148 }; -int _getMercType(int mercID); -const char* _getMercName(int mercID, int mercNameID); +// Returns static string from library memory, no need to free +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); #endif \ No newline at end of file diff --git a/d2quest.c b/d2quest.c index 058529a..621bac9 100644 --- a/d2quest.c +++ b/d2quest.c @@ -3,31 +3,43 @@ #include -void getCheckpointDescriptions(unsigned int quest, const char* *descriptions[16]) { +const char* getQuestName(D2S_QUEST quest) { if(quest > D2S_QUESTDATA_NUMQUESTS) { fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); - return; + return NULL; + } + return questName[quest]; +} + +int getCheckpointDescriptions(D2S_QUEST quest, const char* *descriptions[16]) { + if(quest > D2S_QUESTDATA_NUMQUESTS) { + fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); + return -1; } memcpy(descriptions,(&checkpointDescriptions) + (quest * 16 * sizeof(const char*)), 16 * sizeof(const char*)); } -uint16_t getQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty) { +int getQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t* data) { + // TODO sanity check diff and quest if(quest >= D2S_QUEST_DEN_OF_EVIL && quest <= D2S_QUEST_SISTERS_TO_THE_SLAUGHTER) { - return d->quests[difficulty].actData[D2S_ACT1].questCheckpoints[quest]; + *data = d->quests[difficulty].actData[D2S_ACT1].questCheckpoints[quest]; } else if(quest >= D2S_QUEST_RADAMENT_LAIR && quest <= D2S_QUEST_SEVEN_TOMBS) { - return d->quests[difficulty].actData[D2S_ACT2].questCheckpoints[quest - D2S_QUEST_RADAMENT_LAIR]; + *data = d->quests[difficulty].actData[D2S_ACT2].questCheckpoints[quest - D2S_QUEST_RADAMENT_LAIR]; } else if(quest >= D2S_QUEST_GOLDEN_BIRD && quest <= D2S_QUEST_GUARDIAN) { - return d->quests[difficulty].actData[D2S_ACT3].questCheckpoints[quest - D2S_QUEST_GOLDEN_BIRD]; + *data = d->quests[difficulty].actData[D2S_ACT3].questCheckpoints[quest - D2S_QUEST_GOLDEN_BIRD]; } else if(quest >= D2S_QUEST_FALLEN_ANGEL && quest <= D2S_QUEST_TERROR_END) { - return d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL]; + *data = d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL]; } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) { - return d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH]; + *data = d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH]; + } else { + fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); + return -1; } - fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); return 0; } -void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, uint16_t questData) { +int setQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t questData) { + // TODO sanity check diff and quest 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) { @@ -40,51 +52,76 @@ void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH] = questData; } else { fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); + return -1; } + return 0; } -int isQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty) { - return getQuestStatus(d,quest,difficulty) & D2S_QUEST_STATUS_STARTED; +int isQuestStarted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty) { + uint16_t data = 0; + if(getQuestStatus(d,quest,difficulty,&data) < 0) { + return -1; + } + return data & D2S_QUEST_STATUS_STARTED; } -int isQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty) { - return !(getQuestStatus(d,quest,difficulty) & D2S_QUEST_STATUS_REWARD_AVAILABLE); +int isQuestRewardCollected(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty) { + uint16_t data = 0; + if(getQuestStatus(d,quest,difficulty,&data) < 0) { + return -1; + } + return data & D2S_QUEST_STATUS_REWARD_AVAILABLE; } -int isQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty) { - return getQuestStatus(d,quest,difficulty) & D2S_QUEST_STATUS_COMPLETED; +int isQuestCompleted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty) { + uint16_t data = 0; + if(getQuestStatus(d,quest,difficulty,&data) < 0) { + return -1; + } + return data & D2S_QUEST_STATUS_COMPLETED; } -void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool) { +int setQuestStarted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool) { // To reset the quest, just zero out the whole thing // To set as started, just set bit 2 and clear the rest - uint16_t questData = getQuestStatus(d,quest,difficulty); + uint16_t questData = 0; + if(getQuestStatus(d,quest,difficulty,&questData) < 0) { + return -1; + } if(bool) { questData = D2S_QUEST_STATUS_STARTED; } else { questData = 0x0000; } - setQuestStatus(d,quest,difficulty,questData); + return setQuestStatus(d,quest,difficulty,questData); } -void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool) { +int setQuestRewardCollected(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool) { // To reset, just clear bit 0 and set bit 1. // Do the inverse to set reward as collected (but why whould you tho???) if(bool) { - setQuestCompleted(d,quest,difficulty,1); + return setQuestCompleted(d,quest,difficulty,1); } else { - setQuestCompleted(d,quest,difficulty,0); - uint16_t questData = getQuestStatus(d,quest,difficulty); + if(setQuestCompleted(d,quest,difficulty,0) < 0) { + return -1; + } + uint16_t questData; + if(getQuestStatus(d,quest,difficulty,&questData) < 0) { + return -1; + } questData |= D2S_QUEST_STATUS_REWARD_AVAILABLE; - setQuestStatus(d,quest,difficulty,questData); + return setQuestStatus(d,quest,difficulty,questData); } } -void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool) { +int setQuestCompleted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool) { // To reset, clear bit 0, bit 12 and bit 13 (13 is kinda optional since it will be cleared by // the game when loading the savegame). // To set as completed, just set bit 0 and bit 12 and clear bit 1 - uint16_t questData = getQuestStatus(d,quest,difficulty); + uint16_t questData; + if(getQuestStatus(d,quest,difficulty,&questData) < 0) { + return -1; + } if(bool) { questData &= ~D2S_QUEST_STATUS_REWARD_AVAILABLE; questData |= D2S_QUEST_STATUS_COMPLETED; @@ -93,10 +130,10 @@ void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficul questData &= ~D2S_QUEST_STATUS_COMPLETED; questData &= ~D2S_QUEST_STATUS_SEEN_FINISH_ANIMATION; } - setQuestStatus(d,quest,difficulty,questData); + return setQuestStatus(d,quest,difficulty,questData); } -int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty) { +int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, D2S_DIFFICULTY difficulty) { int ret = 0; switch(specialQuestState) { case D2S_SPECIALQUEST_AKARA_RESPEC: @@ -106,7 +143,7 @@ int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsign return ret; } -void setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty, int bool) { +int setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, D2S_DIFFICULTY difficulty, int bool) { if(difficulty != D2S_DIFFICULTY_NORMAL || difficulty != D2S_DIFFICULTY_NIGHTMARE || difficulty != D2S_DIFFICULTY_HELL) { diff --git a/d2quest.h b/d2quest.h index 5e762bc..d05b987 100644 --- a/d2quest.h +++ b/d2quest.h @@ -1,14 +1,18 @@ #ifndef D2QUEST_H #define D2QUEST_H +// Forward declaration +typedef enum D2S_DIFFICULTY D2S_DIFFICULTY; + #include +#include "d2char.h" #include "d2strings.h" #define D2S_QUESTDATA_HEADER_LENGTH 4 #define D2S_QUESTDATA_NUMQUESTS 27 -enum D2S_QUEST { +typedef enum D2S_QUEST { D2S_QUEST_UNKNOWN = -1, D2S_QUEST_DEN_OF_EVIL = 0, D2S_QUEST_SISTER_BURIAL_GROUNDS, @@ -37,6 +41,10 @@ enum D2S_QUEST { D2S_QUEST_BETRAYAL_OF_HARROGATH, D2S_QUEST_RITE_OF_PASSAGE, D2S_QUEST_EVE_OF_DESTRUCTION +} D2S_QUEST; + +const char* const questName[] = { + }; enum D2S_QUEST_STATUS { @@ -47,9 +55,9 @@ enum D2S_QUEST_STATUS { D2S_QUEST_STATUS_JUST_FINISHED = 0x2000 }; -enum D2S_SPECIALQUEST { +typedef enum D2S_SPECIALQUEST { D2S_SPECIALQUEST_AKARA_RESPEC -}; +} D2S_SPECIALQUEST; const char* const checkpointDescriptions[] = { D2S_QUEST_CHECKPOINT_0, @@ -306,8 +314,6 @@ const char* const checkpointDescriptions[] = { D2S_QUEST_CHECKPOINT_251, D2S_QUEST_CHECKPOINT_252, D2S_QUEST_CHECKPOINT_253, - D2S_QUEST_CHECKPOINT_254, - D2S_QUEST_CHECKPOINT_255, D2S_QUEST_CHECKPOINT_256, D2S_QUEST_CHECKPOINT_257, D2S_QUEST_CHECKPOINT_258, @@ -515,34 +521,35 @@ typedef struct __attribute__((packed)) { D2Quests quests[3]; // 1 set for each difficulty } D2QuestData; -// TODO: These functions are completely unsafe, and don't return success +// Returns static string from library memory, no need to free +const char* getQuestName(D2S_QUEST quest); // Populates `descriptions` with static strings from library memory, no need to free. // `descriptions` contains one string for each bit field of the quest's uint16_t data. // Empty entries (non-existant or unknown checkpoints) will have NULL value. Be careful! -void getCheckpointDescriptions(unsigned int quest, const char* *descriptions[16]); +int getCheckpointDescriptions(D2S_QUEST quest, const char* *descriptions[16]); // Returns quest status for the specified quest and act. -uint16_t getQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty); -void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, uint16_t questData); +int getQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t* data); +int setQuestStatus(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, uint16_t questData); -int isQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty); -int isQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty); -int isQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty); +int isQuestStarted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty); +int isQuestRewardCollected(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty); +int isQuestCompleted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty); // Set bool to 1 to set the status or 0 to remove it -void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); -void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); +int setQuestStarted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool); +int setQuestRewardCollected(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool); // When called to set the request to NOT completed (`bool` = 0), this will NOT set the reward collected status // which *may* render the quest unobtainable, this is done in case we may want to further modify the quest state. // If you want to mark the quest as not completed just to get the reward, please use `setQuestRewardCollected(,,0)` // instead. -void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); +int setQuestCompleted(D2QuestData* d, D2S_QUEST quest, D2S_DIFFICULTY difficulty, int bool); // Some quests have extra fields outside their quest data that govern certain states of the quest // So far, I only know of the respec that Akara offers when clearing Den of Evil -int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty); -void setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty, int bool); +int getSpecialQuestStatus(D2QuestData* d, D2S_SPECIALQUEST specialQuestState, D2S_DIFFICULTY difficulty); +int setSpecialQuestStatus(D2QuestData* d, D2S_SPECIALQUEST specialQuestState, D2S_DIFFICULTY difficulty, int bool); #endif \ No newline at end of file diff --git a/d2skills.c b/d2skills.c new file mode 100644 index 0000000..3302233 --- /dev/null +++ b/d2skills.c @@ -0,0 +1,17 @@ +#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) { + fprintf(stderr,"libd2char error: skillID %d doesn't exist\n",skillID); + return NULL; + } + return skills[skillID]; +} \ No newline at end of file diff --git a/d2skills.h b/d2skills.h index 7ecf888..74415d3 100644 --- a/d2skills.h +++ b/d2skills.h @@ -7,6 +7,9 @@ #define D2S_SKILL_NUMSKILLS 357 +// TODO skill class trees +typedef int D2S_SKILL; + const char* const skills[] = { D2S_SKILL_0, D2S_SKILL_1, @@ -367,4 +370,8 @@ const char* const skills[] = { D2S_SKILL_356 }; +// Returns static string from library memory, no need to free +const char* getSkillName(D2S_SKILL skillID); +D2S_CHARCLASS getSkillClass(D2S_SKILL skillID); + #endif \ No newline at end of file diff --git a/d2strings.h b/d2strings.h index 3949da8..99be047 100644 --- a/d2strings.h +++ b/d2strings.h @@ -534,37 +534,6 @@ const char* D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE = "Guardian"; #define D2S_MERC_NAME_147 "Bill" #define D2S_MERC_NAME_148 "Theodoric" -#define D2S_MERC_ID_0 "Rogue Scout Fire Arrow [Normal" -#define D2S_MERC_ID_1 "Rogue Scout Cold Arrow [Normal" -#define D2S_MERC_ID_2 "Rogue Scout Fire Arrow [Nightmare]" -#define D2S_MERC_ID_3 "Rogue Scout Cold Arrow [Nightmare]" -#define D2S_MERC_ID_4 "Rogue Scout Fire Arrow [Hell]" -#define D2S_MERC_ID_5 "Rogue Scout Cold Arrow [Hell]" -#define D2S_MERC_ID_6 "Desert Mercenary Combat [Normal]" -#define D2S_MERC_ID_7 "Desert Mercenary Defensive [Normal]" -#define D2S_MERC_ID_8 "Desert Mercenary Offensive [Normal]" -#define D2S_MERC_ID_9 "Desert Mercenary Combat [Nightmare]" -#define D2S_MERC_ID_10 "Desert Mercenary Defensive [Nightmare]" -#define D2S_MERC_ID_11 "Desert Mercenary Offensive [Nightmare]" -#define D2S_MERC_ID_12 "Desert Mercenary Combat [Hell]" -#define D2S_MERC_ID_13 "Desert Mercenary Defensive [Hell]" -#define D2S_MERC_ID_14 "Desert Mercenary Offensive [Hell]" -#define D2S_MERC_ID_15 "Eastern Sorceror Fire Spells [Normal]" -#define D2S_MERC_ID_16 "Eastern Sorceror Cold Spells [Normal]" -#define D2S_MERC_ID_17 "Eastern Sorceror Lightning Spells [Normal]" -#define D2S_MERC_ID_18 "Eastern Sorceror Fire Spells [Nightmare]" -#define D2S_MERC_ID_19 "Eastern Sorceror Cold Spells [Nightmare]" -#define D2S_MERC_ID_20 "Eastern Sorceror Lightning Spells [Nightmare]" -#define D2S_MERC_ID_21 "Eastern Sorceror Fire Spells [Hell]" -#define D2S_MERC_ID_22 "Eastern Sorceror Cold Spells [Hell]" -#define D2S_MERC_ID_23 "Eastern Sorceror Lightning Spells [Hell]" -#define D2S_MERC_ID_24 "Barbarian [Normal]" -#define D2S_MERC_ID_25 "Barbarian [Normal]" -#define D2S_MERC_ID_26 "Barbarian [Nightmare]" -#define D2S_MERC_ID_27 "Barbarian [Nightmare]" -#define D2S_MERC_ID_28 "Barbarian [Hell]" -#define D2S_MERC_ID_29 "Barbarian [Hell]" - // Quest checkpoints // Note: Some quests don't have many checkpoints, but unfortunately lots of checkpoints are // missing here. Documentation is pretty much scarce and I'm afraid we won't be able to find diff --git a/d2waypoints.c b/d2waypoints.c index e7322ab..7e9fd81 100644 --- a/d2waypoints.c +++ b/d2waypoints.c @@ -1,6 +1,7 @@ #include "d2waypoints.h" +#include "d2char.h" -int isWaypointActivated(D2WaypointsData* d, unsigned int waypoint, unsigned int difficulty) { +int isWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty) { if(waypoint > D2S_WAYPOINTSDATA_NUMWAYPOINTS) { return -1; } @@ -10,7 +11,7 @@ int isWaypointActivated(D2WaypointsData* d, unsigned int waypoint, unsigned int } // TODO: Return success -void setWaypointActivated(D2WaypointsData* d, unsigned int waypoint, unsigned int difficulty, int activated) { +void setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated) { if(waypoint > D2S_WAYPOINTSDATA_NUMWAYPOINTS) { return; } diff --git a/d2waypoints.h b/d2waypoints.h index c5172ee..7eeb2bc 100644 --- a/d2waypoints.h +++ b/d2waypoints.h @@ -1,6 +1,9 @@ #ifndef D2WAYPOINTS_H #define D2WAYPOINTS_H +// Forward declaration +typedef enum D2S_DIFFICULTY D2S_DIFFICULTY; + #include #include "d2strings.h" @@ -9,6 +12,10 @@ #define D2S_WAYPOINTSDATA_LENGTH 5 #define D2S_WAYPOINTSDATA_NUMWAYPOINTS 39 +typedef enum D2S_WAYPOINT { +asd +} D2S_WAYPOINT; + const char* const waypoints[] = { D2S_WAYPOINT_0, D2S_WAYPOINT_1, @@ -64,7 +71,7 @@ typedef struct __attribute__((packed)) { D2Waypoints waypoints[3]; // 1 set for each difficulty } D2WaypointsData; -int isWaypointActivated(D2WaypointsData* d, unsigned int waypoint, unsigned int difficulty); -void setWaypointActivated(D2WaypointsData* d, unsigned int waypoint, unsigned int difficulty, int activated); +int isWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty); +void setWaypointActivated(D2WaypointsData* d, D2S_WAYPOINT waypoint, D2S_DIFFICULTY difficulty, int activated); #endif \ No newline at end of file diff --git a/docs/d2s_110_format_table.txt b/docs/d2s_110_format_table.txt new file mode 100644 index 0000000..9bc007a --- /dev/null +++ b/docs/d2s_110_format_table.txt @@ -0,0 +1,120 @@ +------------------------------------------------------------------------------- +originally extracted from here: +http://www.coreyh.org/diablo-2-files/documentation/d2s_110_format_table.htm +------------------------------------------------------------------------------- + + +D2S File Format - Version 1.10 + +type name bits desc cond1 condvar1 condval1 cond2 condvar2 condval2 comment +ASC8 dwMajic 4 File ID +0 +DWRD dwVersion 32 File Version +4 +DWRD dwSize 32 File Size +8 +DWRD dwCRC 32 File CRC +c +DWRD dwWeaponSet 32 Weapon Set +10 +ASCI Name 16 Character Name +14 +BYTE charType 8 Character Type +24 // 0x40 = ladder 0x20 = expansion 0x10 =? 0x08 = HasDied 0x04 = Hardcore + 0x02 = ? 0x01 = new character format +BYTE charTitle 8 Character Title +25 +WORD unk1 16 Unknown +26 // 00 00 +BYTE charClass 8 Character Class +28 +WORD unk2 16 Unknown +29 // 10 1E +BYTE charLevel 8 Level +2b +DWRD unk3 32 Unknown +2c +DWRD dwTime 32 Time Stamp +30 +DWRD unk4 32 Unknown // FF FF FF FF +34 +DWRD dwSkillKey[16] 32 Skill Keys // No Array support in format !!! +38 +DWRD dwLeftSkill1 32 Left Skill Weapon Set 1 +78 +DWRD dwRightSkill1 32 Right Skill Weapon Set 1 +7c +DWRD dwLeftSkill2 32 Left Skill Weapon Set 2 +80 +DWRD dwRightSkill2 32 Right Skill Weapon Set 2 +84 +BYTE outfit[16] 8 Character Load graphics // No Array support in format !!! +88 +BYTE colors[16] 8 Character Load Colors // No Array support in format !!! +98 +BYTE Town1 8 Normal Town // Only town for last played mode is set +BYTE Town2 8 Nightmare Town +BYTE Town3 8 Hell Town +DWRD dwMapSeed 32 Map Random Seed +WORD unk5 16 Unknown // 00 00 +BYTE bMercDead 8 Merc Dead Flag +BYTE unk6 8 Unknown +DWRD dwMercControl 32 Merc Control seed +WORD wMercName 16 Merc Name Index +WORD wMercType 16 Merc Type +DWRD dwMercExp 32 Merc Experience +BYTE unk7[0x90] 8 Unknown // No Array support in format !!! + +FILE d2Woo.txt 0 Questinfo Header // Act/Quest info header + +FILE d2Ws.txt 0 Waypoints // waypoints + +FILE d2W4.txt 0 Greetings // NPC greeting control + +PROP Stats 0 Player Stats // stats read like properties + +FILE d2if.txt 0 Player Skills // skills + +FILE itemlist.txt 0 Player Item List + +WORD iCorpses 16 Number of Corpses +FILE corpse.txt iCorpses Corpse List // need to add support for variable 'bits' + +ASC8 d2jf 2 Merc List majic // jf +FILE itemlist.txt 0 Merc Item List 0 bHasMerc 1 + +ASC8 d2kf 2 Iron Golem majic // kf +BYTE bHasGolem 8 Iron Golem Flag +FILE fields.txt 0 Golem Item 0 bHasGolem 1 + + + + //========== corpse.txt // dead body info + +BYTE bodyInfo[12] 8 Corpse Info +FILE itemlist.txt 0 Corpse Item List + + + //========== itemlist.txt // Item record list + +ASC8 dwMajic 2 Item List majic // JM +WORD nItems 16 Number of Items +FILE fields.txt nItems Item Records + + + + + //========== d2Woo.txt // Act/Quest info header + +ASC8 dwMajic 4 Record ID // Woo! +DWRD dwActs 32 Numer of acts +WORD wSize 16 Size in bytes + +FILE d2Act.txt 3*wActs Quest/Act states + + //========== d2Acts.txt // Act status flags + +WORD wActStart 16 Act Start info +WORD wQuestStatus[6] 16 Quest Status +WORD wActEnd 16 Act End flags + + //========== d2Ws.txt // waypoints + +ASC8 wMajic 2 Record ID // ws +BYTE unk[6] 8 Unknown +DWRD wp[3*6] 32 Waypoint Data + + //========== d2W4.txt // NPC state control + +ASC8 wMajic 2 Record ID (0x7701) +WORD wSize 16 size of struct +DWRD normal[2] 32 Normal +DWRD nightmare[2] 32 Nightmare +DWRD hell[2] 32 Hell +DWRD normal1[2] 32 Normal1 +DWRD nightmare1[2] 32 Nightmare1 +DWRD hell1[2] 32 Hell1 + + + //========== d2if.txt // skills + +ASC8 wMajic 2 Record ID // if +BYTE skill_lvls[30] 8 Skill Levels diff --git a/docs/d2s_mercenaries_1.09.html b/docs/d2s_mercenaries_1.09.html new file mode 100644 index 0000000..7dca5d9 --- /dev/null +++ b/docs/d2s_mercenaries_1.09.html @@ -0,0 +1,314 @@ + + + + + + + + + Diablo II v1.09 (English) Mercenary Names + + + +

Diablo II (English) Mercenary Names

+ +

for Diablo II v1.09 and the Diablo II Expansion +Set: Lord of Destruction

+ +

Rogue Scouts

+ + + + + + + +
+ + + + + + + + + + + + + + + +
IndexName
0Aliza
1Amplisa
2Annor
3Abhaya
4Elly
5Paige
6Basanti
7Blaise
8Kyoko
9Klaudia
10Kundri
11Kyle
12Visala
13Elexa
+ + + + + + + + + + + + + + + +
IndexName
14Floria
15Fiona
16Gwinni
17Gaile
18Hannah
19Heather
20Iantha
21Diane
22Isolde
23Divo
24Ithera
25Itonya
26Liene
27Maeko
+ + + + + + + + + + + + + + +
IndexName
28Mahala
29Liaza
30Meghan
31Olena
32Oriana
33Ryann
34Rozene
35Raissa
36Sharyn
37Shikha
38Debi
39Tylena
40Wendy
+ +
+ +

Desert Mercenaries

+ + + + + + + +
+ + + + + + + + +
IndexName
0Hazade
1Alhizeer
2Azrael
3Ahsab
4Chalan
5Haseen
6Razan
+ + + + + + + + +
IndexName
7Emilio
8Pratham
9Fazel
10Jemali
11Kasim
12Gulzar
13Mizan
+ + + + + + + + +
IndexName
14Leharas
15Durga
16Neeraj
17Ilzan
18Zanarhi
19Waheed
20Vikhyat
+ +
+ +

Eastern Sorcerors

+ + + + + + + +
+ + + + + + + + +
IndexName
0Jelani
1Barani
2Jabari
3Devak
4Raldin
5Telash
6Ajheed
+ + + + + + + + +
IndexName
7Narphet
8Khaleel
9Phaet
10Geshef
11Vanji
12Haphet
13Thadar
+ + + + + + + +
IndexName
14Yatiraj
15Rhadge
16Yashied
17Jarulf
18Flux
19Scorch
+ +
+ +

Barbarians

+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
IndexName
0Varaya
1Khan
2Klisk
3Bors
4Brom
5Wiglaf
6Hrothgar
7Scyld
8Healfdane
9Heorogar
10Halgaunt
11Hygelac
12Egtheow
13Bohdan
14Wulfgar
15Hild
16Heatholaf
+ + + + + + + + + + + + + + + + + + +
IndexName
17Weder
18Vikhyat
19Unferth
20Sigemund
21Heremod
22Hengest
23Folcwald
24Frisian
25Hnaef
26Guthlaf
27Oslaf
28Yrmenlaf
29Garmund
30Freawaru
31Eadgils
32Onela
33Damien
+ + + + + + + + + + + + + + + + + + +
IndexName
34Erfor
35Weohstan
36Wulf
37Bulwye
38Lief
39Magnus
40Klatu
41Drus
42Hoku
43Kord
44Uther
45Ip
46Ulf
47Tharr
48Kaelim
49Ulric
50Alaric
+ + + + + + + + + + + + + + + + + +
IndexName
51Ethelred
52Caden
53Elgifu
54Tostig
55Alcuin
56Emund
57Sigurd
58Gorm
59Hollis
60Ragnar
61Torkel
62Wulfstan
63Alban
64Barloc
65Bill
66Theodoric
+ +
+ +

Mercenary Type Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeMercenaryAttributeDifficulty
0Rogue ScoutFire ArrowNormal
1Rogue ScoutCold ArrowNormal
2Rogue ScoutFire ArrowNightmare
3Rogue ScoutCold ArrowNightmare
4Rogue ScoutFire ArrowHell
5Rogue ScoutCold ArrowHell
6Desert MercenaryCombatNormal
7Desert MercenaryDefensiveNormal
8Desert MercenaryOffensiveNormal
9Desert MercenaryCombatNightmare
10Desert MercenaryDefensiveNightmare
11Desert MercenaryOffensiveNightmare
12Desert MercenaryCombatHell
13Desert MercenaryDefensiveHell
14Desert MercenaryOffensiveHell
15Eastern SorcerorFire SpellsNormal
16Eastern SorcerorCold SpellsNormal
17Eastern SorcerorLightning SpellsNormal
18Eastern SorcerorFire SpellsNightmare
19Eastern SorcerorCold SpellsNightmare
20Eastern SorcerorLightning SpellsNightmare
21Eastern SorcerorFire SpellsHell
22Eastern SorcerorCold SpellsHell
23Eastern SorcerorLightning SpellsHell
24BarbarianNormal
25BarbarianNormal
26BarbarianNightmare
27BarbarianNightmare
28BarbarianHell
29BarbarianHell
+ +
+ + + + diff --git a/docs/d2s_notes.txt b/docs/d2s_notes.txt new file mode 100644 index 0000000..f299ca7 --- /dev/null +++ b/docs/d2s_notes.txt @@ -0,0 +1,223 @@ +------------------------------------------------------------------------------- +originally extracted from here: +http://www.coreyh.org/diablo-2-files/documentation/d2s_notes.txt +------------------------------------------------------------------------------- + +Summary of the various sections. Note the header's ID is actually a file ID, but you get the idea :) + +[color=blue]ID, content[/color] +0xaa55aa55, header +"Woo!", Quest info +"WS", Waypoint info +0x7701, NPC info +"gf", Main stats info +"if", Skill info +"JM", Main itemlist +"JM", Corpse item list +"jf", Mercenary section (expansion char only) +"kf", Iron Golem list (expansion char only) + +Note that individual items ALSO has the JM ID as do the Mercenary section if you have one. Confusing, yes :) + + +[color=blue]Header[/color] ++0000 file identifier, 0xaa55aa55 ++0004 file version 92 ++0008 file size ++000c checksum, d2fog.27f5 ++0010 0 if [ptClient+428]b is 0, otherwise 1 ++0014 character name, 16 bytes ++0024 flags from [ptClient+0a]b, bit 5 (of 0-7) is set by SAVE code if expansion game ++0025 acts done (see link in post below for more info) +(+0024 and +0025 is actually returned as a word from [ptClient+0a]w ++0026 empty filler to the 2 previous bytes, 0 ++0027 empty filler to the 2 previous bytes, 0 ++0028 character class from [ptClient+08]b, hopefully matches that of hUnit :) ++0029 hard coded to 0x10 ++002a hard coded to 0x1e ++002b clvl from hUnit ++002c ? from [ptClient+454]dw ++0030 time ++0034 -1, function always return -1 ++0038 32 2-byte values, supposedly skills assigned to function keys ++0078 8 2-byte values, supposedly skills assigned to mouse buttons ++0088 16 2-byte values (could be 8 4-byte values) set by d2common.283a, seems to relate to appearance of items/character ++00a8 act playing in normal difficulty ++00a9 act playing in nightmare difficulty ++00aa act playing in hell difficulty + +Of the three values above, 2 will be 0 the other will be the actual value with bit 7 set to indicate which difficulty is saved + ++00ab from [ptGame+78], should be initial seed of game ++00af start of mercenary info, much comes from 6fc71c10 (as ebx+xx), needs checking anyway: + ++00af flags, only 00100000 seems to be in use set if 6fcad880 returns non 0 ++00b3 ebx+00 ++00b7 ebx+04, then subtract [d2common.2957+148], should be from mercenary txt ++00b9 ebx+08 ++00b9 exp of mercenary from hUnit + ++00bf to +014e empty, all 0. These bytes can be used for your own custom saved information. just make sure you load it properly too :) + +That concludes the main header of the save file. Next follow various sections of information. + +[color=blue]Quest info[/color] ++014f "Woo!" ++0153 version of block? 0x00000006 ++0157 blocksize, 0x012a ++0159 quest info stuff (to come) + +[color=blue]Waypoint info[/color] ++0279 "WS" ++027b version of block? 0x00000001 ++027f block size 0x0050 ++0281 waypoint info stuff (to come) + +[color=blue]NPC info[/color] ++02c9 0x7701 ++02cb block size, 0x0034 ++02cd NPW info stuff (to come) + +[color=blue]Main stats info[/color] ++02fd "gf" ++02ff bitfield indicating which of the 16 main stats follow ++0301 stats (dw) indicated by bitfield, from hUnit + +The above section is of variable length + +[color=blue]Skill info[/color] ++03xx+00 "if" ++03xx+02 base slvl (b) for 30 skills + +[color=blue]Item info[/color] ++03xx+30 Start of item info + +The item info is mostly made up of various lists of items. A list will usually contain a header that has a two byte "string", for example "JM" (I would say many of those strings you find are actually short for various programmer names) followed by a word indicating the number of items in the list to follow. Next follow each item itself and I think most (all?) of them will start of with the "JM" string (yes confusing since it is used in two different cases so to speak) followed by item specific data. Socketed items follow right after the item they are socketed into and are not counted in the list header for number of items in the list. + +The various lists (of which not all need to be present) are: + +[color=blue]Main itemlist[/color] ++00 "JM" ++02 number of items in list ++04 List of items + +This includes all items your character have, including those in the stash. + + +[color=blue]Corpse item list[/color] ++00 "JM" ++02 number of corpses ++04 if coprse exists, 12 bytes not used ++10 if corpse exists, list of items + +The game obviously have had the ability to save several corpses for a character. Currently, only one corpse is supported though. The "number of corpses" can only be set to 0 or 1 and can thus be thought of as a flag for the existance of a corpse. If the corpse exists there follow 4 dwords of random data. The first value is actually set from an uninitialized local variable and can thus be anything that happens to sit on the stack. The next two values are x and y coordinates (not sure if they actually make any sense though). None of the three values are read by the code by the way. I guess the first value was once which map the coprse was on or something. In any case, thsoe 12 bytes can be ignored. Next follows a normal list of items if a corpse existed. + +[color=blue]Mercenary item list[/color] ++00 "jf" (only exists if expansion game regardless of if you have a mercenary or not) ++02 "JM" (only exists if you actually have a mercenary) ++04 number of items in list (only exists if you actuall have a mercenary) ++06 List of items (only exists if you actually have a mercenary) + +In an expansion game you then get: + +[color=blue]Iron Golem list[/color] ++00 "kf" ++02 0 or 1 (b), a 1 indictaing an Iron Golem exists ++03 if an Iron Golem eixts the item used to create it will follow here + + + + +Next to be added is detailed info on the data for each item saved in a list. It is a quite variable content depending on the item and also quite large. It will follow below. Note that the same function that compress an item for saving seems to be used to compress items for sending between server and client. It has the ability to mask many properties in such cases for non identified items for example when you gamble I would guess. I will not at all handle that here but only the case for actually saving an item. + +Since items are saved in a very compressed way on bit levels (and not bytes). In addition, what actually is saved varies with the item type and so on. I will thus not give offsetts but rather the number of bits (in decimal notation) something is saved in. The order would be the one the game places them though, so disregarding the fact that some section might be missing for some items the order should NEVER be another than the one I list below. + + +[color=blue]Common item data[/color] +16 "JM" +32 flags [ptItemstats+18], ptItemstats is [hUnit+70] + +Note, the flags are somewhat modified, some removed and some set by the save code but in much should be identical with the run time flags. + +10 version of item, 0, 1 or 100. 100 are new expansion items, 1 are new classic items and 0 is old pre expansion items. Note that all items should be converted to new ones in a current game (I think) at least no item should remain as version 0. + +3 mode, from hUnit+0c + +The mode of items seems to mostly be were the item actually is "located", as oposed to some action it performs. See the thread maping out the ptUnit (which I call hUnit in this thread) for more info. Although I can't imagine a situation were the item is in mode 3 (ground) or 5 (whatever that might be) the save file has a special case for them. In that case, the mode would be followed by 2 32 bit x and y coordinates (from d2common.2856 and 2859). For other items we instead have the three following entries. + +4 body location [ptItemstats+40]. This tells were, if at all, the item is equiped + +4 x coordinate in inventory (d2common.2856) + +4 y coordinate in inventory (d2common.2859) + +3 page number PLUS 1. The page tells where in the invenotry the item is. Example of different pages are stash cube, main invenotry on character and so on. Pages like trade screen and such should not matter although I am not sure what happens if the game tries to save your character while the trade screen is open, you might end up with items on that page too for example. Same with an item on the cursor. + +32 item code + +The 3 letter code each base item have. This is for non ears only (flag 00010000 in the flag data above is set for ears). Ears does not save the code, instead they have: + + 3 class of ear + n*7 name of ear. This is the character name of the ear and is ended by a 0 value. The name is stored at [ptItemstats+44] (first letter) and the following at [ptItemstats+46] and onwards. + +For the interested, in non saved structures, if the item is gold (which obviously never save as items), the ammount of gold is inserted after the item code. First comes a 1 bit indicating the size. A 1 indicate a 32 bit value a 0 indicate a 12 bit value. That 12/32 bit value then follows and specify the ammount of gold. + +Compact save items will have no other data than the above one. Flag 00200000 is set on compact save items. Note that flag is set only upon save, not normally in the flag register. It will be cleared in the process of loading. The compact saving info of an item is fetched from the appropriate item.txt file upon saving and checked for. + + + + +[color=blue]Non compact save item data[/color] +3 number of socketed items +32 creation seed, from [hUnit+34] +7 ilvl, from [ptItemstats+28] +4 quality, from [ptItemstats+00] +1 flag for variable picture (itemtypes "varinvgfx") +3 if flag=1, number indicating which picture to use +1 flag for autoprefix on item +11 if flag=1, info on which autoprefix + +Next follows data depending on the quality of the item. + +Low quality +3 type of low quality property + +Normal quality +No special data saved + +Superior +3 type of superiorproperty + +Magic +11 which prefix the item has +11 which suffix the item has + +In both cases it is the entry in the appropriate affix table (were a 0 value indicate none). This applies to the autoprefix above as well. + +Rare and Crafted +8 which prefix name the item has +8 which suffix name the item has +1 flag indicating if a prefix follows +11 if flag=1, which prefix the item has +1 flag indicating if a suffix follows +11 if flag=1, which suffix the item has +1 flag indicating if a prefix follows +11 if flag=1, which prefix the item has +1 flag indicating if a suffix follows +11 if flag=1, which suffix the item has +1 flag indicating if a prefix follows +11 if flag=1, which prefix the item has +1 flag indicating if a suffix follows +11 if flag=1, which suffix the item has + +Each rare item can have up to 3 prefixes and 3 suffixes. + +Set +12 which set (in setitems.txt) the item is part of + +Unique +12 which unique (in unqiue.txt) the item is + + +...more to come + diff --git a/docs/d2s_save_file_format_1.13d.html b/docs/d2s_save_file_format_1.13d.html new file mode 100644 index 0000000..e77b3d6 --- /dev/null +++ b/docs/d2s_save_file_format_1.13d.html @@ -0,0 +1,1270 @@ + +

Diablo II Save Game File Format

+

for Diablo II Expansion Set v1.13d

+
Updated July 1, 2012
+

This page was originally written by Trevin Beattie, whose site is no more (his latest version of this page is available +here though).
+Now this page is maintained by me, Yuri Sakhno (George1).

+ +

Introduction

+

This page describes the format of saved game files for the game Diablo II Expansion Set v1.13d. +While the information presented here is mostly aplicable to earlier versions of the game, there were some drastic +changes in version 1.10 (particularly, in how character stats are saved), so if you intend to read files of the versions +of the game erlier than that, you would probably be better off opening that save in some recent version of the game and +then saving it again (upgrading the saved game file).

+

(Note: all values larger than a byte are stored in x86 little-endian order — +i.e., least significant byte first. A "short" is 2 bytes long, +and a "long" is 4 bytes long. Values starting with "0x" are given +in hexadecimal notation; otherwise they are decimal.)

+ +

File Header

+

Each save file starts with a file header. Depending on the circumstances, this may be the only section present in saved game file.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
0longFile identifier. This must be the value 0xAA55AA55.
4longFile version. The following values are known:
+     0x47  v1.00 through v1.06
+     0x57  v1.07 or Expansion Set v1.08
+     0x59  standard game v1.08
+     0x5C  v1.09 (both the standard game and the Expansion Set.)
+     0x60  v1.10 and above
+ As it was outlined above, this document only covers version 0x60 of the file format.
8longSize of the file, in bytes.
12longChecksum of the netire save file. If you attempt to hack the file without storing the + correct checksum afterwards, your game will fail to load. + Fortunately, the checksum algorithm is very simple. + After clearing the checksum field, you add up the values of all the bytes + in the file, rotating the running total one bit to the left before adding + each byte. Then store the result in this field.
16longActive arms. Determines which weapon set is currently active.
2016 charsCharacter name. The name may be up to 15 characters long; + the rest of the field must be padded with null-characters. Remember the rules for + Diablo II character names: 2-15 characters, containing only upper and + lower case letters (A-Z), with the possible addition of one dash ( - ) or + underscore ( _ ) as long as it is not the first or last character of the + name.
36byte +
Character status. This is a bit field:
+ + + + + + + + + + + + + + + + + + + + + +
76543210
unknownExpansion
Character
unknownDiedHardcoreunknown
+
Note: the "died" bit indicates that your character + has died at some point in the past. It is never cleared when you resume the game. + To find out whether your character is currently dead, you need to look + in the item list below to see if there is some corpse data. + Obviously, if you have a hardcore character and this bit is set, you won't be able + to play the game with that charcter anymore.
37byte + Character progression. This number tells (sort of) how many acts + you have completed from all difficulty levels. It appears to be + incremented when you kill the final demon in an act — i.e., Andarial, + Duriel, Mephisto, and Diablo / Baal. There's a catch to that last + one: in an Expansion game, the value is not incremented after + killing Diablo, but is incremented by 2 after killing Baal. (The + reason is unknown.) So it skips the values 4, 9, and 14. +

I believe this value is used in determining your character's + title. The title is one of the following values (depending on the + character class' gender):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ValueStandardHardcoreValueExpansionHardcode Expansion
0-3(no title)0-3(no title)
4-7Sir / DameCount / Countess5-8SlayerDestroyer
8-11Lord / LadyDuke / Duchess10-13ChampionConqueror
12Baron / BaronessKing / Queen15Patriarch / MatriarchGuardian
+
382 bytesunknown; probably some kind of padding
40byteCharacter class. The defined classes are:
+      0x00  Amazon
+      0x01  Sorceress
+      0x02  Necromancer
+      0x03  Paladin
+      0x04  Barbarian
+      0x05  Druid (Expansion character only)
+      0x06  Assassin (Expansion character only)
412 bytesunknown; I've only seen the values { 16, 30 } here.
43byteCharacter's level. This is the level shown on the character selection screen, but it + should equal the level given in the character statistics section.
44longunknown
48longTime stamp. This is in the standard time() format of the number + of seconds which have elapsed since midnight, January 1, 1970 (UTC).
52longunknown
5616 longsThese are the skill Ids assigned to the hotkeys for Skill 1 + through Skill 16. If a skill hotkey is not assigned to a skill, the value is 0xFFFF. +

+
Hotkey definitions are stored in the character.key + file. The structure of that file is not covered by this document.
120longThe action assigned to the left mouse button. The value of this field is a skill Id.
124longThe action assigned to the right mouse button. The value of this field is also a skill Id.
128longIn an Expansion character, the action assigned to the alternate left + mouse button. (The button assignments are swapped when you swap weapons.)
132longIn an Expansion character, the action assigned to the alternate right mouse button.
13632 bytesunknown
1683 bytesThese bytes indicate which difficulty the character is playing. + The first byte corresponds to Normal, the second Nightmare, and the third + Hell. If the value is zero, the character is not playing at that + level. Otherwise, the value looks like this: + + + + + + + + + + + + + + + + + + +
76543210
ActiveunknownWhich Act the
character is in (0-4)
+
171longMap Id. This value looks like a random number, but it corresponds with one of the longs + found in the character.map file, according to the difficulty being played.
175shortunknown
177shortIf your Expansion character has a mercenary who is currently dead, this field is non-zero.
179longThis looks like a random Id for your mercenary. It is 0 if you have never had a mercenary. + If your mercenary has died or (in the standard game) been left behind when you move on to the next act, + this field is still set to the last mercenary you had.
183shortThis is a numerical index into the game's language-dependent string table for mercenary names. + There is a separate list for each type of mercenary (Rogue Scout, Desert Mercenary, Eastern Sorceror, + and Barbarian). Trevin wrote a list of mercenary names for the English 1.09 patch.
185shortThis code determines the difficulty level and act where your mercenary was found, as well as the attribute + of your mercenary (i.e. Cold, Fire, Lightning). Trevin wrote a + list of the mercenary codes appended to the end of the mercenary name.
187longYour mercenary's experience points.
191144 bytesunknown
+ +

For the newly-created character, this is the only information present in the file (i.e. the file consists of just the header). +The save file is extended (all other sections added) when you exit the game (even if you haven't done anything in it), +but the very first save created by the game (i.e. right after you click the OK button on the character-creation screen) +will be the save with just the header present. Such a save is still a legitimate save, which the game can successfully load.

+ +

Quest Completion Data

+

The quest data begins with the following header:

+ + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
3354 charsThe string identifier "Woo!".
3396 bytesunknown; there are values { 0x06, 0x00, 0x00, 0x00, 0x2A, 0x01 } always present here.
+

The header is followed by three structures, one for each difficulty level. Note that the byte +offsets given here are offsets into the structure; the first structure is at offset 345 in the file, +the second one is at offset 441, and the third one at 537. You have to add the offsets from the table +to these values to get the actual offset in the file for the corresponding field for the specific difficulty level.

+

Although there is some variation in the meaning of the bits per quest, some of the bits appear to have constant meaning.

+

Bit 0 indicates the quest is complete. If bit 0 is not set but the rest of the field is non-zero, +then the quest has been started, but not finished.

+

Bit 1 generally means you have completed the requirements for the quest +(i.e., killed the boss demon), and all that's left is to collect the reward — +for example, "Charsi will imbue an item with magical power." Not all +quests have this option. If this bit is set, bit 0 must be cleared.

+

Bit 2 is often set when an NPC gives you a quest.

+

Bit 12 is set when you have seen the swirling fire animation that closes a quest icon.

+

Bit 13 indicates the quest was completed in the current game; when you save +the game and then reload it, all bit 13's are cleared.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
0shortThis field contains a 1 if you have been introduced (by Warriv) to Act I.
26 shorts +
These fields contain quest completion data for each quest in Act I.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
short #QuestNotes
0Den of EvilBit 4 is set when you enter the Den.
1Sisters' Burial GroundsBit 4 is set when you enter the Burial Grounds.
2Tools of the TradeBit 6 is set when you pick up the Horadric Malus.
3The Search for CainBit 4 is set when you enter Tristram.
Bit 10 indicates + whether you have completed the secret Cow Level ("Moo"). If + you want to fight the Cow King again, just clear this bit!
If you + enter Act II without rescuing Deckard Cain, bit 14 will get + set. You will not be able to rescue Cain yourself; the Rogues + will have done it instead, and as a consequence, you will be charged + a fee if you want Cain to identify items for you.
4The Forgotten TowerBit 2 is set when you read the Moldy Tome.
Bit 6 is set when + you enter the Forgotten Tower.
5Sisters to the Slaughter
+
14shortuncertain; perhaps this gets set to a non-zero value after you travel from Act I to Act II.
16shortThis field contains a 1 if you have been introduced (by Jerhyn) to Act II.
186 shorts +
These fields contain quest completion data for each quest in Act II.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
short #QuestNotes
0Radament's LairBit 4 is set when you find Radament.
1The Horadric StaffBit 4 is set when Cain tells you about the Viper Amulet.
+ Bit 5 is set when Cain tells you about the Staff of Kings.
+ Bit 10 is set when Cain tells you about the Horadric Staff.
+ Bit 11 is set when you make the Horadric Staff.
2Tainted SunBit 2 is set when the sun goes out.
+ Bit 3 is set when Drognan tells you why.
3Arcane Sanctuary
4The Summoner
5The Seven TombsBit 3 is set when you talk to Tyrael.
+ Bit 4 is set when you talk to Jerhyn (after killing Duriel).
+ Bit 5 is set when you kill Duriel.
+ Bit 6 is set when Atma congratulates you.
+ Bit 7 is set when Warriv congratulates you.
+ Bit 8 is set by Drognan.
+ Bit 9 is set by Lysander.
+ Bit 10 is set by Cain.
+ Bit 11 is set by Fara.
+
30shortuncertain; perhaps this gets set to a non-zero value after you travel from Act II to Act III.
32shortThis field contains a 1 if you have been introduced (by Hratli) to Act III.
346 shorts +
These fields contain quest completion data for each quest in Act III.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
short #QuestNotes
0Lam Esen's Tome
1Khalim's Will
2Blade of the Old ReligionBit 2 is set when you pick up the Gidbinn.
+ Bit 3 is set when Hratli asks you to find the Gidbinn.
3The Golden BirdBit 2 is set when Cain tells you about the Jade Figurine.
+ Bit 4 is set when Cain tells you about the Golden Bird.
+ Bit 5 is set when you are given the Potion of Life, and cleared again when you + drink the Potion. (This prevents you from drinking more than one in a game.)
+ Bit 6 is set when you find the Jade Figurine.
4The Blackened Temple
5The Guardian
+
46shortuncertain; perhaps this gets set to a non-zero value after you travel from Act III to Act IV.
48shortThis field contains a 1 if you have been introduced to Act IV.
506 shorts +
These fields contain quest completion data for each quest in Act + IV. Note that there are only three quests here, as opposed to 6 for + the first three Acts.
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
short #QuestNotes
0The Fallen Angel
1Terror's End
2Hell's Forge
3-5unusedIt looks like quest data for Act IV still has place for 6 quests, despite the fact that this act only has 3.
+
62shortuncertain; perhaps this gets set to a non-zero value after you travel from Act IV to Act V in an Expansion game, + but this assumption has not been verified yet.
64shortunknown; in an Expansion character, this was set to 1 after + completing Terror's End and talking to Cain in act IV.
662 shortsunknown
706 shorts +
These fields contain quest completion data for each quest in Act V.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
short #QuestNotes
0Siege on HarrogathBit 3 is set when you find Shenk.
+ Bit 5 is set when Larzuk offers to socket an item for you.
1Rescue on Mount Arreat
2Prison of IceBit 7 is set when you read the Scroll of Resistance.
+ Bit 8 is set after you rescue Anya and talk to Malah.
3Betrayal of HarrogathBit 4 is set when Anya offers to personalize an item for you.
4Rite of Passage
5Eve of DestructionBit 4 is set when Larzuk congratulates you.
+ Bit 5 is set when Cain congratulates you.
+ Bit 6 is set when Malah congratulates you.
+ Bit 7 is set by Tyrael.
+ Bit 8 is set by Qual-Kehk.
+ Bit 9 is set by Anya.
+
827 shortsunknown
+ +

Waypoints Data

+

The waypoints data begins with the following header:

+ + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
6332 charsThe string identifier "WS".
6356 bytesunknown; there are values { 0x01, 0x00, 0x00, 0x00, 0x50, 0x00 } always present here.
+

The header is followed by three structures, one per each difficulty level. +Note that the byte offsets given here are offsets into the structure; the first structure is at offset 641 in the file, +the second one is at offset 665, and the third at 689. You have to add the offsets from the table +to these values to get the actual offset in the file for the corresponding field for the specific difficulty level.

+ + + + + + + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
02 bytesunknown; there are values { 0x02, 0x01 } always present here.
25 bytesWaypoints. This is a bitfield, with one bit assigned to each + waypoint in LSB order — so bit 0 in the Rogue Encampment waypoint for Act + I. The first waypoint in every Act is activated as soon as you enter + that Act. There are 9 waypoints (bits) in each of Acts I, II, and + III, and 3 waypoints (bits) in Act IV, so the last waypoint before Diablo + (River of Flame) is bit 29 (since we start counting from 0). The + first waypoint for Act V follows at bit 30, and continues to the last + (ninth) waypoint in Act V at bit 38. +

+
The first waypoint in each of the difficulty levels is always activated, + even if you have never been to that difficulty level.
717 bytesunknown
+ +

There is an additional byte value at file offset 713 after the three waypoints structures. +This byte always has value 0x01 and probably serves as some kind of trailer.

+ +

NPC Introductions

+

Trevin's data on the next section was very sketchy, and hasn't improved since at all.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
7142 charsThe string identifier "w4".
7161 byteunknown
7171 byte +
You have been introduced to:
+ + + + + + + + + + + + + + + + + + + + + + + +
76543210
WarrivCharsiKashyaAkaraGheed
+
7181 byte + + + + + + + + + + + + + + + + + + + + + + + +
76543210
GreizMeshifGeglashLysanderFaraDrognan
+
7191 byte + + + + + + + + + + + + + + + + + + + + + + +
76543210
AlkorAshearaCainElzix
+
7201 byte + + + + + + + + + + + + + + + + + + + + + + +
76543210
MalahAnyaNatalyaMeshifOrmus
+
7211 byte + + + + + + + + + + + + + + + + + + + +
76543210
CainQual-KehkNihlathak
+
7223 bytesunknown
7258 bytesIntroductions repeated for Nightmare difficulty.
7338 bytesIntroductions repeated for Hell difficulty.
7411 byte +

It would appear that bits 1-6 of byte 741 get set after you take the + caravan to Act II in Normal difficulty. Bit 7 of byte 741 through + bit 1 of byte 743 get set after you sail to Act III. On entering Act + IV, bits 2, 5, 6, & 7 of byte 743 and bits 0, 3, & 4 of byte 744 + get set.

+

When you return to a previous act and talk to the NPC's, these bits are + cleared.

+
You have yet to be welcomed back by:
+ + + + + + + + + + + + + + + + + + + + + + + +
76543210
Warriv?CharsiWarrivKashyaAkaraGheed
+
7421 byte + + + + + + + + + + + + + + + + + + + + + + + +
76543210
GreizJerhynMeshifGeglash?FaraDrognan?
+
7431 byte + + + + + + + + + + + + + + + + + + + + + + +
76543210
AlkorHratliAsheara??Elzix
+
7441 byte + + + + + + + + + + + + + + + + + + + + +
76543210
??Ormus
+
7454 bytesunknown
7498 bytesGreetings repeated for Nightmare difficulty.
7578 bytesGreetings repeated for Hell difficulty.
+ +

Character Statistics

+

The character statistics begin with 2-character identifier:

+ + + + + + + + + + + + + +
Byte PositionSizeContents
7652 charsThe string identifier "gf".
+

From this point on, the contents of the file are variable, because character stats are stored in packed format +and certain stats may be absent (if the stat is absent in the save file, its value is 0.

+

Starting from patch version 1.10 Diablo II stores stats differently than it used to be in previous game version. +Every character stat is stored as a two-value pair. These pairs (and even the values inside them are not +byte-aligned. They may start in the middle of one byte, and continue to the second. +Here is the basic structure of the pair (note that field sizes are given in bits):

+ + + + + + + + + + + + + + + + + +
Field SizeDescription
9Stat Id. This field determines the stat whose value is stored in the value-pair and, more importantly, + the size of the next field in the pair.
variableThe value that is to be assigned to the corresponding stat. The size of the field, in bits, + is determined by the stat itself. Read on to find out where this information can be obtained.
+

The stats list is terminated by the 9-bit value of 0x1FF (all 9 bits are set), +i.e. the entire list is read in a loop, where you read the Id first and, if that Id is 0x1FF, +you exit the loop, otherwise you read the next n bits as a stat value and repeat the loop.

+

The Ids of stats (and sizes of values) are determined by the data-tables normally stored inside +the game archive (the MPQ files). The file for this specific purpose is named ItemStatCost.txt, +which is a kind of CSV file, but with tabulation characters used as separators instead of commas. +The game actually uses the ItemStatCost.bin one, which is sort of a compiled version +of the corresponding text file.

+

Here is an Excel-formatted ItemStatCost.xlsx file that contains +the data for 1.13d patch with some nice formatting and extra comments. This file actually contains +data from two tables, the one needed for the purpose of reading character stats is given on the ItemStatCost sheet.

+

The column ID specifies the Id of the stat, as stored in the 9-bit field of the two-value pair. +The row containing that Id describes the stat. There is a textual name of the stat in the Stat column, +as well as the size of the value, in bits, that follows the Id in the two-value pair. This size is specified +by the CSvBits column. Only values that have value 1 in the Saved column (first 16 stats) +are actually saved in the character stats section of the save file.

+

The stats described by the ItemStatCost table are as follows (in table below Stat Name corresponds +to the value in the Stat column from the data table):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Stat NameDetails
strengthThese stats are self-explanatory. They are always present.
energy
dexterity
vitality
statptsThe number of Stat Points earned but not distributed. + This stat may be absent from the save file if you have distibuted all stat points.
newskillsThe number of Skill Choices earned but not distributed. + This stat may be absent from the save file if you have distibuted all skill points.
hitpointsCurrent amount of Life points. +

+
These 6 stats are (usually) always present. (There is + an exception: if your character is dead, the current Life stat will be + gone!) They are also not plain integer values! + Instead, each field is a fixed-point binary number, with a 24-bit integer + part and an 8-bit fraction part. For example, if the Current Life + stat contains the value 0x020AC0, then to get the amount of life + remaining you take that value and divide by 256.0 to get 522.75 + (rounding the number to an integer for display. Note that the + current amount of Life, Mana or Stamina may be more than the base amount, + because the base does not take into account any blessings bestowed by + magical items you are carrying.
maxhpBase amount of Life points.
manaCurrent amount of Mana points.
maxmanaBase amount of Mana points.
staminaCurrent amount of Stamina points.
maxstaminaBase amount of Stamina points.
levelYour character's level. This value must be in the range 1-99 + (and is therefore always present, even on a new character, with + a minor exception) and should be + the same as byte 43 in the file header.
experienceThe amount of experience your character has. If you haven't + killed a single monster in the game, your experience will be 0, and this + field is not stored. Otherwise, this field is always present.
goldThe amount of gold you are carrying with you (in your inventory or backpack). + Just as a helpful reminder, the maximum amount of gold you may carry is directly + proportional to your level, at 10,000 gold per level. Thus, a new character can only + carry 10,000 gold pieces, but a level 99 character (the maximum) can carry nearly + a million in gold (990,000).
goldbankThe amount of gold you have stowed away (in stash). Just as a helpful + reminder, starting from the 1.13c patch onwards, the maximum amount of gold + in your stash does not depend on your character's level, and is now a flat + cap of 2,500,000 instead.
+

As it was specified above, the stats list is terminated with a stat Id with a special meaning +(the Id has value 0x1FF in this case), and the stat value for this stat Id is not stored +(you may view it as a stat whose stat value is 0 bits in size). After that the remaining bits are +padded with 0-bits to the nearest byte-boundary so that the next section is byte-aligned.

+ +

Character Skills

+

The character skills section begins with the 2-character header, +"if". This is followed by 30 bytes, each byte corresponding to +one of the character's special skills. To save space, Trevin listed the skills +in a separate table.

+ +

Item List

+

The next major section of the save file is the item list. It begins with the following header:

+ + + + + + + + + + + + + + + +
SizeContents
2 charsThe string identifier "JM".
shortThe number of items your character has. This includes items + equipped, tucked in your belt, stored in your inventory, stored in your + stash, and hidden in the Horadric Cube. It does not, + however, include gems, runes, or jewels which have been inserted into a + socketed item. (Those are counted as part of the item.)
+

This header is followed by a list of items. The format of the items is described +on the Item Format page.

+

After the list of items, you will find another item list header similar to +the one shown above; only this time the item count will be either 0 or 1. The value 0 +means that your character is currently alive. If the value is 1, then that means +your character is dead (if you load this save, a corpse will be lying at your feet in town), +in which case 12 bytes of (unknown) data will follow, after which there will be +another items list header (the one with the identifier "JM" and item count) +and item list for items on your corpse. Sadly, the meaning of the 12 bytes is unknown.

+

If you have an Expansion character, then the corpse item list (if there is one) will be +followed by the 2-character identifier "jf". If and only +if you have a mercenary (alive or dead), this header is followed by an item +list header and (possibly empty) item list containing items equipped on the +mercenary. This item list is followed by the 2-character trailer "kf".

+

If you have a necromancer, it is possible for you to have an Iron Golem that +is preserved when your game is saved and restored. The Iron Golem is based on an +item. Following the mercenary item list, there will be a single byte that is 0x00 +if there is no golem, or 0x01 if there is. If there is a golem, this byte is +followed by a single item.

+ + diff --git a/docs/d2s_save_file_format_1.13d.txt b/docs/d2s_save_file_format_1.13d.txt new file mode 100644 index 0000000..5831676 --- /dev/null +++ b/docs/d2s_save_file_format_1.13d.txt @@ -0,0 +1,786 @@ +------------------------------------------------------------------------------- +originally extracted from here: +http://www.coreyh.org/diablo-2-files/documentation/d2s_save_file_format_1.13d.html +------------------------------------------------------------------------------- + + + Diablo II Save Game File Format + + for Diablo II Expansion Set v1.13d + + Updated July 1, 2012 + +This page was originally written by Trevin Beattie, whose site is no more (his +latest version of this page is available here though). +Now this page is maintained by me, Yuri Sakhno (George1). + +Introduction + +This page describes the format of saved game files for the game Diablo II +Expansion Set v1.13d. While the information presented here is mostly aplicable +to earlier versions of the game, there were some drastic changes in version +1.10 (particularly, in how character stats are saved), so if you intend to read +files of the versions of the game erlier than that, you would probably be +better off opening that save in some recent version of the game and then saving +it again (upgrading the saved game file). + +(Note: all values larger than a byte are stored in x86 little-endian order — +i.e., least significant byte first. A "short" is 2 bytes long, and a "long" is +4 bytes long. Values starting with "0x" are given in hexadecimal notation; +otherwise they are decimal.) + +File Header + +Each save file starts with a file header. Depending on the circumstances, this +may be the only section present in saved game file. + +┌────────┬──────┬─────────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│0 │long │File identifier. This must be the value 0xAA55AA55. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │File version. The following values are known: │ +│ │ │ 0x47 v1.00 through v1.06 │ +│ │ │ 0x57 v1.07 or Expansion Set v1.08 │ +│ │ │ 0x59 standard game v1.08 │ +│4 │long │ 0x5C v1.09 (both the standard game and the Expansion │ +│ │ │Set.) │ +│ │ │ 0x60 v1.10 and above │ +│ │ │As it was outlined above, this document only covers version │ +│ │ │0x60 of the file format. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│8 │long │Size of the file, in bytes. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Checksum of the netire save file. If you attempt to hack the │ +│ │ │file without storing the correct checksum afterwards, your │ +│ │ │game will fail to load. Fortunately, the checksum algorithm is │ +│12 │long │very simple. After clearing the checksum field, you add up the │ +│ │ │values of all the bytes in the file, rotating the running │ +│ │ │total one bit to the left before adding each byte. Then store │ +│ │ │the result in this field. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│16 │long │Active arms. Determines which weapon set is currently active. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Character name. The name may be up to 15 characters long; the │ +│ │ │rest of the field must be padded with null-characters. │ +│ │16 │Remember the rules for Diablo II character names: 2-15 │ +│20 │chars │characters, containing only upper and lower case letters │ +│ │ │(A-Z), with the possible addition of one dash ( - ) or │ +│ │ │underscore ( _ ) as long as it is not the first or last │ +│ │ │character of the name. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Character status. This is a bit field: │ +│ │ │┌────┬────┬─────────┬───────┬────┬────────┬────┬────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│ │ │├────┴────┼─────────┼───────┼────┼────────┼────┴────┤ │ +│ │ ││unknown │Expansion│unknown│Died│Hardcore│unknown │ │ +│ │ ││ │Character│ │ │ │ │ │ +│36 │byte │└─────────┴─────────┴───────┴────┴────────┴─────────┘ │ +│ │ │Note: the "died" bit indicates that your character has died at │ +│ │ │some point in the past. It is never cleared when you resume │ +│ │ │the game. To find out whether your character is currently │ +│ │ │dead, you need to look in the item list below to see if there │ +│ │ │is some corpse data. Obviously, if you have a hardcore │ +│ │ │character and this bit is set, you won't be able to play the │ +│ │ │game with that charcter anymore. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Character progression. This number tells (sort of) how many │ +│ │ │acts you have completed from all difficulty levels. It appears │ +│ │ │to be incremented when you kill the final demon in an act — │ +│ │ │i.e., Andarial, Duriel, Mephisto, and Diablo / Baal. There's a │ +│ │ │catch to that last one: in an Expansion game, the value is not │ +│ │ │incremented after killing Diablo, but is incremented by 2 │ +│ │ │after killing Baal. (The reason is unknown.) So it skips the │ +│ │ │values 4, 9, and 14. │ +│ │ │ │ +│ │ │I believe this value is used in determining your character's │ +│ │ │title. The title is one of the following values (depending on │ +│37 │byte │the character class' gender): │ +│ │ │ │ +│ │ │Value Standard Hardcore Value Expansion Hardcode │ +│ │ │ Expansion │ +│ │ │0-3 (no title) 0-3 (no title) │ +│ │ │4-7 Sir / Dame Count / 5-8 Slayer Destroyer │ +│ │ │ Countess │ +│ │ │8-11 Lord / Duke / 10-13 Champion Conqueror │ +│ │ │ Lady Duchess │ +│ │ │ Baron / King / Patriarch │ +│ │ │12 Baroness Queen 15 / Guardian │ +│ │ │ Matriarch │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│38 │2 │unknown; probably some kind of padding │ +│ │bytes │ │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Character class. The defined classes are: │ +│ │ │ 0x00 Amazon │ +│ │ │ 0x01 Sorceress │ +│40 │byte │ 0x02 Necromancer │ +│ │ │ 0x03 Paladin │ +│ │ │ 0x04 Barbarian │ +│ │ │ 0x05 Druid (Expansion character only) │ +│ │ │ 0x06 Assassin (Expansion character only) │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│41 │2 │unknown; I've only seen the values { 16, 30 } here. │ +│ │bytes │ │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Character's level. This is the level shown on the character │ +│43 │byte │selection screen, but it should equal the level given in the │ +│ │ │character statistics section. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│44 │long │unknown │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Time stamp. This is in the standard time() format of the │ +│48 │long │number of seconds which have elapsed since midnight, January │ +│ │ │1, 1970 (UTC). │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│52 │long │unknown │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │These are the skill Ids assigned to the hotkeys for Skill 1 │ +│ │ │through Skill 16. If a skill hotkey is not assigned to a │ +│56 │16 │skill, the value is 0xFFFF. │ +│ │longs │ │ +│ │ │Hotkey definitions are stored in the character.key file. The │ +│ │ │structure of that file is not covered by this document. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│120 │long │The action assigned to the left mouse button. The value of │ +│ │ │this field is a skill Id. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│124 │long │The action assigned to the right mouse button. The value of │ +│ │ │this field is also a skill Id. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │In an Expansion character, the action assigned to the │ +│128 │long │alternate left mouse button. (The button assignments are │ +│ │ │swapped when you swap weapons.) │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│132 │long │In an Expansion character, the action assigned to the │ +│ │ │alternate right mouse button. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│136 │32 │unknown │ +│ │bytes │ │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │These bytes indicate which difficulty the character is │ +│ │ │playing. The first byte corresponds to Normal, the second │ +│ │ │Nightmare, and the third Hell. If the value is zero, the │ +│ │ │character is not playing at that level. Otherwise, the value │ +│ │ │looks like this: │ +│168 │3 │┌──────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ +│ │bytes ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│ │ │├──────┼─────┴─────┴─────┴─────┼─────┴─────┴─────┤ │ +│ │ ││ │ │Which Act the │ │ +│ │ ││Active│unknown │character is in │ │ +│ │ ││ │ │(0-4) │ │ +│ │ │└──────┴───────────────────────┴─────────────────┘ │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │Map Id. This value looks like a random number, but it │ +│171 │long │corresponds with one of the longs found in the character.map │ +│ │ │file, according to the difficulty being played. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│175 │short │unknown │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│177 │short │If your Expansion character has a mercenary who is currently │ +│ │ │dead, this field is non-zero. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │This looks like a random Id for your mercenary. It is 0 if you │ +│ │ │have never had a mercenary. If your mercenary has died or (in │ +│179 │long │the standard game) been left behind when you move on to the │ +│ │ │next act, this field is still set to the last mercenary you │ +│ │ │had. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │This is a numerical index into the game's language-dependent │ +│ │ │string table for mercenary names. There is a separate list for │ +│183 │short │each type of mercenary (Rogue Scout, Desert Mercenary, Eastern │ +│ │ │Sorceror, and Barbarian). Trevin wrote a list of mercenary │ +│ │ │names for the English 1.09 patch. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│ │ │This code determines the difficulty level and act where your │ +│185 │short │mercenary was found, as well as the attribute of your │ +│ │ │mercenary (i.e. Cold, Fire, Lightning). Trevin wrote a list of │ +│ │ │the mercenary codes appended to the end of the mercenary name. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│187 │long │Your mercenary's experience points. │ +├────────┼──────┼─────────────────────────────────────────────────────────────────┤ +│191 │144 │unknown │ +│ │bytes │ │ +└────────┴──────┴─────────────────────────────────────────────────────────────────┘ + +For the newly-created character, this is the only information present in the +file (i.e. the file consists of just the header). The save file is extended +(all other sections added) when you exit the game (even if you haven't done +anything in it), but the very first save created by the game (i.e. right after +you click the OK button on the character-creation screen) will be the save with +just the header present. Such a save is still a legitimate save, which the game +can successfully load. + +Quest Completion Data + +The quest data begins with the following header: + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│335 │4 chars│The string identifier "Woo!". │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│339 │6 bytes│unknown; there are values { 0x06, 0x00, 0x00, 0x00, 0x2A, │ +│ │ │0x01 } always present here. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +The header is followed by three structures, one for each difficulty level. Note +that the byte offsets given here are offsets into the structure; the first +structure is at offset 345 in the file, the second one is at offset 441, and +the third one at 537. You have to add the offsets from the table to these +values to get the actual offset in the file for the corresponding field for the +specific difficulty level. + +Although there is some variation in the meaning of the bits per quest, some of +the bits appear to have constant meaning. + +Bit 0 indicates the quest is complete. If bit 0 is not set but the rest of the +field is non-zero, then the quest has been started, but not finished. + +Bit 1 generally means you have completed the requirements for the quest (i.e., +killed the boss demon), and all that's left is to collect the reward — for +example, "Charsi will imbue an item with magical power." Not all quests have +this option. If this bit is set, bit 0 must be cleared. + +Bit 2 is often set when an NPC gives you a quest. + +Bit 12 is set when you have seen the swirling fire animation that closes a +quest icon. + +Bit 13 indicates the quest was completed in the current game; when you save the +game and then reload it, all bit 13's are cleared. + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│0 │short │This field contains a 1 if you have been introduced (by │ +│ │ │Warriv) to Act I. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │These fields contain quest completion data for each quest in│ +│ │ │Act I. │ +│ │ │┌──────┬───────────────────┬───────────────────────────────┐│ +│ │ ││short │ Quest │ Notes ││ +│ │ ││ # │ │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││0 │Den of Evil │Bit 4 is set when you enter the││ +│ │ ││ │ │Den. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││1 │Sisters' Burial │Bit 4 is set when you enter the││ +│ │ ││ │Grounds │Burial Grounds. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││2 │Tools of the Trade │Bit 6 is set when you pick up ││ +│ │ ││ │ │the Horadric Malus. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 4 is set when you enter ││ +│ │ ││ │ │Tristram. ││ +│ │ ││ │ │Bit 10 indicates whether you ││ +│ │ ││ │ │have completed the secret Cow ││ +│2 │6 ││ │ │Level ("Moo"). If you want to ││ +│ │shorts ││ │ │fight the Cow King again, just ││ +│ │ ││ │ │clear this bit! ││ +│ │ ││3 │The Search for Cain│If you enter Act II without ││ +│ │ ││ │ │rescuing Deckard Cain, bit 14 ││ +│ │ ││ │ │will get set. You will not be ││ +│ │ ││ │ │able to rescue Cain yourself; ││ +│ │ ││ │ │the Rogues will have done it ││ +│ │ ││ │ │instead, and as a consequence, ││ +│ │ ││ │ │you will be charged a fee if ││ +│ │ ││ │ │you want Cain to identify items││ +│ │ ││ │ │for you. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 2 is set when you read the ││ +│ │ ││4 │The Forgotten Tower│Moldy Tome. ││ +│ │ ││ │ │Bit 6 is set when you enter the││ +│ │ ││ │ │Forgotten Tower. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││5 │Sisters to the │ ││ +│ │ ││ │Slaughter │ ││ +│ │ │└──────┴───────────────────┴───────────────────────────────┘│ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│14 │short │uncertain; perhaps this gets set to a non-zero value after │ +│ │ │you travel from Act I to Act II. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│16 │short │This field contains a 1 if you have been introduced (by │ +│ │ │Jerhyn) to Act II. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │These fields contain quest completion data for each quest in│ +│ │ │Act II. │ +│ │ │┌──────┬───────────────────┬───────────────────────────────┐│ +│ │ ││short │ Quest │ Notes ││ +│ │ ││ # │ │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││0 │Radament's Lair │Bit 4 is set when you find ││ +│ │ ││ │ │Radament. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 4 is set when Cain tells ││ +│ │ ││ │ │you about the Viper Amulet. ││ +│ │ ││ │ │Bit 5 is set when Cain tells ││ +│ │ ││1 │The Horadric Staff │you about the Staff of Kings. ││ +│ │ ││ │ │Bit 10 is set when Cain tells ││ +│ │ ││ │ │you about the Horadric Staff. ││ +│ │ ││ │ │Bit 11 is set when you make the││ +│ │ ││ │ │Horadric Staff. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 2 is set when the sun goes ││ +│ │ ││2 │Tainted Sun │out. ││ +│18 │6 ││ │ │Bit 3 is set when Drognan tells││ +│ │shorts ││ │ │you why. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││3 │Arcane Sanctuary │ ││ +│ │ │├──────┼───────────────────┤ ││ +│ │ ││4 │The Summoner │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 3 is set when you talk to ││ +│ │ ││ │ │Tyrael. ││ +│ │ ││ │ │Bit 4 is set when you talk to ││ +│ │ ││ │ │Jerhyn (after killing Duriel). ││ +│ │ ││ │ │Bit 5 is set when you kill ││ +│ │ ││ │ │Duriel. ││ +│ │ ││5 │The Seven Tombs │Bit 6 is set when Atma ││ +│ │ ││ │ │congratulates you. ││ +│ │ ││ │ │Bit 7 is set when Warriv ││ +│ │ ││ │ │congratulates you. ││ +│ │ ││ │ │Bit 8 is set by Drognan. ││ +│ │ ││ │ │Bit 9 is set by Lysander. ││ +│ │ ││ │ │Bit 10 is set by Cain. ││ +│ │ ││ │ │Bit 11 is set by Fara. ││ +│ │ │└──────┴───────────────────┴───────────────────────────────┘│ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│30 │short │uncertain; perhaps this gets set to a non-zero value after │ +│ │ │you travel from Act II to Act III. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│32 │short │This field contains a 1 if you have been introduced (by │ +│ │ │Hratli) to Act III. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │These fields contain quest completion data for each quest in│ +│ │ │Act III. │ +│ │ │┌──────┬───────────────────┬───────────────────────────────┐│ +│ │ ││short │ Quest │ Notes ││ +│ │ ││ # │ │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││0 │Lam Esen's Tome │ ││ +│ │ │├──────┼───────────────────┤ ││ +│ │ ││1 │Khalim's Will │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 2 is set when you pick up ││ +│ │ ││2 │Blade of the Old │the Gidbinn. ││ +│ │ ││ │Religion │Bit 3 is set when Hratli asks ││ +│ │ ││ │ │you to find the Gidbinn. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │6 ││ │ │Bit 2 is set when Cain tells ││ +│34 │shorts ││ │ │you about the Jade Figurine. ││ +│ │ ││ │ │Bit 4 is set when Cain tells ││ +│ │ ││ │ │you about the Golden Bird. ││ +│ │ ││ │ │Bit 5 is set when you are given││ +│ │ ││3 │The Golden Bird │the Potion of Life, and cleared││ +│ │ ││ │ │again when you drink the ││ +│ │ ││ │ │Potion. (This prevents you from││ +│ │ ││ │ │drinking more than one in a ││ +│ │ ││ │ │game.) ││ +│ │ ││ │ │Bit 6 is set when you find the ││ +│ │ ││ │ │Jade Figurine. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││4 │The Blackened │ ││ +│ │ ││ │Temple │ ││ +│ │ │├──────┼───────────────────┤ ││ +│ │ ││5 │The Guardian │ ││ +│ │ │└──────┴───────────────────┴───────────────────────────────┘│ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│46 │short │uncertain; perhaps this gets set to a non-zero value after │ +│ │ │you travel from Act III to Act IV. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│48 │short │This field contains a 1 if you have been introduced to Act │ +│ │ │IV. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │These fields contain quest completion data for each quest in│ +│ │ │Act IV. Note that there are only three quests here, as │ +│ │ │opposed to 6 for the first three Acts. │ +│ │ │┌──────┬───────────────────┬───────────────────────────────┐│ +│ │ ││short │ Quest │ Notes ││ +│ │ ││ # │ │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││0 │The Fallen Angel │ ││ +│50 │6 │├──────┼───────────────────┤ ││ +│ │shorts ││1 │Terror's End │ ││ +│ │ │├──────┼───────────────────┤ ││ +│ │ ││2 │Hell's Forge │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │It looks like quest data for ││ +│ │ ││3-5 │unused │Act IV still has place for 6 ││ +│ │ ││ │ │quests, despite the fact that ││ +│ │ ││ │ │this act only has 3. ││ +│ │ │└──────┴───────────────────┴───────────────────────────────┘│ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │uncertain; perhaps this gets set to a non-zero value after │ +│62 │short │you travel from Act IV to Act V in an Expansion game, but │ +│ │ │this assumption has not been verified yet. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│64 │short │unknown; in an Expansion character, this was set to 1 after │ +│ │ │completing Terror's End and talking to Cain in act IV. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│66 │2 │unknown │ +│ │shorts │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │These fields contain quest completion data for each quest in│ +│ │ │Act V. │ +│ │ │┌──────┬───────────────────┬───────────────────────────────┐│ +│ │ ││short │ Quest │ Notes ││ +│ │ ││ # │ │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 3 is set when you find ││ +│ │ ││0 │Siege on Harrogath │Shenk. ││ +│ │ ││ │ │Bit 5 is set when Larzuk offers││ +│ │ ││ │ │to socket an item for you. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││1 │Rescue on Mount │ ││ +│ │ ││ │Arreat │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 7 is set when you read the ││ +│ │ ││2 │Prison of Ice │Scroll of Resistance. ││ +│70 │6 ││ │ │Bit 8 is set after you rescue ││ +│ │shorts ││ │ │Anya and talk to Malah. ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││3 │Betrayal of │Bit 4 is set when Anya offers ││ +│ │ ││ │Harrogath │to personalize an item for you.││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││4 │Rite of Passage │ ││ +│ │ │├──────┼───────────────────┼───────────────────────────────┤│ +│ │ ││ │ │Bit 4 is set when Larzuk ││ +│ │ ││ │ │congratulates you. ││ +│ │ ││ │ │Bit 5 is set when Cain ││ +│ │ ││ │ │congratulates you. ││ +│ │ ││5 │Eve of Destruction │Bit 6 is set when Malah ││ +│ │ ││ │ │congratulates you. ││ +│ │ ││ │ │Bit 7 is set by Tyrael. ││ +│ │ ││ │ │Bit 8 is set by Qual-Kehk. ││ +│ │ ││ │ │Bit 9 is set by Anya. ││ +│ │ │└──────┴───────────────────┴───────────────────────────────┘│ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│82 │7 │unknown │ +│ │shorts │ │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +Waypoints Data + +The waypoints data begins with the following header: + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│633 │2 chars│The string identifier "WS". │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│635 │6 bytes│unknown; there are values { 0x01, 0x00, 0x00, 0x00, 0x50, │ +│ │ │0x00 } always present here. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +The header is followed by three structures, one per each difficulty level. Note +that the byte offsets given here are offsets into the structure; the first +structure is at offset 641 in the file, the second one is at offset 665, and +the third at 689. You have to add the offsets from the table to these values to +get the actual offset in the file for the corresponding field for the specific +difficulty level. + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│0 │2 bytes│unknown; there are values { 0x02, 0x01 } always present │ +│ │ │here. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Waypoints. This is a bitfield, with one bit assigned to each│ +│ │ │waypoint in LSB order — so bit 0 in the Rogue Encampment │ +│ │ │waypoint for Act I. The first waypoint in every Act is │ +│ │ │activated as soon as you enter that Act. There are 9 │ +│ │ │waypoints (bits) in each of Acts I, II, and III, and 3 │ +│ │ │waypoints (bits) in Act IV, so the last waypoint before │ +│2 │5 bytes│Diablo (River of Flame) is bit 29 (since we start counting │ +│ │ │from 0). The first waypoint for Act V follows at bit 30, and│ +│ │ │continues to the last (ninth) waypoint in Act V at bit 38. │ +│ │ │ │ +│ │ │The first waypoint in each of the difficulty levels is │ +│ │ │always activated, even if you have never been to that │ +│ │ │difficulty level. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│7 │17 │unknown │ +│ │bytes │ │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +There is an additional byte value at file offset 713 after the three waypoints +structures. This byte always has value 0x01 and probably serves as some kind of +trailer. + +NPC Introductions + +Trevin's data on the next section was very sketchy, and hasn't improved since +at all. + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│714 │2 chars│The string identifier "w4". │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│716 │1 byte │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │You have been introduced to: │ +│ │ │┌──────┬────┬──────┬────┬──────┬─────┬─────┬────┐ │ +│717 │1 byte ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│ │ │├──────┼────┼──────┼────┼──────┼─────┼─────┼────┤ │ +│ │ ││Warriv│ │Charsi│ │Kashya│Akara│Gheed│ │ │ +│ │ │└──────┴────┴──────┴────┴──────┴─────┴─────┴────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬───┬──────┬───────┬────────┬────┬───────┬───┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│718 │1 byte │├─────┼───┼──────┼───────┼────────┼────┼───────┼───┤ │ +│ │ ││Greiz│ │Meshif│Geglash│Lysander│Fara│Drognan│ │ │ +│ │ │└─────┴───┴──────┴───────┴────────┴────┴───────┴───┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬────┬───────┬────┬────┬─────┬────┬─────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│719 │1 byte │├─────┼────┼───────┼────┴────┼─────┼────┼─────┤ │ +│ │ ││Alkor│ │Asheara│ │Cain │ │Elzix│ │ +│ │ │└─────┴────┴───────┴─────────┴─────┴────┴─────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬─────┬────┬───────┬──────┬────┬────┬─────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│720 │1 byte │├─────┼─────┼────┼───────┼──────┼────┴────┼─────┤ │ +│ │ ││Malah│Anya │ │Natalya│Meshif│ │Ormus│ │ +│ │ │└─────┴─────┴────┴───────┴──────┴─────────┴─────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌────┬────┬────┬────┬────┬────┬─────────┬─────────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│721 │1 byte │├────┴────┴────┴────┴────┼────┼─────────┼─────────┤ │ +│ │ ││ │Cain│Qual-Kehk│Nihlathak│ │ +│ │ │└────────────────────────┴────┴─────────┴─────────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│722 │3 bytes│unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│725 │8 bytes│Introductions repeated for Nightmare difficulty. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│733 │8 bytes│Introductions repeated for Hell difficulty. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │It would appear that bits 1-6 of byte 741 get set after you │ +│ │ │take the caravan to Act II in Normal difficulty. Bit 7 of │ +│ │ │byte 741 through bit 1 of byte 743 get set after you sail to│ +│ │ │Act III. On entering Act IV, bits 2, 5, 6, & 7 of byte 743 │ +│ │ │and bits 0, 3, & 4 of byte 744 get set. │ +│ │ │ │ +│ │ │When you return to a previous act and talk to the NPC's, │ +│741 │1 byte │these bits are cleared. │ +│ │ │ │ +│ │ │You have yet to be welcomed back by: │ +│ │ │┌──────┬───┬──────┬──────┬──────┬─────┬─────┬───┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│ │ │├──────┼───┼──────┼──────┼──────┼─────┼─────┼───┤ │ +│ │ ││Warriv│? │Charsi│Warriv│Kashya│Akara│Gheed│ │ │ +│ │ │└──────┴───┴──────┴──────┴──────┴─────┴─────┴───┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬──────┬──────┬───────┬───┬────┬───────┬───┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│742 │1 byte │├─────┼──────┼──────┼───────┼───┼────┼───────┼───┤ │ +│ │ ││Greiz│Jerhyn│Meshif│Geglash│? │Fara│Drognan│? │ │ +│ │ │└─────┴──────┴──────┴───────┴───┴────┴───────┴───┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬──────┬───────┬────┬────┬────┬────┬─────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│743 │1 byte │├─────┼──────┼───────┼────┴────┼────┼────┼─────┤ │ +│ │ ││Alkor│Hratli│Asheara│ │? │? │Elzix│ │ +│ │ │└─────┴──────┴───────┴─────────┴────┴────┴─────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ +│ │ ││ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ +│744 │1 byte │├─────┴─────┴─────┼─────┼─────┼─────┴─────┼─────┤ │ +│ │ ││ │? │? │ │Ormus│ │ +│ │ │└─────────────────┴─────┴─────┴───────────┴─────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│745 │4 bytes│unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│749 │8 bytes│Greetings repeated for Nightmare difficulty. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│757 │8 bytes│Greetings repeated for Hell difficulty. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +Character Statistics + +The character statistics begin with 2-character identifier: + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│765 │2 chars│The string identifier "gf". │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +From this point on, the contents of the file are variable, because character +stats are stored in packed format and certain stats may be absent (if the stat +is absent in the save file, its value is 0. + +Starting from patch version 1.10 Diablo II stores stats differently than it +used to be in previous game version. Every character stat is stored as a +two-value pair. These pairs (and even the values inside them are not +byte-aligned. They may start in the middle of one byte, and continue to the +second. Here is the basic structure of the pair (note that field sizes are +given in bits): + +┌────────┬────────────────────────────────────────────────────────────────────┐ +│ Field │ Description │ +│ Size │ │ +├────────┼────────────────────────────────────────────────────────────────────┤ +│ │Stat Id. This field determines the stat whose value is stored in the│ +│9 │value-pair and, more importantly, the size of the next field in the │ +│ │pair. │ +├────────┼────────────────────────────────────────────────────────────────────┤ +│ │The value that is to be assigned to the corresponding stat. The size│ +│variable│of the field, in bits, is determined by the stat itself. Read on to │ +│ │find out where this information can be obtained. │ +└────────┴────────────────────────────────────────────────────────────────────┘ + +The stats list is terminated by the 9-bit value of 0x1FF (all 9 bits are set), +i.e. the entire list is read in a loop, where you read the Id first and, if +that Id is 0x1FF, you exit the loop, otherwise you read the next n bits as a +stat value and repeat the loop. + +The Ids of stats (and sizes of values) are determined by the data-tables +normally stored inside the game archive (the MPQ files). The file for this +specific purpose is named ItemStatCost.txt, which is a kind of CSV file, but +with tabulation characters used as separators instead of commas. The game +actually uses the ItemStatCost.bin one, which is sort of a compiled version of +the corresponding text file. + +Here is an Excel-formatted ItemStatCost.xlsx file that contains the data for +1.13d patch with some nice formatting and extra comments. This file actually +contains data from two tables, the one needed for the purpose of reading +character stats is given on the ItemStatCost sheet. + +The column ID specifies the Id of the stat, as stored in the 9-bit field of the +two-value pair. The row containing that Id describes the stat. There is a +textual name of the stat in the Stat column, as well as the size of the value, +in bits, that follows the Id in the two-value pair. This size is specified by +the CSvBits column. Only values that have value 1 in the Saved column (first 16 +stats) are actually saved in the character stats section of the save file. + +The stats described by the ItemStatCost table are as follows (in table below +Stat Name corresponds to the value in the Stat column from the data table): + +┌──────────┬───────────────────────────────────────────────────────────────────┐ +│Stat Name │ Details │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│strength │ │ +├──────────┤ │ +│energy │ │ +├──────────┤These stats are self-explanatory. They are always present. │ +│dexterity │ │ +├──────────┤ │ +│vitality │ │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │The number of Stat Points earned but not distributed. This stat may│ +│statpts │be absent from the save file if you have distibuted all stat │ +│ │points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │The number of Skill Choices earned but not distributed. This stat │ +│newskills │may be absent from the save file if you have distibuted all skill │ +│ │points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │Current amount of Life points. │ +│ │ │ +│ │These 6 stats are (usually) always present. (There is an exception:│ +│ │if your character is dead, the current Life stat will be gone!) │ +│ │They are also not plain integer values! Instead, each field is a │ +│ │fixed-point binary number, with a 24-bit integer part and an 8-bit │ +│hitpoints │fraction part. For example, if the Current Life stat contains the │ +│ │value 0x020AC0, then to get the amount of life remaining you take │ +│ │that value and divide by 256.0 to get 522.75 (rounding the number │ +│ │to an integer for display. Note that the current amount of Life, │ +│ │Mana or Stamina may be more than the base amount, because the base │ +│ │does not take into account any blessings bestowed by magical items │ +│ │you are carrying. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│maxhp │Base amount of Life points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│mana │Current amount of Mana points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│maxmana │Base amount of Mana points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│stamina │Current amount of Stamina points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│maxstamina│Base amount of Stamina points. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │Your character's level. This value must be in the range 1-99 (and │ +│level │is therefore always present, even on a new character, with a minor │ +│ │exception) and should be the same as byte 43 in the file header. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │The amount of experience your character has. If you haven't killed │ +│experience│a single monster in the game, your experience will be 0, and this │ +│ │field is not stored. Otherwise, this field is always present. │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │The amount of gold you are carrying with you (in your inventory or │ +│ │backpack). Just as a helpful reminder, the maximum amount of gold │ +│gold │you may carry is directly proportional to your level, at 10,000 │ +│ │gold per level. Thus, a new character can only carry 10,000 gold │ +│ │pieces, but a level 99 character (the maximum) can carry nearly a │ +│ │million in gold (990,000). │ +├──────────┼───────────────────────────────────────────────────────────────────┤ +│ │The amount of gold you have stowed away (in stash). Just as a │ +│goldbank │helpful reminder, starting from the 1.13c patch onwards, the │ +│ │maximum amount of gold in your stash does not depend on your │ +│ │character's level, and is now a flat cap of 2,500,000 instead. │ +└──────────┴───────────────────────────────────────────────────────────────────┘ + +As it was specified above, the stats list is terminated with a stat Id with a +special meaning (the Id has value 0x1FF in this case), and the stat value for +this stat Id is not stored (you may view it as a stat whose stat value is 0 +bits in size). After that the remaining bits are padded with 0-bits to the +nearest byte-boundary so that the next section is byte-aligned. + +Character Skills + +The character skills section begins with the 2-character header, "if". This is +followed by 30 bytes, each byte corresponding to one of the character's special +skills. To save space, Trevin listed the skills in a separate table. + +Item List + +The next major section of the save file is the item list. It begins with the +following header: + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│2 chars │The string identifier "JM". │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │The number of items your character has. This includes items │ +│ │equipped, tucked in your belt, stored in your inventory, │ +│short │stored in your stash, and hidden in the Horadric Cube. It │ +│ │does not, however, include gems, runes, or jewels which have │ +│ │been inserted into a socketed item. (Those are counted as │ +│ │part of the item.) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +This header is followed by a list of items. The format of the items is +described on the Item Format page. + +After the list of items, you will find another item list header similar to the +one shown above; only this time the item count will be either 0 or 1. The value +0 means that your character is currently alive. If the value is 1, then that +means your character is dead (if you load this save, a corpse will be lying at +your feet in town), in which case 12 bytes of (unknown) data will follow, after +which there will be another items list header (the one with the identifier "JM" +and item count) and item list for items on your corpse. Sadly, the meaning of +the 12 bytes is unknown. + +If you have an Expansion character, then the corpse item list (if there is one) +will be followed by the 2-character identifier "jf". If and only if you have a +mercenary (alive or dead), this header is followed by an item list header and +(possibly empty) item list containing items equipped on the mercenary. This +item list is followed by the 2-character trailer "kf". + +If you have a necromancer, it is possible for you to have an Iron Golem that is +preserved when your game is saved and restored. The Iron Golem is based on an +item. Following the mercenary item list, there will be a single byte that is +0x00 if there is no golem, or 0x01 if there is. If there is a golem, this byte +is followed by a single item. + diff --git a/docs/d2s_save_item_format_1.13d.html b/docs/d2s_save_item_format_1.13d.html new file mode 100644 index 0000000..9fa333e --- /dev/null +++ b/docs/d2s_save_item_format_1.13d.html @@ -0,0 +1,1125 @@ + +

Diablo II Item Format

+

for Diablo II v1.13d Expansion Set: Lord of Destruction

+
Updated June 23, 2012
+

This file was originally written by Trevin Beattie, whose site is no more (his latest version of this file is available +here though).

+

Welcome!

+

Thanks for showing an interest in my Diablo II Item Format page. While +you're browsing, be sure to check out the preview of my game +editor for unix+Motif. I currently have the item editor in +development!

+

Introduction

+

Having searched the web, I found very few references to the Diablo II +.d2s file format, and most of them covered the old (pre-1.08) +version. Diablo II v1.09 has significantly changed the file format. +I have started another page which details the +layout of the major parts of the .d2s file. This document +focuses specifically on the item structure — all those pieces of the file +tagged "JM".

+

Rather than describe everything in terms of byte offsets, I'm going to define +the layout as a series of variable-length bit fields. This is a critical +part of the item format, because the position of many of the fields can change +depending on what comes before it. If I say a certain value is a 3-bit +field starting at bit position 150, for example, this translates to bits 6 and 7 +of the byte 18 and bit 0 of byte 19 in the data structure. You can read an +arbitrary bit field programatically using the following code (in C):

+
#define read_bits(start,size) \
+    ((*((unsigned long *) &data[(start) / 8])
+      >> ((start) & 7)) & ((1 << (size)) - 1))
+

Item List Header

+

An item list begins with the following simple header:

+ + + + + + + + + + + + + + + + + + +
Byte PositionSizeContents
02 charsIdentifier string "JM" { 0x4A, 0x4D }
216 bitsThe number of items your character has. This does not include + gems or jewels which have been glued into socketed items.
+

Your item list ends with another 4-byte structure similar to the above, +except the second field is zero (i.e., +{ 0x4A, 0x4D, 0x00, 0x00 }).

+

In the Expansion Set, your hireling has his/her own item list. This +list is separated from yours by the 2-character identifier "jf". This is +followed by an item list header for the hireling, and then his/her items. +The second item list is not terminated with the same 4-byte structure as +the first; instead, it is followed by the 2-character identifier "kf".

+

Item Structure part 1: Simple Items

+

There are still many fields in the item structure which I haven't figured out +yet, but I'll leave placeholders for them in case I find out what they mean in +the future. All sizes are in bits unless otherwise specified.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bit PositionSizeContents
02 charsIdentifier string "JM" { 0x4A, 0x4D }
164unknown
201Item has been identified
216unknown
271Item is Socketed
281unknown
291This bit is set on items which you have picked up since the last time + the game was saved. Why?...
302unknown
321 +
Item is a Player Ear
+
Thanks go to Mike of Denmark for identifying this bit.
331"Newbie" item. This bit is set on the weapon and shield your + character is given when you start the game. Apparently, this gives + the item the property of having a repair cost of 1gp, as well as a sell + value of 1gp.
343unknown
371 +
Item is simple (only 111 bits {14 bytes} of item data)
+
Thanks go to Guillaume Courtin of France for discovering the + meaning of this bit.
381Item is Ethereal (Cannot be Repaired)
391unknown; this bit is 1 on the items I've looked at
401Item has been personalized (by Anya in Act V)
411unknown
421It looks like this bit indicates the item has been given a Rune Word.
4315unknown; some of these bits may be set
583 +
Item location. Actually, I have only seen a few + values for these bits, so I'm not 100% certain of its validity. If + you see any other value here, let me know what it is and where the item is + located.
+ + + + + + + + + + + + + + + + + + + + + + + +
0Item is stored (see bit field 73)
1Item is equipped (somewhere on your body)
2Item is tucked in your belt (or sash)
4Item is being moved (i.e., has been picked up by the mouse).
6Item is glued into a socket.
+
614 +
If the item is equipped, this field tells where it is. Possible + values are:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1head (helmet)
2neck (amulet)
3torso (armor)
4right hand (weapon)
5left hand (shield)
6right finger (ring)
7left finger (ring)
8waist (belt)
9feet (boots)
10hands (gloves)
11alternate right hand (Expansion Set only)
12alternate left hand (Expansion Set only)
+
654 +

Column number of the left corner of the item, counting from 0. + Your inventory has ten columns (numbered 0-9), your stash has six, and the + Horadric Cube has four.

+

Note: Your belt is considered (for the purposes of the + item format) to have no rows, but either 4, 8, 12, or 16 columns. If + you prefer, you can divide this field and use the 2 bits at position 67-68 + for the row (but only for belts).

+

Note 2: If the item is equipped, glued to a socket, or + in transit, then this field appears to contain old data from the last time + the item was stored. I.e., it may be non-zero, but the value is + unused.

693 +

Row number of the top of the item, counting from 0. Your + inventory has four rows (numbered 0-3), your stash has four in normal + characters or eight in Expansion Set characters, and the Horadric Cube has + four. (In the belt, this field is always zero.)

+

Note: If the item is equipped, tucked in your belt, + glued to a socket, or in transit, then this field appears to contain old + data from the last time the item was stored. I.e., it may be + non-zero, but the value is unused.

721unknown
733 +
Actually, bit 74 seems to always be 0, but since bits + 73 and 75 are related I just lump them all together. If the item is + neither equipped nor in your belt, this field tells where it is. + Possible values are:
+ + + + + + + + + + + + + + + + + + + +
0not here (check bit field 58)
1inventory
4Horadric Cube
5stash
+
If you find an item having any other value in this field, let me + know what the value is and the item's location!
764 chars
(8 bits ea.)
Item's type. The type is 3 lower-case letters or + numbers followed by a space; e.g., "amu " (Amulet) or "2hs " + (Two-Handed Sword). I have started a list of item identifiers (not + posted; sorry), but it is by no means complete; I'm sure I don't even have + half of what's out there!
Warning: This field is + not byte-aligned! It starts in the middle of byte 9 and + runs to the middle of byte 13.
1083The number of gems (or skulls or jewels) which have been glued to this + item (if socketed). + There will be this many additional item structures for the gems + immediately following this item, in the order that the gems were inserted.
+

Item Variant: Player Ears

+
The following information was provided by Mike of Denmark.
+

If the item is a Player Ear, its structure is slightly different than the +Simple Items above. The last two fields in the Simple Item structure are +replaced by the following:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bit PositionSizeContents
763Character class of the ear's former owner. The defined classes + are:
     0  + Amazon
     1  + Sorceress
     2  + Necromancer
     3  + Paladin
     4  + Barbarian
     5  Druid (Expansion character + only)
     6  Assassin (Expansion character + only)
797Character level of the ear's former owner.
867First character of the former owner's name.
937 × N-1Second character of the former owner's name; Repeat until you get the + whole name (15 characters maximum).
86 + 7 × N70  (this indicates the end of the name)
+

Following the end of the name, the rest of the final byte will be padded with +0's if necessary, and the Player Ear structure ends there.

+

Item Structure part 2: Extended Items

+

By "extended items" I mean any items which are not simple. +Simple items are those which need no further information than that given +above — such as gems, potions, and small quest items — and their structure length +is fixed at 14 bytes. Everything else has an extended structure with a +possibly variable length set of bit fields. First, I'll describe the part +of the structure that appears to be the same for all extended items. From +that point on, there will be no more "bit positions"; only "this field follows +that field, if it exists".

+ + + + + + + + + + + + + + + + + + + + + + + +
Bit PositionSizeContents
11132Unique identifier. Diablo II randomly generates a value for this + field in order to discourage cheaters from "duping" items. + Supposedly, if it detects more than one extended item with the same unique + Id, it will delete the duplicates. (It hasn't done that for me in + single player mode, though.)
1437 +
This appears to be the item's level; i.e., the level with which the + item was created (or 'dropped'). The item level is based on the + level of the monster who dropped it, the level of the area you're in if + found in a chest, or, in rare cases, your characters level. The item + level determines what modifiers are allowed on the item.
+
Note: this is just a theory at this point, but it seems to hold + for the items I've examined.
1504 +
Item quality. This field can be one of the following values, + which determines the quality-specific bit fields that follow:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1low quality
2normal
3high quality
4magically enhanced
5part of a set
6rare
7unique
8crafted
+
Thanks go to Guillaume Courtin of France for finding the value of + crafted items.
+

WARNING: DATA BELOW THIS POINT MAY CONTAIN ERRORS

+

Ring Data

+

After the above data, if the item is a ring, amulet, jewel, or charm, then it +has a 1 bit followed by three more bits. All other items (that I've seen) +have just a single 0 bit.

+ + + + + + + + + + + + + + + + +
SizeContents
1If this bit is set, the item has one of multiple pictures + associated with it; the next field determines which picture a particular + item uses. If this bit is 0, the next field is absent. The + picture field is used for rings, amulets, jewels, and charms.
3Picture. Optional; only present if the previous bit is 1. + This field chooses the particular graphic used to display the ring.
+

From this point on, my information is very iffy.

+

Unknown Field

+ + + + + + + + + + + + + + + +
SizeContents
1This bit apparently is set for certain class-specific Expansion Set + items. It indicates the presence of the next 11-bit field. If + this bit is 0, the next field is absent.
11 +
Credit for the discovery of this field's meaning goes entirely to + Guillaume Courtin of France. Thanks!
+
This field indicates magic properties which are inherent in certain + class-specific items. A given class-specific item will (almost) + always start with the same set of properties, even if its quality is + "normal". Other quality ratings may add more properties to the + standard set. It appears that items which will have this field + are:
+
    +
  • Amazon-only bows, spears, and javelins
  • +
  • Voodoo heads (Necromancer-only shields)
  • +
  • Paladin-only shields
  • +
  • Orbs (Sorceress-Only wands)
+

Low Quality Item Data

+

If the item is one of low quality, it has 3 more bits that give the quality +details:

+ + + + + + + + + + + + +
SizeContents
3 +
Quality:
+ + + + + + + + + + + + + + + + + + + +
0Crude
1Cracked
2Damaged
3Low Quality
+
I haven't recorded any instances of other values, but that doesn't + mean there won't be any. Also, I'm certain the value has something + to do with mods on an item's inherent (non-recorded) properties, such as + weapon damage, but I haven't figured out yet what the correlation is.
+

Normal Item Data

+

Normal items have no extra quality data.

+

High Quality ("Superior") Item Data

+

If the item is one of high quality, it has 3 additional bits.

+ + + + + + + + + + + +
SizeContents
3unknown. I'm certain the value has something to do with mods + on an item's inherent (non-recorded) properties, such as weapon damage, + but I haven't figured out yet what the correlation is.
+

Magically Enhanced Item Data

+

+Magically enhanced items have two 11-bit fields representing the item's prefix +and suffix. Either one (but not both) may be omitted. The prefix and +suffix each are used in choosing the magical +enhancements for an item (although the enhancements are modifiable), and can +also increase the minimum level required to use them item and affect the item's +color.

+
+ + + + + + + + + + + + + + + +
SizeContents
11Item prefix (i.e., "Gold" or "Tangerine"). I've started a list + of prefix identifiers, but it is very sparse at this time. If + this field is 0, the item has no prefix.
11Item suffix (i.e., "of Greed" or "of Life"). I've started a list + of suffix identifiers, but it is very sparse at this time. If + this field is 0, the item has no suffix.
+

Set Item Data

+

Set items have a 12-bit field containing the ID of the set. +(Not the set member, but the whole set.) The set member is +identified by cross-referencing the item +type with the set Id. Also note that set items have an +extra field following the item-specific data. +

+ + + + + + + + + + + + +
SizeContents
12 +
Set identifier; i.e., all items which are part of the set will have + the same value in this field. Since I've only identified a few set + items, I'll give their ID's here:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
2Cleglaw's Brace
3Iratha's Finery
4Isenhart's Armory
6Milabrega's Regalia
7Cathan's Traps
11Berserker's Arsenal
12Death's Disguise
13Angelic Raiment
+

Rare Item Data

+

This is by far the worst beast to decode. Rare items have a +variable number of bits before we get to the item contents, and this number can +vary anywhere from 55 to 88!

+

Update 3/14/2002: EUREKA!! I've +finally figured out the variable fields!; See the table below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SizeContents
8This is the Id for the first + word of the item's name (i.e., "Stone" or "Doom").
8This is the ID for the second + word of the item's name (i.e., "Finger" or "Shroud").
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11First magic + prefix (optional). Although this "prefix" isn't actually + shown in the item name, it is used in determining the magical properties, + required level, coloring, and other attributes of the rare item.
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11First magic + suffix (optional). Although this "suffix" isn't actually + shown in the item name, it is used in determining the magical properties, + required level, coloring, and other attributes of the rare item.
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Second magic prefix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Second magic suffix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Third magic prefix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the next field is absent.
11Third magic suffix (optional)
+

Unique Item Data

+

Unique items have an additional 12 bit field, which in most cases is +the unique item ID. The few exceptions are certain quest items (e.g., the +Horadric Malus).

+ + + + + + + + + + + + +
SizeContents
12 +
Item identifier. Since I've only identified a few unique items, + I'll give their ID's here:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
13Ume's Lament Grim Wand
31Hellplague Long Sword
75Wormskull Bone Helm
77Undead Crown Crown (no, that is not a typo!)
91Goldskin Full Plate Mail
120Nagelring Ring (not a typo either; I checked)
123Amulet of the Viper
125Horadric Staff
126Hell Forge Hammer
4095
(0xFFF)
(other; probably a quest + item)
+
+

Crafted Item Data

+

Crafted items appear to be coded exactly like rare items, having a rare name +(two parts) and six optional prefixes / suffixes.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SizeContents
8This is the Id for the first + word of the item's name (i.e., "Stone" or "Doom").
8This is the Id for the second + word of the item's name (i.e., "Finger" or "Shroud").
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11First magic + prefix (optional). Although this "prefix" isn't actually + shown in the item name, it is used in determining the magical properties, + required level, coloring, and other attributes of the crafted item.
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11First magic + suffix (optional). Although this "suffix" isn't actually + shown in the item name, it is used in determining the magical properties, + required level, coloring, and other attributes of the crafted item.
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Second magic prefix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Second magic suffix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Third magic prefix (optional)
1If this field is 1, the next 11-bit field is present. If 0, the + next field is absent.
11Third magic suffix (optional)
+

Rune Word

+

If the item has a rune word (indicated by bit +42 being set), there is an additional field at this point.

+ + + + + + + + + + + + + + + +
SizeContents
12This appears to be an index to the rune word, although I + can't say what the index is based on. The first rune word, + "Ancient's Pledge", has a value of 27. The next rune word, "Black", + has a value of 32. etc.
4Unknown; the value is 5 on all items I've looked at.
+

Personalization

+

The following segment is present if and only if the item is personalized +(i.e., bit +40 is set). Only armor and weapons (except for quest items) can be +personalized.

+ + + + + + + + + + + + + + + + + + + + + + + +
SizeContents
7First character of the owner's name (just plain ASCII!)
7Second character of the owner's name
7 × N-2Repeat until you get the whole name (15 characters maximum)
70  (this indicates the end of the name)
+

Unknown Field

+

All items have this field between the personalization (if it exists) and the +item-specific data:

+ + + + + + + + + + + +
SizeContents
1unknown; this usually is 0, but is 1 on a Tome of Identify. + (It's still 0 on a Tome of Townportal.)
+

Item Structure part 3: Item-Specific Data

+

The presence of the following fields depends on the item type. Fields +which are present will be stored in the order shown. Unfortunately there +is no means of telling which fields are present from the item data itself; you +need to look up the item +type in a table to figure out whether it is a weapon, armor, or stack, and +read the fields accordingly.

+

Armor: Defense Rating

+ + + + + + + + + + + +
SizeContents
10Defense value +10. i.e., a defense rating of 23 would be + stored in this field as 33; thus the maximum defense value you can store + is 1013 (although I haven't tried it). Note that this is the base + defense rating, before applying any magical enhancements (i.e., the number + shown in white).
+

Armor and Weapons: Durability

+

Even though stacked weapons don't show any durability rating in the game, +they still have two 8-bit fields in the same spot. This includes bombs +(exploding and gas potions). The values in such cases are very small, so +I'm not sure what they mean.

+ + + + + + + + + + + + + + + +
SizeContents
8Maximum Durability. Note that this is the base durability, + before applying any magical enhancements (i.e., the number shown in + white).
Note: I've found an indestructable item, and it appears + that in such a case the maximum durability field is zero!
8Current Durability. This may be greater than the maximum + durability if the item is magically enhanced.
Note: I've found + an indestructable item, and it appears that in such a case the current + durability field is missing!
+

Armor and (non-stacked) Weapons: Sockets

+

The following field is present if and only if the item is socketed (i.e., bit +27 is set).

+ + + + + + + + + + + + +
SizeContents
4Number of sockets
Note that even though this field is 4 bits + wide, each item type has a built-in upper limit to the total number of + sockets. This limit is built into the game. The most I've ever + seen is 6 for, e.g., a gothic axe.
+

Tomes:

+

Tomes have an extra 5 bits inserted at this point. I have no idea what +purpose they serve. It looks like the value is 0 on all of my tomes.

+ + + + + + + + + + + +
SizeContents
5unknown
+

Stacked Weapons, Quivers, Keys, and Tomes: Quantity

+ + + + + + + + + + + +
SizeContents
9Quantity
+

Item Structure part 3: Magical Enhancements

+

Item Structure part 2bis: Set Item Data +Revisited

+

Items which are part of a set have an additional 5 bits following the +item-specific data.

+ + + + + + + + + + + +
SizeContents
5This appears to be an indicator of how many lists of magic properties + follows. The first list are the properties the item has if you do + not have any other members of the set. Following lists are applied + once you equip other items in the set. The value is 1 if there are + two (total) property lists, or 3 if there are three property lists.
+

Following the item-specific data are a variable number of variable length bit +fields describing any magical enhancements placed on the item. Each +property begins with a 9-bit identifier. An identifier of 0x1FF +(all 1's) indicates the end of the property list ... except in the event the +item belongs to a set, in which case there will be another one or two groups of +magical properties following, depending on whether the set item data (above) is +1 or 3, respectively. Also, if an item has been given a Rune +Word, it appears that the Rune Word's properties begin with a 0x1FF +identifier (presumably to set them apart from the item's normal properties... +but I need to examine more items to be certain.)

+

Because the number of bits (and fields) after the 9-bit identifier varies, I +do not give a field width here. Instead, check my table +of magic properties for field sizes. I'm sure it's not complete, but +it does have most of the common properties.

+

Following the last 9-bit value of 0x1FF, the rest of the final byte will be +padded with 0's if necessary, and the item structure ends there. For +example, if the item had 341 bits of data, the last (43rd) byte will +be 0x1F. If the item had 248 bits of data, the last (31st) byte +will be 0xFF.

+ + diff --git a/docs/d2s_save_item_format_1.13d.txt b/docs/d2s_save_item_format_1.13d.txt new file mode 100644 index 0000000..edd7e63 --- /dev/null +++ b/docs/d2s_save_item_format_1.13d.txt @@ -0,0 +1,802 @@ +------------------------------------------------------------------------------- +originally extracted from here: +http://www.coreyh.org/diablo-2-files/documentation/d2s_save_item_format_1.13d.html +------------------------------------------------------------------------------- + + + Diablo II Item Format + + for Diablo II v1.13d Expansion Set: Lord of Destruction + + Updated June 23, 2012 + +This file was originally written by Trevin Beattie, whose site is no more (his +latest version of this file is available here though). + +Welcome! + +Thanks for showing an interest in my Diablo II Item Format page. While you're +browsing, be sure to check out the preview of my game editor for unix+Motif. I +currently have the item editor in development! + +Introduction + +Having searched the web, I found very few references to the Diablo II .d2s file +format, and most of them covered the old (pre-1.08) version. Diablo II v1.09 +has significantly changed the file format. I have started another page which +details the layout of the major parts of the .d2s file. This document focuses +specifically on the item structure — all those pieces of the file tagged "JM". + +Rather than describe everything in terms of byte offsets, I'm going to define +the layout as a series of variable-length bit fields. This is a critical part +of the item format, because the position of many of the fields can change +depending on what comes before it. If I say a certain value is a 3-bit field +starting at bit position 150, for example, this translates to bits 6 and 7 of +the byte 18 and bit 0 of byte 19 in the data structure. You can read an +arbitrary bit field programatically using the following code (in C): + +#define read_bits(start,size) \ + ((*((unsigned long *) &data[(start) / 8]) + >> ((start) & 7)) & ((1 << (size)) - 1)) + +Item List Header + +An item list begins with the following simple header: + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Byte │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│0 │2 chars│Identifier string "JM" { 0x4A, 0x4D } │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │The number of items your character has. This does not │ +│2 │16 bits│include gems or jewels which have been glued into socketed │ +│ │ │items. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +Your item list ends with another 4-byte structure similar to the above, except +the second field is zero (i.e., { 0x4A, 0x4D, 0x00, 0x00 }). + +In the Expansion Set, your hireling has his/her own item list. This list is +separated from yours by the 2-character identifier "jf". This is followed by an +item list header for the hireling, and then his/her items. The second item list +is not terminated with the same 4-byte structure as the first; instead, it is +followed by the 2-character identifier "kf". + +Item Structure part 1: Simple Items + +There are still many fields in the item structure which I haven't figured out +yet, but I'll leave placeholders for them in case I find out what they mean in +the future. All sizes are in bits unless otherwise specified. + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Bit │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│0 │2 chars│Identifier string "JM" { 0x4A, 0x4D } │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│16 │4 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│20 │1 │Item has been identified │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│21 │6 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│27 │1 │Item is Socketed │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│28 │1 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│29 │1 │This bit is set on items which you have picked up since the │ +│ │ │last time the game was saved. Why?... │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│30 │2 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│32 │1 │Item is a Player Ear │ +│ │ │Thanks go to Mike of Denmark for identifying this bit. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │"Newbie" item. This bit is set on the weapon and shield your│ +│33 │1 │character is given when you start the game. Apparently, this│ +│ │ │gives the item the property of having a repair cost of 1gp, │ +│ │ │as well as a sell value of 1gp. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│34 │3 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Item is simple (only 111 bits {14 bytes} of item data) │ +│37 │1 │Thanks go to Guillaume Courtin of France for discovering the│ +│ │ │meaning of this bit. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│38 │1 │Item is Ethereal (Cannot be Repaired) │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│39 │1 │unknown; this bit is 1 on the items I've looked at │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│40 │1 │Item has been personalized (by Anya in Act V) │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│41 │1 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│42 │1 │It looks like this bit indicates the item has been given a │ +│ │ │Rune Word. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│43 │15 │unknown; some of these bits may be set │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Item location. Actually, I have only seen a few values for │ +│ │ │these bits, so I'm not 100% certain of its validity. If you │ +│ │ │see any other value here, let me know what it is and where │ +│ │ │the item is located. │ +│ │ │┌───────────┬──────────────────────────────────┐ │ +│ │ ││0 │Item is stored (see bit field 73) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││1 │Item is equipped (somewhere on │ │ +│58 │3 ││ │your body) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││2 │Item is tucked in your belt (or │ │ +│ │ ││ │sash) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││4 │Item is being moved (i.e., has │ │ +│ │ ││ │been picked up by the mouse). │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││6 │Item is glued into a socket. │ │ +│ │ │└───────────┴──────────────────────────────────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │If the item is equipped, this field tells where it is. │ +│ │ │Possible values are: │ +│ │ │┌───────────┬──────────────────────────────────┐ │ +│ │ ││1 │head (helmet) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││2 │neck (amulet) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││3 │torso (armor) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││4 │right hand (weapon) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││5 │left hand (shield) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││6 │right finger (ring) │ │ +│61 │4 │├───────────┼──────────────────────────────────┤ │ +│ │ ││7 │left finger (ring) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││8 │waist (belt) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││9 │feet (boots) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││10 │hands (gloves) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││11 │alternate right hand (Expansion │ │ +│ │ ││ │Set only) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││12 │alternate left hand (Expansion Set│ │ +│ │ ││ │only) │ │ +│ │ │└───────────┴──────────────────────────────────┘ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Column number of the left corner of the item, counting from │ +│ │ │0. Your inventory has ten columns (numbered 0-9), your stash│ +│ │ │has six, and the Horadric Cube has four. │ +│ │ │ │ +│ │ │Note: Your belt is considered (for the purposes of the item │ +│ │ │format) to have no rows, but either 4, 8, 12, or 16 columns.│ +│65 │4 │If you prefer, you can divide this field and use the 2 bits │ +│ │ │at position 67-68 for the row (but only for belts). │ +│ │ │ │ +│ │ │Note 2: If the item is equipped, glued to a socket, or in │ +│ │ │transit, then this field appears to contain old data from │ +│ │ │the last time the item was stored. I.e., it may be non-zero,│ +│ │ │but the value is unused. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Row number of the top of the item, counting from 0. Your │ +│ │ │inventory has four rows (numbered 0-3), your stash has four │ +│ │ │in normal characters or eight in Expansion Set characters, │ +│ │ │and the Horadric Cube has four. (In the belt, this field is │ +│69 │3 │always zero.) │ +│ │ │ │ +│ │ │Note: If the item is equipped, tucked in your belt, glued to│ +│ │ │a socket, or in transit, then this field appears to contain │ +│ │ │old data from the last time the item was stored. I.e., it │ +│ │ │may be non-zero, but the value is unused. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│72 │1 │unknown │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Actually, bit 74 seems to always be 0, but since bits 73 and│ +│ │ │75 are related I just lump them all together. If the item is│ +│ │ │neither equipped nor in your belt, this field tells where it│ +│ │ │is. Possible values are: │ +│ │ │┌───────────┬──────────────────────────────────┐ │ +│ │ ││0 │not here (check bit field 58) │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│73 │3 ││1 │inventory │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││4 │Horadric Cube │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││5 │stash │ │ +│ │ │└───────────┴──────────────────────────────────┘ │ +│ │ │If you find an item having any other value in this field, │ +│ │ │let me know what the value is and the item's location! │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Item's type. The type is 3 lower-case letters or numbers │ +│ │ │followed by a space; e.g., "amu " (Amulet) or "2hs " │ +│ │4 chars│(Two-Handed Sword). I have started a list of item │ +│76 │(8 bits│identifiers (not posted; sorry), but it is by no means │ +│ │ea.) │complete; I'm sure I don't even have half of what's out │ +│ │ │there! │ +│ │ │Warning: This field is not byte-aligned! It starts in the │ +│ │ │middle of byte 9 and runs to the middle of byte 13. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │The number of gems (or skulls or jewels) which have been │ +│ │ │glued to this item (if socketed). There will be this many │ +│108 │3 │additional item structures for the gems immediately │ +│ │ │following this item, in the order that the gems were │ +│ │ │inserted. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +Item Variant: Player Ears + +The following information was provided by Mike of Denmark. + +If the item is a Player Ear, its structure is slightly different than the +Simple Items above. The last two fields in the Simple Item structure are +replaced by the following: + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Bit │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Character class of the ear's former owner. The defined │ +│ │ │classes are: │ +│ │ │ 0 Amazon │ +│ │ │ 1 Sorceress │ +│76 │3 │ 2 Necromancer │ +│ │ │ 3 Paladin │ +│ │ │ 4 Barbarian │ +│ │ │ 5 Druid (Expansion character only) │ +│ │ │ 6 Assassin (Expansion character only) │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│79 │7 │Character level of the ear's former owner. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│86 │7 │First character of the former owner's name. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│93 │7 × N-1│Second character of the former owner's name; Repeat until │ +│ │ │you get the whole name (15 characters maximum). │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│86 + 7 ×│7 │0 (this indicates the end of the name) │ +│N │ │ │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + +Following the end of the name, the rest of the final byte will be padded with +0's if necessary, and the Player Ear structure ends there. + +Item Structure part 2: Extended Items + +By "extended items" I mean any items which are not simple. Simple items are +those which need no further information than that given above — such as gems, +potions, and small quest items — and their structure length is fixed at 14 +bytes. Everything else has an extended structure with a possibly variable +length set of bit fields. First, I'll describe the part of the structure that +appears to be the same for all extended items. From that point on, there will +be no more "bit positions"; only "this field follows that field, if it exists". + +┌────────┬───────┬────────────────────────────────────────────────────────────┐ +│ Bit │ Size │ Contents │ +│Position│ │ │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Unique identifier. Diablo II randomly generates a value for │ +│ │ │this field in order to discourage cheaters from "duping" │ +│111 │32 │items. Supposedly, if it detects more than one extended item│ +│ │ │with the same unique Id, it will delete the duplicates. (It │ +│ │ │hasn't done that for me in single player mode, though.) │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │This appears to be the item's level; i.e., the level with │ +│ │ │which the item was created (or 'dropped'). The item level is│ +│ │ │based on the level of the monster who dropped it, the level │ +│143 │7 │of the area you're in if found in a chest, or, in rare │ +│ │ │cases, your characters level. The item level determines what│ +│ │ │modifiers are allowed on the item. │ +│ │ │Note: this is just a theory at this point, but it seems to │ +│ │ │hold for the items I've examined. │ +├────────┼───────┼────────────────────────────────────────────────────────────┤ +│ │ │Item quality. This field can be one of the following values,│ +│ │ │which determines the quality-specific bit fields that │ +│ │ │follow: │ +│ │ │┌───────────┬──────────────────────────────────┐ │ +│ │ ││1 │low quality │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││2 │normal │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││3 │high quality │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│150 │4 ││4 │magically enhanced │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││5 │part of a set │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││6 │rare │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││7 │unique │ │ +│ │ │├───────────┼──────────────────────────────────┤ │ +│ │ ││8 │crafted │ │ +│ │ │└───────────┴──────────────────────────────────┘ │ +│ │ │Thanks go to Guillaume Courtin of France for finding the │ +│ │ │value of crafted items. │ +└────────┴───────┴────────────────────────────────────────────────────────────┘ + + WARNING: DATA BELOW THIS POINT MAY CONTAIN ERRORS + +Ring Data + +After the above data, if the item is a ring, amulet, jewel, or charm, then it +has a 1 bit followed by three more bits. All other items (that I've seen) have +just a single 0 bit. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │If this bit is set, the item has one of multiple pictures │ +│ │associated with it; the next field determines which picture a│ +│1 │particular item uses. If this bit is 0, the next field is │ +│ │absent. The picture field is used for rings, amulets, jewels,│ +│ │and charms. │ +├───────────────┼───────────────────────────────────┬─────────────────────────┤ +│ │Picture. Optional; only present if │ │ +│3 │the previous bit is 1. This field │[Ring_of_the_Leech] │ +│ │chooses the particular graphic used│ │ +│ │to display the ring. │ │ +└───────────────┴───────────────────────────────────┴─────────────────────────┘ + +From this point on, my information is very iffy. + +Unknown Field + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │This bit apparently is set for certain class-specific │ +│1 │Expansion Set items. It indicates the presence of the next │ +│ │11-bit field. If this bit is 0, the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Credit for the discovery of this field's meaning goes │ +│ │entirely to Guillaume Courtin of France. Thanks! │ +│ │This field indicates magic properties which are inherent in │ +│ │certain class-specific items. A given class-specific item │ +│ │will (almost) always start with the same set of properties, │ +│ │even if its quality is "normal". Other quality ratings may │ +│11 │add more properties to the standard set. It appears that │ +│ │items which will have this field are: │ +│ │ │ +│ │ • Amazon-only bows, spears, and javelins │ +│ │ • Voodoo heads (Necromancer-only shields) │ +│ │ • Paladin-only shields │ +│ │ • Orbs (Sorceress-Only wands) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Low Quality Item Data + +If the item is one of low quality, it has 3 more bits that give the quality +details: + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼────────────────────────────────────┬────────────────────────┤ +│ │Quality: │ │ +│ │┌──────┬───────────────────┐ │ │ +│ ││0 │Crude │ │ │ +│ │├──────┼───────────────────┤ │ │ +│ ││1 │Cracked │ │ │ +│ │├──────┼───────────────────┤ │ │ +│ ││2 │Damaged │ │ │ +│ │├──────┼───────────────────┤ │ │ +│3 ││3 │Low Quality │ │[Crude_Heavy_Boots] │ +│ │└──────┴───────────────────┘ │ │ +│ │I haven't recorded any instances of │ │ +│ │other values, but that doesn't mean │ │ +│ │there won't be any. Also, I'm │ │ +│ │certain the value has something to │ │ +│ │do with mods on an item's inherent │ │ +│ │(non-recorded) properties, such as │ │ +│ │weapon damage, but I haven't figured│ │ +│ │out yet what the correlation is. │ │ +└───────────────┴────────────────────────────────────┴────────────────────────┘ + +Normal Item Data + +Normal items have no extra quality data. + +High Quality ("Superior") Item Data + +If the item is one of high quality, it has 3 additional bits. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │unknown. I'm certain the value has something to do with mods │ +│3 │on an item's inherent (non-recorded) properties, such as │ +│ │weapon damage, but I haven't figured out yet what the │ +│ │correlation is. │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Magically Enhanced Item Data + +[Sturdy_Spi] Magically enhanced items have two 11-bit fields representing the +item's prefix and suffix. Either one (but not both) may be omitted. The prefix +and suffix each are used in choosing the magical enhancements for an item +(although the enhancements are modifiable), and can also increase the minimum +level required to use them item and affect the item's color. + +[Mesh_Belt_] +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Item prefix (i.e., "Gold" or "Tangerine"). I've started a │ +│11 │list of prefix identifiers, but it is very sparse at this │ +│ │time. If this field is 0, the item has no prefix. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Item suffix (i.e., "of Greed" or "of Life"). I've started a │ +│11 │list of suffix identifiers, but it is very sparse at this │ +│ │time. If this field is 0, the item has no suffix. │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Set Item Data + +Set items have a 12-bit field containing the ID of the set. (Not the set +member, but the whole set.) The set member is identified by cross-referencing +the item type with the set Id. Also note that set items have an extra field +following the item-specific data. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────┬───────────────────────────────────┤ +│ │Set identifier; i.e., all│ │ +│ │items which are part of │ │ +│ │the set will have the │ │ +│ │same value in this field.│ │ +│ │Since I've only │ │ +│ │identified a few set │ │ +│ │items, I'll give their │ │ +│ │ID's here: │ │ +│ │┌────┬─────────────┐ │ │ +│ ││2 │Cleglaw's │ │ │ +│ ││ │Brace │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││3 │Iratha's │ │ │ +│ ││ │Finery │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││4 │Isenhart's │ │ │ +│12 ││ │Armory │ │[Deaths_Hand_Leather_Gloves] │ +│ │├────┼─────────────┤ │ │ +│ ││6 │Milabrega's │ │ │ +│ ││ │Regalia │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││7 │Cathan's │ │ │ +│ ││ │Traps │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││11 │Berserker's │ │ │ +│ ││ │Arsenal │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││12 │Death's │ │ │ +│ ││ │Disguise │ │ │ +│ │├────┼─────────────┤ │ │ +│ ││13 │Angelic │ │ │ +│ ││ │Raiment │ │ │ +│ │└────┴─────────────┘ │ │ +└───────────────┴─────────────────────────┴───────────────────────────────────┘ + +Rare Item Data + +[Loath_Song_Battle_Axe] This is by far the worst beast to decode. Rare items +have a variable number of bits before we get to the item contents, and this +number can vary anywhere from 55 to 88! + +[Eagle_Mark_Amulet] Update 3/14/2002: EUREKA!! I've finally figured out the +variable fields!; See the table below. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│8 │This is the Id for the first word of the item's name (i.e., │ +│ │"Stone" or "Doom"). │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│8 │This is the ID for the second word of the item's name (i.e., │ +│ │"Finger" or "Shroud"). │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │First magic prefix (optional). Although this "prefix" isn't │ +│11 │actually shown in the item name, it is used in determining │ +│ │the magical properties, required level, coloring, and other │ +│ │attributes of the rare item. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │First magic suffix (optional). Although this "suffix" isn't │ +│11 │actually shown in the item name, it is used in determining │ +│ │the magical properties, required level, coloring, and other │ +│ │attributes of the rare item. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Second magic prefix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Second magic suffix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Third magic prefix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Third magic suffix (optional) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Unique Item Data + +Unique items have an additional 12 bit field, which in most cases is the unique +item ID. The few exceptions are certain quest items (e.g., the Horadric Malus). + +┌──────────────┬─────────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├──────────────┼─────────────────────┬───────────────────────────────────────────┤ +│ │Item identifier. │ │ +│ │Since I've only │ │ +│ │identified a few │ │ +│ │unique items, I'll │ │ +│ │give their ID's │ │ +│ │here: │ │ +│ │┌───────┬───────────┐│ │ +│ ││ │Ume's ││ │ +│ ││13 │Lament Grim││ │ +│ ││ │Wand ││ │ +│ │├───────┼───────────┤│ │ +│ ││31 │Hellplague ││ │ +│ ││ │Long Sword ││ │ +│ │├───────┼───────────┤│ │ +│ ││75 │Wormskull ││ │ +│ ││ │Bone Helm ││ │ +│ │├───────┼───────────┤│ │ +│ ││ │Undead ││ │ +│ ││ │Crown Crown││ │ +│ ││77 │(no, that ││ │ +│ ││ │is not a ││ │ +│ ││ │typo!) ││ │ +│12 │├───────┼───────────┤│[Hellplague] │ +│ ││ │Goldskin ││ │ +│ ││91 │Full Plate ││ │ +│ ││ │Mail ││ │ +│ │├───────┼───────────┤│ │ +│ ││ │Nagelring ││ │ +│ ││ │Ring (not a││ │ +│ ││120 │typo ││ │ +│ ││ │either; I ││ │ +│ ││ │checked) ││ │ +│ │├───────┼───────────┤│ │ +│ ││123 │Amulet of ││ │ +│ ││ │the Viper ││ │ +│ │├───────┼───────────┤│ │ +│ ││125 │Horadric ││ │ +│ ││ │Staff ││ │ +│ │├───────┼───────────┤│ │ +│ ││126 │Hell Forge ││ │ +│ ││ │Hammer ││ │ +│ │├───────┼───────────┤│ │ +│ ││4095 │(other; ││ │ +│ ││(0xFFF)│probably a ││ │ +│ ││ │quest item)││ │ +│ │└───────┴───────────┘│ │ +└──────────────┴─────────────────────┴───────────────────────────────────────────┘ + +Crafted Item Data + +Crafted items appear to be coded exactly like rare items, having a rare name +(two parts) and six optional prefixes / suffixes. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│8 │This is the Id for the first word of the item's name (i.e., │ +│ │"Stone" or "Doom"). │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│8 │This is the Id for the second word of the item's name (i.e., │ +│ │"Finger" or "Shroud"). │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │First magic prefix (optional). Although this "prefix" isn't │ +│11 │actually shown in the item name, it is used in determining │ +│ │the magical properties, required level, coloring, and other │ +│ │attributes of the crafted item. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │First magic suffix (optional). Although this "suffix" isn't │ +│11 │actually shown in the item name, it is used in determining │ +│ │the magical properties, required level, coloring, and other │ +│ │attributes of the crafted item. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Second magic prefix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Second magic suffix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Third magic prefix (optional) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │If this field is 1, the next 11-bit field is present. If 0, │ +│ │the next field is absent. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│11 │Third magic suffix (optional) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Rune Word + +If the item has a rune word (indicated by bit 42 being set), there is an +additional field at this point. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │This appears to be an index to the rune word, although I │ +│12 │can't say what the index is based on. The first rune word, │ +│ │"Ancient's Pledge", has a value of 27. The next rune word, │ +│ │"Black", has a value of 32. etc. │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│4 │Unknown; the value is 5 on all items I've looked at. │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Personalization + +The following segment is present if and only if the item is personalized (i.e., +bit 40 is set). Only armor and weapons (except for quest items) can be +personalized. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│7 │First character of the owner's name (just plain ASCII!) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│7 │Second character of the owner's name │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│7 × N-2 │Repeat until you get the whole name (15 characters maximum) │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│7 │0 (this indicates the end of the name) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Unknown Field + +All items have this field between the personalization (if it exists) and the +item-specific data: + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│1 │unknown; this usually is 0, but is 1 on a Tome of Identify. │ +│ │(It's still 0 on a Tome of Townportal.) │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Item Structure part 3: Item-Specific Data + +The presence of the following fields depends on the item type. Fields which are +present will be stored in the order shown. Unfortunately there is no means of +telling which fields are present from the item data itself; you need to look up +the item type in a table to figure out whether it is a weapon, armor, or stack, +and read the fields accordingly. + +Armor: Defense Rating + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Defense value +10. i.e., a defense rating of 23 would be │ +│ │stored in this field as 33; thus the maximum defense value │ +│10 │you can store is 1013 (although I haven't tried it). Note │ +│ │that this is the base defense rating, before applying any │ +│ │magical enhancements (i.e., the number shown in white). │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Armor and Weapons: Durability + +Even though stacked weapons don't show any durability rating in the game, they +still have two 8-bit fields in the same spot. This includes bombs (exploding +and gas potions). The values in such cases are very small, so I'm not sure what +they mean. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Maximum Durability. Note that this is the base durability, │ +│ │before applying any magical enhancements (i.e., the number │ +│8 │shown in white). │ +│ │Note: I've found an indestructable item, and it appears that │ +│ │in such a case the maximum durability field is zero! │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │Current Durability. This may be greater than the maximum │ +│8 │durability if the item is magically enhanced. │ +│ │Note: I've found an indestructable item, and it appears that │ +│ │in such a case the current durability field is missing! │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Armor and (non-stacked) Weapons: Sockets + +The following field is present if and only if the item is socketed (i.e., bit +27 is set). + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼───────────────────────────────────┬─────────────────────────┤ +│ │Number of sockets │ │ +│ │Note that even though this field is│ │ +│ │4 bits wide, each item type has a │ │ +│4 │built-in upper limit to the total │[Socketed_Mask] │ +│ │number of sockets. This limit is │ │ +│ │built into the game. The most I've │ │ +│ │ever seen is 6 for, e.g., a gothic │ │ +│ │axe. │ │ +└───────────────┴───────────────────────────────────┴─────────────────────────┘ + +Tomes: + +Tomes have an extra 5 bits inserted at this point. I have no idea what purpose +they serve. It looks like the value is 0 on all of my tomes. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│5 │unknown │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Stacked Weapons, Quivers, Keys, and Tomes: Quantity + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│9 │Quantity │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Item Structure part 3: Magical Enhancements + +Item Structure part 2^bis: Set Item Data Revisited + +Items which are part of a set have an additional 5 bits following the +item-specific data. + +┌───────────────┬─────────────────────────────────────────────────────────────┐ +│ Size │ Contents │ +├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │This appears to be an indicator of how many lists of magic │ +│ │properties follows. The first list are the properties the │ +│5 │item has if you do not have any other members of the set. │ +│ │Following lists are applied once you equip other items in the│ +│ │set. The value is 1 if there are two (total) property lists, │ +│ │or 3 if there are three property lists. │ +└───────────────┴─────────────────────────────────────────────────────────────┘ + +Following the item-specific data are a variable number of variable length bit +fields describing any magical enhancements placed on the item. Each property +begins with a 9-bit identifier. An identifier of 0x1FF (all 1's) indicates the +end of the property list ... except in the event the item belongs to a set, in +which case there will be another one or two groups of magical properties +following, depending on whether the set item data (above) is 1 or 3, +respectively. Also, if an item has been given a Rune Word, it appears that the +Rune Word's properties begin with a 0x1FF identifier (presumably to set them +apart from the item's normal properties... but I need to examine more items to +be certain.) + +Because the number of bits (and fields) after the 9-bit identifier varies, I do +not give a field width here. Instead, check my table of magic properties for +field sizes. I'm sure it's not complete, but it does have most of the common +properties. + +Following the last 9-bit value of 0x1FF, the rest of the final byte will be +padded with 0's if necessary, and the item structure ends there. For example, +if the item had 341 bits of data, the last (43^rd) byte will be 0x1F. If the +item had 248 bits of data, the last (31^st) byte will be 0xFF. + diff --git a/docs/d2s_save_skills_format_1.13d.txt b/docs/d2s_save_skills_format_1.13d.txt new file mode 100644 index 0000000..0117eb3 --- /dev/null +++ b/docs/d2s_save_skills_format_1.13d.txt @@ -0,0 +1,310 @@ +------------------------------------------------------------------------------- +originally extracted from here: +http://www.coreyh.org/diablo-2-files/documentation/d2s_save_skills_format_1.13d.html +------------------------------------------------------------------------------- + + + Diablo II Character Skills + +Well, I did say I would list the character skills in a separate table, and I +guess I've put it off long enough. So here it is! + +There are two numbers shown for each character skill. One is the offset into +the character skills section of the saved character file. The other is the +skill ID used in some of the magical properties (i.e., "+2 to Bash (Barbarian +Only)", "level 3 Fire Bolt (33/33 Charges)", etc.), and in the button actions. +The common skill ID's are only used in button actions. + +┌────────────────────────────────────────────────────────────────────────────┐ +│ Common Skills │ +├──────────────────────┬───┬──────────────────────┬───┬──────────────────────┤ +│┌────┬───────────────┐│ │┌────┬───────────────┐│ │┌───┬────────────────┐│ +││ ID │ Skill ││ ││ ID │ Skill ││ ││ID │ Skill ││ +│├────┼───────────────┤│ │├────┼───────────────┤│ │├───┼────────────────┤│ +││0 │Attack ││ ││3 │Unsummon ││ ││217│Scroll of ││ +│├────┼───────────────┤│ │├────┼───────────────┤│ ││ │Identify ││ +││1 │Kick ││ ││4 │Left Hand Throw││ │├───┼────────────────┤│ +│├────┼───────────────┤│ │├────┼───────────────┤│ ││218│Tome of Identify││ +││2 │Throw ││ ││5 │Left Hand Swing││ │├───┼────────────────┤│ +│└────┴───────────────┘│ │└────┴───────────────┘│ ││219│Scroll of Town ││ +│ │ │ │ ││ │Portal ││ +│ │ │ │ │├───┼────────────────┤│ +│ │ │ │ ││220│Tome of Town ││ +│ │ │ │ ││ │Portal ││ +│ │ │ │ │└───┴────────────────┘│ +└──────────────────────┴───┴──────────────────────┴───┴──────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Amazon Skills │ +├───────────────────────────────────────┬───┬──────────────────────────────────────┬───┬──────────────────────────────────────┤ +│┌─────────────────────────────────────┐│ │┌────────────────────────────────────┐│ │┌────────────────────────────────────┐│ +││ Bow and Crossbow Skills ││ ││ Passive and Magic Skills ││ ││ Javelin and Spear Skills ││ +│├────┬───┬──────────┬───┬─────────────┤│ │├────┬──┬──────────┬───┬─────────────┤│ │├────┬──┬──────────┬───┬─────────────┤│ +││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID│ Skill │Lvl│Prerequisites││ ││Off.│ID│ Skill │Lvl│Prerequisites││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ +││0 │6 │Magic │1 │ ││ ││2 │8 │Inner │1 │ ││ ││4 │10│Jab │1 │ ││ +││ │ │Arrow │ │ ││ ││ │ │Sight │ │ ││ │├────┼──┼──────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ ││8 │14│Power │6 │Jab ││ +││1 │7 │Fire Arrow│1 │ ││ ││3 │9 │Critical │1 │ ││ ││ │ │Strike │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Strike │ │ ││ │├────┼──┼──────────┼───┼─────────────┤│ +││5 │11 │Cold Arrow│6 │ ││ │├────┼──┼──────────┼───┼─────────────┤│ ││9 │15│Poison │6 │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││7 │13│Dodge │6 │ ││ ││ │ │Javelin │ │ ││ +││6 │12 │Multiple │6 │Magic Arrow ││ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ +││ │ │Shot │ │ ││ ││11 │17│Slow │12 │Inner Sight ││ ││13 │19│Impale │12 │Jab ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Missiles │ │ ││ │├────┼──┼──────────┼───┼─────────────┤│ +││10 │16 │Exploding │12 │Fire Arrow, ││ │├────┼──┼──────────┼───┼─────────────┤│ ││14 │20│Lightning │12 │Poison ││ +││ │ │Arrow │ │Multiple Shot││ ││12 │18│Avoid │12 │Dodge ││ ││ │ │Bolt │ │Javelin ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ +││15 │21 │Ice Arrow │18 │Cold Arrow ││ ││17 │23│Penetrate │18 │Critical ││ ││ │ │Charged │ │Power Strike,││ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │ │ │Strike ││ ││18 │24│Strike │18 │Lightning ││ +││16 │22 │Guided │18 │Cold Arrow, ││ │├────┼──┼──────────┼───┼─────────────┤│ ││ │ │ │ │Bolt ││ +││ │ │Arrow │ │Multiple Shot││ ││22 │28│Dopplezon │24 │Slow Missiles││ │├────┼──┼──────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ ││19 │25│Plague │18 │Lightning ││ +││20 │26 │Strafe │24 │Guided Arrow ││ ││23 │29│Evade │24 │Avoid ││ ││ │ │Javelin │ │Bolt ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ +││21 │27 │Immolation│24 │Exploding ││ ││26 │32│Valkyrie │30 │Dopplezon, ││ ││24 │30│Fend │24 │Impale ││ +││ │ │Arrow │ │Arrow ││ ││ │ │ │ │Evade ││ │├────┼──┼──────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ ││28 │34│Lightning │30 │Charged ││ +││25 │31 │Freezing │30 │Ice Arrow ││ ││27 │33│Pierce │30 │Penetrate ││ ││ │ │Strike │ │Strike ││ +││ │ │Arrow │ │ ││ │└────┴──┴──────────┴───┴─────────────┘│ │├────┼──┼──────────┼───┼─────────────┤│ +│└────┴───┴──────────┴───┴─────────────┘│ │ │ ││29 │35│Lightning │30 │Plague ││ +│ │ │ │ ││ │ │Fury │ │Javelin ││ +│ │ │ │ │└────┴──┴──────────┴───┴─────────────┘│ +└───────────────────────────────────────┴───┴──────────────────────────────────────┴───┴──────────────────────────────────────┘ + +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Sorceress Skills │ +├────────────────────────────────────┬───┬────────────────────────────────────────┬───┬─────────────────────────────────────┤ +│┌──────────────────────────────────┐│ │┌──────────────────────────────────────┐│ │┌───────────────────────────────────┐│ +││ Fire Spells ││ ││ Lightning Spells ││ ││ Cold Spells ││ +│├────┬──┬────────┬───┬─────────────┤│ │├────┬───┬───────────┬───┬─────────────┤│ │├────┬──┬─────────┬───┬─────────────┤│ +││Off.│ID│ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID│ Skill │Lvl│Prerequisites││ +│├────┼──┼────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +││0 │36│Fire │1 │ ││ ││2 │38 │Charged │1 │ ││ ││3 │39│Ice Bolt │1 │ ││ +││ │ │Bolt │ │ ││ ││ │ │Bolt │ │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +│├────┼──┼────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ ││4 │40│Frozen │1 │ ││ +││1 │37│Warmth │1 │ ││ ││6 │42 │Static │6 │ ││ ││ │ │Armor │ │ ││ +│├────┼──┼────────┼───┼─────────────┤│ ││ │ │Field │ │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +││5 │41│Inferno │6 │ ││ │├────┼───┼───────────┼───┼─────────────┤│ ││8 │44│Frost │6 │ ││ +│├────┼──┼────────┼───┼─────────────┤│ ││7 │43 │Telekinesis│6 │ ││ ││ │ │Nova │ │ ││ +││10 │46│Blaze │12 │Inferno ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +│├────┼──┼────────┼───┼─────────────┤│ ││12 │48 │Nova │12 │Static Field ││ ││9 │45│Ice Blast│6 │Ice Bolt ││ +││11 │47│Fire │12 │Fire Bolt ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │Ball │ │ ││ ││13 │49 │Lightning │12 │Charged Bolt ││ ││14 │50│Shiver │12 │Ice Blast, ││ +│├────┼──┼────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Armor │ │Frozen Armor ││ +││15 │51│Fire │18 │Blaze ││ ││17 │53 │Chain │18 │Lightning ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │Wall │ │ ││ ││ │ │Lightning │ │ ││ ││19 │55│Glacial │18 │Ice Blast ││ +│├────┼──┼────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Spike │ │ ││ +││16 │52│Enchant │18 │Warmth, ││ ││18 │54 │Teleport │18 │Telekinesis ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │ │ │Fire Ball ││ │├────┼───┼───────────┼───┼─────────────┤│ ││23 │59│Blizzard │24 │Frost Nova, ││ +│├────┼──┼────────┼───┼─────────────┤│ ││ │ │Thunder │ │Nova, ││ ││ │ │ │ │Glacial Spike││ +││20 │56│Meteor │24 │Fire Ball, ││ ││21 │57 │Storm │24 │Chain ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │ │ │Fire Wall ││ ││ │ │ │ │Lightning ││ ││24 │60│Chilling │24 │Shiver Armor ││ +│├────┼──┼────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Armor │ │ ││ +││25 │61│Fire │30 │ ││ ││ │ │Energy │ │Teleport, ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │Mastery │ │ ││ ││22 │58 │Shield │24 │Chain ││ ││28 │64│Frozen │30 │Blizzard ││ +│├────┼──┼────────┼───┼─────────────┤│ ││ │ │ │ │Lightning ││ ││ │ │Orb │ │ ││ +││26 │62│Hydra │30 │Enchant ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +│└────┴──┴────────┴───┴─────────────┘│ ││27 │63 │Lightning │30 │ ││ ││29 │65│Cold │30 │ ││ +│ │ ││ │ │Mastery │ │ ││ ││ │ │Mastery │ │ ││ +│ │ │└────┴───┴───────────┴───┴─────────────┘│ │└────┴──┴─────────┴───┴─────────────┘│ +└────────────────────────────────────┴───┴────────────────────────────────────────┴───┴─────────────────────────────────────┘ + +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Necromancer Skills │ +├──────────────────────────────────────┬───┬──────────────────────────────────────┬───┬─────────────────────────────────────┤ +│┌────────────────────────────────────┐│ │┌────────────────────────────────────┐│ │┌───────────────────────────────────┐│ +││ Curses ││ ││ Poison and Bone Spells ││ ││ Summoning Spells ││ +│├────┬──┬──────────┬───┬─────────────┤│ │├────┬──┬──────────┬───┬─────────────┤│ │├────┬──┬─────────┬───┬─────────────┤│ +││Off.│ID│ Skill │Lvl│Prerequisites││ ││Off.│ID│ Skill │Lvl│Prerequisites││ ││Off.│ID│ Skill │Lvl│Prerequisites││ +│├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +││0 │66│Amplify │1 │ ││ ││1 │67│Teeth │1 │ ││ ││3 │69│Skeleton │1 │Raise ││ +││ │ │Damage │ │ ││ │├────┼──┼──────────┼───┼─────────────┤│ ││ │ │Mastery │ │Skeleton ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││2 │68│Bone Armor│1 │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +││5 │71│Dim Vision│6 │ ││ │├────┼──┼──────────┼───┼─────────────┤│ ││4 │70│Raise │1 │ ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││7 │73│Poison │6 │ ││ ││ │ │Skeleton │ │ ││ +││6 │72│Weaken │6 │Amplify ││ ││ │ │Dagger │ │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │ │ │Damage ││ │├────┼──┼──────────┼───┼─────────────┤│ ││9 │75│Clay │6 │ ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││8 │74│Corpse │6 │Teeth ││ ││ │ │Golem │ │ ││ +││10 │76│Iron │12 │Amplify ││ ││ │ │Explosion │ │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │Maiden │ │Damage ││ │├────┼──┼──────────┼───┼─────────────┤│ ││13 │79│Golem │12 │Clay Golem ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││12 │78│Bone Wall │12 │Bone Armor ││ ││ │ │Mastery │ │ ││ +││11 │77│Terror │12 │Weaken ││ │├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼─────────┼───┼─────────────┤│ +│├────┼──┼──────────┼───┼─────────────┤│ ││ │ │ │ │Poison ││ ││ │ │Raise │ │Raise ││ +││15 │81│Confuse │18 │Dim Vision ││ ││17 │83│Poison │18 │Dagger, ││ ││14 │80│Skeletal │12 │Skeleton ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││ │ │Explosion │ │Corpse ││ ││ │ │Mage │ │ ││ +││16 │82│Life Tap │18 │Iron Maiden ││ ││ │ │ │ │Explosion ││ │├────┼──┼─────────┼───┼─────────────┤│ +│├────┼──┼──────────┼───┼─────────────┤│ │├────┼──┼──────────┼───┼─────────────┤│ ││19 │85│Blood │18 │Clay Golem ││ +││20 │86│Attract │24 │Confuse ││ ││18 │84│Bone Spear│18 │Corpse ││ ││ │ │Golem │ │ ││ +│├────┼──┼──────────┼───┼─────────────┤│ ││ │ │ │ │Explosion ││ │├────┼──┼─────────┼───┼─────────────┤│ +││21 │87│Decrepify │24 │Terror ││ │├────┼──┼──────────┼───┼─────────────┤│ ││23 │89│Summon │24 │Golem Mastery││ +│├────┼──┼──────────┼───┼─────────────┤│ ││22 │88│Bone │24 │Bone Wall, ││ ││ │ │Resist │ │ ││ +││25 │91│Lower │30 │Life Tap, ││ ││ │ │Prison │ │Bone Spear ││ │├────┼──┼─────────┼───┼─────────────┤│ +││ │ │Resist │ │Decrepify ││ │├────┼──┼──────────┼───┼─────────────┤│ ││24 │90│Iron │24 │Blood Golem ││ +│└────┴──┴──────────┴───┴─────────────┘│ ││26 │92│Poison │30 │Poison ││ ││ │ │Golem │ │ ││ +│ │ ││ │ │Nova │ │Explosion ││ │├────┼──┼─────────┼───┼─────────────┤│ +│ │ │├────┼──┼──────────┼───┼─────────────┤│ ││28 │94│Fire │30 │Iron Golem ││ +│ │ ││27 │93│Bone │30 │Bone Spear ││ ││ │ │Golem │ │ ││ +│ │ ││ │ │Spirit │ │ ││ │├────┼──┼─────────┼───┼─────────────┤│ +│ │ │└────┴──┴──────────┴───┴─────────────┘│ ││ │ │ │ │Raise ││ +│ │ │ │ ││29 │95│Revive │30 │Skeletal ││ +│ │ │ │ ││ │ │ │ │Mage, ││ +│ │ │ │ ││ │ │ │ │Iron Golem ││ +│ │ │ │ │└────┴──┴─────────┴───┴─────────────┘│ +└──────────────────────────────────────┴───┴──────────────────────────────────────┴───┴─────────────────────────────────────┘ + +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Paladin Skills │ +├────────────────────────────────────────┬───┬──────────────────────────────────────────┬───┬────────────────────────────────────────┤ +│┌──────────────────────────────────────┐│ │┌────────────────────────────────────────┐│ │┌──────────────────────────────────────┐│ +││ Combat Skills ││ ││ Offensive Auras ││ ││ Defensive Auras ││ +│├────┬───┬───────────┬───┬─────────────┤│ │├────┬───┬─────────────┬───┬─────────────┤│ │├────┬───┬───────────┬───┬─────────────┤│ +││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││0 │96 │Sacrifice │1 │ ││ ││2 │98 │Might │1 │ ││ ││3 │99 │Prayer │1 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││1 │97 │Smite │1 │ ││ ││6 │102│Holy Fire │6 │Might ││ ││4 │100│Resist Fire│1 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││5 │101│Holy Bolt │6 │ ││ ││7 │103│Thorns │6 │ ││ ││8 │104│Defiance │6 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││10 │106│Zeal │12 │Sacrifice ││ ││12 │108│Blessed Aim │12 │Might ││ ││9 │105│Resist Cold│6 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││11 │107│Charge │12 │Smite ││ ││17 │113│Concentration│18 │Blessed Aim ││ ││13 │109│Cleansing │12 │Prayer ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││15 │111│Vengeance │18 │Zeal ││ ││18 │114│Holy Freeze │18 │Holy Fire ││ ││14 │110│Resist │12 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ ││ │ │Lightning │ │ ││ +││16 │112│Blessed │18 │Holy Bolt ││ ││22 │118│Holy Shock │24 │Holy Freeze ││ │├────┼───┼───────────┼───┼─────────────┤│ +││ │ │Hammer │ │ ││ │├────┼───┼─────────────┼───┼─────────────┤│ ││19 │115│Vigor │18 │Cleansing, ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││23 │119│Sanctuary │24 │Thorns, ││ ││ │ │ │ │Defiance ││ +││20 │116│Conversion │24 │Vengeance ││ ││ │ │ │ │Holy Freeze ││ │├────┼───┼───────────┼───┼─────────────┤│ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────────┼───┼─────────────┤│ ││24 │120│Meditation │24 │Cleansing ││ +││ │ │ │ │Charge, ││ ││26 │122│Fanaticism │30 │Concentration││ │├────┼───┼───────────┼───┼─────────────┤│ +││21 │117│Holy Shield│24 │Blessed ││ │├────┼───┼─────────────┼───┼─────────────┤│ ││28 │124│Redemption │30 │Vigor ││ +││ │ │ │ │Hammer ││ ││27 │123│Conviction │30 │Sanctuary ││ │├────┼───┼───────────┼───┼─────────────┤│ +│├────┼───┼───────────┼───┼─────────────┤│ │└────┴───┴─────────────┴───┴─────────────┘│ ││29 │125│Salvation │30 │ ││ +││ │ │Fist of the│ │Blessed ││ │ │ │└────┴───┴───────────┴───┴─────────────┘│ +││25 │121│Heavens │30 │Hammer, ││ │ │ │ │ +││ │ │ │ │Conversion ││ │ │ │ │ +│└────┴───┴───────────┴───┴─────────────┘│ │ │ │ │ +└────────────────────────────────────────┴───┴──────────────────────────────────────────┴───┴────────────────────────────────────────┘ + +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Barbarian Skills │ +├────────────────────────────────────────┬───┬────────────────────────────────────────┬───┬──────────────────────────────────────┤ +│┌──────────────────────────────────────┐│ │┌──────────────────────────────────────┐│ │┌────────────────────────────────────┐│ +││ Combat Skills ││ ││ Combat Masteries ││ ││ Warcries ││ +│├────┬───┬───────────┬───┬─────────────┤│ │├────┬───┬───────────┬───┬─────────────┤│ │├────┬───┬─────────┬───┬─────────────┤│ +││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││0 │126│Bash │1 │ ││ ││1 │127│Sword │1 │ ││ ││4 │130│Howl │1 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Mastery │ │ ││ │├────┼───┼─────────┼───┼─────────────┤│ +││6 │132│Leap │6 │ ││ │├────┼───┼───────────┼───┼─────────────┤│ ││5 │131│Find │1 │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││2 │128│Axe Mastery│1 │ ││ ││ │ │Potion │ │ ││ +││7 │133│Double │6 │Bash ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││ │ │Swing │ │ ││ ││3 │129│Mace │1 │ ││ ││11 │137│Taunt │6 │Howl ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Mastery │ │ ││ │├────┼───┼─────────┼───┼─────────────┤│ +││13 │139│Stun │12 │Bash ││ │├────┼───┼───────────┼───┼─────────────┤│ ││12 │138│Shout │6 │Howl ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││8 │134│Pole Arm │6 │ ││ │├────┼───┼─────────┼───┼─────────────┤│ +││14 │140│Double │12 │Double Swing ││ ││ │ │Mastery │ │ ││ ││16 │142│Find Item│12 │Find Potion ││ +││ │ │Throw │ │ ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼───────────┼───┼─────────────┤│ ││9 │135│Throwing │6 │ ││ ││20 │146│Battle │18 │Taunt ││ +││17 │143│Leap Attack│18 │Leap ││ ││ │ │Mastery │ │ ││ ││ │ │Cry │ │ ││ +│├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││18 │144│Concentrate│18 │Stun ││ ││10 │136│Spear │6 │ ││ ││23 │149│Battle │24 │Shout ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││ │ │Mastery │ │ ││ ││ │ │Orders │ │ ││ +││21 │147│Frenzy │24 │Double Throw ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼───────────┼───┼─────────────┤│ ││15 │141│Increased │12 │ ││ ││24 │150│Grim Ward│24 │Find Item ││ +││25 │151│Whirlwind │30 │Leap Attack, ││ ││ │ │Stamina │ │ ││ │├────┼───┼─────────┼───┼─────────────┤│ +││ │ │ │ │Concentrate ││ │├────┼───┼───────────┼───┼─────────────┤│ ││28 │154│War Cry │30 │Battle Cry, ││ +│├────┼───┼───────────┼───┼─────────────┤│ ││19 │145│Iron Skin │18 │ ││ ││ │ │ │ │Battle Orders││ +││26 │152│Berserk │30 │Concentrate ││ │├────┼───┼───────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +│└────┴───┴───────────┴───┴─────────────┘│ ││22 │148│Increased │24 │Increased ││ ││29 │155│Battle │30 │Battle Orders││ +│ │ ││ │ │Speed │ │Stamina ││ ││ │ │Command │ │ ││ +│ │ │├────┼───┼───────────┼───┼─────────────┤│ │└────┴───┴─────────┴───┴─────────────┘│ +│ │ ││27 │153│Natural │30 │Iron Skin ││ │ │ +│ │ ││ │ │Resistance │ │ ││ │ │ +│ │ │└────┴───┴───────────┴───┴─────────────┘│ │ │ +└────────────────────────────────────────┴───┴────────────────────────────────────────┴───┴──────────────────────────────────────┘ + +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Druid Skills │ +├───────────────────────────────────────┬───┬──────────────────────────────────────┬───┬────────────────────────────────────────┤ +│┌─────────────────────────────────────┐│ │┌────────────────────────────────────┐│ │┌──────────────────────────────────────┐│ +││ Summoning ││ ││ Shape Shifting ││ ││ Elemental ││ +│├────┬───┬──────────┬───┬─────────────┤│ │├────┬───┬─────────┬───┬─────────────┤│ │├────┬───┬───────────┬───┬─────────────┤│ +││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││0 │221│Raven │1 │ ││ ││2 │223│Wearwolf │1 │ ││ ││4 │225│Firestorm │1 │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││1 │222│Plague │1 │ ││ ││3 │224│Shape │1 │Wearwolf ││ ││8 │229│Molten │6 │Firestorm ││ +││ │ │Poppy │ │ ││ ││ │ │Shifting │ │ ││ ││ │ │Boulder │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││5 │226│Oak Sage │6 │ ││ ││7 │228│Wearbear │6 │ ││ ││9 │230│Arctic │6 │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ ││ │ │Blast │ │ ││ +││ │ │Summon │ │ ││ ││11 │232│Feral │12 │Wearwolf ││ │├────┼───┼───────────┼───┼─────────────┤│ +││6 │227│Spirit │6 │Raven ││ ││ │ │Rage │ │ ││ ││13 │234│Eruption │12 │Molten ││ +││ │ │Wolf │ │ ││ │├────┼───┼─────────┼───┼─────────────┤│ ││ │ │ │ │Boulder ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││12 │233│Maul │12 │Wearbear ││ │├────┼───┼───────────┼───┼─────────────┤│ +││10 │231│Cycle of │12 │Plague Poppy ││ │├────┼───┼─────────┼───┼─────────────┤│ ││14 │235│Cyclone │12 │Arctic Blast ││ +││ │ │Life │ │ ││ ││17 │238│Rabies │18 │Feral Rage ││ ││ │ │Armor │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ │├────┼───┼───────────┼───┼─────────────┤│ +││15 │236│Heart of │18 │Oak Sage ││ ││18 │239│Fire │18 │Feral Rage, ││ ││19 │240│Twister │18 │Cyclone Armor││ +││ │ │Wolverine │ │ ││ ││ │ │Claws │ │Maul ││ │├────┼───┼───────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ ││23 │244│Volcano │24 │Eruption ││ +││ │ │Summon │ │Oak Sage, ││ ││21 │242│Hunger │24 │Fire Claws ││ │├────┼───┼───────────┼───┼─────────────┤│ +││16 │237│Fenris │18 │Summon Spirit││ │├────┼───┼─────────┼───┼─────────────┤│ ││24 │245│Tornado │24 │Twister ││ +││ │ │ │ │Wolf ││ ││22 │243│Shock │24 │Maul ││ │├────┼───┼───────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Wave │ │ ││ ││28 │249│Armageddon │30 │Volcano, ││ +││20 │241│Vines │24 │Cycle of Life││ │├────┼───┼─────────┼───┼─────────────┤│ ││ │ │ │ │Hurricane ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││27 │248│Fury │30 │Rabies ││ │├────┼───┼───────────┼───┼─────────────┤│ +││25 │246│Spirit of │30 │Heart of ││ │└────┴───┴─────────┴───┴─────────────┘│ ││29 │250│Hurricane │30 │Tornado ││ +││ │ │Barbs │ │Wolverine ││ │ │ │└────┴───┴───────────┴───┴─────────────┘│ +│├────┼───┼──────────┼───┼─────────────┤│ │ │ │ │ +││26 │247│Summon │30 │Summon Fenris││ │ │ │ │ +││ │ │Grizzly │ │ ││ │ │ │ │ +│└────┴───┴──────────┴───┴─────────────┘│ │ │ │ │ +└───────────────────────────────────────┴───┴──────────────────────────────────────┴───┴────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Assassin Skills │ +├───────────────────────────────────────┬───┬───────────────────────────────────────┬───┬──────────────────────────────────────┤ +│┌─────────────────────────────────────┐│ │┌─────────────────────────────────────┐│ │┌────────────────────────────────────┐│ +││ Traps ││ ││ Shadow Disciplines ││ ││ Martial Arts ││ +│├────┬───┬──────────┬───┬─────────────┤│ │├────┬───┬──────────┬───┬─────────────┤│ │├────┬───┬─────────┬───┬─────────────┤│ +││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ ││Off.│ID │ Skill │Lvl│Prerequisites││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││0 │251│Fire │1 │ ││ ││1 │252│Claw │1 │ ││ ││3 │254│Tiger │1 │ ││ +││ │ │Trauma │ │ ││ ││ │ │Mastery │ │ ││ ││ │ │Strike │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││5 │256│Shock │6 │Fire Trauma ││ ││2 │253│Psychic │1 │ ││ ││4 │255│Dragon │1 │ ││ +││ │ │Field │ │ ││ ││ │ │Hammer │ │ ││ ││ │ │Talon │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼─────────┼───┼─────────────┤│ +││6 │257│Blade │6 │ ││ ││7 │258│Quickness │6 │Claw Mastery ││ ││8 │259│Fists of │6 │ ││ +││ │ │Sentinel │ │ ││ │├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Fire │ │ ││ +│├────┼───┼──────────┼───┼─────────────┤│ ││12 │263│Weapon │12 │Claw Mastery ││ │├────┼───┼─────────┼───┼─────────────┤│ +││ │ │Charged │ │ ││ ││ │ │Block │ │ ││ ││9 │260│Dragon │6 │Dragon Talon ││ +││10 │261│Bolt │12 │Shock Field ││ │├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Claw │ │ ││ +││ │ │Sentry │ │ ││ ││13 │264│Cloak of │12 │Psychic ││ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Shadows │ │Hammer ││ ││14 │265│Cobra │12 │Tiger Strike ││ +││ │ │Wake of │ │ ││ │├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Strike │ │ ││ +││11 │262│Fire │12 │Fire Trauma ││ ││16 │267│Fade │18 │Quickness ││ │├────┼───┼─────────┼───┼─────────────┤│ +││ │ │Sentry │ │ ││ │├────┼───┼──────────┼───┼─────────────┤│ ││18 │269│Claws of │18 │Fists of Fire││ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Shadow │ │Cloak of ││ ││ │ │Thunder │ │ ││ +││ │ │ │ │Blade ││ ││17 │268│Warrior │18 │Shadows, ││ │├────┼───┼─────────┼───┼─────────────┤│ +││15 │266│Blade Fury│18 │Sentinel, ││ ││ │ │ │ │Weapon Block ││ ││19 │270│Dragon │18 │Dragon Claw ││ +││ │ │ │ │Wake of Fire ││ │├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Tail │ │ ││ +││ │ │ │ │Sentry ││ ││22 │273│Mind Blast│24 │Cloak of ││ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ ││ │ │ │ │Shadows ││ ││23 │274│Blades of│24 │Claws of ││ +││20 │271│Lightning │24 │Charged Bolt ││ │├────┼───┼──────────┼───┼─────────────┤│ ││ │ │Ice │ │Thunder ││ +││ │ │Sentry │ │Sentry ││ ││27 │278│Venom │30 │Fade ││ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │├────┼───┼──────────┼───┼─────────────┤│ ││24 │275│Dragon │24 │Dragon Tail ││ +││21 │272│Inferno │24 │Wake of Fire ││ ││28 │279│Shadow │30 │Shadow ││ ││ │ │Flight │ │ ││ +││ │ │Sentry │ │Sentry ││ ││ │ │Master │ │Warrior ││ │├────┼───┼─────────┼───┼─────────────┤│ +│├────┼───┼──────────┼───┼─────────────┤│ │└────┴───┴──────────┴───┴─────────────┘│ ││29 │280│Royal │30 │Cobra Strike,││ +││25 │276│Death │30 │Lightning ││ │ │ ││ │ │Strike │ │Blades of Ice││ +││ │ │Sentry │ │Sentry ││ │ │ │└────┴───┴─────────┴───┴─────────────┘│ +│├────┼───┼──────────┼───┼─────────────┤│ │ │ │ │ +││26 │277│Blade │30 │Blade Fury ││ │ │ │ │ +││ │ │Shield │ │ ││ │ │ │ │ +│└────┴───┴──────────┴───┴─────────────┘│ │ │ │ │ +└───────────────────────────────────────┴───┴───────────────────────────────────────┴───┴──────────────────────────────────────┘ diff --git a/docs/d2s_save_stat_format_1.13d.txt b/docs/d2s_save_stat_format_1.13d.txt new file mode 100644 index 0000000..2aebe56 --- /dev/null +++ b/docs/d2s_save_stat_format_1.13d.txt @@ -0,0 +1,19 @@ + +stat id | stat name | value width in bits +--------------------------------------------- + 0x00 strength 10 + 0x01 energy 10 + 0x02 dexterity 10 + 0x03 vitality 10 + 0x04 statpts 10 + 0x05 newskills 8 + 0x06 hitpoints 21 + 0x07 maxhp 21 + 0x08 mana 21 + 0x09 maxmana 21 + 0x0A stamina 21 + 0x0B maxstamina 21 + 0x0C level 7 + 0x0D experience 32 + 0x0E gold 25 + 0x0F goldbank 25 diff --git a/docs/d2s_skills_1.09.html b/docs/d2s_skills_1.09.html new file mode 100644 index 0000000..987390f --- /dev/null +++ b/docs/d2s_skills_1.09.html @@ -0,0 +1,1337 @@ + + + +Diablo II Character Skills + + +

Diablo II Character Skills

+ +

Well, I did say I would list the character skills in a separate +table, and I guess I've put it off long enough.  So here it is!

+ +

There are two numbers shown for each character skill.  One is +the offset into the character skills +section of the saved +character file.  The other is the skill ID used in some of +the magical +properties (i.e., "+2 to Bash (Barbarian Only)", "level 3 Fire +Bolt (33/33 Charges)", etc.), and in the button actions.  +The common skill ID's are only used in button actions.

+ + + + + + + + +
Common Skills
+ + + + + + + + +
IDSkill
0Attack
1Kick
2Throw
  + + + + + + + + +
IDSkill
3Unsummon
4Left Hand Throw
5Left Hand Swing
  + + + + + + + + + + +
IDSkill
217Scroll of Identify
218Tome of Identify
219Scroll of Town Portal
220Tome of Town Portal
+ +
+ + + + + + + + +
Amazon Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bow and Crossbow Skills
Off.IDSkillLvlPrerequisites
06Magic Arrow1 
17Fire Arrow1 
511Cold Arrow6 
612Multiple Shot6Magic Arrow
1016Exploding Arrow12Fire Arrow,
Multiple Shot
1521Ice Arrow18Cold Arrow
1622Guided Arrow18Cold Arrow,
Multiple Shot
2026Strafe24Guided Arrow
2127Immolation Arrow24Exploding Arrow
2531Freezing Arrow30Ice Arrow
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Passive and Magic Skills
Off.IDSkillLvlPrerequisites
28Inner Sight1 
39Critical Strike1 
713Dodge6 
1117Slow Missiles12Inner Sight
1218Avoid12Dodge
1723Penetrate18Critical Strike
2228Dopplezon24Slow Missiles
2329Evade24Avoid
2632Valkyrie30Dopplezon,
Evade
2733Pierce30Penetrate
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Javelin and Spear Skills
Off.IDSkillLvlPrerequisites
410Jab1 
814Power Strike6Jab
915Poison Javelin6 
1319Impale12Jab
1420Lightning Bolt12Poison Javelin
1824Charged Strike18Power Strike,
Lightning Bolt
1925Plague Javelin18Lightning Bolt
2430Fend24Impale
2834Lightning Strike30Charged Strike
2935Lightning Fury30Plague Javelin
+ +
+ + + + + + + + +
Sorceress Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fire Spells
Off.IDSkillLvlPrerequisites
036Fire Bolt1 
137Warmth1 
541Inferno6 
1046Blaze12Inferno
1147Fire Ball12Fire Bolt
1551Fire Wall18Blaze
1652Enchant18Warmth,
Fire Ball
2056Meteor24Fire Ball,
Fire Wall
2561Fire Mastery30 
2662Hydra30Enchant
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lightning Spells
Off.IDSkillLvlPrerequisites
238Charged Bolt1 
642Static Field6 
743Telekinesis6 
1248Nova12Static Field
1349Lightning12Charged Bolt
1753Chain Lightning18Lightning
1854Teleport18Telekinesis
2157Thunder Storm24Nova,
Chain Lightning
2258Energy Shield24Teleport,
Chain Lightning
2763Lightning Mastery30 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cold Spells
Off.IDSkillLvlPrerequisites
339Ice Bolt1 
440Frozen Armor1 
844Frost Nova6 
945Ice Blast6Ice Bolt
1450Shiver Armor12Ice Blast,
Frozen Armor
1955Glacial Spike18Ice Blast
2359Blizzard24Frost Nova,
Glacial Spike
2460Chilling Armor24Shiver Armor
2864Frozen Orb30Blizzard
2965Cold Mastery30 
+ +
+ + + + + + + + +
Necromancer Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Curses
Off.IDSkillLvlPrerequisites
066Amplify Damage1 
571Dim Vision6 
672Weaken6Amplify Damage
1076Iron Maiden12Amplify Damage
1177Terror12Weaken
1581Confuse18Dim Vision
1682Life Tap18Iron Maiden
2086Attract24Confuse
2187Decrepify24Terror
2591Lower Resist30Life Tap,
Decrepify
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Poison and Bone Spells
Off.IDSkillLvlPrerequisites
167Teeth1 
268Bone Armor1 
773Poison Dagger6 
874Corpse Explosion6Teeth
1278Bone Wall12Bone Armor
1783Poison Explosion18Poison Dagger,
Corpse Explosion
1884Bone Spear18Corpse Explosion
2288Bone Prison24Bone Wall,
Bone Spear
2692Poison Nova30Poison Explosion
2793Bone Spirit30Bone Spear
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summoning Spells
Off.IDSkillLvlPrerequisites
369Skeleton Mastery1Raise Skeleton
470Raise Skeleton1 
975Clay Golem6 
1379Golem Mastery12Clay Golem
1480Raise Skeletal Mage12Raise Skeleton
1985Blood Golem18Clay Golem
2389Summon Resist24Golem Mastery
2490Iron Golem24Blood Golem
2894Fire Golem30Iron Golem
2995Revive30Raise Skeletal Mage,
Iron Golem
+ +
+ + + + + + + + +
Paladin Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Combat Skills
Off.IDSkillLvlPrerequisites
096Sacrifice1 
197Smite1 
5101Holy Bolt6 
10106Zeal12Sacrifice
11107Charge12Smite
15111Vengeance18Zeal
16112Blessed Hammer18Holy Bolt
20116Conversion24Vengeance
21117Holy Shield24Charge,
Blessed Hammer
25121Fist of the Heavens30Blessed Hammer,
Conversion
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Offensive Auras
Off.IDSkillLvlPrerequisites
298Might1 
6102Holy Fire6Might
7103Thorns6 
12108Blessed Aim12Might
17113Concentration18Blessed Aim
18114Holy Freeze18Holy Fire
22118Holy Shock24Holy Freeze
23119Sanctuary24Thorns,
Holy Freeze
26122Fanaticism30Concentration
27123Conviction30Sanctuary
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Defensive Auras
Off.IDSkillLvlPrerequisites
399Prayer1 
4100Resist Fire1 
8104Defiance6 
9105Resist Cold6 
13109Cleansing12Prayer
14110Resist Lightning12 
19115Vigor18Cleansing,
Defiance
24120Meditation24Cleansing
28124Redemption30Vigor
29125Salvation30 
+ +
+ + + + + + + + +
Barbarian Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Combat Skills
Off.IDSkillLvlPrerequisites
0126Bash1 
6132Leap6 
7133Double Swing6Bash
13139Stun12Bash
14140Double Throw12Double Swing
17143Leap Attack18Leap
18144Concentrate18Stun
21147Frenzy24Double Throw
25151Whirlwind30Leap Attack,
Concentrate
26152Berserk30Concentrate
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Combat Masteries
Off.IDSkillLvlPrerequisites
1127Sword Mastery1 
2128Axe Mastery1 
3129Mace Mastery1 
8134Pole Arm Mastery6 
9135Throwing Mastery6 
10136Spear Mastery6 
15141Increased Stamina12 
19145Iron Skin18 
22148Increased Speed24Increased Stamina
27153Natural Resistance30Iron Skin
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Warcries
Off.IDSkillLvlPrerequisites
4130Howl1 
5131Find Potion1 
11137Taunt6Howl
12138Shout6Howl
16142Find Item12Find Potion
20146Battle Cry18Taunt
23149Battle Orders24Shout
24150Grim Ward24Find Item
28154War Cry30Battle Cry,
Battle Orders
29155Battle Command30Battle Orders
+ +
+ + + + + + + + +
Druid Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summoning
Off.IDSkillLvlPrerequisites
0221Raven1 
1222Plague Poppy1 
5226Oak Sage6 
6227Summon Spirit Wolf6Raven
10231Cycle of Life12Plague Poppy
15236Heart of Wolverine18Oak Sage
16237Summon Fenris18Oak Sage,
Summon Spirit Wolf
20241Vines24Cycle of Life
25246Spirit of Barbs30Heart of Wolverine
26247Summon Grizzly30Summon Fenris
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Shape Shifting
Off.IDSkillLvlPrerequisites
2223Wearwolf1 
3224Shape Shifting1Wearwolf
7228Wearbear6 
11232Feral Rage12Wearwolf
12233Maul12Wearbear
17238Rabies18Feral Rage
18239Fire Claws18Feral Rage,
Maul
21242Hunger24Fire Claws
22243Shock Wave24Maul
27248Fury30Rabies
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Elemental
Off.IDSkillLvlPrerequisites
4225Firestorm1 
8229Molten Boulder6Firestorm
9230Arctic Blast6 
13234Eruption12Molten Boulder
14235Cyclone Armor12Arctic Blast
19240Twister18Cyclone Armor
23244Volcano24Eruption
24245Tornado24Twister
28249Armageddon30Volcano,
Hurricane
29250Hurricane30Tornado
+ +
+ + + + + + + + +
Assassin Skills
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Traps
Off.IDSkillLvlPrerequisites
0251Fire Trauma1 
5256Shock Field6Fire Trauma
6257Blade Sentinel6 
10261Charged Bolt Sentry12Shock Field
11262Wake of Fire Sentry12Fire Trauma
15266Blade Fury18Blade Sentinel,
Wake of Fire Sentry
20271Lightning Sentry24Charged Bolt Sentry
21272Inferno Sentry24Wake of Fire Sentry
25276Death Sentry30Lightning Sentry
26277Blade Shield30Blade Fury
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Shadow Disciplines
Off.IDSkillLvlPrerequisites
1252Claw Mastery1 
2253Psychic Hammer1 
7258Quickness6Claw Mastery
12263Weapon Block12Claw Mastery
13264Cloak of Shadows12Psychic Hammer
16267Fade18Quickness
17268Shadow Warrior18Cloak of Shadows,
Weapon Block
22273Mind Blast24Cloak of Shadows
27278Venom30Fade
28279Shadow Master30Shadow Warrior
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Martial Arts
Off.IDSkillLvlPrerequisites
3254Tiger Strike1 
4255Dragon Talon1 
8259Fists of Fire6 
9260Dragon Claw6Dragon Talon
14265Cobra Strike12Tiger Strike
18269Claws of Thunder18Fists of Fire
19270Dragon Tail18Dragon Claw
23274Blades of Ice24Claws of Thunder
24275Dragon Flight24Dragon Tail
29280Royal Strike30Cobra Strike,
Blades of Ice
+ + + + diff --git a/docs/design b/docs/design new file mode 100644 index 0000000..97864e1 --- /dev/null +++ b/docs/design @@ -0,0 +1,33 @@ +skills +---- +User should be able to + - obtain skill name with ID (ID -> name, with skill name const char array) + - translate char skill IDs with skill IDs (ID -> ID, with character class skillenums) + +mercs +------ +User should be able to + - obtain merc name + - set merc name (just change ID) + - obtain merc characteristics (type, subtype, difficulty) + - set merc type, subtype and difficulty (in a single function) + +quests +------ +User should be able to + - get quest name with ID + - get quest descriptions + - get quest data + - set quest data + +waypoints +---------- +User should be able to: + - get waypoint name with ID + - get waypoint active + - set waypoint active + + + + +