summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc2
-rw-r--r--crawl-ref/source/debug.cc131
-rw-r--r--crawl-ref/source/dungeon.cc13
-rw-r--r--crawl-ref/source/externs.h5
-rw-r--r--crawl-ref/source/files.cc22
-rw-r--r--crawl-ref/source/items.cc62
-rw-r--r--crawl-ref/source/makeitem.cc7
-rw-r--r--crawl-ref/source/mon-util.cc62
-rw-r--r--crawl-ref/source/mon-util.h2
-rw-r--r--crawl-ref/source/mtransit.cc4
-rw-r--r--crawl-ref/source/spells2.cc12
-rw-r--r--crawl-ref/source/spells3.cc7
-rw-r--r--crawl-ref/source/tags.cc10
13 files changed, 246 insertions, 93 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index e017f96054..946050484b 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -1165,7 +1165,7 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
for (int i = 0; i < MAX_ITEMS; i++)
{
item_def &item(mitm[i]);
- if (!is_valid_item(item) || item.pos.x == 0 || item.pos.y == 0)
+ if (!is_valid_item(item) || held_by_monster(item))
continue;
if (item.link != NON_ITEM)
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index c697fb51ca..26675953c9 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -2117,7 +2117,7 @@ void debug_item_scan( void )
{
for (int y = 0; y < GYM; y++)
{
- // These are unlinked monster inventory items -- skip them:
+ // Unlinked temporary items.
if (x == 0 && y == 0)
continue;
@@ -2162,8 +2162,21 @@ void debug_item_scan( void )
strcpy(name, mitm[i].name(DESC_PLAIN).c_str());
- // Don't check (-1,-1) player items or (0,0) monster items
- if ((mitm[i].pos.x > 0 || mitm[i].pos.y > 0) && !visited[i])
+ const monsters* mon = holding_monster(mitm[i]);
+
+ // Don't check (-1,-1) player items or (-2, -2) monstert items
+ // (except to make sure that the monster is alive).
+ if (mitm[i].pos.origin())
+ {
+ mpr( "Unlinked temporary item:", MSGCH_ERROR );
+ _dump_item( name, i, mitm[i] );
+ }
+ else if (mon != NULL && !mon->type == -1)
+ {
+ mpr( "Unlinked item held by dead monster:", MSGCH_ERROR );
+ _dump_item( name, i, mitm[i] );
+ }
+ else if ((mitm[i].pos.x > 0 || mitm[i].pos.y > 0) && !visited[i])
{
mpr( "Unlinked item:", MSGCH_ERROR );
_dump_item( name, i, mitm[i] );
@@ -2381,7 +2394,8 @@ void debug_mons_scan()
_announce_level_prob(warned);
mprf(MSGCH_WARN, "Floating monster: %s at (%d,%d)",
- m->name(DESC_PLAIN, true).c_str(), m->pos().x, m->pos().y);
+ m->full_name(DESC_PLAIN, true).c_str(),
+ m->pos().x, m->pos().y);
warned = true;
for (int j = 0; j < MAX_MONSTERS; ++j)
{
@@ -2397,17 +2411,79 @@ void debug_mons_scan()
{
mprf(MSGCH_WARN, "Also at (%d, %d): %s",
m->pos().x, m->pos().y,
- m2->name(DESC_PLAIN, true).c_str());
+ m2->full_name(DESC_PLAIN, true).c_str());
}
else if (m2->type != -1)
{
mprf(MSGCH_WARN, "Dead mon also at (%d, %d): %s",
m->pos().x, m->pos().y,
- m2->name(DESC_PLAIN, true).c_str());
+ m2->full_name(DESC_PLAIN, true).c_str());
}
}
- }
- }
+ } // if (mgrd(m->pos()) != i)
+
+ for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ {
+ const int idx = m->inv[j];
+ if (idx == NON_ITEM)
+ continue;
+
+ item_def &item(mitm[idx]);
+
+ if (!is_valid_item(item))
+ {
+ _announce_level_prob(warned);
+ warned = true;
+ mprf(MSGCH_WARN, "Monster %s (%d, %d) holding invalid item in "
+ "slot %d.",
+ m->full_name(DESC_PLAIN, true).c_str(),
+ m->pos().x, m->pos().y, j);
+ continue;
+ }
+
+ const monsters* holder = holding_monster(item);
+
+ if (holder == NULL)
+ {
+ _announce_level_prob(warned);
+ warned = true;
+ mprf(MSGCH_WARN, "Monster %s (%d, %d) holding non-monster "
+ "item.",
+ m->full_name(DESC_PLAIN, true).c_str(),
+ m->pos().x, m->pos().y);
+ _dump_item( item.name(DESC_PLAIN, false, true).c_str(),
+ idx, item );
+ continue;
+ }
+
+ if (holder != m)
+ {
+ _announce_level_prob(warned);
+ warned = true;
+ mprf(MSGCH_WARN, "Monster %s (%d, %d) holding item %s, but "
+ "item think's it's held by monster %s "
+ "(%d, %d)",
+ m->full_name(DESC_PLAIN, true).c_str(),
+ m->pos().x, m->pos().y,
+ holder->full_name(DESC_PLAIN, true).c_str(),
+ holder->pos().x, holder->pos().y);
+
+ bool found = false;
+ for (int k = 0; k < NUM_MONSTER_SLOTS; k++)
+ {
+ if (holder->inv[k] == idx)
+ {
+ mpr("Other monster thinks it's holding the item, too.",
+ MSGCH_WARN);
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ mpr("Other monster isn't holding it, though.", MSGCH_WARN);
+ } // if (holder != m)
+ } // for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ } // for (int i = 0; i < MAX_MONSTERS; ++i)
// No problems?
if (!warned)
@@ -4797,7 +4873,6 @@ void wizard_give_monster_item(monsters *mon)
}
int index = get_item_slot(10);
-
if (index == NON_ITEM)
{
mpr("Too many items on level, bailing.");
@@ -4805,36 +4880,44 @@ void wizard_give_monster_item(monsters *mon)
}
// Move monster's old item to player's inventory as last step.
- int old_eq = NON_ITEM;
+ int old_eq = NON_ITEM;
+ bool unequipped = false;
if (mon->inv[mon_slot] != NON_ITEM)
{
old_eq = mon->inv[mon_slot];
-
// Alternative weapons don't get (un)wielded unless the monster
// can wield two weapons.
if (mon_slot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))
+ {
mon->unequip(*(mon->mslot_item(mon_slot)), mon_slot, 1, true);
+ unequipped = true;
+ }
+ mon->inv[mon_slot] = NON_ITEM;
}
- item_def &new_item = mitm[index];
- new_item = item;
- new_item.link = NON_ITEM;
- new_item.pos.reset();
-
- mon->inv[mon_slot] = index;
+ mitm[index] = item;
- // Alternative weapons don't get (un)wielded unless the monster
- // can wield two weapons.
- if (mon_slot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))
- mon->equip(new_item, mon_slot, 1);
+ unwind_var<int> save_speedinc(mon->speed_increment);
+ if (!mon->pickup_item(mitm[index], false, true))
+ {
+ mpr("Monster wouldn't take item.");
+ if (old_eq != NON_ITEM)
+ {
+ mon->inv[mon_slot] = old_eq;
+ if (unequipped)
+ mon->equip(mitm[old_eq], mon_slot, 1);
+ }
+ mitm[index].clear();
+ return;
+ }
// Item is gone from player's inventory
dec_inv_item_quantity(player_slot, item.quantity);
- if ((mon->flags & MF_HARD_RESET) && !(new_item.flags & ISFLAG_SUMMONED))
+ if ((mon->flags & MF_HARD_RESET) && !(item.flags & ISFLAG_SUMMONED))
mprf(MSGCH_WARN, "WARNING: Monster has MF_HARD_RESET and all its "
"items will disappear when it does.");
- else if ((new_item.flags & ISFLAG_SUMMONED) && !mon->is_summoned())
+ else if ((item.flags & ISFLAG_SUMMONED) && !mon->is_summoned())
mprf(MSGCH_WARN, "WARNING: Item is summoned and will disappear when "
"the monster does.");
@@ -4846,6 +4929,8 @@ void wizard_give_monster_item(monsters *mon)
mprf(MSGCH_WARN, "WARNING: Item is summoned and shouldn't really "
"be anywhere but in the inventory of a summoned monster.");
+ mitm[old_eq].pos.reset();
+ mitm[old_eq].link = NON_ITEM;
move_item_to_player(old_eq, mitm[old_eq].quantity);
}
}
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 5a587c2a45..20df74f463 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -1087,8 +1087,11 @@ static void _fixup_misplaced_items()
for (int i = 0; i < MAX_ITEMS; i++)
{
item_def& item(mitm[i]);
- if (!is_valid_item(item) || (item.pos.x == 0))
+ if (!is_valid_item(item) || (item.pos.x == 0)
+ || held_by_monster(item))
+ {
continue;
+ }
if (in_bounds(item.pos))
{
@@ -5598,7 +5601,10 @@ void place_spec_shop( int level_number,
if (orb != NON_ITEM && _need_varied_selection(env.shop[i].type))
{
if (!one_chance_in(stocked[mitm[orb].sub_type] + 1))
+ {
+ mitm[orb].clear();
orb = NON_ITEM; // try again
+ }
}
if (orb != NON_ITEM
@@ -5612,10 +5618,7 @@ void place_spec_shop( int level_number,
// Reset object and try again.
if (orb != NON_ITEM)
- {
- mitm[orb].base_type = OBJ_UNASSIGNED;
- mitm[orb].quantity = 0;
- }
+ mitm[orb].clear();
}
if (orb == NON_ITEM)
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 7dc87f11a9..86d93be0d4 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -220,6 +220,11 @@ struct coord_def
{
return origin();
}
+
+ bool equals(const int xi, const int yi) const
+ {
+ return (xi == x && yi == y);
+ }
};
class actor
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index f9e4b4cf73..8376a17824 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -804,26 +804,6 @@ bool travel_load_map( branch_type branch, int absdepth )
return (true);
}
-static void _sanity_test_monster_inventory()
-{
- // Sanity forcing of monster inventory items (required?)
- for (int i = 0; i < MAX_MONSTERS; i++)
- {
- if (menv[i].type == -1)
- continue;
-
- for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
- {
- if (menv[i].inv[j] == NON_ITEM)
- continue;
-
- // items carried by monsters shouldn't be linked
- if (mitm[menv[i].inv[j]].link != NON_ITEM)
- mitm[menv[i].inv[j]].link = NON_ITEM;
- }
- }
-}
-
static void _place_player_on_stair(level_area_type old_level_type,
branch_type old_branch,
int stair_taken)
@@ -1256,8 +1236,6 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode,
_redraw_all();
- _sanity_test_monster_inventory();
-
if (load_mode != LOAD_VISITOR)
dungeon_events.fire_event(DET_ENTERING_LEVEL);
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 200656794c..7dff728830 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -110,13 +110,18 @@ void link_items(void)
igrd.init(NON_ITEM);
// Link all items on the grid, plus shop inventory,
- // but DON'T link the huge pile of monster items at (0,0).
+ // but DON'T link the huge pile of monster items at (-2,-2).
for (int i = 0; i < MAX_ITEMS; i++)
{
- if (!is_valid_item(mitm[i]) || mitm[i].pos.origin())
+ // Don't mess with monster held items, since the index of the holding
+ // monster is stored in the link field.
+ if (held_by_monster(mitm[i]))
+ continue;
+
+ if (!is_valid_item(mitm[i]))
{
- // Item is not assigned, or is monster item. Ignore.
+ // Item is not assigned. Ignore.
mitm[i].link = NON_ITEM;
continue;
}
@@ -365,37 +370,39 @@ void unlink_item( int dest )
if (dest == NON_ITEM || !is_valid_item( mitm[dest] ))
return;
- if (mitm[dest].pos.origin())
+ monsters* monster = holding_monster(mitm[dest]);
+
+ if (monster != NULL)
{
- // (0,0) is where the monster items are (and they're unlinked by igrd),
- // although it also contains items that are not linked in yet.
- //
- // Check if a monster has it:
- for (int c = 0; c < MAX_MONSTERS; c++)
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
{
- monsters *monster = &menv[c];
-
- if (monster->type == -1)
- continue;
-
- for (int cy = 0; cy < NUM_MONSTER_SLOTS; cy++)
+ if (monster->inv[i] == dest)
{
- if (monster->inv[cy] == dest)
- {
- monster->inv[cy] = NON_ITEM;
+ monster->inv[i] = NON_ITEM;
- mitm[dest].pos.reset();
- mitm[dest].link = NON_ITEM;
- return;
- }
+ mitm[dest].pos.reset();
+ mitm[dest].link = NON_ITEM;
+ return;
}
}
-
- // Always return because this item might just be temporary.
+ mprf(MSGCH_ERROR, "Item %s claims to be held by monster %s, but "
+ "it isn't in the monster's inventory.",
+ mitm[dest].name(DESC_PLAIN, false, true).c_str(),
+ monster->name(DESC_PLAIN, true).c_str());
+ // Don't return so the debugging code can take a look at it.
+ }
+ // Unlinking a newly created item, or a a temporary one, or an item in
+ // the player's inventory.
+ else if (mitm[dest].pos.origin() || mitm[dest].pos.equals(-1, -1))
+ {
+ mitm[dest].pos.reset();
+ mitm[dest].link = NON_ITEM;
return;
}
else
{
+ ASSERT(in_bounds(mitm[dest].pos));
+
// Linked item on map:
//
// Use the items (x,y) to access the list (igrd[x][y]) where
@@ -1629,8 +1636,11 @@ int move_item_to_player( int obj, int quant_got, bool quiet,
}
coord_def p = mitm[obj].pos;
- dungeon_events.fire_position_event(
- dgn_event(DET_ITEM_PICKUP, p, 0, obj, -1), p);
+ // If moving an item directly from a monster to the player without the
+ // item having been on the grid, then it really isn't a position event.
+ if (in_bounds(p))
+ dungeon_events.fire_position_event(
+ dgn_event(DET_ITEM_PICKUP, p, 0, obj, -1), p);
item_def &item = you.inv[freeslot];
// Copy item.
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 85ab12bd5b..714c614e1d 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -2897,11 +2897,12 @@ static void _give_monster_item(monsters *mon, int thing,
bool (monsters::*pickupfn)(item_def&, int) = NULL)
{
item_def &mthing = mitm[thing];
+ ASSERT(is_valid_item(mthing));
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
"Giving %s to %s...", mthing.name(DESC_PLAIN).c_str(),
- mon->name(DESC_PLAIN).c_str());
+ mon->name(DESC_PLAIN, true).c_str());
#endif
mthing.pos.reset();
@@ -2922,9 +2923,11 @@ static void _give_monster_item(monsters *mon, int thing,
mprf(MSGCH_DIAGNOSTICS, "Destroying %s because %s doesn't want it!",
mthing.name(DESC_PLAIN).c_str(), mon->name(DESC_PLAIN).c_str());
#endif
- destroy_item(thing);
+ destroy_item(thing, true);
return;
}
+ ASSERT(is_valid_item(mthing));
+ ASSERT(holding_monster(mthing) == mon);
if (!force_item || mthing.colour == BLACK)
item_colour( mthing );
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 1a0699d392..39d115431a 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -4188,8 +4188,65 @@ void monsters::pickup_message(const item_def &item, int near)
}
}
+bool held_by_monster(const item_def &item)
+{
+ return (item.pos.equals(-2, -2)
+ && !invalid_monster_index(item.link - NON_ITEM - 1));
+}
+
+monsters* holding_monster(const item_def &item)
+{
+ if (!item.pos.equals(-2, -2))
+ return (NULL);
+ const int midx = item.link - NON_ITEM - 1;
+ if (invalid_monster_index(midx))
+ return (NULL);
+
+ return (&menv[midx]);
+}
+
bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
{
+ ASSERT(is_valid_item(item));
+
+ const monsters *other_mon = holding_monster(item);
+
+ if (other_mon != NULL)
+ {
+ if (other_mon == this)
+ {
+ if (inv[slot] == item.index())
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Monster %s already holding item %s.",
+ name(DESC_PLAIN, true).c_str(),
+ item.name(DESC_PLAIN, false, true).c_str());
+ return (false);
+ }
+ else
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Items %s thinks it's alread held by "
+ "monster %s.",
+ item.name(DESC_PLAIN, false, true).c_str(),
+ name(DESC_PLAIN, true).c_str());
+ }
+ }
+ else if (other_mon->type == -1)
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Item %s, held by dead monster, being "
+ "picked up by monster %s.",
+ item.name(DESC_PLAIN, false, true).c_str(),
+ name(DESC_PLAIN, true).c_str());
+ }
+ else
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Item %s, held by monster %s, being "
+ "picked up by monster %s.",
+ item.name(DESC_PLAIN, false, true).c_str(),
+ other_mon->name(DESC_PLAIN, true).c_str(),
+ name(DESC_PLAIN, true).c_str());
+ }
+ }
+
// If a monster chooses a two-handed weapon as main weapon, it will
// first have to drop any shield it might wear.
// (Monsters will always favour damage over protection.)
@@ -4227,8 +4284,12 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
const int item_index = item.index();
unlink_item(item_index);
+
inv[slot] = item_index;
+ item.pos.set(-2, -2);
+ item.link = NON_ITEM + 1 + mindex();
+
pickup_message(item, near);
equip(item, slot, near);
lose_pickup_energy();
@@ -4271,6 +4332,7 @@ bool monsters::drop_item(int eslot, int near)
item.quantity > 1 ? "them" : "it");
item_was_destroyed(item, mindex());
+ destroy_item(item_index);
}
else if (!move_item_to_grid(&item_index, pos()))
{
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 789d424eb0..d76302d155 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -856,4 +856,6 @@ bool mons_can_pass(const monsters *mon, dungeon_feature_type grid);
mon_inv_type equip_slot_to_mslot(equipment_type eq);
mon_inv_type item_to_mslot(const item_def &item);
+bool held_by_monster(const item_def &item);
+monsters* holding_monster(const item_def &item);
#endif
diff --git a/crawl-ref/source/mtransit.cc b/crawl-ref/source/mtransit.cc
index d49c053cc3..14f37c4d66 100644
--- a/crawl-ref/source/mtransit.cc
+++ b/crawl-ref/source/mtransit.cc
@@ -316,8 +316,8 @@ void follower::restore_mons_items(monsters &m)
item_def &it = mitm[islot];
it = items[i];
- it.pos.reset();
- it.link = NON_ITEM;
+ it.pos.set(-2, -2);
+ it.link = NON_ITEM + 1 + m.mindex();
}
}
}
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index b76445aad2..48ff558ec8 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -1718,6 +1718,11 @@ bool cast_tukimas_dance(int pow, god_type god,
if (i == NON_ITEM)
success = false;
+ else
+ // Copy item now so that mitm[i] is occupied and doesn't get picked
+ // by get_item_slot() when giving the dancing weapon it's item
+ // during create_monster().
+ mitm[i] = you.inv[wpn];
int monster;
@@ -1736,7 +1741,10 @@ bool cast_tukimas_dance(int pow, god_type god,
0, god));
if (monster == -1)
+ {
+ mitm[i].clear();
success = false;
+ }
}
if (!success)
@@ -1760,8 +1768,8 @@ bool cast_tukimas_dance(int pow, god_type god,
// Copy the unwielded item.
mitm[i] = you.inv[wpn];
mitm[i].quantity = 1;
- mitm[i].pos.reset();
- mitm[i].link = NON_ITEM;
+ mitm[i].pos.set(-2, -2);
+ mitm[i].link = NON_ITEM + 1 + monster;
// Mark the weapon as thrown, so that we'll autograb it when the
// tango's done.
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 46b10f6558..20a478ccd1 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -813,11 +813,8 @@ void equip_undead(const coord_def &a, int corps, int monster, int monnum)
if (mon->inv[mslot] != NON_ITEM)
return;
- unlink_item(objl);
- mon->inv[mslot] = objl;
-
- if (mslot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))
- mon->equip(item, mslot, 0);
+ unwind_var<int> save_speedinc(mon->speed_increment);
+ mon->pickup_item(mitm[objl], false, true);
} // while
}
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index e5ff017648..fde326b19b 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1767,11 +1767,11 @@ void marshallItem(writer &th, const item_def &item)
marshallShort(th, item.pos.y);
marshallLong(th, item.flags);
- marshallShort(th, item.link); // unused
- if (item.pos.x == -1 && item.pos.y == -1)
- marshallShort(th, -1); // unused
- else
+ marshallShort(th, item.link);
+ if (item.pos.x >= 0 && item.pos.y >= 0)
marshallShort(th, igrd(item.pos)); // unused
+ else
+ marshallShort(th, -1); // unused
marshallByte(th, item.slot);
@@ -1794,8 +1794,8 @@ void unmarshallItem(reader &th, item_def &item)
item.pos.x = unmarshallShort(th);
item.pos.y = unmarshallShort(th);
item.flags = (unsigned long) unmarshallLong(th);
+ item.link = unmarshallShort(th);
- unmarshallShort(th); // mitm[].link -- unused
unmarshallShort(th); // igrd[item.x][item.y] -- unused
item.slot = unmarshallByte(th);