summaryrefslogtreecommitdiff
path: root/src/emap/quest.c
blob: ff9d5de45a9e2caf5656970bde579853dae0d285 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// Copyright (c) 2014 - 2015 Evol developers

#include "common/hercules.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "common/conf.h"
#include "common/HPMi.h"
#include "common/memmgr.h"
#include "common/mmo.h"
#include "common/socket.h"
#include "common/strlib.h"
#include "map/itemdb.h"
#include "map/script.h"
#include "map/quest.h"

#include "plugins/HPMHooking.h"

#include "emap/quest.h"

/**
 * Reads and parses an entry from the quest_db.
 *
 * @param cs     The config setting containing the entry.
 * @param n      The sequential index of the current config setting.
 * @param source The source configuration file.
 * @return The parsed quest entry.
 * @retval NULL in case of errors.
 */
struct quest_db *equest_read_db_sub_pre(struct config_setting_t **csPtr,
                                        int *nPtr,
                                        const char **sourcePtr)
{
    struct quest_db *entry = NULL;
    struct config_setting_t *t = NULL;
    int i32 = 0, quest_id;
    const char *str = NULL;
    const int n = *nPtr;
    struct config_setting_t *cs = *csPtr;
    const char *source = *sourcePtr;

    /*
     * Id: Quest ID                    [int]
     * Name: Quest Name                [string]
     * TimeLimit: Time Limit (seconds) [int, optional]
     * Targets: (                      [array, optional]
     *     {
     *         MobId: Mob ID           [int]
     *         Count:                  [int]
     *     },
     *     ... (can repeated up to MAX_QUEST_OBJECTIVES times)
     * )
     * Drops: (
     *     {
     *         ItemId: Item ID to drop [int]
     *         Rate: Drop rate         [int]
     *         MobId: Mob ID to match  [int, optional]
     *     },
     *     ... (can be repeated)
     * )
     */

    if (!libconfig->setting_lookup_int(cs, "Id", &quest_id)) {
        ShowWarning("quest_read_db: Missing id in \"%s\", entry #%d, skipping.\n", source, n);
        hookStop();
        return NULL;
    }
    if (quest_id < 0 || quest_id >= MAX_QUEST_DB) {
        ShowWarning("quest_read_db: Invalid quest ID '%d' in \"%s\", entry #%d (min: 0, max: %d), skipping.\n", quest_id, source, n, MAX_QUEST_DB);
        hookStop();
        return NULL;
    }

    if (!libconfig->setting_lookup_string(cs, "Name", &str) || !*str) {
        ShowWarning("quest_read_db_sub: Missing Name in quest %d of \"%s\", skipping.\n", quest_id, source);
        hookStop();
        return NULL;
    }

    script->set_constant2(str, quest_id, false, false);

    CREATE(entry, struct quest_db, 1);
    entry->id = quest_id;
    //safestrncpy(entry->name, str, sizeof(entry->name));

    if (libconfig->setting_lookup_int(cs, "TimeLimit", &i32)) // This is an unsigned value, do not check for >= 0
        entry->time = (unsigned int)i32;

    if ((t=libconfig->setting_get_member(cs, "Targets")) && config_setting_is_list(t)) {
/*
        int i, len = libconfig->setting_length(t);
        for (i = 0; i < len && entry->objectives_count < MAX_QUEST_OBJECTIVES; i++) {
            // Note: We ensure that objectives_count < MAX_QUEST_OBJECTIVES because
            //       quest_log (as well as the client) expect this maximum size.
            struct config_setting_t *tt = libconfig->setting_get_elem(t, i);
            int mob_id = 0, count = 0;
            if (!tt)
                break;
            if (!config_setting_is_group(tt))
                continue;
            if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id) || mob_id <= 0)
                continue;
            if (!libconfig->setting_lookup_int(tt, "Count", &count) || count <= 0)
                continue;
            RECREATE(entry->objectives, struct quest_objective, ++entry->objectives_count);
            entry->objectives[entry->objectives_count-1].mob = mob_id;
            entry->objectives[entry->objectives_count-1].count = count;
        }
*/
        entry->objectives_count = 1;
        RECREATE(entry->objectives, struct quest_objective, 1);
        entry->objectives[0].mob = 1;
        entry->objectives[0].count = 0;
    }

    if ((t=libconfig->setting_get_member(cs, "Drops")) && config_setting_is_list(t)) {
        int i, len = libconfig->setting_length(t);
        for (i = 0; i < len; i++) {
            struct config_setting_t *tt = libconfig->setting_get_elem(t, i);
            int mob_id = 0, nameid = 0, rate = 0;
            if (!tt)
                break;
            if (!config_setting_is_group(tt))
                continue;
            if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id))
                mob_id = 0; // Zero = any monster
            if (mob_id < 0)
                continue;
            if (!libconfig->setting_lookup_int(tt, "ItemId", &nameid) || !itemdb->exists(nameid))
                continue;
            if (!libconfig->setting_lookup_int(tt, "Rate", &rate) || rate <= 0)
                continue;
            RECREATE(entry->dropitem, struct quest_dropitem, ++entry->dropitem_count);
            entry->dropitem[entry->dropitem_count-1].mob_id = mob_id;
            entry->dropitem[entry->dropitem_count-1].nameid = nameid;
            entry->dropitem[entry->dropitem_count-1].rate = rate;
        }
    }
    hookStop();
    return entry;
}