summaryrefslogtreecommitdiff
path: root/src/engine/RandomItemTable.cpp
diff options
context:
space:
mode:
authorMegaMech <MegaMech@users.noreply.github.com>2025-12-18 11:24:38 -0700
committerGitHub <noreply@github.com>2025-12-18 11:24:38 -0700
commitf0c2cea0eec6c49a335e9c044fcc28218e1ab749 (patch)
tree422128eeb081feffca8ad3ac87566a35358e077f /src/engine/RandomItemTable.cpp
parent99b56300556434580ed23edc27e5e7d982751e47 (diff)
Impl RandomItemTable class (#598)
* Impl RandomItem class * Refactor func * Impl RandomItemTable * Revert probability inaccuracy * Remove unnecessary comment * Fix compile, probably * As per review 1 --------- Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Diffstat (limited to 'src/engine/RandomItemTable.cpp')
-rw-r--r--src/engine/RandomItemTable.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/engine/RandomItemTable.cpp b/src/engine/RandomItemTable.cpp
new file mode 100644
index 000000000..603dc5c1e
--- /dev/null
+++ b/src/engine/RandomItemTable.cpp
@@ -0,0 +1,104 @@
+#include "RandomItemTable.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();
+}