Ejemplo n.º 1
0
/*
 * Summon a creature of the specified type
 *
 * This function is rather dangerous XXX XXX XXX
 */
static void do_cmd_wiz_named(int r_idx, bool slp)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int i, x, y;

	/* Paranoia */
	if (!r_idx) return;
	if (r_idx >= z_info->r_max-1) return;

	/* Try 10 times */
	for (i = 0; i < 10; i++) {
		int d = 1;

		/* Pick a location */
		scatter(&y, &x, py, px, d, 0);

		/* Require empty grids */
		if (!cave_empty_bold(y, x)) continue;

		/* Place it (allow groups) */
		if (place_new_monster(cave, y, x, r_idx, slp, TRUE, ORIGIN_DROP_WIZARD)) break;
	}
}
Ejemplo n.º 2
0
/*!
 * @brief モンスターにとって所定の地点が召還に相応しい地点かどうかを返す。 /
 * Determine if there is a space near the player in which a summoned creature can appear
 * @param y1 判定を行いたいマスのY座標
 * @param x1 判定を行いたいマスのX座標
 * @return 召還に相応しいならばTRUEを返す
 */
bool summon_possible(int y1, int x1)
{
	int y, x;

	/* Start at the player's location, and check 2 grids in each dir */
	for (y = y1 - 2; y <= y1 + 2; y++)
	{
		for (x = x1 - 2; x <= x1 + 2; x++)
		{
			/* Ignore illegal locations */
			if (!in_bounds(y, x)) continue;

			/* Only check a circular area */
			if (distance(y1, x1, y, x)>2) continue;

			/* ...nor on the Pattern */
			if (pattern_tile(y, x)) continue;

			/* Require empty floor grid in line of projection */
			if (cave_empty_bold(y, x) && projectable(y1, x1, y, x) && projectable(y, x, y1, x1)) return (TRUE);
		}
	}

	return FALSE;
}
Ejemplo n.º 3
0
/* Create a trap during play. All traps are untyped until discovered. */
void create_trap(struct cave *c, int y, int x)
{
	assert(cave_in_bounds(c, y, x));
	assert(cave_empty_bold(y, x));

	/* Place an invisible trap */
	cave_set_feat(c, y, x, FEAT_INVIS);
}
Ejemplo n.º 4
0
/*!
 * @brief ウィザードモード用モンスターの群れ生成 / Summon a horde of monsters
 * @return なし
 */
static void do_cmd_summon_horde(void)
{
	int wy = p_ptr->y, wx = p_ptr->x;
	int attempts = 1000;

	while (--attempts)
	{
		scatter(&wy, &wx, p_ptr->y, p_ptr->x, 3, 0);
		if (cave_empty_bold(wy, wx)) break;
	}

	(void)alloc_horde(wy, wx);
}
Ejemplo n.º 5
0
/**
 * Attempts to place a group of monsters of race `r_idx` around
 * the given location. The number of monsters to place is `total`.
 *
 * 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.) 
 */
static bool place_new_monster_group(struct cave *c, int y, int x, 
		monster_race *r_ptr, bool sleep, int total, byte origin)
{
	int n, i;

	int hack_n;

	/* x and y coordinates of the placed monsters */
	byte hack_y[GROUP_MAX];
	byte hack_x[GROUP_MAX];

	assert(r_ptr);
	
	/* Start on the monster */
	hack_n = 1;
	hack_x[0] = x;
	hack_y[0] = y;

	/* Puddle monsters, breadth first, up to total */
	for (n = 0; (n < hack_n) && (hack_n < total); n++) {
		/* Grab the location */
		int hx = hack_x[n];
		int hy = hack_y[n];

		/* Check each direction, up to total */
		for (i = 0; (i < 8) && (hack_n < total); i++) {
			int mx = hx + ddx_ddd[i];
			int my = hy + ddy_ddd[i];

			/* Walls and Monsters block flow */
			if (!cave_empty_bold(my, mx)) continue;

			/* Attempt to place another monster */
			if (place_new_monster_one(my, mx, r_ptr, sleep, origin)) {
				/* Add it to the "hack" set */
				hack_y[hack_n] = my;
				hack_x[hack_n] = mx;
				hack_n++;
			}
		}
	}

	/* Success */
	return (TRUE);
}
Ejemplo n.º 6
0
/**
 * Place monsters, up to the number asked for, in a rectangle centered on 
 * y0, x0.  Accept values for monster depth, symbol, and maximum vertical 
 * and horizontal displacement.  Call monster restriction functions if 
 * needed.
 *
 * Return prematurely if the code starts looping too much (this may happen 
 * if y0 or x0 are out of bounds, or the area is already occupied).
 */
extern void spread_monsters(char symbol, int depth, int num, int y0, int x0,
			    int dy, int dx)
{
    int i, j;			/* Limits on loops */
    int count;
    int y = y0, x = x0;
    int start_mon_num = m_max;
    bool dummy;

    /* Restrict monsters.  Allow uniques. */
    (void) mon_restrict(symbol, (byte) depth, &dummy, TRUE);

    /* Set generation level */
    monster_level = depth;

    /* Build the monster probability table. */
    if (!get_mon_num(depth))
	return;


    /* Try to summon monsters within our rectangle of effect. */
    for (count = 0, i = 0; ((count < num) && (i < 50)); i++) {
	/* Get a location */
	if ((dy == 0) && (dx == 0)) {
	    y = y0;
	    x = x0;
	    if (!in_bounds(y, x))
		return;
	} else {
	    for (j = 0; j < 10; j++) {
		y = rand_spread(y0, dy);
		x = rand_spread(x0, dx);
		if (!in_bounds(y, x)) {
		    if (j < 9)
			continue;
		    else
			return;
		}
		break;
	    }
	}

	/* Require "empty" floor grids */
	if (!cave_empty_bold(y, x))
	    continue;

	/* Place the monster (sleeping, allow groups, quickly) */
	(void) place_monster(y, x, TRUE, TRUE, TRUE);

	/* Rein in monster groups and escorts a little. */
	if (m_max - start_mon_num > num * 2)
	    break;

	/* Count the monster(s), reset the loop count */
	count++;
	i = 0;
    }

    /* Remove monster restrictions. */
    (void) mon_restrict('\0', (byte) depth, &dummy, TRUE);

    /* Reset monster generation level. */
    monster_level = p_ptr->danger;
}
Ejemplo n.º 7
0
/*
 * Places a ghost somewhere.
 */
