mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 02:53:51 +00:00
Novel open replacement for AzerothCore-style
creature_loot_template / gameobject_loot_template SQL
tables. The 13th open format added to the editor.
Pairs naturally with the WIT item catalog from the
preceding commit: each loot drop's itemId references an
entry in a WIT file, so a content pack ships both the
item definitions and the loot tables that reference them.
The runtime composes WIT + WLOT + WSPN to drive the full
"creature dies, drops items" flow without any SQL.
Format:
• magic "WLOT", version 1, little-endian
• per table: creatureId / flags / dropCount /
moneyMin..Max / itemDropCount + drops[]
• per drop: itemId / chancePercent (float, 0..100) /
minQty / maxQty / drop_flags
Table flags: QuestOnly, GroupOnly, Pickpocket
Drop flags: QuestRequired, GroupRollOnly, AlwaysDrop
dropCount is the slot budget — how many distinct drops
to roll per kill. Each item drop is rolled independently
against its chancePercent (so dropCount=2 with 4 candidate
drops at varying chances gives the classic "up to 2 distinct
items per kill" behavior). Drops with the AlwaysDrop flag
bypass the slot budget — used for guaranteed quest items.
API: WoweeLootLoader::save / load / exists /
findByCreatureId; presets makeStarter (1 table, 1 drop),
makeBandit (4 candidates, dropCount=2, matches the camp
spawns from WSPN at creatureId=1000), makeBoss (6 candidates
including guaranteed quest item via AlwaysDrop and a
group-only epic at 5%).
CLI added (5 flags, 486 documented total now):
--gen-loot / --gen-loot-bandit / --gen-loot-boss
--info-wlot / --validate-wlot
Validator catches: creatureId=0, duplicates, chance not in
0..100, NaN chance, money min > max, minQty > maxQty,
dropCount=0 with non-empty drops list (silent dead config).
All 3 presets save / load / re-validate clean. The bandit
table's creatureId=1000 deliberately matches WSPN's
makeCamp creatureId so the open-format demo content pack
already has working cross-references.
107 lines
3.7 KiB
C++
107 lines
3.7 KiB
C++
#pragma once
|
||
|
||
#include <cstdint>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace wowee {
|
||
namespace pipeline {
|
||
|
||
// Wowee Open Loot Table (.wlot) — novel replacement for the
|
||
// creature_loot_template / gameobject_loot_template SQL
|
||
// tables AzerothCore-style servers use to drive what drops
|
||
// when a creature is killed (or a chest is opened). The
|
||
// 13th open format added to the editor.
|
||
//
|
||
// Pairs naturally with the WIT item catalog from the
|
||
// previous commit: each loot drop's itemId references an
|
||
// entry in a WIT file, so a content pack ships both the
|
||
// item definitions and the loot tables that reference them.
|
||
//
|
||
// One file holds many creature loot tables in one catalog.
|
||
// Each table has a moneyMin/moneyMax range plus a list of
|
||
// possible item drops. dropCount controls how many distinct
|
||
// drops to roll per kill (one die roll per slot, independent).
|
||
//
|
||
// Binary layout (little-endian):
|
||
// magic[4] = "WLOT"
|
||
// version (uint32) = current 1
|
||
// nameLen (uint32) + name bytes -- catalog label
|
||
// entryCount (uint32)
|
||
// entries (each):
|
||
// creatureId (uint32)
|
||
// flags (uint32)
|
||
// dropCount (uint8) + pad[3]
|
||
// moneyMinCopper (uint32)
|
||
// moneyMaxCopper (uint32)
|
||
// itemDropCount (uint32)
|
||
// itemDrops (itemDropCount × {
|
||
// itemId (uint32)
|
||
// chancePercent (float) -- 0..100
|
||
// minQty (uint8)
|
||
// maxQty (uint8)
|
||
// drop_flags (uint8) + pad[1]
|
||
// })
|
||
struct WoweeLoot {
|
||
enum TableFlags : uint32_t {
|
||
QuestOnly = 0x01, // table only used while killer has matching quest
|
||
GroupOnly = 0x02, // table only used in group / raid (not solo)
|
||
Pickpocket = 0x04, // alternate table used by rogues, not normal kill
|
||
};
|
||
|
||
enum DropFlags : uint8_t {
|
||
QuestRequired = 0x01, // drop only if killer has matching quest
|
||
GroupRollOnly = 0x02, // skip on solo kills (rare/epic-tier loot)
|
||
AlwaysDrop = 0x04, // bypass dropCount slot limit
|
||
};
|
||
|
||
struct ItemDrop {
|
||
uint32_t itemId = 0;
|
||
float chancePercent = 100.0f;
|
||
uint8_t minQty = 1;
|
||
uint8_t maxQty = 1;
|
||
uint8_t flags = 0;
|
||
};
|
||
|
||
struct Entry {
|
||
uint32_t creatureId = 0;
|
||
uint32_t flags = 0;
|
||
uint8_t dropCount = 1; // distinct drops rolled per kill
|
||
uint32_t moneyMinCopper = 0;
|
||
uint32_t moneyMaxCopper = 0;
|
||
std::vector<ItemDrop> itemDrops;
|
||
};
|
||
|
||
std::string name;
|
||
std::vector<Entry> entries;
|
||
|
||
bool isValid() const { return !entries.empty(); }
|
||
|
||
// Lookup by creatureId — nullptr if not present.
|
||
const Entry* findByCreatureId(uint32_t creatureId) const;
|
||
};
|
||
|
||
class WoweeLootLoader {
|
||
public:
|
||
static bool save(const WoweeLoot& cat,
|
||
const std::string& basePath);
|
||
static WoweeLoot load(const std::string& basePath);
|
||
static bool exists(const std::string& basePath);
|
||
|
||
// Preset emitters used by --gen-loot* variants.
|
||
//
|
||
// makeStarter — minimal: 1 creature with 1 drop slot,
|
||
// 1 item @ 50% chance + 0..50 copper.
|
||
// makeBandit — bandit table: dropCount=2, 4 candidate
|
||
// items (linen, cloth, knife, ale), each
|
||
// at distinct chances; 5..50 copper.
|
||
// makeBoss — elite boss: dropCount=4, 6 candidates
|
||
// including a guaranteed quest item, plus
|
||
// GroupRollOnly epic at 5%; 50..200 silver.
|
||
static WoweeLoot makeStarter(const std::string& catalogName);
|
||
static WoweeLoot makeBandit(const std::string& catalogName);
|
||
static WoweeLoot makeBoss(const std::string& catalogName);
|
||
};
|
||
|
||
} // namespace pipeline
|
||
} // namespace wowee
|