/** * Set the terrain type for a square. * * This should be the only function that sets terrain, apart from the savefile * loading code. */ void square_set_feat(struct chunk *c, int y, int x, int feat) { int current_feat = c->squares[y][x].feat; assert(c); assert(y >= 0 && y < c->height); assert(x >= 0 && x < c->width); /* Track changes */ if (current_feat) c->feat_count[current_feat]--; if (feat) c->feat_count[feat]++; /* Make the change */ c->squares[y][x].feat = feat; /* Make the new terrain feel at home */ if (character_dungeon) { /* Remove traps if necessary */ if (!square_player_trap_allowed(c, y, x)) square_destroy_trap(c, y, x); square_note_spot(c, y, x); square_light_spot(c, y, x); } else { /* Make sure no incorrect wall flags set for dungeon generation */ sqinfo_off(c->squares[y][x].info, SQUARE_WALL_INNER); sqinfo_off(c->squares[y][x].info, SQUARE_WALL_OUTER); sqinfo_off(c->squares[y][x].info, SQUARE_WALL_SOLID); } }
/** * Determine if a trap actually exists in this square. * * Called with vis = 0 to accept any trap, = 1 to accept only visible * traps, and = -1 to accept only invisible traps. * * Clear the SQUARE_TRAP flag if none exist. */ static bool square_verify_trap(struct chunk *c, int y, int x, int vis) { struct trap *trap = square_trap(c, y, x); bool trap_exists = false; /* Scan the square trap list */ while (trap) { /* Accept any trap */ if (!vis) return true; /* Accept traps that match visibility requirements */ if ((vis == 1) && trf_has(trap->flags, TRF_VISIBLE)) return true; if ((vis == -1) && !trf_has(trap->flags, TRF_VISIBLE)) return true; /* Note that a trap does exist */ trap_exists = true; } /* No traps in this location. */ if (!trap_exists) { /* No traps */ sqinfo_off(c->squares[y][x].info, SQUARE_TRAP); /* Take note */ square_note_spot(c, y, x); } /* Report failure */ return false; }
/** * Let the floor carry an object, deleting old ignored items if necessary. * The calling function must deal with the dropped object on failure. * * Optionally put the object at the top or bottom of the pile */ bool floor_carry(struct chunk *c, int y, int x, struct object *drop, bool last) { int n = 0; struct object *obj, *ignore = floor_get_oldest_ignored(y, x); /* Fail if the square can't hold objects */ if (!square_isobjectholding(c, y, x)) return false; /* Scan objects in that grid for combination */ for (obj = square_object(c, y, x); obj; obj = obj->next) { /* Check for combination */ if (object_similar(obj, drop, OSTACK_FLOOR)) { /* Combine the items */ object_absorb(obj, drop); /* Result */ return true; } /* Count objects */ n++; } /* The stack is already too large */ if (n >= z_info->floor_size || (!OPT(player, birth_stacking) && n)) { /* Delete the oldest ignored object */ if (ignore) { square_excise_object(c, y, x, ignore); delist_object(c, ignore); object_delete(&ignore); } else return false; } /* Location */ drop->iy = y; drop->ix = x; /* Forget monster */ drop->held_m_idx = 0; /* Link to the first or last object in the pile */ if (last) pile_insert_end(&c->squares[y][x].obj, drop); else pile_insert(&c->squares[y][x].obj, drop); /* Record in the level list */ list_object(c, drop); /* Redraw */ square_note_spot(c, y, x); square_light_spot(c, y, x); /* Result */ return true; }
/** * Determine if a trap actually exists in this square. * * Called with vis = 0 to accept any trap, = 1 to accept only visible * traps, and = -1 to accept only invisible traps. * * Clear the SQUARE_TRAP flag if none exist. */ static bool square_verify_trap(struct chunk *c, int y, int x, int vis) { struct trap *trap = c->squares[y][x].trap; bool trap_exists = FALSE; /* Scan the square trap list */ while (trap) { /* Accept any trap */ if (!vis) return TRUE; /* Accept traps that match visibility requirements */ if ((vis == 1) && trf_has(trap->flags, TRF_VISIBLE)) return TRUE; if ((vis == -1) && !trf_has(trap->flags, TRF_VISIBLE)) return TRUE; /* Note that a trap does exist */ trap_exists = TRUE; } /* No traps in this location. */ if (!trap_exists) { /* No traps */ sqinfo_off(c->squares[y][x].info, SQUARE_TRAP); /* No reason to mark this square, ... */ sqinfo_off(c->squares[y][x].info, SQUARE_MARK); /* ... unless certain conditions apply */ square_note_spot(c, y, x); } /* Report failure */ return FALSE; }
/** * Called from project() to affect objects * * Called for projections with the PROJECT_ITEM flag set, which includes * beam, ball and breath effects. * * \param who is the monster list index of the caster * \param r is the distance from the centre of the effect * \param y the coordinates of the grid being handled * \param x the coordinates of the grid being handled * \param dam is the "damage" from the effect at distance r from the centre * \param typ is the projection (GF_) type * \param protected_obj is an object that should not be affected by the * projection, typically the object that created it * \return whether the effects were obvious * * Note that this function determines if the player can see anything that * happens by taking into account: blindness, line-of-sight, and illumination. * * Hack -- effects on objects which are memorized but not in view are also seen. */ bool project_o(int who, int r, int y, int x, int dam, int typ, const struct object *protected_obj) { struct object *obj = square_object(cave, y, x); bool obvious = false; /* Scan all objects in the grid */ while (obj) { bool ignore = false; bool do_kill = false; const char *note_kill = NULL; struct object *next = obj->next; project_object_handler_context_t context = { who, r, y, x, dam, typ, obj, obvious, do_kill, ignore, note_kill, }; project_object_handler_f object_handler = object_handlers[typ]; if (object_handler != NULL) object_handler(&context); obvious = context.obvious; do_kill = context.do_kill && (obj != protected_obj); ignore = context.ignore; note_kill = context.note_kill; /* Attempt to destroy the object */ if (do_kill) { char o_name[80]; /* Effect observed */ if (obj->known && !ignore_item_ok(obj) && square_isseen(cave, y, x)) { obvious = true; object_desc(o_name, sizeof(o_name), obj, ODESC_BASE); } /* Artifacts, and other objects, get to resist */ if (obj->artifact || ignore) { /* Observe the resist */ if (obvious && obj->known && !ignore_item_ok(obj)) msg("The %s %s unaffected!", o_name, VERB_AGREEMENT(obj->number, "is", "are")); } else if (obj->mimicking_m_idx) { /* Reveal mimics */ if (obvious) become_aware(cave_monster(cave, obj->mimicking_m_idx)); } else { /* Describe if needed */ if (obvious && obj->known && note_kill && !ignore_item_ok(obj)) msgt(MSG_DESTROY, "The %s %s!", o_name, note_kill); /* Delete the object */ square_excise_object(cave, y, x, obj); delist_object(cave, obj); object_delete(&obj); /* Redraw */ square_note_spot(cave, y, x); square_light_spot(cave, y, x); } } /* Next object */ obj = next; } /* Return "Anything seen?" */ return (obvious); }
/** * Grab all objects from the grid. */ void process_monster_grab_objects(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny) { struct monster_lore *lore = get_lore(mon->race); struct object *obj; bool visible = mflag_has(mon->mflag, MFLAG_VISIBLE); /* Learn about item pickup behavior */ for (obj = square_object(c, ny, nx); obj; obj = obj->next) { if (!tval_is_money(obj) && visible) { rf_on(lore->flags, RF_TAKE_ITEM); rf_on(lore->flags, RF_KILL_ITEM); break; } } /* Abort if can't pickup/kill */ if (!rf_has(mon->race->flags, RF_TAKE_ITEM) && !rf_has(mon->race->flags, RF_KILL_ITEM)) { return; } /* Take or kill objects on the floor */ obj = square_object(c, ny, nx); while (obj) { char o_name[80]; bool safe = obj->artifact ? true : false; struct object *next = obj->next; /* Skip gold */ if (tval_is_money(obj)) { obj = next; continue; } /* Skip mimicked objects */ if (obj->mimicking_m_idx) { obj = next; continue; } /* Get the object name */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* React to objects that hurt the monster */ if (react_to_slay(obj, mon)) safe = true; /* Try to pick up, or crush */ if (safe) { /* Only give a message for "take_item" */ if (rf_has(mon->race->flags, RF_TAKE_ITEM) && visible && square_isview(c, ny, nx) && !ignore_item_ok(obj)) { /* Dump a message */ msg("%s tries to pick up %s, but fails.", m_name, o_name); } } else if (rf_has(mon->race->flags, RF_TAKE_ITEM)) { /* Describe observable situations */ if (square_isseen(c, ny, nx) && !ignore_item_ok(obj)) msg("%s picks up %s.", m_name, o_name); /* Carry the object */ square_excise_object(c, ny, nx, obj); monster_carry(c, mon, obj); square_note_spot(c, ny, nx); square_light_spot(c, ny, nx); } else { /* Describe observable situations */ if (square_isseen(c, ny, nx) && !ignore_item_ok(obj)) msgt(MSG_DESTROY, "%s crushes %s.", m_name, o_name); /* Delete the object */ square_excise_object(c, ny, nx, obj); delist_object(c, obj); object_delete(&obj); square_note_spot(c, ny, nx); square_light_spot(c, ny, nx); } /* Next object */ obj = next; } }