s16b place_ghost(void)
{
#if 0 /* DGDGDGDG */
	int y, x, hp, level, grace, gclass;

	monster_race *r_ptr = &r_info[max_r_idx - 1];

	FILE *fp;

	bool err = FALSE;
	bool town = FALSE;

	char name[100];
	char tmp[1024];

	/* Hack -- no ghosts in the town */
	if (!dun_level) return (FALSE);

	/* Already have a ghost */
	if (r_ptr->cur_num >= r_ptr->max_num)
	{
		return (FALSE);
	}

	/* Dungeon -- Use Dungeon Level */
	else
	{
		/* And even then, it only happens sometimes */
		if (14 > randint((dun_level / 2) + 11)) return (FALSE);

		/* Only a 45% chance */
		if (magik(45)) return (FALSE);

		/* Level is dungeon level */
		level = dun_level;
	}


	/* Choose a bones file */
	sprintf(tmp, "%s%sbone%03d.%03d", ANGBAND_DIR_BONE, PATH_SEP, dungeon_type, level);

	/* Grab permission */
	safe_setuid_grab();

	/* Open the bones file */
	fp = my_fopen(tmp, "r");

	/* Drop permission */
	safe_setuid_drop();

	/* No bones file to use */
	if (!fp) return (FALSE);

	/* Scan the file */
	err = (fscanf(fp, "%[^\n]\n%d\n%d\n%d", name, &hp, &grace, &gclass) != 4);


	/* Close the file */
	fclose(fp);

	/* Previously, the bone file would now be deleted. The new
	 * method is to only remove the bone file when the ghost is
	 * destroyed. This means that failing to kill a ghost will
	 * not lose it permenently -TM-
	 * fd_kill(tmp); */

	/* Catch errors */
	if (err)
	{
		msg_print("Warning -- deleted corrupt 'ghost' file!");
		return (FALSE);
	}

	/* Create "town" flag */
	/* TM- What is this? Previously, if the player and dungeon levels
	 * were equal then a 'town' ghost was created. I can't see why
	 * 'town'. They are simply ghosts with abilities determined by
	 * previous class. Currently we just pick between the two.
	 * WAS: if (level == p_ptr->lev) town = TRUE;
	 */
	if (!rand_int(2)) town = TRUE;

	/* Set up the ghost */
	set_ghost(name, hp, grace, gclass, level, town);


	/* Hack -- pick a nice (far away) location */
	while (1)
	{

		/* Pick a location */
		y = randint(cur_hgt - 2);
		x = randint(cur_wid - 2);

		/* Require "naked" floor grid */
		if (!cave_empty_bold(y, x)) continue;

		/* Accept far away grids */
		if (distance(p_ptr->py, p_ptr->px, y, x) > MAX_SIGHT + 5) break;
	}


	/*** Place the Ghost by Hand (so no-one else does it accidentally) ***/

	r_ptr->cur_num = 0;
	r_ptr->max_num = 1;

	if (!place_monster_one(y, x, max_r_idx - 1, 0, FALSE, MSTATUS_ENEMY))
	{
		return FALSE;
	}

	/* Make sure it looks right */
	r_ptr->x_attr = r_ptr->d_attr;
	r_ptr->x_char = r_ptr->d_char;
	return TRUE;
#else 
	return (FALSE);
#endif
}
Ejemplo n.º 8
0
/*!
 * @brief フロア移動時、プレイヤーの移動先モンスターが既にいた場合ランダムな近隣に移動させる / When a monster is at a place where player will return,
 * @return なし
 */
static void get_out_monster(void)
{
	int tries = 0;
	int dis = 1;
	int oy = p_ptr->y;
	int ox = p_ptr->x;
	MONSTER_IDX m_idx = cave[oy][ox].m_idx;

	/* Nothing to do if no monster */
	if (!m_idx) return;

	/* Look until done */
	while (TRUE)
	{
		monster_type *m_ptr;

		/* Pick a (possibly illegal) location */
		int ny = rand_spread(oy, dis);
		int nx = rand_spread(ox, dis);

		tries++;

		/* Stop after 1000 tries */
		if (tries > 10000) return;

		/*
		 * Increase distance after doing enough tries
		 * compared to area of possible space
		 */
		if (tries > 20 * dis * dis) dis++;

		/* Ignore illegal locations */
		if (!in_bounds(ny, nx)) continue;

		/* Require "empty" floor space */
		if (!cave_empty_bold(ny, nx)) continue;

		/* Hack -- no teleport onto glyph of warding */
		if (is_glyph_grid(&cave[ny][nx])) continue;
		if (is_explosive_rune_grid(&cave[ny][nx])) continue;

		/* ...nor onto the Pattern */
		if (pattern_tile(ny, nx)) continue;

		/*** It's a good place ***/

		m_ptr = &m_list[m_idx];

		/* Update the old location */
		cave[oy][ox].m_idx = 0;

		/* Update the new location */
		cave[ny][nx].m_idx = m_idx;

		/* Move the monster */
		m_ptr->fy = ny;
		m_ptr->fx = nx; 

		/* No need to do update_mon() */

		/* Success */
		return;
	}
}
Ejemplo n.º 9
0
/*
 * Allocate objects upon opening a chest.
 *
 * Disperse treasures from the given chest, centered at (x,y).
 *
 * In Oangband, chests are nice finds.  Small chests distribute 3-5 items,
 * while large chests can distribute 5-7.  Item types are biased to be
 * useful for the character, and they can frequently be of good quality
 * (or better).   Code in object2.c helps these items be even better. -LM-
 *
 * The "value" of the items in a chest is based on the "power" of the chest,
 * which is in turn based on the level on which the chest is generated.
 */
