d2quest.c 5.91 KB
#include "d2char.h"
#include "d2quest.h"

#include <stdio.h>

void getCheckpointDescriptions(unsigned int quest, const char* *descriptions[16]) {
    if(quest > D2S_QUESTDATA_NUMQUESTS) {
        fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest);
        return;
    }
    memcpy(descriptions,(&checkpointDescriptions) + (quest * 16 * sizeof(const char*)), 16 * sizeof(const char*));
}

uint16_t getQuestStatus(D2QuestData* d, unsigned int quest, unsigned int difficulty) {
    if(quest >= D2S_QUEST_DEN_OF_EVIL && quest <= D2S_QUEST_SISTERS_TO_THE_SLAUGHTER) {
        return 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];
    } else if(quest >= D2S_QUEST_GOLDEN_BIRD && quest <= D2S_QUEST_GUARDIAN) {
        return 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];
    } 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];
    }
    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) {
    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) {
        d->quests[difficulty].actData[D2S_ACT2].questCheckpoints[quest - D2S_QUEST_RADAMENT_LAIR] = questData;
    } else if(quest >= D2S_QUEST_GOLDEN_BIRD && quest <= D2S_QUEST_GUARDIAN) {
        d->quests[difficulty].actData[D2S_ACT3].questCheckpoints[quest - D2S_QUEST_GOLDEN_BIRD] = questData;
    } else if(quest >= D2S_QUEST_FALLEN_ANGEL && quest <= D2S_QUEST_TERROR_END) {
        d->quests[difficulty].actData[D2S_ACT4].questCheckpoints[quest - D2S_QUEST_FALLEN_ANGEL] = questData;
    } else if(quest >= D2S_QUEST_SIEGE_ON_HARROGATH && quest <= D2S_QUEST_EVE_OF_DESTRUCTION) {
        d->quests[difficulty].expansionAct.questCheckpoints[quest - D2S_QUEST_SIEGE_ON_HARROGATH] = questData;
    } else {
        fprintf(stderr,"libd2char error: quest %d doesn't exist\n",quest);
    }
}

int isQuestStarted(D2QuestData* d, unsigned int quest, unsigned int difficulty) {
    return getQuestStatus(d,quest,difficulty) & 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 isQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int difficulty) {
    return getQuestStatus(d,quest,difficulty) & D2S_QUEST_STATUS_COMPLETED;
}

void setQuestStarted(D2QuestData* d, unsigned int quest, unsigned int 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);
    if(bool) {
        questData = D2S_QUEST_STATUS_STARTED;
    } else {
        questData = 0x0000;
    }
    setQuestStatus(d,quest,difficulty,questData);
}

void setQuestRewardCollected(D2QuestData* d, unsigned int quest, unsigned int 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);
    } else {
        setQuestCompleted(d,quest,difficulty,0);
        uint16_t questData = getQuestStatus(d,quest,difficulty);
        questData |= D2S_QUEST_STATUS_REWARD_AVAILABLE;
        setQuestStatus(d,quest,difficulty,questData);
    }
}

void setQuestCompleted(D2QuestData* d, unsigned int quest, unsigned int 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);
    if(bool) {
        questData &= ~D2S_QUEST_STATUS_REWARD_AVAILABLE;
        questData |= D2S_QUEST_STATUS_COMPLETED;
        questData |= D2S_QUEST_STATUS_SEEN_FINISH_ANIMATION;
    } else {
        questData &= ~D2S_QUEST_STATUS_COMPLETED;
        questData &= ~D2S_QUEST_STATUS_SEEN_FINISH_ANIMATION;
    }
    setQuestStatus(d,quest,difficulty,questData);
}

int getSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty) {
    int ret = 0;
    switch(specialQuestState) {
        case D2S_SPECIALQUEST_AKARA_RESPEC:
            ret = d->quests[difficulty].akaraRespecData & D2S_QUEST_STATUS_REWARD_AVAILABLE;
        break;
    }
    return ret;
}

void setSpecialQuestStatus(D2QuestData* d, unsigned int specialQuestState, unsigned int difficulty, int bool) {
    if(difficulty != D2S_DIFFICULTY_NORMAL    || 
       difficulty != D2S_DIFFICULTY_NIGHTMARE || 
       difficulty != D2S_DIFFICULTY_HELL) {
        fprintf(stderr,"libd2char error: difficulty %d doesn't exist\n",difficulty);
    }
    switch(specialQuestState) {
        case D2S_SPECIALQUEST_AKARA_RESPEC:
            // This operation only makes sense if the quest is actually completed, otherwise ignore request
            if(isQuestCompleted(d,D2S_QUEST_DEN_OF_EVIL,difficulty)) {
                if(bool) {
                    d->quests[difficulty].akaraRespecData = 0x8001;
                } else {
                    d->quests[difficulty].akaraRespecData = 0x2002;
                }
            }
        break;
    }
}