/** * Remove an object from the gear list, leaving it unattached * \param obj the object being tested * \return whether an object was removed */ static bool gear_excise_object(struct object *obj) { int i; pile_excise(&player->gear_k, obj->known); pile_excise(&player->gear, obj); /* Change the weight */ player->upkeep->total_weight -= (obj->number * obj->weight); /* Make sure it isn't still equipped */ for (i = 0; i < player->body.count; i++) { if (slot_object(player, i) == obj) { player->body.slots[i].obj = NULL; player->upkeep->equip_cnt--; } } /* Update the gear */ calc_inventory(player->upkeep, player->gear, player->body); /* Housekeeping */ player->upkeep->update |= (PU_BONUS); player->upkeep->notice |= (PN_COMBINE); player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); return true; }
/** * Handles the "death" of a monster. * * Disperses treasures carried by the monster centered at the monster location. * Note that objects dropped may disappear in crowded rooms. * * Checks for "Quest" completion when a quest monster is killed. * * Note that only the player can induce "monster_death()" on Uniques. * Thus (for now) all Quest monsters should be Uniques. * * If `stats` is true, then we skip updating the monster memory. This is * used by stats-generation code, for efficiency. */ void monster_death(struct monster *mon, bool stats) { int dump_item = 0; int dump_gold = 0; struct object *obj = mon->held_obj; bool visible = (mflag_has(mon->mflag, MFLAG_VISIBLE) || rf_has(mon->race->flags, RF_UNIQUE)); /* Delete any mimicked objects */ if (mon->mimicked_obj) object_delete(&mon->mimicked_obj); /* Drop objects being carried */ while (obj) { struct object *next = obj->next; /* Object no longer held */ obj->held_m_idx = 0; pile_excise(&mon->held_obj, obj); /* Count it and drop it - refactor once origin is a bitflag */ if (!stats) { if (tval_is_money(obj) && (obj->origin != ORIGIN_STOLEN)) dump_gold++; else if (!tval_is_money(obj) && ((obj->origin == ORIGIN_DROP) || (obj->origin == ORIGIN_DROP_PIT) || (obj->origin == ORIGIN_DROP_VAULT) || (obj->origin == ORIGIN_DROP_SUMMON) || (obj->origin == ORIGIN_DROP_SPECIAL) || (obj->origin == ORIGIN_DROP_BREED) || (obj->origin == ORIGIN_DROP_POLY) || (obj->origin == ORIGIN_DROP_WIZARD))) dump_item++; } /* Change origin if monster is invisible, unless we're in stats mode */ if (!visible && !stats) obj->origin = ORIGIN_DROP_UNKNOWN; drop_near(cave, obj, 0, mon->fy, mon->fx, true); obj = next; } /* Forget objects */ mon->held_obj = NULL; /* Take note of any dropped treasure */ if (visible && (dump_item || dump_gold)) lore_treasure(mon, dump_item, dump_gold); /* Update monster list window */ player->upkeep->redraw |= PR_MONLIST; /* Check if we finished a quest */ quest_check(mon); }
/** * Remove an object from the gear list, leaving it unattached * \param obj the object being tested * \return whether an object was removed */ bool gear_excise_object(struct object *obj) { int i; pile_excise(&player->gear, obj); /* Make sure it isn't still equipped */ for (i = 0; i < player->body.count; i++) { if (slot_object(player, i) == obj) player->body.slots[i].obj = NULL; } /* Housekeeping */ player->upkeep->update |= (PU_BONUS | PU_MANA | PU_INVEN); player->upkeep->notice |= (PN_COMBINE); player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); return TRUE; }
/** * Excise an object from a floor pile, leaving it orphaned. */ void square_excise_object(struct chunk *c, int y, int x, struct object *obj) { pile_excise(&c->squares[y][x].obj, obj); }
/** * Excise an object from a floor pile, leaving it orphaned. */ void square_excise_object(struct chunk *c, int y, int x, struct object *obj) { assert(square_in_bounds(c, y, x)); pile_excise(&c->squares[y][x].obj, obj); }
NOTEARDOWN /* Testing the linked list functions in obj-pile.c */ int test_obj_piles(void *state) { struct object *pile = NULL; struct object *o1 = object_new(); struct object *o2 = object_new(); struct object *o3 = object_new(); struct object *o4 = object_new(); pile_insert(&pile, o1); eq(pile_contains(pile, o1), TRUE); eq(pile_contains(pile, o2), FALSE); ptreq(pile, o1); ptreq(pile_last_item(pile), o1); pile_insert_end(&pile, o2); eq(pile_contains(pile, o1), TRUE); eq(pile_contains(pile, o2), TRUE); eq(pile_contains(pile, o3), FALSE); ptreq(pile, o1); ptreq(pile_last_item(pile), o2); pile_insert_end(&pile, o3); eq(pile_contains(pile, o1), TRUE); eq(pile_contains(pile, o2), TRUE); eq(pile_contains(pile, o3), TRUE); ptreq(pile, o1); ptreq(pile_last_item(pile)->prev, o2); ptreq(pile_last_item(pile), o3); /* Now let's try excision */ /* From the top */ pile_excise(&pile, o1); ptreq(pile, o2); eq(pile_contains(pile, o1), FALSE); /* Now put it back */ pile_insert(&pile, o1); /* From the end */ pile_excise(&pile, o3); ptreq(pile, o1); eq(pile_contains(pile, o3), FALSE); ptreq(pile_last_item(pile), o2); ptreq(pile_last_item(pile)->prev, o1); object_delete(o3); /* Now put it back, and add another */ o3 = object_new(); pile_insert_end(&pile, o3); pile_insert_end(&pile, o4); /* Try removing from the middle */ pile_excise(&pile, o3); ptreq(pile, o1); /* Now the list should look like o1 <-> o2 <-> o4, so check that */ ptreq(o1->prev, NULL); ptreq(o1->next, o2); ptreq(o2->prev, o1); ptreq(o2->next, o4); ptreq(o3->prev, NULL); ptreq(o3->next, NULL); ptreq(o4->prev, o2); ptreq(o4->next, NULL); /* Free up */ object_pile_free(pile); ok; }