static void chest_death(bool scatter, int y, int x, s16b o_idx)
{
	int number, i;
	bool obj_success=FALSE;
	object_type *o_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	/* Access chest */
	o_ptr = &o_list[o_idx];

	/* Determine how much to drop. */
	if (o_ptr->sval >= SV_CHEST_MIN_LARGE) number = 4 + randint1(3);
	else number = 2 + randint1(3);

	/* Zero pval means empty chest */
	if (!o_ptr->pval) number = 0;

	/* Opening a chest */
	opening_chest = TRUE;

	/* Determine the "value" of the items */
	object_level = ABS(o_ptr->pval);

	/* Select an item type that the chest will disperse. */
	required_tval = get_choice();

	/* Drop some objects (non-chests) */
	for (; number > 0; --number)
	{
		/* Get local object */
		i_ptr = &object_type_body;

		/* Wipe the object */
		object_wipe(i_ptr);

		/* Make an object with a specified tval.  Grant a possibility for
		 * items to be forced good, or even great.  With the new definitions
		 * of goodness, this can make for quite interesting loot.  -LM-
		 */
		switch (required_tval)
		{
			case TV_HARD_ARMOR:
			case TV_SOFT_ARMOR:
			case TV_DRAG_ARMOR:
			case TV_SHIELD:
			case TV_CLOAK:
			case TV_BOOTS:
			case TV_GLOVES:
			case TV_HELM:
			case TV_CROWN:
			case TV_BOW:
			case TV_SWORD:
			case TV_HAFTED:
			case TV_POLEARM:
			case TV_DIGGING:
			case TV_SHOT:
			case TV_BOLT:
			case TV_ARROW:
			{
				if (randint1(200) < object_level)
				{
					obj_success=make_object(i_ptr, TRUE, TRUE, TRUE);
					break;
				}

				else if (randint1(40) < object_level)
				{
					obj_success=make_object(i_ptr, TRUE, FALSE, TRUE);
					break;
				}
				else
				{
					obj_success=make_object(i_ptr, FALSE, FALSE, TRUE);
					break;
				}
			}

			case TV_MAGIC_BOOK:
			case TV_PRAYER_BOOK:
			case TV_DRUID_BOOK:
			case TV_NECRO_BOOK:
			{
				if (randint1(80) < object_level)
				{
				  obj_success=make_object(i_ptr, TRUE, FALSE, TRUE);
				}
				else
				{
				  obj_success=make_object(i_ptr, FALSE, FALSE, TRUE);
				}

				break;
			}

			case TV_SCROLL:
			case TV_POTION:
			case TV_RING:
			case TV_AMULET:
			case TV_WAND:
			case TV_STAFF:
			case TV_ROD:
			{
				if (randint1(100) < (object_level - 10) / 2)
				{
					obj_success=make_object(i_ptr, TRUE, FALSE, TRUE);
				}

				else
				{
					obj_success=make_object(i_ptr, FALSE, FALSE, TRUE);
				}

				break;
			}

			default:
			{
				obj_success=make_object(i_ptr, FALSE, FALSE, TRUE);
				break;
			}
		}

		/* If no object was made, we need to try another tval. */
		if (!obj_success)
		{
			required_tval = get_choice();
		}

		/* If chest scatters its contents, pick any floor square. */
		if (scatter)
		{
			for (i = 0; i < 200; i++)
			{
				/* Pick a totally random spot. */
				y = randint0(DUNGEON_HGT);
				x = randint0(DUNGEON_WID);

				/* Must be an empty floor. */
				if (!cave_empty_bold(y, x)) continue;

				/* Place the object there. */
				if (obj_success)
				  drop_near(i_ptr, -1, y, x);

				/* Done. */
				break;
			}
		}
		/* Normally, drop object near the chest. */
		else
		  if (obj_success)
		    drop_near(i_ptr, -1, y, x);
	}

	/* Clear this global variable, to avoid messing up object generation. */
	required_tval = 0;

	/* Reset the object level */
	object_level = p_ptr->depth;

	/* No longer opening a chest */
	opening_chest = FALSE;

	/* Empty */
	o_ptr->pval = 0;

	/* Known */
	object_known(o_ptr);
}
Ejemplo n.º 10
0
bool quest_poison_gen_hook(char *fmt)
{
	int cy = 1, cx = 1, x, y, try = 10000, r_idx;
	bool (*old_get_mon_num_hook)(int r_idx);

	if (cquest.status != QUEST_STATUS_TAKEN) return FALSE;
	if (p_ptr->wilderness_y != wild_locs[cquest.data[0]][0]) return FALSE;
	if (p_ptr->wilderness_x != wild_locs[cquest.data[0]][1]) return FALSE;
	if (p_ptr->wild_mode) return FALSE;

	/* Find a good position */
	while (try)
	{
		/* Get a random spot */
		cy = randint(cur_hgt - 24) + 22;
		cx = randint(cur_wid - 34) + 32;

		/* Is it a good spot ? */
		if (cave_empty_bold(cy, cx)) break;

		/* One less try */
		try--;
	}

	/* Place the baddies */

	/* Backup the old hook */
	old_get_mon_num_hook = get_mon_num_hook;

	/* Require "okay" monsters */
	get_mon_num_hook = create_molds_hook;

	/* Prepare allocation table */
	get_mon_num_prep();

	/* Pick a monster, using the level calculation */
	for (x = cx - 25; x <= cx + 25; x++)
		for (y = cy - 25; y <= cy + 25; y++)
		{
			if (!in_bounds(y, x)) continue;

			if (distance(cy, cx, y, x) > 25) continue;

			if (magik(80) && ((cave[y][x].feat == FEAT_DEEP_WATER) || (cave[y][x].feat == FEAT_SHAL_WATER))) cave_set_feat(y, x, FEAT_TAINTED_WATER);

			if (distance(cy, cx, y, x) > 10) continue;

			if (magik(60))
			{
				int m_idx;

				r_idx = get_mon_num(30);
				m_idx = place_monster_one(y, x, r_idx, 0, FALSE, MSTATUS_ENEMY);

				/* Sometimes make it up some levels */
				if (magik(80) && m_idx)
				{
					monster_type *m_ptr = &m_list[m_idx];

					if (m_ptr->level < p_ptr->lev)
					{
						m_ptr->exp = MONSTER_EXP(m_ptr->level + randint(p_ptr->lev - m_ptr->level));
						monster_check_experience(m_idx, TRUE);
					}
				}
			}
		}

	/* Reset restriction */
	get_mon_num_hook = old_get_mon_num_hook;

	/* Prepare allocation table */
	get_mon_num_prep();

	return FALSE;
}
bool quest_poison_finish_hook(char *fmt)
{
	object_type forge, *q_ptr;
	s32b q_idx;

	q_idx = get_next_arg(fmt);

	if (q_idx != QUEST_POISON) return FALSE;

	c_put_str(TERM_YELLOW, "The water is clean again! Thank you so much.", 8, 0);
	c_put_str(TERM_YELLOW, "The beautiful Mallorns are safe. Take this as a proof of our gratitude.", 9, 0);

	q_ptr = &forge;
	object_prep(q_ptr, lookup_kind(TV_DRAG_ARMOR, SV_DRAGON_BLUE));
	q_ptr->found = OBJ_FOUND_REWARD;
	q_ptr->number = 1;
	q_ptr->name2 = EGO_ELVENKIND;
	apply_magic(q_ptr, 1, FALSE, FALSE, FALSE);
	object_aware(q_ptr);
	object_known(q_ptr);
	q_ptr->ident |= IDENT_STOREB;
	(void)inven_carry(q_ptr, FALSE);

	/* Continue the plot */
	*(quest[q_idx].plot) = QUEST_NULL;

	del_hook(HOOK_QUEST_FINISH, quest_poison_finish_hook);
	process_hooks_restart = TRUE;

	return TRUE;
}
/**********************************************************************
 * Spells: Note, we are still using the old "Book Spell System"
 **********************************************************************/
