#include #include "d2char.h" #include "d2mercs.h" #include "d2skills.h" uint32_t calcChecksum(D2CharHeader* c, void* charData) { uint32_t origChecksum = c->checksum; c->checksum = 0; uint32_t sum = 0; void* data = malloc(c->fileSize); memcpy(data, (void*)c, D2S_HEADER_LENGTH); memcpy(data + D2S_HEADER_LENGTH, charData, c->fileSize - D2S_HEADER_LENGTH); for(int i = 0; i < c->fileSize; ++i) { sum = (sum << 1) + ((uint8_t*)data)[i]; } free(data); c->checksum = origChecksum; return sum; } int checkChecksum(D2CharHeader* c, void* charData) { uint32_t checksum = calcChecksum(c, charData); return c->checksum == checksum; } int isHardcore(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_HARDCORE; } int hasDied(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_DIED; } int isExpansion(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_EXPANSION; } int isLadder(D2CharHeader* c) { return c->charStatus & D2S_CHARSTATUS_LADDER; } int getCurrentAct(D2CharHeader* c) { if(isExpansion(c)) { return c->charProgress % 5; } else { return c->charProgress % 4; } } int isFemale(D2CharHeader* c) { return (c->charClass == D2S_CHARCLASS_AMAZON || c->charClass == D2S_CHARCLASS_ASSASSIN || c->charClass == D2S_CHARCLASS_SORCERESS); } const char* getCharacterTitle(D2CharHeader* c) { int tier; if(isExpansion(c)) { // Expansion tier = c->charProgress / 5; if(isHardcore(c)) { // Expansion Hardcore switch(tier) { case 1: return D2S_CHARPROGRESS_EXPANSION_TIER1_NAME_HARDCORE; break; case 2: return D2S_CHARPROGRESS_EXPANSION_TIER2_NAME_HARDCORE; break; case 3: return D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_HARDCORE; break; } } else { // Expansion Softcore switch(tier) { case 1: return D2S_CHARPROGRESS_EXPANSION_TIER1_NAME; break; case 2: return D2S_CHARPROGRESS_EXPANSION_TIER2_NAME; break; case 3: return isFemale(c) ? D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_F : D2S_CHARPROGRESS_EXPANSION_TIER3_NAME_M; break; } } } else { // Classic if(isHardcore(c)) { // Classic Hardcore switch(tier) { case 1: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_HARDCORE_M; break; case 2: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_HARDCORE_M; break; case 3: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_HARDCORE_F : D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_HARDCORE_M; break; } } else { // Classic Softcore switch(tier) { case 1: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER1_NAME_M; break; case 2: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER2_NAME_M; break; case 3: return isFemale(c) ? D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_F : D2S_CHARPROGRESS_CLASSIC_TIER3_NAME_M; break; } } } return D2S_CHARPROGRESS_TIER0_NAME; } size_t getLastPlayed(D2CharHeader* c, char* buf, size_t bufLen) { // In amd64, since long is 64 bits long, time_t is also 64 bits long // thus needing conversion from the save file type, which is a uint32_t #ifdef __x86_64__ uint64_t convTimestamp = c->lastPlayed; #else uint32_t convTimestamp = c->lastPlayed; #endif struct tm* time = localtime((time_t*)&convTimestamp); size_t ret = strftime(buf, bufLen, "%c", time); if(!ret) { fprintf(stderr,"libd2char error: Provided buffer for time string was too small\n"); } return ret; } const char* getSkillName(int skillID) { return skills[skillID]; } int getCurrentDifficulty(D2CharHeader* c) { for(int i = D2S_DIFFICULTY_NORMAL; i <= D2S_DIFFICULTY_HELL; ++i) { if(c->difficulty[i] & D2S_DIFFICULTY_ACTIVE) { return i; } } return D2S_DIFFICULTY_UNKNOWN; } const char* getMercName(D2CharHeader* c) { return _getMercName(c->mercenaryType, c->mercenaryNameID); } const char* getMercType(D2CharHeader* c) { return mercTypes[c->mercenaryType]; }