summaryrefslogtreecommitdiff
path: root/src/engine/RandomItemTable.cpp
blob: 5251bfbf70947f193c66eaf8eedc412ebae6b1da (plain)
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
#include "RandomItemTable.h"
#include "defines.h"
#include "port/Game.h"

extern "C" {
#include "math_util.h"
}

RandomItemTable::RandomItemTable() {
    mDistanceEnabled = false;
}

bool RandomItemTable::Add(const std::string& resourceName, uint32_t rank, uint32_t weight, float distance) {
    const ItemInfo* info = gItemRegistry.GetInfo(resourceName);
    if (!info) {
        printf("[ItemTables] Failed to add %s to table,\n  item name passed into resourceName does not exist!\n", resourceName.c_str());
        return false;
    }

    if (rank >= mTable.size()) {
        if (rank >= NUM_PLAYERS) {
            printf("[ItemTables] Failed to add item table, rank value too high!\n");
            return false;
        }
        mTable.resize(rank + 1);
    }

    // Check if already exists
    for (const ItemEntry& entry : mTable[rank]) {
        if (entry.Id == info->Id) {
            printf("[ItemTables] %s already exists for this rank, skipping...\n", resourceName.c_str());
            return false;
        }
    }

    mTable[rank].push_back(ItemEntry{info->Id, weight, distance});

    return true;
}

uint8_t RandomItemTable::Roll(uint32_t rank) const {
    if (rank >= mTable.size()) {
        printf("[ItemTables] [Roll] Invalid rank input %d. Giving player a none item\n", rank);
        return ITEM_NONE;
    }

    // Items that could be selected for this rank
    const std::vector<ItemEntry>& itemList = mTable.at(rank);
    if (itemList.empty()) {
        printf("[ItemTables] [Roll] itemList empty. Giving player a none item\n");
        return ITEM_NONE;
    }

    // Calculate total weight
    uint32_t totalWeight = 0;
    for (const ItemEntry& entry : itemList) {
        if (this->IsBlacklisted(entry.Id)) {
            continue;
        }
        totalWeight += entry.Weight;
    }

    // Avoid division by zero
    if (totalWeight == 0) {
        printf("[ItemTables] [Roll] No items to give out for this rank. Giving player a none item\n");
        return ITEM_NONE;
    }

    // Pick a random number from zero to (totalWeight - 1)
    uint32_t rand = random_int(totalWeight - 1);

    // Cumulative sum over weights
    uint32_t accumulated = 0;
    for (const ItemEntry& entry : itemList) {
        if (this->IsBlacklisted(entry.Id)) {
            continue;
        }
        accumulated += entry.Weight;
        if (rand < accumulated) {
            return static_cast<uint8_t>(entry.Id);
        }
    }

    // Fallback (should not happen)
    printf("[ItemTables] [Roll] Reached unreachable code\n");
    [[unlikely]] return ITEM_NONE;
}

void RandomItemTable::Blacklist(const std::string& resourceName) {
    const ItemInfo* info = gItemRegistry.GetInfo(resourceName);
    if (!info) {
        return;
    }

    mBlacklist.insert(info->Id);
}

bool RandomItemTable::IsBlacklisted(uint32_t itemId) const {
    //return mBlacklist.contains(itemId);
    return mBlacklist.find(itemId) != mBlacklist.end();
}

void RandomItemTable::ClearBlacklist() {
    mBlacklist.clear();
}