cptr do_necromancy_spell(int spell, int mode)
{
    bool name = (mode == SPELL_NAME) ? TRUE : FALSE;
    bool desc = (mode == SPELL_DESC) ? TRUE : FALSE;
    bool info = (mode == SPELL_INFO) ? TRUE : FALSE;
    bool cast = (mode == SPELL_CAST) ? TRUE : FALSE;
    bool fail = (mode == SPELL_FAIL) ? TRUE : FALSE;

    int plev = p_ptr->lev;

    switch (spell)
    {
    /* Stench of Death */
    case 0:
        if (name) return "Cold Touch";
        if (desc) return "Damage an adjacent monster with a chilling touch.";
        if (info) return _necro_info_damage(2, 6, plev + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_COLD, 2, 6, plev + p_ptr->to_d_spell)) return NULL;
        break;

    case 1:
        if (name) return "Summon Rat";
        if (desc) return "Summons a rat to feast on the dead!";
        if (cast || fail) _necro_do_summon(SUMMON_RAT, 1, fail);
        break;

    case 2:
        if (name) return "Detect Life";
        if (desc) return "Detects all living monsters in your vicinity.";
        if (info) return info_radius(DETECT_RAD_DEFAULT);
        if (cast) detect_monsters_living(DETECT_RAD_DEFAULT, "You sense the presence of life around you.");
        break;

    case 3:
        if (name) return "Detect Unlife";
        if (desc) return "Detects all nonliving monsters in your vicinity.";
        if (info) return info_radius(DETECT_RAD_DEFAULT);
        if (cast) detect_monsters_nonliving(DETECT_RAD_DEFAULT);
        break;

    case 4:
        if (name) return "Poison Touch";
        if (desc) return "Damage an adjacent monster with a venomous touch.";
        if (info) return _necro_info_damage(4, 6, plev + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_POIS, 4, 6, plev + p_ptr->to_d_spell)) return NULL;
        break;

    case 5:
        if (name) return "Summon Bats";
        if (desc) return "Summons bats to feast on the living!";
        if (cast || fail) _necro_do_summon(SUMMON_BAT, 1 + randint1(2), fail);
        break;

    case 6:
        if (name) return "Eldritch Howl";
        if (desc) return "Emit a terrifying howl.";
        if (cast) project_hack(GF_ELDRITCH_HOWL, spell_power(plev * 3));
        break;

    case 7:
        if (name) return "Black Touch";
        if (desc) return "Damage an adjacent monster with a dark touch.";
        if (info) return _necro_info_damage(6, 6, plev * 3 / 2 + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_DARK, 6, 6, plev * 3 / 2 + p_ptr->to_d_spell)) return NULL;
        break;

    /* Sepulchral Ways */
    case 8:
        if (name) return "Summon Wolves";
        if (desc) return "Summons wolves to feast on the living!";
        if (cast || fail) _necro_do_summon(SUMMON_WOLF, 1 + randint1(2), fail);
        break;

    case 9:
        if (name) return "Black Cloak";
        if (desc) return "You become shrouded in darkness.";
        if (cast) 
        {
            set_tim_dark_stalker(spell_power(randint1(plev) + plev), FALSE);
        }
        break;

    case 10:
        if (name) return "Undead Sight";
        if (desc) return "Learn about your nearby surroundings by communing with the dead.";
        if (info) return info_radius(DETECT_RAD_MAP);
        if (cast)
        {
            map_area(DETECT_RAD_MAP);
            detect_traps(DETECT_RAD_DEFAULT, TRUE);
            detect_doors(DETECT_RAD_DEFAULT);
            detect_stairs(DETECT_RAD_DEFAULT);
        }
        break;

    case 11:
        if (name) return "Undead Lore";
        if (desc) return "Ask the dead to examine an object for you.";
        if (cast) ident_spell(NULL);
        break;

    case 12:
        if (name) return "Repelling Touch";
        if (desc) return "Conjure a foul wind to blow an adjacent monster away.";
    
        if (cast)
        {
            int y, x, dir;

            if (!_necro_check_touch()) return NULL;
            if (!get_rep_dir2(&dir)) return NULL;
            if (dir == 5) return NULL;

            y = py + ddy[dir];
            x = px + ddx[dir];

            if (!cave[y][x].m_idx)
            {
                msg_print("There is no monster.");
                return NULL;
            }
            else
            {
                int i;
                int ty = y, tx = x;
                int oy = y, ox = x;
                int m_idx = cave[y][x].m_idx;
                monster_type *m_ptr = &m_list[m_idx];
                char m_name[80];
    
                monster_desc(m_name, m_ptr, 0);
                touch_zap_player(cave[y][x].m_idx);    
    
                for (i = 0; i < 10; i++)
                {
                    y += ddy[dir];
                    x += ddx[dir];
                    if (cave_empty_bold(y, x))
                    {
                        ty = y;
                        tx = x;
                    }
                    else break;
                }
                if ((ty != oy) || (tx != ox))
                {
                    msg_format("A foul wind blows %s away!", m_name);
                    cave[oy][ox].m_idx = 0;
                    cave[ty][tx].m_idx = m_idx;
                    m_ptr->fy = ty;
                    m_ptr->fx = tx;
    
                    update_mon(m_idx, TRUE);
                    lite_spot(oy, ox);
                    lite_spot(ty, tx);
    
                    if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
                        p_ptr->update |= (PU_MON_LITE);
                }
            }
        }
        break;

    case 13:
        if (name) return "Vampiric Touch";
        if (desc) return "Steal life from an adjacent foe.";
        if (info) return _necro_info_damage(0, 0, plev * 4 + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_OLD_DRAIN, 0, 0, plev * 4 + p_ptr->to_d_spell)) return NULL;
        break;

    case 14:
        if (name) return "Dread of Night";
        if (desc) return "Summons Dread to do your bidding. Beware of failure!";
        if (cast || fail) _necro_do_summon(SUMMON_DREAD, 1 + randint0(3), fail);
        break;

    case 15:
        if (name) return "Entomb";
        if (desc) return "Entombs chosen foe.";
        if (cast)
        {
            int dir; 
            if (!get_fire_dir(&dir)) return NULL;
            fire_ball_hide(GF_ENTOMB, dir, plev, 0);
            p_ptr->update |= (PU_FLOW);
            p_ptr->redraw |= (PR_MAP);
        }
        break;

    /* Return of the Dead */
    case 16:
        if (name) return "Summon Zombies";
        if (desc) return "The dead are back and hungry for brains!";
        if (cast || fail) _necro_do_summon(SUMMON_ZOMBIE, 2 + randint1(3), fail);
        break;

    case 17:
        if (name) return "Summon Skeletons";
        if (desc) return "Summon skeletal assistance.";
        if (cast || fail) _necro_do_summon(SUMMON_SKELETON, 1 + randint0(3), fail);
        break;

    case 18:
        if (name) return "Summon Ghosts";
        if (desc) return "Recall the spirits of slain warriors for unholy servitude.";
        if (cast || fail) _necro_do_summon(SUMMON_GHOST, 1 + randint0(3), fail);
        break;

    case 19:
        if (name) return "Summon Vampires";
        if (desc) return "Its time to command the commanders!";
        if (cast || fail) _necro_do_summon(SUMMON_VAMPIRE, 1 + randint0(2), fail);
        break;

    case 20:
        if (name) return "Summon Wraiths";
        if (desc) return "Summon wights and wraiths to do your bidding.";
        if (cast || fail) _necro_do_summon(SUMMON_WIGHT, 1 + randint0(2), fail);
        break;

    case 21:
        if (name) return "Summon Liches";
        if (desc) return "Call forth former necromancers.";
        if (cast || fail) _necro_do_summon(SUMMON_LICH, 1 + randint0(2), fail);
        break;

    case 22:
        if (name) return "Unholy Word";
        if (desc) return "Utter an unspeakable word. The morale of your visible evil pets is temporarily boosted and they will serve you with renewed enthusiasm.";
        if (cast) project_hack(GF_UNHOLY_WORD, plev * 6);
        break;

    case 23:
        if (name) return "Lost Cause";
        if (desc) return "Make a last ditch Kamikaze effort for victory!";
        if (cast) discharge_minion();
        break;

    /* Necromatic Tome */
    case 24:
        if (name) return "Draining Touch";
        if (desc) return "Steal mana from an adjacent foe.";
        if (info) return _necro_info_damage(5, 5, plev/2 + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_DRAINING_TOUCH, 5, 5, plev/2 + p_ptr->to_d_spell)) return NULL;
        break;

    case 25:
        if (name) return "Unhallow Ground";
        if (desc) return "Makes the current square unholy.";
        if (cast) warding_glyph(); /* TODO: Add new cave feature! */
        break;

    case 26:
    {
        int base = spell_power(20);
        if (name) return "Shield of the Dead";
        if (desc) return "Grants temporary protection";
        if (info) return info_duration(base, base);
        if (cast)
        {
            set_tim_res_nether(randint1(base) + base, FALSE);
            set_oppose_pois(randint1(base) + base, FALSE);
            set_oppose_cold(randint1(base) + base, FALSE);
            set_shield(randint1(base) + base, FALSE);
        }
        break;
    }
    case 27:
        if (name) return "Rending Touch";
        if (desc) return "Damage an adjacent monster with a disintegrating touch.";
        if (info) return _necro_info_damage(20, 20, plev + p_ptr->to_d_spell);
        if (cast && !_necro_do_touch(GF_DISINTEGRATE, 20, 20, plev + p_ptr->to_d_spell)) return NULL;
        break;

    case 28:
        if (name) return "Repose of the Dead";
        if (desc) return "Sleep the sleep of the dead for a few rounds, during which time nothing can awaken you, except perhaps death. When (if?) you wake up, you will be thoroughly refreshed!";
        if (cast)
        {
            if (!get_check("You will enter a deep slumber. Are you sure?")) return NULL;
            repose_of_the_dead = TRUE;
            set_paralyzed(4 + randint1(4), FALSE);
        }
        break;

    case 29:
        if (name) return "Sepulchral Wind";
        if (desc) return "You call forth the wind of the dead. All nearby monsters are blown away!";
        {
            int power = spell_power(plev * 4);
            if (info) return info_power(power);
            if (cast) banish_monsters(power);
        }
        break;

    case 30:
        if (name) return "Deadly Touch";
        if (desc) return "Attempt to kill an adjacent monster.";
        if (cast && !_necro_do_touch(GF_DEATH_TOUCH, 0, 0, plev * 200)) return NULL;
        break;

    case 31:
        if (name) return "Necromancy";
        if (desc) return "Bridge the world of the living with the world of the dead!  Vast hordes of undead will come forth to serve the one true necromancer!";
        if (cast)
        {
            int i;
            int sp_sides = 20 + plev;
            int sp_base = plev;
            int power = spell_power(plev);

            power += randint1(power);

            for (i = 0; i < 18; i++)
            {
                int attempt = 10;
                int my, mx, what;

                while (attempt--)
                {
                    scatter(&my, &mx, py, px, 4, 0);

                    /* Require empty grids */
                    if (cave_empty_bold2(my, mx)) break;
                }
                if (attempt < 0) continue;
                switch (randint1(4))
                {
                case 1: what = SUMMON_LICH; break;
                case 2: what = SUMMON_WIGHT; break;
                case 3: what = SUMMON_VAMPIRE; break;
                case 4:
                default: what = SUMMON_GHOST; break;
                }
                summon_specific(-1, my, mx, power, what, (PM_ALLOW_GROUP | PM_FORCE_PET | PM_HASTE));
            }
            set_fast(randint1(sp_sides) + sp_base, FALSE);
        }
        break;

    }

    return "";
}
Ejemplo n.º 12
0
_rush_result _rush_attack(int rng, _rush_type type)
{
    _rush_result result = _rush_cancelled;
    int tx, ty;
    int tm_idx = 0;
    u16b path_g[32];
    int path_n, i;
    bool moved = FALSE;
    int flg = 0;
    int dis = 0;

    if (type == _rush_normal)
        flg = PROJECT_STOP | PROJECT_KILL;
    else if (type == _rush_acrobatic)
        flg = PROJECT_THRU | PROJECT_KILL;
    else
        flg = PROJECT_DISI | PROJECT_THRU;

    if (!p_ptr->duelist_target_idx)
    {
        msg_print("You need to select a foe first (Mark Target).");
        return result;
    }

    tm_idx = p_ptr->duelist_target_idx;
    tx = m_list[tm_idx].fx;
    ty = m_list[tm_idx].fy;

    dis = distance(ty, tx, py, px);

    /* Foe must be visible.  For all charges except the phase charge, the
       foe must also be in your line of sight */
    if (!m_list[p_ptr->duelist_target_idx].ml ||
        (type != _rush_phase && !los(ty, tx, py, px)))
    {
        msg_format("%^s is not in your line of sight.", duelist_current_challenge());
        return result;
    }

    if (dis > rng)
    {
        msg_format("Your foe is out of range (%d vs %d).", dis, rng);
        if (!get_check("Charge anyway? ")) return result;
    }

    project_length = rng;
    path_n = project_path(path_g, project_length, py, px, ty, tx, flg);
    project_length = 0;

    if (!path_n) return result;

    result = _rush_failed;

    /* Use ty and tx as to-move point */
    ty = py;
    tx = px;

    /* Scrolling the cave would invalidate our path! */
    if (!dun_level && !p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle)
        wilderness_scroll_lock = TRUE;

    /* Project along the path */
    for (i = 0; i < path_n; i++)
    {
        monster_type *m_ptr;
        cave_type *c_ptr;
        bool can_enter = FALSE;
        bool old_pass_wall = p_ptr->pass_wall;

        int ny = GRID_Y(path_g[i]);
        int nx = GRID_X(path_g[i]);
        c_ptr = &cave[ny][nx];

        switch (type)
        {
        case _rush_normal:
            can_enter = cave_empty_bold(ny, nx) && player_can_enter(c_ptr->feat, 0);
            break;

        case _rush_acrobatic:
            can_enter = !c_ptr->m_idx && player_can_enter(c_ptr->feat, 0);
            break;
        
        case _rush_phase:
            p_ptr->pass_wall = TRUE;
            can_enter = !c_ptr->m_idx && player_can_enter(c_ptr->feat, 0);
            p_ptr->pass_wall = old_pass_wall;
            break;
        }

        if (can_enter)
        {
            ty = ny;
            tx = nx;
            continue;
        }

        if (!c_ptr->m_idx)
        {
            msg_print("Failed!");
            break;
        }

        /* Move player before updating the monster */
        if (!player_bold(ty, tx)) move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
        moved = TRUE;

        /* Update the monster */
        update_mon(c_ptr->m_idx, TRUE);

        /* Found a monster */
        m_ptr = &m_list[c_ptr->m_idx];

        /* But it is not the monster we seek! */
        if (tm_idx != c_ptr->m_idx)
        {
            /* Acrobatic Charge attempts to displace monsters on route */
            if (type == _rush_acrobatic)
            {
                /* Swap position of player and monster */
                set_monster_csleep(c_ptr->m_idx, 0);
                move_player_effect(ny, nx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
                ty = ny;
                tx = nx;
                continue;
            }
            /* Normal Charge just attacks first monster on route */
            else
                msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone");
        }

        /* Attack the monster */
        if (tm_idx == p_ptr->duelist_target_idx) result = _rush_succeeded;
        py_attack(ny, nx, 0);
        break;
    }

    if (!moved && !player_bold(ty, tx)) move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
    if (!dun_level && !p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle)
    {
        wilderness_scroll_lock = FALSE;
        wilderness_move_player(px, py);
    }
    return result;
}
Ejemplo n.º 13
0
/**
 * 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(int y, int x, monster_race *r_ptr, 
		bool sleep, byte origin)
{
	int i;

	monster_type *n_ptr;
	monster_type monster_type_body;

	const char *name;

	assert(in_bounds(y, x));

	/* Require empty space */
	if (!cave_empty_bold(y, x)) return (FALSE);

	/* No creation on glyph of warding */
	if (cave->feat[y][x] == FEAT_GLYPH) return (FALSE);

	assert(r_ptr && r_ptr->name);
	name = r_ptr->name;

	/* "unique" monsters must be "unique" */
	if (rf_has(r_ptr->flags, RF_UNIQUE) && r_ptr->cur_num >= r_ptr->max_num)
		return (FALSE);

	/* Depth monsters may NOT be created out of depth */
	if (rf_has(r_ptr->flags, RF_FORCE_DEPTH) && p_ptr->depth < r_ptr->level)
		return (FALSE);

	/* Add to level feeling */
	cave->mon_rating += r_ptr->power / 20;

	/* Check out-of-depth-ness */
	if (r_ptr->level > p_ptr->depth) {
		if (rf_has(r_ptr->flags, RF_UNIQUE)) { /* OOD unique */
			if (OPT(cheat_hear))
				msg("Deep Unique (%s).", name);
		} else { /* Normal monsters but OOD */
			if (OPT(cheat_hear))
				msg("Deep Monster (%s).", name);
		}
		/* Boost rating by power per 10 levels OOD */
		cave->mon_rating += (r_ptr->level - p_ptr->depth) * r_ptr->power / 200;
	}
	/* Note uniques for cheaters */
	else if (rf_has(r_ptr->flags, RF_UNIQUE) && OPT(cheat_hear))
		msg("Unique (%s).", name);

	/* Get local monster */
	n_ptr = &monster_type_body;

	/* Clean out the monster */
	(void)WIPE(n_ptr, monster_type);

	/* Save the race */
	n_ptr->r_idx = r_ptr->ridx;

	/* Enforce sleeping if needed */
	if (sleep && r_ptr->sleep) {
		int val = r_ptr->sleep;
		n_ptr->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10));
	}

	/* Uniques get a fixed amount of HP */
	if (rf_has(r_ptr->flags, RF_UNIQUE))
		n_ptr->maxhp = r_ptr->avg_hp;
	else {
		n_ptr->maxhp = mon_hp(r_ptr, RANDOMISE);
		n_ptr->maxhp = MAX(n_ptr->maxhp, 1);
	}

	/* And start out fully healthy */
	n_ptr->hp = n_ptr->maxhp;

	/* Extract the monster base speed */
	n_ptr->mspeed = r_ptr->speed;

	/* Hack -- small racial variety */
	if (!rf_has(r_ptr->flags, RF_UNIQUE)) {
		/* Allow some small variation per monster */
		i = extract_energy[r_ptr->speed] / 10;
		if (i) n_ptr->mspeed += rand_spread(0, i);
	}

	/* Give a random starting energy */
	n_ptr->energy = (byte)randint0(50);

	/* Force monster to wait for player */
	if (rf_has(r_ptr->flags, RF_FORCE_SLEEP))
		n_ptr->mflag |= (MFLAG_NICE);

	/* Radiate light? */
	if (rf_has(r_ptr->flags, RF_HAS_LIGHT))
		p_ptr->update |= PU_UPDATE_VIEW;
	
	/* Is this obviously a monster? (Mimics etc. aren't) */
	if (rf_has(r_ptr->flags, RF_UNAWARE)) 
		n_ptr->unaware = TRUE;
	else
		n_ptr->unaware = FALSE;

	/* Set the color if necessary */
	if (rf_has(r_ptr->flags, RF_ATTR_RAND))
		n_ptr->attr = randint1(BASIC_COLORS - 1);

	/* Place the monster in the dungeon */
	if (!place_monster(y, x, n_ptr, origin))
		return (FALSE);

	/* Success */
	return (TRUE);
	
	
}
Ejemplo n.º 14
0
/**
 * Attempts to place a monster of the given race at the given location.
 *
 * Note that certain monsters are placed with a large group of
 * identical or similar monsters. However, if `group_okay` is false,
 * then such monsters are placed by themselves.
 *
 * 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.) 
 *
 * Note the "bizarre" use of non-recursion to prevent annoying output
 * when running a code profiler.
 *
 * Note the use of the "monster allocation table" to restrict
 * the "get_mon_num()" function to "legal" escort types.
 */
