/** * True if the cave square was seen before the current update */ bool square_wasseen(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_WASSEEN); }
/** * True if the square is on the trap detection edge */ bool square_isdedge(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_DEDGE); }
/** * Attempts to place a copy of the given monster at the given position in * the dungeon. * * All of the monster placement routines eventually call this function. This * is what actually puts the monster in the dungeon (i.e., it notifies the cave * and sets the monsters position). The dungeon loading code also calls this * function directly. * * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP, * ORIGIN_DROP_PIT, etc.) The dungeon loading code calls this with origin = 0, * which prevents the monster's drops from being generated again. * * Returns the m_idx of the newly copied monster, or 0 if the placement fails. */ s16b place_monster(struct chunk *c, int y, int x, struct monster *mon, byte origin) { s16b m_idx; struct monster *new_mon; assert(square_in_bounds(c, y, x)); assert(!square_monster(c, y, x)); /* Get a new record */ m_idx = mon_pop(c); if (!m_idx) return 0; /* Copy the monster */ new_mon = cave_monster(c, m_idx); memcpy(new_mon, mon, sizeof(struct monster)); /* Set the ID */ new_mon->midx = m_idx; /* Set the location */ c->squares[y][x].mon = new_mon->midx; new_mon->fy = y; new_mon->fx = x; assert(square_monster(c, y, x) == new_mon); update_mon(new_mon, c, true); /* Hack -- Count the number of "reproducers" */ if (rf_has(new_mon->race->flags, RF_MULTIPLY)) num_repro++; /* Count racial occurrences */ new_mon->race->cur_num++; /* Create the monster's drop, if any */ if (origin) (void)mon_create_drop(c, new_mon, origin); /* Make mimics start mimicking */ if (origin && new_mon->race->mimic_kinds) { struct object *obj; struct object_kind *kind = new_mon->race->mimic_kinds->kind; struct monster_mimic *mimic_kind; int i = 1; /* Pick a random object kind to mimic */ for (mimic_kind = new_mon->race->mimic_kinds; mimic_kind; mimic_kind = mimic_kind->next, i++) { if (one_in_(i)) kind = mimic_kind->kind; } if (tval_is_money_k(kind)) { obj = make_gold(player->depth, kind->name); } else { obj = object_new(); object_prep(obj, kind, new_mon->race->level, RANDOMISE); apply_magic(obj, new_mon->race->level, true, false, false, false); obj->number = 1; obj->origin = ORIGIN_DROP_MIMIC; obj->origin_depth = player->depth; } obj->mimicking_m_idx = m_idx; new_mon->mimicked_obj = obj; /* Put the object on the floor if it goes, otherwise no mimicry */ if (floor_carry(c, y, x, obj, false)) { list_object(c, obj); } else { /* Clear the mimicry */ obj->mimicking_m_idx = 0; new_mon->mimicked_obj = NULL; /* Give the object to the monster if appropriate */ if (rf_has(new_mon->race->flags, RF_MIMIC_INV)) { monster_carry(c, new_mon, obj); } else { /* Otherwise delete the mimicked object */ object_delete(&obj); } } } /* Result */ return m_idx; }
/** * Attempts to place a monster of the given race at the given location. * * If `sleep` is true, the monster is placed with its default sleep value, * which is given in monster.txt. * * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP, * ORIGIN_DROP_PIT, etc.) * * To give the player a sporting chance, some especially dangerous * monsters are marked as "FORCE_SLEEP" in monster.txt, which will * cause them to be placed with low energy. This helps ensure that * if such a monster suddenly appears in line-of-sight (due to a * summon, for instance), the player gets a chance to move before * they do. * * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters. * * This is the only function which may place a monster in the dungeon, * except for the savefile loading code, which calls place_monster() * directly. */ static bool place_new_monster_one(struct chunk *c, int y, int x, struct monster_race *race, bool sleep, byte origin) { int i; struct monster *mon; struct monster monster_body; assert(square_in_bounds(c, y, x)); assert(race && race->name); /* Not where monsters already are */ if (square_monster(c, y, x)) return false; /* Not where the player already is */ if ((player->py == y) && (player->px == x)) return false; /* Prevent monsters from being placed where they cannot walk, but allow other feature types */ if (!square_is_monster_walkable(c, y, x)) return false; /* No creation on glyph of warding */ if (square_iswarded(c, y, x)) return false; /* "unique" monsters must be "unique" */ if (rf_has(race->flags, RF_UNIQUE) && race->cur_num >= race->max_num) return (false); /* Depth monsters may NOT be created out of depth */ if (rf_has(race->flags, RF_FORCE_DEPTH) && player->depth < race->level) return (false); /* Add to level feeling, note uniques for cheaters */ c->mon_rating += race->power / 20; /* Check out-of-depth-ness */ if (race->level > player->depth) { if (rf_has(race->flags, RF_UNIQUE)) { /* OOD unique */ if (OPT(cheat_hear)) msg("Deep unique (%s).", race->name); } else { /* Normal monsters but OOD */ if (OPT(cheat_hear)) msg("Deep monster (%s).", race->name); } /* Boost rating by power per 10 levels OOD */ c->mon_rating += (race->level - player->depth) * race->power / 200; } else if (rf_has(race->flags, RF_UNIQUE) && OPT(cheat_hear)) msg("Unique (%s).", race->name); /* Get local monster */ mon = &monster_body; /* Clean out the monster */ memset(mon, 0, sizeof(struct monster)); /* Save the race */ mon->race = race; /* Enforce sleeping if needed */ if (sleep && race->sleep) { int val = race->sleep; mon->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10)); } /* Uniques get a fixed amount of HP */ if (rf_has(race->flags, RF_UNIQUE)) mon->maxhp = race->avg_hp; else { mon->maxhp = mon_hp(race, RANDOMISE); mon->maxhp = MAX(mon->maxhp, 1); } /* And start out fully healthy */ mon->hp = mon->maxhp; /* Extract the monster base speed */ mon->mspeed = race->speed; /* Hack -- small racial variety */ if (!rf_has(race->flags, RF_UNIQUE)) { /* Allow some small variation per monster */ i = turn_energy(race->speed) / 10; if (i) mon->mspeed += rand_spread(0, i); } /* Give a random starting energy */ mon->energy = (byte)randint0(50); /* Force monster to wait for player */ if (rf_has(race->flags, RF_FORCE_SLEEP)) mflag_on(mon->mflag, MFLAG_NICE); /* Radiate light? */ if (rf_has(race->flags, RF_HAS_LIGHT)) player->upkeep->update |= PU_UPDATE_VIEW; /* Is this obviously a monster? (Mimics etc. aren't) */ if (rf_has(race->flags, RF_UNAWARE)) mflag_on(mon->mflag, MFLAG_UNAWARE); else mflag_off(mon->mflag, MFLAG_UNAWARE); /* Set the color if necessary */ if (rf_has(race->flags, RF_ATTR_RAND)) mon->attr = randint1(BASIC_COLORS - 1); /* Place the monster in the dungeon */ if (!place_monster(c, y, x, mon, origin)) return (false); /* Success */ return (true); }
/** * True if the cave square is internally lit. */ bool square_isbright(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return feat_is_bright(c->squares[y][x].feat); }
/** * Deletes a monster by index. * * When a monster is deleted, all of its objects are deleted. */ void delete_monster_idx(int m_idx) { int x, y; struct object *obj; struct monster *mon; assert(m_idx > 0); mon = cave_monster(cave, m_idx); /* Monster location */ y = mon->fy; x = mon->fx; assert(square_in_bounds(cave, y, x)); /* Hack -- Reduce the racial counter */ mon->race->cur_num--; /* Hack -- count the number of "reproducers" */ if (rf_has(mon->race->flags, RF_MULTIPLY)) num_repro--; /* Hack -- remove target monster */ if (target_get_monster() == mon) target_set_monster(NULL); /* Hack -- remove tracked monster */ if (player->upkeep->health_who == mon) health_track(player->upkeep, NULL); /* Monster is gone */ cave->squares[y][x].mon = 0; /* Delete objects */ obj = mon->held_obj; while (obj) { struct object *next = obj->next; /* Preserve unseen artifacts (we assume they were created as this * monster's drop) - this will cause unintended behaviour in preserve * off mode if monsters can pick up artifacts */ if (obj->artifact && !(obj->known && obj->known->artifact)) obj->artifact->created = false; /* Delete the object */ delist_object(cave, obj); object_delete(&obj); obj = next; } /* Delete mimicked objects */ if (mon->mimicked_obj) { square_excise_object(cave, y, x, mon->mimicked_obj); delist_object(cave, mon->mimicked_obj); object_delete(&mon->mimicked_obj); } /* Wipe the Monster */ memset(mon, 0, sizeof(struct monster)); /* Count monsters */ cave->mon_cnt--; /* Visual update */ square_light_spot(cave, y, x); }
/** * True if the square is a wall square (impedes the player). * * This function is the logical negation of square_isprojectable(). */ bool square_iswall(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return !square_isprojectable(c, y, x); }
/** * True if cave square is a solid wall (generation) */ bool square_iswall_solid(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_WALL_SOLID); }
/** * True if a monster can walk through the tile. * * This is needed for polymorphing. A monster may be on a feature that isn't * an empty space, causing problems when it is replaced with a new monster. */ bool square_is_monster_walkable(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return feat_is_monster_walkable(c->squares[y][x].feat); }
/** * True if any projectable can pass through the square. * * This function is the logical negation of square_iswall(). */ bool square_isprojectable(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return feat_is_projectable(c->squares[y][x].feat); }
/** * True if cave square is marked for projection processing */ bool square_isproject(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_PROJECT); }
/** * True if cave square can't be teleported from by the player */ bool square_isno_teleport(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_NO_TELEPORT); }
/** * True if cave square has monster restrictions (generation) */ bool square_ismon_restrict(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_MON_RESTRICT); }
/** * True if the square has a known trap */ bool square_istrap(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_TRAP); }
/** * True if the square is a permanent wall or one of the "stronger" walls. * * The stronger walls are granite, magma and quartz. This excludes things like * secret doors and rubble. */ bool square_isstrongwall(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return square_ismineral(c, y, x) || square_isperm(c, y, x); }
/** * True if the square has an unknown trap */ bool square_isinvis(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_INVIS); }
/** * True if cave square is an outer wall (generation) */ bool square_iswall_outer(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return sqinfo_has(c->squares[y][x].info, SQUARE_WALL_OUTER); }