diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/acr.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/debug.cc | 131 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/files.cc | 22 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 62 | ||||
-rw-r--r-- | crawl-ref/source/makeitem.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 62 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/mtransit.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/spells2.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 10 |
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); |