aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-10 20:37:29 -0400
committerhistoria <[not public]>2026-07-10 20:37:29 -0400
commit131cbbe586463a7232f332650af5f0b2c13dc7e9 (patch)
tree080ac50225b2ec07c01dbca22e4480fb8046a156
parentd35aa505d2a103a41a45d3a8f42be7f2f2b5a28b (diff)
downloadthehouseoficarus-131cbbe586463a7232f332650af5f0b2c13dc7e9.tar.gz
feat(admin): remove unused fields from drop tables
-rw-r--r--building_guide/drops.md57
-rw-r--r--data/.admin_history.json1
-rw-r--r--data/drops/herb_table_high.yaml2
-rw-r--r--data/drops/herb_table_low.yaml2
-rw-r--r--data/drops/herb_table_mid.yaml2
-rw-r--r--data/mobs/flight_attendant.yaml47
-rw-r--r--internal/admin/static/dropeditor.js66
-rw-r--r--internal/validate/checks.go72
8 files changed, 190 insertions, 59 deletions
diff --git a/building_guide/drops.md b/building_guide/drops.md
index f71f712..edac103 100644
--- a/building_guide/drops.md
+++ b/building_guide/drops.md
@@ -4,7 +4,11 @@
(`gem_table.yaml` → `gem_table`); reference it from behaviors/mobs by that name. Do not put
an `id:` field in the file — it is ignored.
-Shared drop tables can be referenced by multiple behaviors:
+### Shared drop table entries
+
+Shared drop tables in `data/drops/` are pure weighted pools of items. Each entry supports
+only three fields (four with `table`):
+
```yaml
# data/drops/gem_table.yaml
drops:
@@ -18,6 +22,34 @@ drops:
weight: 1
```
+| Field | Required | Description |
+|-------|----------|-------------|
+| `item_id` | XOR with `table` | Item ID to drop |
+| `table` | XOR with `item_id` | Reference to another shared drop table (can nest) |
+| `weight` | yes | Relative drop weight |
+| `quantity` | no | Amount to drop (default 1) |
+
+**`item_id` and `table` are mutually exclusive per entry.** The entry drops *either* the named
+item *or* rolls on the referenced sub-table; never both.
+
+### What does NOT belong on a shared drop table
+
+The following fields are **meaningless on shared drop table entries** and are ignored by the
+engine — they belong on the *referencing* gather entry in the object config instead:
+
+- `depletes` — controls whether the gatherable node depletes (per-drop; ore vs gem). Set on
+ the `gather.drops[]` entry in the object YAML that references this table.
+- `level` — skill-level gate on a drop. Only meaningful on the outer gather entry.
+- `xp` — skill XP for this drop. Only meaningful on the outer gather entry.
+- `tool` — tool-type filter. Only meaningful on the outer gather entry.
+- `success_message` — per-drop message. Overridden by the outer entry when referenced via
+ `table:`.
+
+The admin Drop Table editor intentionally shows only `item_id`/`table` (toggle), `weight`,
+and `quantity`. Edit the raw YAML if you need niche overrides.
+
+### Examples
+
Bird's nest drop table:
```yaml
# data/drops/birds_nest_drop.yaml
@@ -39,16 +71,21 @@ drops:
quantity: 10000
```
-Referenced from a gather behavior:
+Referenced from a gather behavior (note `depletes` lives on the **outer** entries here,
+not inside `gem_table`):
```yaml
-drops:
- - item_id: copper_ore
- weight: 90
- depletes: true
- - table: gem_table # pulls from data/drops/gem_table.yaml
- weight: 10
- depletes: false
+gather:
+ drops:
+ - item_id: copper_ore
+ weight: 90
+ level: 1
+ xp: 17
+ depletes: true
+ success_message: "You manage to mine some copper ore."
+ - table: gem_table # pulls from data/drops/gem_table.yaml
+ weight: 10
+ depletes: false # gem drops don't deplete the rock
+ success_message: "You spot a glint of something valuable!"
```
---
-
diff --git a/data/.admin_history.json b/data/.admin_history.json
deleted file mode 100644
index 499b27d..0000000
--- a/data/.admin_history.json
+++ /dev/null
@@ -1 +0,0 @@
-{"history":[{"time":"2026-07-10T19:25:32-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:35-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:38-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:41-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:42-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:44-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:44-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:45-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:48-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n - steps: []\n","is_delete":false,"is_create":false},{"time":"2026-07-10T19:25:48-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n - steps: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n - steps: []\n","is_delete":false,"is_create":false}],"redo":null} \ No newline at end of file
diff --git a/data/drops/herb_table_high.yaml b/data/drops/herb_table_high.yaml
index 8631a3c..25e96b2 100644
--- a/data/drops/herb_table_high.yaml
+++ b/data/drops/herb_table_high.yaml
@@ -1,4 +1,4 @@
-entries:
+drops:
- item_id: grimy_kwuarm
weight: 7
- item_id: grimy_snapdragon
diff --git a/data/drops/herb_table_low.yaml b/data/drops/herb_table_low.yaml
index 7c20bb6..1cbbed8 100644
--- a/data/drops/herb_table_low.yaml
+++ b/data/drops/herb_table_low.yaml
@@ -1,4 +1,4 @@
-entries:
+drops:
- item_id: grimy_guam
weight: 10
- item_id: grimy_marrentill
diff --git a/data/drops/herb_table_mid.yaml b/data/drops/herb_table_mid.yaml
index 17e3275..382f225 100644
--- a/data/drops/herb_table_mid.yaml
+++ b/data/drops/herb_table_mid.yaml
@@ -1,4 +1,4 @@
-entries:
+drops:
- item_id: grimy_harralander
weight: 8
- item_id: grimy_ranarr
diff --git a/data/mobs/flight_attendant.yaml b/data/mobs/flight_attendant.yaml
index e595e67..a0be1e8 100644
--- a/data/mobs/flight_attendant.yaml
+++ b/data/mobs/flight_attendant.yaml
@@ -1,27 +1,30 @@
-name: flight attendant
description: A smiling flight attendant in a crisp uniform, ready to assist passengers.
-unique: false
-protected: true
+id: flight_attendant
idle_descriptions:
- adjusts her name badge
- smiles politely at you
+name: flight attendant
+protected: true
talk:
- nodes:
- start:
- condition:
- player_flag: 1001_look_sign
- not: true
- messages: ['"Hi there, how can I help?"']
- goto: thanks
- options:
- - text: '"Oh, nothing... Small crowd on this ship. Just looking for conversation."'
- goto: sign_reminder
- - text: '"Goodbye."'
- thanks:
- messages: ['"Thank for flying with Denali. Watch your step on the way out please."']
- options:
- - text: '"Thank you."'
- sign_reminder:
- messages:
- - '"Yeah, just us two! Not a lot of people heading into the belt these days."'
- - '"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination."'
+ nodes:
+ sign_reminder:
+ messages:
+ - '"Yeah, just us two! Not a lot of people heading into the belt these days."'
+ - '"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination."'
+ start:
+ condition:
+ not: true
+ player_flag: 1001_look_sign
+ goto: thanks
+ messages:
+ - '"Hi there, how can I help?"'
+ options:
+ - goto: sign_reminder
+ text: '"Oh, nothing... Small crowd on this ship. Just looking for conversation."'
+ - text: '"Goodbye."'
+ thanks:
+ messages:
+ - '"Thank for flying with Denali. Watch your step on the way out please."'
+ options:
+ - text: '"Thank you."'
+unique: false
diff --git a/internal/admin/static/dropeditor.js b/internal/admin/static/dropeditor.js
index 566d696..ac1df97 100644
--- a/internal/admin/static/dropeditor.js
+++ b/internal/admin/static/dropeditor.js
@@ -11,10 +11,6 @@ var DROP_SECTIONS = [
['table', 'Table', 'search', 'e.g. gem_table', '', null, 'drops'],
['weight', 'Weight', 'number', '10', 'narrow'],
['quantity', 'Quantity', 'number', '1', 'narrow'],
- ['level', 'Level', 'number', '1', 'narrow'],
- ['xp', 'XP', 'number', '5', 'narrow'],
- ['depletes', 'Depletes', 'checkbox'],
- ['success_message', 'Success Message', 'text', 'You get some %n.', 'wide'],
]
}
];
@@ -113,16 +109,37 @@ function renderArraySection(sec, data) {
var arr = dropData[cardPath(sec)] || [];
var h = '';
arr.forEach(function(item, idx) {
+ var isItem = item._type !== undefined ? item._type !== 't' : !item.table;
+ var showKey = isItem ? 'item_id' : 'table';
+ var hideKey = isItem ? 'table' : 'item_id';
+
h += '<div class="obj-sub-row" data-idx="' + idx + '">';
+ h += '<input type="hidden" id="' + fieldID(sec, hideKey, idx) + '" value="' + escAttr(item[hideKey] || '') + '">';
h += '<div class="obj-card-grid">';
- sec.fields.forEach(function(f) {
- h += renderField(sec, f, data, idx);
- });
+
+ h += '<div class="obj-field obj-narrow">' +
+ '<span style="visibility:hidden">.</span>' +
+ '<span class="obj-drop-kind-label">' + (isItem ? 'Item' : 'Table') + '</span>' +
+ '</div>';
+
+ var showField = sec.fields.find(function(f) { return f[0] === showKey; });
+ if (showField) {
+ h += renderField(sec, showField, data, idx);
+ }
+
+ var weightField = sec.fields.find(function(f) { return f[0] === 'weight'; });
+ var qtyField = sec.fields.find(function(f) { return f[0] === 'quantity'; });
+ if (weightField) h += renderField(sec, weightField, data, idx);
+ if (qtyField) h += renderField(sec, qtyField, data, idx);
+
h += '</div>';
h += '<button class="btn btn-sm btn-danger obj-sub-remove" onclick="removeArrayItem(\'' + sec.id + '\',' + idx + ')">X</button>';
h += '</div>';
});
- h += '<button class="btn btn-sm obj-sub-add" onclick="addArrayItem(\'' + sec.id + '\')">+ Add Entry</button>';
+ h += '<div style="display:flex;gap:6px;padding:6px 10px">';
+ h += '<button class="btn btn-sm obj-sub-add" style="flex:1;margin-top:0" onclick="addDropRow(\'' + sec.id + '\',\'item\')">+ Add Item Row</button>';
+ h += '<button class="btn btn-sm obj-sub-add" style="flex:1;margin-top:0" onclick="addDropRow(\'' + sec.id + '\',\'table\')">+ Add Table Row</button>';
+ h += '</div>';
return h;
}
@@ -130,6 +147,16 @@ function renderField(sec, f, data, idx) {
return ced_renderField(sec, f, data, idx, null, null, cardPath, fieldID, getVal);
}
+function addDropRow(cardID, kind) {
+ var sec = DROP_SECTIONS.find(function(s) { return s.id === cardID; });
+ if (!sec || !sec.isArray) return;
+ var arr = dropData[sec.path] || [];
+ var empty = { _type: (kind === 'table' ? 't' : 'i'), weight: 10, quantity: 0 };
+ arr.push(empty);
+ dropData[sec.path] = arr;
+ renderCurrent();
+}
+
function toggleCard(id) {
expandedCards[id] = expandedCards[id] === false ? true : false;
renderCurrent();
@@ -140,19 +167,6 @@ function toggleCardWidth(id) {
renderCurrent();
}
-function addArrayItem(cardID) {
- var sec = DROP_SECTIONS.find(function(s) { return s.id === cardID; });
- if (!sec || !sec.isArray) return;
- var arr = dropData[sec.path] || [];
- var empty = {};
- sec.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
- });
- arr.push(empty);
- dropData[sec.path] = arr;
- renderCurrent();
-}
-
function removeArrayItem(cardID, idx) {
var sec = DROP_SECTIONS.find(function(s) { return s.id === cardID; });
if (!sec || !sec.isArray) return;
@@ -178,7 +192,12 @@ function saveDrop() {
sec.fields.forEach(function(f) {
var fid = fieldID(sec, f[0], idx);
var el = document.getElementById(fid);
- if (el) item[f[0]] = collectFieldValue(el, f[2]);
+ if (el) {
+ var val = collectFieldValue(el, f[2]);
+ if (val !== '' && val !== null && val !== undefined && val !== 0 && val !== false) {
+ item[f[0]] = val;
+ }
+ }
});
if (Object.keys(item).length > 0) arr.push(item);
});
@@ -246,6 +265,9 @@ function duplicateDrop() {
delete copy._raw;
delete copy._path;
copy.id = newID;
+ if (copy.drops && Array.isArray(copy.drops)) {
+ copy.drops.forEach(function(e) { delete e._type; });
+ }
var dir = '';
if (dropData._path) {
diff --git a/internal/validate/checks.go b/internal/validate/checks.go
index f89e52d..bbcb820 100644
--- a/internal/validate/checks.go
+++ b/internal/validate/checks.go
@@ -2,6 +2,8 @@ package validate
import (
"fmt"
+ "os"
+ "path/filepath"
"sort"
"strings"
@@ -732,7 +734,24 @@ func validateDropTables(s Source) []Issue {
})
continue
}
- for _, d := range dt.Drops {
+
+ // Detect files that use "entries:" instead of "drops:" as the top-level list key.
+ // DropTableDef only reads "drops:", so "entries:" produces an empty list.
+ if len(dt.Drops) == 0 {
+ raw, rawErr := os.ReadFile(filepath.Join(s.DataDir, "drops", id+".yaml"))
+ if rawErr == nil {
+ content := string(raw)
+ if strings.Contains(content, "\nentries:") || strings.HasPrefix(content, "entries:") {
+ issues = append(issues, Issue{
+ Level: "ERROR",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q: uses key 'entries:' instead of 'drops:' — entries are not loaded; rename to 'drops:'", id),
+ })
+ }
+ }
+ }
+
+ for i, d := range dt.Drops {
if d.ItemID != "" && !itemIDs[d.ItemID] {
issues = append(issues, Issue{
Level: "ERROR",
@@ -749,6 +768,57 @@ func validateDropTables(s Source) []Issue {
id, d.Table),
})
}
+
+ if d.ItemID != "" && d.Table != "" {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: both item_id and table set (only one is used per entry)", id, i+1),
+ })
+ }
+ if d.ItemID == "" && d.Table == "" {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: neither item_id nor table set (roll produces nothing)", id, i+1),
+ })
+ }
+
+ if d.Depletes {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: 'depletes' is ignored on shared drop table entries; set it on the gather entry that references this table instead", id, i+1),
+ })
+ }
+ if d.Level > 0 {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: 'level' is ignored on shared drop table entries; set it on the gather entry that references this table", id, i+1),
+ })
+ }
+ if d.XP > 0 {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: 'xp' is ignored on shared drop table entries; set it on the gather entry that references this table", id, i+1),
+ })
+ }
+ if d.Tool != "" {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: 'tool' is ignored on shared drop table entries; set it on the gather entry that references this table", id, i+1),
+ })
+ }
+ if d.SuccessMessage != "" {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "integrity",
+ Message: fmt.Sprintf("Drop table %q entry %d: 'success_message' is ignored on shared drop table entries; set it on the gather entry that references this table", id, i+1),
+ })
+ }
}
}