Commit 67c0083bbda0760634bfc0e0a0a00f74d42347a1
1 parent
6d88e3be
Missing some changes on previous commits
Showing
8 changed files
with
87 additions
and
5 deletions
d2char.c
@@ -136,6 +136,10 @@ size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen) { | @@ -136,6 +136,10 @@ size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen) { | ||
136 | } | 136 | } |
137 | 137 | ||
138 | const char* getSkillName(int skillID) { | 138 | const char* getSkillName(int skillID) { |
139 | + if(skillID > D2S_SKILL_NUMSKILLS) { | ||
140 | + fprintf(stderr,"libd2char error: skillID %d doesn't exist\n",skillID); | ||
141 | + return NULL; | ||
142 | + } | ||
139 | return skills[skillID]; | 143 | return skills[skillID]; |
140 | } | 144 | } |
141 | 145 |
d2char.h
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | #define D2S_HOTKEYS_LENGTH 64 | 17 | #define D2S_HOTKEYS_LENGTH 64 |
18 | #define D2S_CHAR_APPEARANCE_LENGTH 32 | 18 | #define D2S_CHAR_APPEARANCE_LENGTH 32 |
19 | #define D2S_DIFFICULTY_LENGTH 3 | 19 | #define D2S_DIFFICULTY_LENGTH 3 |
20 | -#define D2S_WAYPOINTS_LENGTH 81 | 20 | +#define D2S_WAYPOINTS_LENGTH 80 |
21 | #define D2S_NPCDATA_LENGTH 51 | 21 | #define D2S_NPCDATA_LENGTH 51 |
22 | 22 | ||
23 | #define D2S_CHARSTATUS_HARDCORE 0x04 | 23 | #define D2S_CHARSTATUS_HARDCORE 0x04 |
@@ -92,11 +92,18 @@ typedef struct __attribute__((packed)){ | @@ -92,11 +92,18 @@ typedef struct __attribute__((packed)){ | ||
92 | uint8_t unknown6[144]; // TODO | 92 | uint8_t unknown6[144]; // TODO |
93 | D2QuestData questData; | 93 | D2QuestData questData; |
94 | uint8_t waypointData[D2S_WAYPOINTS_LENGTH]; | 94 | uint8_t waypointData[D2S_WAYPOINTS_LENGTH]; |
95 | + uint8_t unknown7; // TODO. Apparently this is always 0x01 | ||
95 | uint8_t NPCIntroductions[D2S_NPCDATA_LENGTH]; // TODO: Not implemented | 96 | uint8_t NPCIntroductions[D2S_NPCDATA_LENGTH]; // TODO: Not implemented |
96 | } D2CharHeader; | 97 | } D2CharHeader; |
97 | 98 | ||
98 | // TODO: All setX functions | 99 | // TODO: All setX functions |
99 | 100 | ||
101 | +// TODO: Load from file. | ||
102 | +// int loadD2CharFromFile(const char* file, D2CharHeader** header, void** data); | ||
103 | + | ||
104 | +// TODO: Write to file. | ||
105 | +// int writeD2CharToFile(const char* file, D2CharHeader* header, void* charData,) | ||
106 | + | ||
100 | uint32_t calcChecksum(D2CharHeader* c, void* charData); | 107 | uint32_t calcChecksum(D2CharHeader* c, void* charData); |
101 | int checkChecksum(D2CharHeader* c, void* charData); | 108 | int checkChecksum(D2CharHeader* c, void* charData); |
102 | int isHardcore(D2CharHeader* c); | 109 | int isHardcore(D2CharHeader* c); |
d2mercs.c
1 | #include "d2mercs.h" | 1 | #include "d2mercs.h" |
2 | 2 | ||
3 | +#include <stdlib.h> | ||
4 | + | ||
3 | int _getMercType(int mercID) { | 5 | int _getMercType(int mercID) { |
4 | if(mercID >= 0 && mercID <= 5) { | 6 | if(mercID >= 0 && mercID <= 5) { |
5 | return D2S_MERCTYPE_ROGUE; | 7 | return D2S_MERCTYPE_ROGUE; |
@@ -16,5 +18,8 @@ int _getMercType(int mercID) { | @@ -16,5 +18,8 @@ int _getMercType(int mercID) { | ||
16 | 18 | ||
17 | const char* _getMercName(int mercID, int mercNameID) { | 19 | const char* _getMercName(int mercID, int mercNameID) { |
18 | int offset = _getMercType(mercID); | 20 | int offset = _getMercType(mercID); |
21 | + if(offset == D2S_MERCTYPE_UNKNOWN) { | ||
22 | + return NULL; | ||
23 | + } | ||
19 | return mercNames[mercNameID + offset]; | 24 | return mercNames[mercNameID + offset]; |
20 | } | 25 | } |
21 | \ No newline at end of file | 26 | \ No newline at end of file |
d2mercs.h
@@ -3,6 +3,8 @@ | @@ -3,6 +3,8 @@ | ||
3 | 3 | ||
4 | #include "d2strings.h" | 4 | #include "d2strings.h" |
5 | 5 | ||
6 | +// TODO: return compound data (type, subtype, difficulty, not just a string) | ||
7 | + | ||
6 | // The values here are the offsets of each merc's names in the table. | 8 | // The values here are the offsets of each merc's names in the table. |
7 | // i.e: Merc names from pos 41 to 61 are Desert mercs | 9 | // i.e: Merc names from pos 41 to 61 are Desert mercs |
8 | // | 10 | // |
d2quest.c
1 | #include "d2char.h" | 1 | #include "d2char.h" |
2 | #include "d2quest.h" | 2 | #include "d2quest.h" |
3 | 3 | ||
4 | +#include <stdio.h> | ||
5 | + | ||
4 | void getCheckpointDescriptions(unsigned int quest, const char* *descriptions[16]) { | 6 | void getCheckpointDescriptions(unsigned int quest, const char* *descriptions[16]) { |
7 | + if(quest > D2S_QUESTDATA_NUMQUESTS) { | ||
8 | + fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); | ||
9 | + return; | ||
10 | + } | ||
5 | memcpy(descriptions,(&checkpointDescriptions) + (quest * 16 * sizeof(const char*)), 16 * sizeof(const char*)); | 11 | memcpy(descriptions,(&checkpointDescriptions) + (quest * 16 * sizeof(const char*)), 16 * sizeof(const char*)); |
6 | } | 12 | } |
7 | 13 | ||
@@ -17,7 +23,8 @@ uint16_t getQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficu | @@ -17,7 +23,8 @@ uint16_t getQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficu | ||
17 | } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) { | 23 | } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) { |
18 | return d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH]; | 24 | return d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH]; |
19 | } | 25 | } |
20 | - return D2S_QUEST_UNKNOWN; | 26 | + fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); |
27 | + return 0; | ||
21 | } | 28 | } |
22 | 29 | ||
23 | void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, uint16_t questData) { | 30 | void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, uint16_t questData) { |
@@ -31,6 +38,8 @@ void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, | @@ -31,6 +38,8 @@ void setQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty, | ||
31 | d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL] = questData; | 38 | d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL] = questData; |
32 | } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) { | 39 | } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) { |
33 | d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH] = questData; | 40 | d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH] = questData; |
41 | + } else { | ||
42 | + fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest); | ||
34 | } | 43 | } |
35 | } | 44 | } |
36 | 45 | ||
@@ -98,6 +107,11 @@ int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsign | @@ -98,6 +107,11 @@ int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsign | ||
98 | } | 107 | } |
99 | 108 | ||
100 | void setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty, int bool) { | 109 | void setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty, int bool) { |
110 | + if(difficulty != D2S_DIFFICULTY_NORMAL || | ||
111 | + difficulty != D2S_DIFFICULTY_NIGHTMARE || | ||
112 | + difficulty != D2S_DIFFICULTY_HELL) { | ||
113 | + fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty); | ||
114 | + } | ||
101 | switch(specialQuestState) { | 115 | switch(specialQuestState) { |
102 | case D2S_SPECIALQUEST_AKARA_RESPEC: | 116 | case D2S_SPECIALQUEST_AKARA_RESPEC: |
103 | // This operation only makes sense if the quest is actually completed, otherwise ignore request | 117 | // This operation only makes sense if the quest is actually completed, otherwise ignore request |
d2quest.h
@@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
6 | #include "d2strings.h" | 6 | #include "d2strings.h" |
7 | 7 | ||
8 | #define D2S_QUESTDATA_HEADER_LENGTH 4 | 8 | #define D2S_QUESTDATA_HEADER_LENGTH 4 |
9 | +#define D2S_QUESTDATA_NUMQUESTS 27 | ||
9 | 10 | ||
10 | enum D2S_QUEST { | 11 | enum D2S_QUEST { |
11 | D2S_QUEST_UNKNOWN = -1, | 12 | D2S_QUEST_UNKNOWN = -1, |
@@ -500,17 +501,22 @@ typedef struct __attribute__((packed)) { | @@ -500,17 +501,22 @@ typedef struct __attribute__((packed)) { | ||
500 | typedef struct __attribute__((packed)) { | 501 | typedef struct __attribute__((packed)) { |
501 | D2ActData actData[4]; | 502 | D2ActData actData[4]; |
502 | D2XActData expansionAct; | 503 | D2XActData expansionAct; |
504 | + // My guess is that the following `uint16_t`s all represents some quest data that was added after | ||
505 | + // the game was launched. This also explains why there's version data (supposedly) and length | ||
506 | + // of the quest data in bytes in the header. | ||
503 | uint16_t akaraRespecData; // This uint16_t determines if the player has used Akara's respec or not | 507 | uint16_t akaraRespecData; // This uint16_t determines if the player has used Akara's respec or not |
504 | uint16_t unknown1[6]; | 508 | uint16_t unknown1[6]; |
505 | } D2Quests; | 509 | } D2Quests; |
506 | 510 | ||
507 | typedef struct __attribute__((packed)) { | 511 | typedef struct __attribute__((packed)) { |
508 | - const char* header[D2S_QUESTDATA_HEADER_LENGTH]; | ||
509 | - uint32_t unknown1; | 512 | + const char* header[D2S_QUESTDATA_HEADER_LENGTH]; // Woo! |
513 | + uint32_t unknown1; // This is likely version data | ||
510 | uint16_t size; // in bytes | 514 | uint16_t size; // in bytes |
511 | D2Quests quests[3]; // 1 set for each difficulty | 515 | D2Quests quests[3]; // 1 set for each difficulty |
512 | } D2QuestData; | 516 | } D2QuestData; |
513 | 517 | ||
518 | +// TODO: These functions are completely unsafe, and don't return success | ||
519 | + | ||
514 | // Populates `descriptions` with static strings from library memory, no need to free. | 520 | // Populates `descriptions` with static strings from library memory, no need to free. |
515 | // `descriptions` contains one string for each bit field of the quest's uint16_t data. | 521 | // `descriptions` contains one string for each bit field of the quest's uint16_t data. |
516 | // Empty entries (non-existant or unknown checkpoints) will have NULL value. Be careful! | 522 | // Empty entries (non-existant or unknown checkpoints) will have NULL value. Be careful! |
@@ -527,9 +533,10 @@ int isQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty | @@ -527,9 +533,10 @@ int isQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty | ||
527 | // Set bool to 1 to set the status or 0 to remove it | 533 | // Set bool to 1 to set the status or 0 to remove it |
528 | void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); | 534 | void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); |
529 | void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); | 535 | void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); |
536 | + | ||
530 | // When called to set the request to NOT completed (`bool` = 0), this will NOT set the reward collected status | 537 | // When called to set the request to NOT completed (`bool` = 0), this will NOT set the reward collected status |
531 | // which *may* render the quest unobtainable, this is done in case we may want to further modify the quest state. | 538 | // which *may* render the quest unobtainable, this is done in case we may want to further modify the quest state. |
532 | -// If you want to mark the quest as not completed just to get the reward, please use `setQuestRewardCollected()` | 539 | +// If you want to mark the quest as not completed just to get the reward, please use `setQuestRewardCollected(,,0)` |
533 | // instead. | 540 | // instead. |
534 | void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); | 541 | void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool); |
535 | 542 |
d2skills.h
d2strings.h
@@ -1035,4 +1035,45 @@ const char* D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE = "Guardian"; | @@ -1035,4 +1035,45 @@ const char* D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE = "Guardian"; | ||
1035 | #define D2S_QUEST_CHECKPOINT_430 NULL | 1035 | #define D2S_QUEST_CHECKPOINT_430 NULL |
1036 | #define D2S_QUEST_CHECKPOINT_431 NULL | 1036 | #define D2S_QUEST_CHECKPOINT_431 NULL |
1037 | 1037 | ||
1038 | +// Waypoints | ||
1039 | +#define D2S_WAYPOINT_0 "Rogue Encampment" | ||
1040 | +#define D2S_WAYPOINT_1 "Cold Plains" | ||
1041 | +#define D2S_WAYPOINT_2 "Stony Field" | ||
1042 | +#define D2S_WAYPOINT_3 "Dark Wood" | ||
1043 | +#define D2S_WAYPOINT_4 "Black Marsh" | ||
1044 | +#define D2S_WAYPOINT_5 "Outer Cloister" | ||
1045 | +#define D2S_WAYPOINT_6 "Jail Level 1" | ||
1046 | +#define D2S_WAYPOINT_7 "Inner Cloister" | ||
1047 | +#define D2S_WAYPOINT_8 "Catacombs Level 2" | ||
1048 | +#define D2S_WAYPOINT_9 "Lut Gholein" | ||
1049 | +#define D2S_WAYPOINT_10 "Sewers Level 2" | ||
1050 | +#define D2S_WAYPOINT_11 "Dry Hills" | ||
1051 | +#define D2S_WAYPOINT_12 "Halls of the Dead Level 2" | ||
1052 | +#define D2S_WAYPOINT_13 "Far Oasis" | ||
1053 | +#define D2S_WAYPOINT_14 "Lost City" | ||
1054 | +#define D2S_WAYPOINT_15 "Palace Cellar Level 1" | ||
1055 | +#define D2S_WAYPOINT_16 "Arcane Sanctuary" | ||
1056 | +#define D2S_WAYPOINT_17 "Canyon of the Magi" | ||
1057 | +#define D2S_WAYPOINT_18 "Kurast Docks" | ||
1058 | +#define D2S_WAYPOINT_19 "Spider Forest" | ||
1059 | +#define D2S_WAYPOINT_20 "Great Marsh" | ||
1060 | +#define D2S_WAYPOINT_21 "Flayer Jungle" | ||
1061 | +#define D2S_WAYPOINT_22 "Lower Kurast" | ||
1062 | +#define D2S_WAYPOINT_23 "Kurast Bazaar" | ||
1063 | +#define D2S_WAYPOINT_24 "Upper Kurast" | ||
1064 | +#define D2S_WAYPOINT_25 "Travincal" | ||
1065 | +#define D2S_WAYPOINT_26 "Durance of Hate Level 2" | ||
1066 | +#define D2S_WAYPOINT_27 "Pandemonium Fortress" | ||
1067 | +#define D2S_WAYPOINT_28 "City of the Damned" | ||
1068 | +#define D2S_WAYPOINT_29 "River of Flames" | ||
1069 | +#define D2S_WAYPOINT_30 "Harrogath" | ||
1070 | +#define D2S_WAYPOINT_31 "Frigid Highlands" | ||
1071 | +#define D2S_WAYPOINT_32 "Arreat Plateau" | ||
1072 | +#define D2S_WAYPOINT_33 "Crystalline Passage" | ||
1073 | +#define D2S_WAYPOINT_34 "Halls of Pain" | ||
1074 | +#define D2S_WAYPOINT_35 "Glacial Trail" | ||
1075 | +#define D2S_WAYPOINT_36 "Frozen Tundra" | ||
1076 | +#define D2S_WAYPOINT_37 "The Ancient's Way" | ||
1077 | +#define D2S_WAYPOINT_38 "Worldstone Keep Level 2" | ||
1078 | + | ||
1038 | #endif | 1079 | #endif |
1039 | \ No newline at end of file | 1080 | \ No newline at end of file |