bool place_new_monster(struct cave *c, int y, int x, int r_idx, bool sleep,
	bool group_okay, byte origin)
{
	int i;

	monster_race *r_ptr;

	assert(c);
	
	assert(r_idx > 0);
	r_ptr = &r_info[r_idx];
	
	/* Place one monster, or fail */
	if (!place_new_monster_one(y, x, r_ptr, sleep, origin)) return (FALSE);

	/* We're done unless the group flag is set */
	if (!group_okay) return (TRUE);

	/* Friends for certain monsters */
	if (rf_has(r_ptr->flags, RF_FRIEND)) {
		int total = group_size_2(r_ptr);
		(void)place_new_monster_group(c, y, x, r_ptr, sleep, total, origin);
	}

	/* Friends for certain monsters */
	if (rf_has(r_ptr->flags, RF_FRIENDS)) {
		int total = group_size_1(r_ptr);
		(void)place_new_monster_group(c, y, x, r_ptr, sleep, total, origin);
	}

	/* Escorts for certain monsters */
	if (rf_has(r_ptr->flags, RF_ESCORT)) {
		/* Try to place several "escorts" */
		for (i = 0; i < 50; i++) {
			int nx, ny, z, d = 3;
			monster_race *z_ptr;

			/* Pick a location */
			scatter(&ny, &nx, y, x, d, 0);

			/* Require empty grids */
			if (!cave_empty_bold(ny, nx)) continue;

			/* Set the escort index */
			place_monster_idx = r_idx;

			/* Set the escort hook */
			get_mon_num_hook = place_monster_okay;

			/* Prepare allocation table */
			get_mon_num_prep();

			/* Pick a random race */
			z = get_mon_num(r_ptr->level);

			/* Remove restriction */
			get_mon_num_hook = NULL;

			/* Prepare allocation table */
			get_mon_num_prep();

			/* Handle failure */
			if (!z) break;

			/* Place a single escort */
			z_ptr = &r_info[z];
			(void)place_new_monster_one(ny, nx, z_ptr, sleep, origin);

			/* Place a "group" of escorts if needed */
			if (rf_has(z_ptr->flags, RF_FRIEND)) {
				int total = group_size_2(z_ptr);
				(void)place_new_monster_group(c, ny, nx, z_ptr, sleep, total, origin);
			}
			
			if (rf_has(z_ptr->flags, RF_FRIENDS) || rf_has(r_ptr->flags, RF_ESCORTS)) {
				int total = group_size_1(z_ptr);
				(void)place_new_monster_group(c, ny, nx, z_ptr, sleep, total, origin);
			}
		}
	}

	/* Success */
	return (TRUE);
}
Ejemplo n.º 15
0
// Select a monster from a list and place it in the dungeon.
MakeMonsterDialog::MakeMonsterDialog(void)
{
    int i;
    QPointer<QVBoxLayout> vlay = new QVBoxLayout;
    mon_choice = new QComboBox;
    int y, x;

    QPointer<QLabel>  mon_label = new QLabel(QString("<b><big>Please select a monster:</big></b>"));
    mon_label->setAlignment(Qt::AlignCenter);

    vlay->addWidget(mon_label);
    vlay->addStretch();

    connect(mon_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(update_mon_choice(int)));

    QPointer<QPushButton> close_button = new QPushButton(tr("&Close"));
    connect(close_button, SIGNAL(clicked()), this, SLOT(close()));

    int count = 0;
    mon_num = 0;

    for (i = 1; i < z_info->r_max; i++)
    {
        monster_race *r_ptr = &r_info[i];

        /* Skip "empty" items */
        if (r_ptr->r_name_full.isEmpty()) continue;
        // Skip player_ghost templates
        if (r_ptr->flags2 & (RF2_PLAYER_GHOST)) continue;

        mon_choice->addItem(QString("%1") .arg(i));

        mon_choice->setItemText(count++, get_mon_display_name(i));
    }

    vlay->addWidget(mon_choice);
    vlay->addStretch();
    vlay->addWidget(close_button);

    setLayout(vlay);

    setWindowTitle(tr("Make Monster"));
    this->exec();

    // find the monster
    count = 0;
    for (i = 1; i < z_info->r_max; i++)
    {
        monster_race *r_ptr = &r_info[i];

        /* Skip "empty" items */
        if (r_ptr->r_name_full.isEmpty()) continue;
        // Skip player_ghost templates
        if (r_ptr->flags2 & (RF2_PLAYER_GHOST)) continue;

        // Found the match
        if (count == mon_num) break;
        count++;
    }

    /* Try 10 times */
    for (int k = 0; k < 10; k++)
    {
        int d = 2;

        /* Pick a location */
        scatter(&y, &x, p_ptr->py, p_ptr->px, d, 0);

        /* Require empty grids */
        if (!cave_empty_bold(y, x)) continue;

        /* Place it (allow groups) */
        if (place_monster_aux(y, x, i, (MPLACE_GROUP | MPLACE_OVERRIDE | MPLACE_SLEEP))) break;
    }
}