d2char.c 4.78 KB
#include <stdio.h>

#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];
}