Commit 67c0083bbda0760634bfc0e0a0a00f74d42347a1

Authored by Imanol-Mikel Barba Sabariego
1 parent 6d88e3be

Missing some changes on previous commits

d2char.c
... ... @@ -136,6 +136,10 @@ size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen) {
136 136 }
137 137  
138 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 143 return skills[skillID];
140 144 }
141 145  
... ...
d2char.h
... ... @@ -17,7 +17,7 @@
17 17 #define D2S_HOTKEYS_LENGTH 64
18 18 #define D2S_CHAR_APPEARANCE_LENGTH 32
19 19 #define D2S_DIFFICULTY_LENGTH 3
20   -#define D2S_WAYPOINTS_LENGTH 81
  20 +#define D2S_WAYPOINTS_LENGTH 80
21 21 #define D2S_NPCDATA_LENGTH 51
22 22  
23 23 #define D2S_CHARSTATUS_HARDCORE 0x04
... ... @@ -92,11 +92,18 @@ typedef struct __attribute__((packed)){
92 92 uint8_t unknown6[144]; // TODO
93 93 D2QuestData questData;
94 94 uint8_t waypointData[D2S_WAYPOINTS_LENGTH];
  95 + uint8_t unknown7; // TODO. Apparently this is always 0x01
95 96 uint8_t NPCIntroductions[D2S_NPCDATA_LENGTH]; // TODO: Not implemented
96 97 } D2CharHeader;
97 98  
98 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 107 uint32_t calcChecksum(D2CharHeader* c, void* charData);
101 108 int checkChecksum(D2CharHeader* c, void* charData);
102 109 int isHardcore(D2CharHeader* c);
... ...
d2mercs.c
1 1 #include "d2mercs.h"
2 2  
  3 +#include <stdlib.h>
  4 +
3 5 int _getMercType(int mercID) {
4 6 if(mercID >= 0 && mercID <= 5) {
5 7 return D2S_MERCTYPE_ROGUE;
... ... @@ -16,5 +18,8 @@ int _getMercType(int mercID) {
16 18  
17 19 const char* _getMercName(int mercID, int mercNameID) {
18 20 int offset = _getMercType(mercID);
  21 + if(offset == D2S_MERCTYPE_UNKNOWN) {
  22 + return NULL;
  23 + }
19 24 return mercNames[mercNameID + offset];
20 25 }
21 26 \ No newline at end of file
... ...
d2mercs.h
... ... @@ -3,6 +3,8 @@
3 3  
4 4 #include "d2strings.h"
5 5  
  6 +// TODO: return compound data (type, subtype, difficulty, not just a string)
  7 +
6 8 // The values here are the offsets of each merc's names in the table.
7 9 // i.e: Merc names from pos 41 to 61 are Desert mercs
8 10 //
... ...
d2quest.c
1 1 #include "d2char.h"
2 2 #include "d2quest.h"
3 3  
  4 +#include <stdio.h>
  5 +
4 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 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 23 } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) {
18 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 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 38 d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL] = questData;
32 39 } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) {
33 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 107 }
99 108  
100 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 115 switch(specialQuestState) {
102 116 case D2S_SPECIALQUEST_AKARA_RESPEC:
103 117 // This operation only makes sense if the quest is actually completed, otherwise ignore request
... ...
d2quest.h
... ... @@ -6,6 +6,7 @@
6 6 #include "d2strings.h"
7 7  
8 8 #define D2S_QUESTDATA_HEADER_LENGTH 4
  9 +#define D2S_QUESTDATA_NUMQUESTS 27
9 10  
10 11 enum D2S_QUEST {
11 12 D2S_QUEST_UNKNOWN = -1,
... ... @@ -500,17 +501,22 @@ typedef struct __attribute__((packed)) {
500 501 typedef struct __attribute__((packed)) {
501 502 D2ActData actData[4];
502 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 507 uint16_t akaraRespecData; // This uint16_t determines if the player has used Akara's respec or not
504 508 uint16_t unknown1[6];
505 509 } D2Quests;
506 510  
507 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 514 uint16_t size; // in bytes
511 515 D2Quests quests[3]; // 1 set for each difficulty
512 516 } D2QuestData;
513 517  
  518 +// TODO: These functions are completely unsafe, and don't return success
  519 +
514 520 // Populates `descriptions` with static strings from library memory, no need to free.
515 521 // `descriptions` contains one string for each bit field of the quest's uint16_t data.
516 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 533 // Set bool to 1 to set the status or 0 to remove it
528 534 void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool);
529 535 void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool);
  536 +
530 537 // When called to set the request to NOT completed (`bool` = 0), this will NOT set the reward collected status
531 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 540 // instead.
534 541 void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty, int bool);
535 542  
... ...
d2skills.h
... ... @@ -5,6 +5,8 @@
5 5  
6 6 #include "d2strings.h"
7 7  
  8 +#define D2S_SKILL_NUMSKILLS 357
  9 +
8 10 const char* const skills[] = {
9 11 D2S_SKILL_0,
10 12 D2S_SKILL_1,
... ...
d2strings.h
... ... @@ -1035,4 +1035,45 @@ const char* D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE = &quot;Guardian&quot;;
1035 1035 #define D2S_QUEST_CHECKPOINT_430 NULL
1036 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 1079 #endif
1039 1080 \ No newline at end of file
... ...