Mercurial > hg > early-roguelike
diff xrogue/player.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | ce0cf824c192 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/player.c Tue Apr 21 08:55:20 2015 -0400 @@ -0,0 +1,1478 @@ +/* + player.c - functions for dealing with special player abilities + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <curses.h> +#include "rogue.h" + +/* + * affect: + * cleric affecting undead + */ + +affect() +{ + register struct linked_list *item; + register struct thing *tp; + register char *mname; + bool see; + coord new_pos; + int lvl; + + if (!(player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 4) || + cur_relic[HEIL_ANKH] != 0)) { + msg("You cannot affect undead."); + return; + } + + new_pos.y = hero.y + player.t_newpos.y; + new_pos.x = hero.x + player.t_newpos.x; + + if (cansee(new_pos.y, new_pos.x)) see = TRUE; + else see = FALSE; + + /* Anything there? */ + if (new_pos.y < 0 || new_pos.y > lines-3 || + new_pos.x < 0 || new_pos.x > cols-1 || + mvwinch(mw, new_pos.y, new_pos.x) == ' ') { + msg("Nothing to affect."); + return; + } + + if ((item = find_mons(new_pos.y, new_pos.x)) == 0) { + debug("Affect what @ %d,%d?", new_pos.y, new_pos.x); + return; + } + tp = THINGPTR(item); + mname = monster_name(tp); + + if (on(player, ISINVIS) && off(*tp, CANSEE)) { + msg("%s%s cannot see you", see ? "The " : "It", + see ? mname : ""); + return; + } + + if (off(*tp, TURNABLE) || on(*tp, WASTURNED)) + goto annoy; + turn_off(*tp, TURNABLE); + + lvl = pstats.s_lvl; + if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) { + lvl -= 4; + } + /* Can cleric kill it? */ + if (lvl >= 3 * tp->t_stats.s_lvl) { + unsigned long test; /* For overflow check */ + + msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : ""); + test = pstats.s_exp + tp->t_stats.s_exp; + + /* Be sure there is no overflow before increasing experience */ + if (test > pstats.s_exp) pstats.s_exp = test; + killed(item, FALSE, TRUE, TRUE); + check_level(); + return; + } + + /* Can cleric turn it? */ + if (rnd(100) + 1 > + (100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) { + unsigned long test; /* Overflow test */ + + /* Make the monster flee */ + turn_on(*tp, WASTURNED); /* No more fleeing after this */ + turn_on(*tp, ISFLEE); + runto(tp, &hero); + + /* Disrupt it */ + dsrpt_monster(tp, TRUE, TRUE); + + /* Let player know */ + msg("You have turned %s%s.", see ? "the " : "it", see ? mname : ""); + + /* get points for turning monster -- but check overflow first */ + test = pstats.s_exp + tp->t_stats.s_exp/2; + if (test > pstats.s_exp) pstats.s_exp = test; + check_level(); + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + + return; + } + + /* Otherwise -- no go */ +annoy: + if (see && tp->t_stats.s_intel > 16) + msg("%s laughs at you...", prname(mname, TRUE)); + else + msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : ""); + + /* Annoy monster */ + if (off(*tp, ISFLEE)) runto(tp, &hero); +} + +/* + * the cleric asks his deity for a spell + */ + +pray() +{ + register int num_prayers, prayer_ability, which_prayer; + + which_prayer = num_prayers = prayer_ability = 0; + + if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN && + cur_relic[HEIL_ANKH] == 0) { + msg("You are not permitted to pray."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to pray!"); + return; + } + + prayer_ability = pstats.s_lvl * pstats.s_wisdom - 5; + if (player.t_ctype != C_CLERIC) + prayer_ability /= 2; + + if (cur_relic[HEIL_ANKH]) prayer_ability += 75; + + if (player.t_action != C_PRAY) { + num_prayers = 0; + + /* Get the number of avilable prayers */ + if (pstats.s_wisdom > 16) + num_prayers += pstats.s_wisdom - 16; + + num_prayers += pstats.s_lvl; + if (cur_relic[HEIL_ANKH]) + num_prayers += pstats.s_wisdom - 18; + + if (player.t_ctype != C_CLERIC) + num_prayers /= 2; + + if (num_prayers > MAXPRAYERS) + num_prayers = MAXPRAYERS; + if (num_prayers < 1) { + msg("You are not permitted to pray yet."); + return; + } + + /* Prompt for prayer */ + if (pick_spell( cleric_spells, + prayer_ability, + num_prayers, + pray_time, + "offer", + "prayer")) + player.t_action = C_PRAY; + + return; + } + + /* We've waited our required praying time. */ + which_prayer = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) { + msg("Your prayer fails."); + return; + } + + msg("Your prayer has been granted. "); + + if (cleric_spells[which_prayer].s_type == TYP_POTION) + quaff( cleric_spells[which_prayer].s_which, + NULL, + cleric_spells[which_prayer].s_flag, + FALSE); + else if (cleric_spells[which_prayer].s_type == TYP_SCROLL) + read_scroll( cleric_spells[which_prayer].s_which, + cleric_spells[which_prayer].s_flag, + FALSE); + else if (cleric_spells[which_prayer].s_type == TYP_STICK) { + if (!player_zap(cleric_spells[which_prayer].s_which, + cleric_spells[which_prayer].s_flag)) { + after = FALSE; + return; + } + } + pray_time += cleric_spells[which_prayer].s_cost; +} + +/* + * the magician is going to try and cast a spell + */ + +cast() +{ + register int spell_ability, which_spell, num_spells; + + if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) { + msg("You are not permitted to cast spells."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to cast spells!"); + return; + } + spell_ability = pstats.s_lvl * pstats.s_intel - 5; + if (player.t_ctype != C_MAGICIAN) + spell_ability /= 2; + + if (player.t_action != C_CAST) { + /* + * Get the number of avilable spells + */ + num_spells = 0; + if (pstats.s_intel > 16) + num_spells += pstats.s_intel - 16; + + num_spells += pstats.s_lvl; + if (player.t_ctype != C_MAGICIAN) + num_spells /= 2; + if (num_spells > MAXSPELLS) + num_spells = MAXSPELLS; + if (num_spells < 1) { + msg("You are not allowed to cast spells yet."); + return; + } + + /* prompt for spell */ + if (pick_spell( magic_spells, + spell_ability, + num_spells, + spell_power, + "cast", + "spell")) + player.t_action = C_CAST; + return; + } + + /* We've waited our required casting time. */ + which_spell = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) { + msg("Your attempt fails."); + return; + } + + msg("Your spell is successful. "); + + if (magic_spells[which_spell].s_type == TYP_POTION) + quaff( magic_spells[which_spell].s_which, + NULL, + magic_spells[which_spell].s_flag, + FALSE); + else if (magic_spells[which_spell].s_type == TYP_SCROLL) + read_scroll( magic_spells[which_spell].s_which, + magic_spells[which_spell].s_flag, + FALSE); + else if (magic_spells[which_spell].s_type == TYP_STICK) { + if (!player_zap(magic_spells[which_spell].s_which, + magic_spells[which_spell].s_flag)) { + after = FALSE; + return; + } + } + spell_power += magic_spells[which_spell].s_cost; +} + +/* + * the druid asks his deity for a spell + */ + +chant() +{ + register int num_chants, chant_ability, which_chant; + + which_chant = num_chants = chant_ability = 0; + + if (player.t_ctype != C_DRUID && player.t_ctype != C_MONK) { + msg("You are not permitted to chant."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to chant!"); + return; + } + chant_ability = pstats.s_lvl * pstats.s_wisdom - 5; + if (player.t_ctype != C_DRUID) + chant_ability /= 2; + + if (player.t_action != C_CHANT) { + num_chants = 0; + + /* Get the number of avilable chants */ + if (pstats.s_wisdom > 16) + num_chants += pstats.s_wisdom - 16; + + num_chants += pstats.s_lvl; + + if (player.t_ctype != C_DRUID) + num_chants /= 2; + + if (num_chants > MAXCHANTS) + num_chants = MAXCHANTS; + + if (num_chants < 1) { + msg("You are not permitted to chant yet."); + return; + } + + /* Prompt for chant */ + if (pick_spell( druid_spells, + chant_ability, + num_chants, + chant_time, + "sing", + "chant")) + player.t_action = C_CHANT; + + return; + } + + /* We've waited our required chanting time. */ + which_chant = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if (druid_spells[which_chant].s_cost + chant_time > chant_ability) { + msg("Your chant fails."); + return; + } + + msg("Your chant has been granted. "); + + if (druid_spells[which_chant].s_type == TYP_POTION) + quaff( druid_spells[which_chant].s_which, + NULL, + druid_spells[which_chant].s_flag, + FALSE); + else if (druid_spells[which_chant].s_type == TYP_SCROLL) + read_scroll( druid_spells[which_chant].s_which, + druid_spells[which_chant].s_flag, + FALSE); + else if (druid_spells[which_chant].s_type == TYP_STICK) { + if (!player_zap(druid_spells[which_chant].s_which, + druid_spells[which_chant].s_flag)) { + after = FALSE; + return; + } + } + chant_time += druid_spells[which_chant].s_cost; +} + +/* Constitution bonus */ + +const_bonus() /* Hit point adjustment for changing levels */ +{ + register int bonus; + if (pstats.s_const > 9 && pstats.s_const < 18) + bonus = 0; + else if (pstats.s_const >= 18 && pstats.s_const < 20) + bonus = 1; + else if (pstats.s_const >= 20 && pstats.s_const < 26) + bonus = 2; + else if (pstats.s_const >= 26 && pstats.s_const < 36) + bonus = 3; + else if (pstats.s_const >= 36) + bonus = 4; + else if (pstats.s_const > 7) + bonus = -1; + else + bonus = -2; + switch(player.t_ctype) { + case C_FIGHTER: bonus = min(bonus, 11); + when C_RANGER: bonus = min(bonus, 9); + when C_PALADIN: bonus = min(bonus, 9); + when C_MAGICIAN: bonus = min(bonus, 8); + when C_CLERIC: bonus = min(bonus, 8); + when C_THIEF: bonus = min(bonus, 10); + when C_ASSASSIN: bonus = min(bonus, 10); + when C_DRUID: bonus = min(bonus, 8); + when C_MONK: bonus = min(bonus, 9); + otherwise: bonus = min(bonus, 7); + } + return(bonus); +} + +/* + * Give away slime-molds to monsters. If monster is friendly, + * it will give you a "regular" food ration in return. You have + * to give a slime-mold to Alteran (a unique monster) in order to + * get the special "Card of Alteran" quest item. There's no other + * way to get this artifact and remain alive. + */ + +give(th) +register struct thing *th; +{ + /* + * Find any monster within one space of you + */ + struct linked_list *ll; + struct object *lb; + register int x,y; + register struct linked_list *mon = NULL; + bool gotone = FALSE; + + if (levtype != POSTLEV) { /* no monsters at trading post */ + for (x = hero.x-1; x <= hero.x+1; x++) { + for (y = hero.y-1; y <= hero.y+1; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + gotone = TRUE; /* found a monster to give away to */ + th = THINGPTR(mon); + } + } + } + } + } + if (gotone) { + if ((ll=get_item(pack, "give away", ALL, FALSE, FALSE)) != NULL) { + lb = OBJPTR(ll); + mpos = 0; + switch(lb->o_type) { + case FOOD: + switch (lb->o_which) { + case E_SLIMEMOLD: /* only slime-molds for now */ + if (on(*th, CANSELL)) { /* quartermaster */ + msg("%s laughs at you. "); + return; + } + if ((on(*th, ISFRIENDLY) || off(*th, ISMEAN)) && + off(*th, ISUNIQUE) && off(*th, CANSELL)) { + turn_on(*th, ISRUN); /* we want him awake */ + msg("%s accepts and promptly eats your gift of food. --More--", prname(monster_name(th), TRUE)); + wait_for(' '); + del_pack(ll); /* delete slime-mold */ + /* and add a food ration */ + create_obj(FALSE, FOOD, E_RATION); + msg("%s gives you food in return and nods off to sleep. ", prname(monster_name(th), TRUE)); + turn_off(*th, ISRUN); /* put him to sleep */ + return; + } + else if (on(*th, CARRYCARD) && on(*th, ISUNIQUE)) { + /* Now you get the Card of Alteran */ + msg("%s gives you a strange rectangular card. --More--", prname(monster_name(th), TRUE)); + wait_for(' '); + del_pack(ll); /* get rid of slime-mold */ + create_obj(FALSE, RELIC, ALTERAN_CARD); + msg("%s bids you farewell. ", prname(monster_name(th), TRUE)); + killed(mon, FALSE, FALSE, FALSE); + return; + } + else if (on(*th, ISUNIQUE) && off(*th, ISMEAN)) { + /* Dragons */ + msg("%s is set free by your generosity. ", prname(monster_name(th), TRUE)); + del_pack(ll); /* get rid of it */ + /* just let him roam around */ + turn_on(*th, ISRUN); + if (on(*th, ISFLEE)) turn_off(*th, ISFLEE); + runto(th, &player); + th->t_action = A_NIL; + return; + } + else if (on(*th, ISRUN) && off(*th, ISUNIQUE)) { + /* if NOT sleeping and not a unique */ + switch (rnd(2)) { + case 0: msg("%s ignores you. ", prname(monster_name(th), TRUE)); + when 1: { + msg("%s nips at your hand. ", prname(monster_name(th), TRUE)); + if (rnd(100) < 10) { + del_pack(ll); /* delete it */ + if (off(*th, ISMEAN)) { + msg("The slime-mold makes %s sleepy. ", prname(monster_name(th), TRUE)); + /* put him to sleep */ + turn_off(*th, ISRUN); + return; + } + else { + switch (rnd(2)) { + case 0: msg("%s's eyes roll back. ", prname(monster_name(th), TRUE)); + when 1: msg("%s becomes wanderlust. ", prname(monster_name(th), TRUE)); + } + /* just let him roam around */ + turn_on(*th, ISRUN); + if (on(*th, ISFLEE)) + turn_off(*th, ISFLEE); + runto(th, &player); + th->t_action = A_NIL; + return; + } + } + } + } + } + else { + msg("%s's mouth waters. ", prname(monster_name(th), TRUE)); + /* this wakes him up */ + if (off(*th, ISUNIQUE)) turn_on(*th, ISRUN); + return; + } + otherwise: + switch (rnd(3)) { /* mention food (hint hint) */ + case 0: msg("You cannot give away the %s! ", foods[lb->o_which].mi_name); + when 1: msg("The %s looks rancid! ", foods[lb->o_which].mi_name); + when 2: msg("You change your mind. "); + } + return; + } + otherwise: + switch (rnd(3)) { /* do not mention other items */ + case 0: msg("You feel foolish. "); + when 1: msg("You change your mind. "); + when 2: msg("%s ignores you. ", prname(monster_name(th), TRUE)); + } + + return; + } + } + } + else msg("Your efforts are futile. "); + return; +} + +/* + * Frighten a monster. Useful for the 'good' characters. + */ + +fright(th) +register struct thing *th; +{ + /* + * Find any monster within one space of you + */ + register int x,y; + register struct linked_list *mon; + bool gotone = FALSE; + + if (levtype != POSTLEV) { /* no monsters at trading post */ + for (x = hero.x-1; x <= hero.x+1; x++) { + for (y = hero.y-1; y <= hero.y+1; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + gotone = TRUE; /* found a monster to give away to */ + th = THINGPTR(mon); + } + } + } + } + } + if (gotone) { /* If 'good' character or is wearing a ring of fear */ + if (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK || ISWEARING(R_FEAR) != 0) { + + player.t_action = A_NIL; + player.t_no_move = movement(&player); + switch (player.t_ctype) { + case C_FIGHTER: /* loss of strength */ + pstats.s_str--; + if (pstats.s_str < 3) pstats.s_str = 3; + when C_RANGER: /* loss of charisma */ + case C_PALADIN: + pstats.s_charisma--; + if (pstats.s_charisma < 3) pstats.s_charisma = 3; + when C_CLERIC: /* loss of wisdom */ + case C_DRUID: + pstats.s_wisdom--; + if (pstats.s_wisdom < 3) pstats.s_wisdom = 3; + when C_MAGICIAN: /* loss of wisdom intelligence */ + pstats.s_intel--; + if (pstats.s_intel < 3) pstats.s_intel = 3; + when C_THIEF: /* loss of dexterity */ + case C_ASSASSIN: + pstats.s_dext--; + if (pstats.s_dext < 3) pstats.s_dext = 3; + when C_MONK: /* loss of constitution */ + pstats.s_const--; + if (pstats.s_const < 3) pstats.s_const = 3; + otherwise: /* this msg can induce great fear */ + msg("You miss. "); + } + + /* Cause a panic. Good thru level 16. */ + if (level < 17) { + msg("You wave your arms and yell! "); + do_panic(th->t_index); + pstats.s_hpt -= (pstats.s_hpt/2)+1; + if (pstats.s_hpt < 25) msg("You heart quivers... "); + if (pstats.s_hpt < 1) { + msg("Your heart stops!! --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_FRIGHT); + } + return; + } + else { + /* He can't do it after level 16 */ + switch (rnd(20)) { + case 0: case 2: + msg("You stamp your foot!! "); + when 4: case 8: + msg("%s laughs at you! ",prname(monster_name(th),TRUE)); + when 10: case 12: + msg("You forget what you are doing? "); + otherwise: + msg(nothing); + } + return; + } + } + else { + switch (rnd(25)) { + case 0: case 2: case 4: + msg("You motion angrily! "); + when 6: case 8: case 10: + msg("You can't frighten anything. "); + when 12: case 14: case 16: + msg("Your puff up your face. "); + otherwise: + msg(nothing); + } + return; + } + } + else { + msg("There is nothing to fear but fear itself. "); + return; + } +} + +/* Routines for thieves */ + +/* + * gsense: Sense gold + */ + +gsense() +{ + /* Thief & assassin can do this, but fighter & ranger can later */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + ((player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER) && + pstats.s_lvl >= 12)) { + read_scroll(S_GFIND, NULL, FALSE); + } + else msg("You seem to have no gold sense."); + return; +} + +/* + * xsense: Sense traps + */ + +xsense() +{ + /* Only thief can do this, but assassin, fighter, & monk can later */ + if (player.t_ctype == C_THIEF || ((player.t_ctype == C_ASSASSIN || + player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK) && + pstats.s_lvl >= 14)) { + read_scroll(S_FINDTRAPS, NULL, FALSE); + } + else msg("You seem not to be able to sense traps."); + return; +} + +/* + * steal: + * Steal in direction given in delta + */ + +steal() +{ + register struct linked_list *item; + register struct thing *tp; + register char *mname; + coord new_pos; + int thief_bonus = -50; + bool isinvisible = FALSE; + + + /* let the fighter steal after level 15 */ + if (player.t_ctype == C_FIGHTER && pstats.s_lvl < 15) { + msg(nothing); + return; + } + else if (player.t_ctype != C_THIEF && + player.t_ctype != C_ASSASSIN && + player.t_ctype != C_FIGHTER) { + msg("Only thieves and assassins can steal."); + return; + } + if (on(player, ISBLIND)) { + msg("You can't see anything."); + return; + } + + new_pos.y = hero.y + player.t_newpos.y; + new_pos.x = hero.x + player.t_newpos.x; + + /* Anything there? */ + if (new_pos.y < 0 || new_pos.y > lines-3 || + new_pos.x < 0 || new_pos.x > cols-1 || + mvwinch(mw, new_pos.y, new_pos.x) == ' ') { + msg("Nothing to steal from."); + return; + } + + if ((item = find_mons(new_pos.y, new_pos.x)) == NULL) + debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x); + tp = THINGPTR(item); + if (on(*tp, ISSTONE)) { + msg ("You can't steal from stone!"); + return; + } + + if (on(*tp, ISFLEE)) { + msg("You can't get your hand in anywhere! "); + return; + } + + isinvisible = invisible(tp); + if (isinvisible) mname = "creature"; + else mname = monster_name(tp); + + /* Can player steal something unnoticed? */ + if (player.t_ctype == C_THIEF) thief_bonus = 9; + if (player.t_ctype == C_ASSASSIN) thief_bonus = 6; + if (player.t_ctype == C_FIGHTER) thief_bonus = 3; + if (on(*tp, ISUNIQUE)) thief_bonus -= 15; + if (isinvisible) thief_bonus -= 20; + if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50; + + if (on(*tp, ISHELD) || tp->t_action == A_FREEZE || + rnd(100) < + (thief_bonus + 2*dex_compute() + 5*pstats.s_lvl - + 5*(tp->t_stats.s_lvl - 3))) { + register struct linked_list *s_item, *pack_ptr; + int count = 0; + unsigned long test; /* Overflow check */ + + s_item = NULL; /* Start stolen goods out as nothing */ + + /* Find a good item to take */ + for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr)) + if ((OBJPTR(pack_ptr))->o_type != RELIC && + pack_ptr != tp->t_using && /* Monster can't be using it */ + rnd(++count) == 0) + s_item = pack_ptr; + + /* + * Find anything? + */ + if (s_item == NULL) { + msg("%s apparently has nothing to steal.", prname(mname, TRUE)); + return; + } + + /* Take it from monster */ + if (tp->t_pack) detach(tp->t_pack, s_item); + + /* Recalculate the monster's encumberance */ + updpack(TRUE, tp); + + /* Give it to player */ + if (add_pack(s_item, FALSE) == FALSE) { + (OBJPTR(s_item))->o_pos = hero; + fall(s_item, TRUE); + } + + /* Get points for stealing -- but first check for overflow */ + test = pstats.s_exp + tp->t_stats.s_exp/2; + if (test > pstats.s_exp) pstats.s_exp = test; + + /* + * Do adjustments if player went up a level + */ + check_level(); + } + + else { + msg("Your attempt fails."); + + /* Annoy monster (maybe) */ + if (rnd(40) >= dex_compute() + thief_bonus) { + /* + * If this is a charmed creature, there is a chance it + * will become uncharmed. + */ + if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + } + if (on(*tp, CANSELL)) { + turn_off(*tp, CANSELL); + tp->t_action = A_NIL; + tp->t_movement = 0; + if (rnd(100) < 50) /* make him steal something */ + turn_on(*tp, STEALMAGIC); + else + turn_on(*tp, STEALGOLD); + if (!isinvisible) + msg("%s looks insulted.", prname(mname, TRUE)); + } + runto(tp, &hero); + } + } +} + +/* + * Take charmed monsters with you via up or down commands. + */ + +take_with() +{ + register struct thing *tp; + register struct linked_list *item; + struct linked_list *nitem; + register int t; + + t = 0; + for (item = mlist; item != NULL; item = nitem) { + nitem = next(item); + t++; + if (t > 5) break; + tp = THINGPTR(item); + if (on(*tp, ISCHARMED)) { + monsters[tp->t_index].m_normal = TRUE; + turn_on(*tp, ISELSEWHERE); + detach(mlist, item); + attach(tlist, item); /* remember him next level */ + check_residue(tp); + continue; + } + } +} + +/* + * this routine lets the player pick the spell that they + * want to cast regardless of character class + */ + +pick_spell(spells, ability, num_spells, power, prompt, type) +struct spells spells[]; /* spell list */ +int ability; /* spell ability */ +int num_spells; /* number of spells that can be cast */ +int power; /* spell power */ +const char *prompt; /* prompt for spell list */ +const char *type; /* type of thing--> spell, prayer, chant */ +{ + bool nohw = FALSE; + register int i; + int curlen, + maxlen = 0, + dummy = 0, + which_spell, + spell_left; + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to start a %s!", type); + return(FALSE); + } + + /* Prompt for spells */ + msg("Which %s are you %sing? (* for list): ", type, prompt); + + which_spell = (int) (wgetch(cw) - 'a'); + msg(""); /* Get rid of the prompt */ + if (which_spell == (int) ESC - (int) 'a') { + after = FALSE; + return(FALSE); + } + if (which_spell >= 0 && which_spell < num_spells) nohw = TRUE; + + else if (slow_invent) { + register char c; + + nohw = TRUE; + do { + for (i=0; i<num_spells; i++) { + msg(""); + mvwaddch(msgw, 0, 0, '['); + waddch(msgw, (char) ((int) 'a' + i)); + wprintw(msgw, "] A %s of ", type); + if (spells[i].s_type == TYP_POTION) + waddstr(msgw, p_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_SCROLL) + waddstr(msgw, s_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_STICK) + waddstr(msgw, ws_magic[spells[i].s_which].mi_name); + waddstr(msgw, morestr); + wclrtobot(msgw); + clearok(msgw, FALSE); + draw(msgw); + do { + c = wgetch(cw); + } while (c != ' ' && c != ESC); + if (c == ESC) + break; + } + msg(""); + wmove(msgw, 0, 0); + wprintw(msgw, "Which %s are you %sing? ", type, prompt); + clearok(msgw, FALSE); + draw(msgw); + + which_spell = (int) (wgetch(cw) - 'a'); + } while (which_spell != (int) (ESC - 'a') && + (which_spell < 0 || which_spell >= num_spells)); + + if (which_spell == (int) (ESC - 'a')) { + mpos = 0; + msg(""); + after = FALSE; + return(FALSE); + } + } + else { + /* Now display the possible spells */ + wclear(hw); + touchwin(hw); + wmove(hw, 2, 0); + wprintw(hw, " Cost %c%s", toupper(*type),type+1); + mvwaddstr(hw, 3, 0, + "-----------------------------------------------"); + maxlen = 47; /* Maximum width of header */ + + for (i=0; i<num_spells; i++) { + sprintf(prbuf, "[%c] %3d A %s of ", + (char) ((int) 'a' + i), spells[i].s_cost, type); + if (spells[i].s_type == TYP_POTION) + strcat(prbuf, p_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_SCROLL) + strcat(prbuf, s_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_STICK) + strcat(prbuf, ws_magic[spells[i].s_which].mi_name); + mvwaddstr(hw, i+4, 0, prbuf); + + /* Get the length of the line */ + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + } + + spell_left = ability - power; + if (spell_left < 0) { + spell_left = 0; + if (spell_left < -20) power = ability + 20; + } + sprintf(prbuf, "[Current %s power = %d]", type, spell_left); + + mvwaddstr(hw, 0, 0, prbuf); + wprintw(hw, " Which %s are you %sing? ", type, prompt); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && num_spells + 3 < lines - 3) { + over_win(cw, hw, num_spells + 5, maxlen + 3, 0, curlen, NULL); + } + else draw(hw); + } + + if (!nohw) { + which_spell = (int) (wgetch(cw) - 'a'); + while (which_spell < 0 || which_spell >= num_spells) { + if (which_spell == (int) ESC - (int) 'a') { + after = FALSE; + + /* Restore the screen */ + if (num_spells + 3 < lines / 2) { + clearok(cw, FALSE); + touchwin(cw); + } + else restscr(cw); + return(FALSE); + } + wmove(hw, 0, 0); + wclrtoeol(hw); + wprintw(hw, "Please enter one of the listed %ss. ", type); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && num_spells + 3 < lines - 3) { + over_win(cw, hw, num_spells + 5, maxlen + 3, + 0, curlen, NULL); + } + else draw(hw); + + which_spell = (int) (wgetch(cw) - 'a'); + } + } + + /* Now restore the screen if we have to */ + if (!nohw) { + if (num_spells + 3 < lines / 2) { + touchwin(cw); + clearok(cw, FALSE); + } + else { + restscr(cw); + } + } + + if (spells[which_spell].s_type == TYP_STICK && + need_dir(STICK, spells[which_spell].s_which)) { + if (!get_dir(&player.t_newpos)) { + after = FALSE; + return(FALSE); + } + } + player.t_selection = which_spell; + player.t_no_move = (which_spell/3 + 1) * movement(&player); + + spell_left = dummy; /* hack to stop IRIX complaint about dummy */ + /* not being used. */ + return(TRUE); +} + +/* + * opt_player: + * Let the player know what's happening with himself + */ + +opt_player() +{ + int i = 1; /* initialize counters */ + int j = 2; + + wclear(hw); + wmove(hw, 0, 0); + wprintw(hw, "Current player effects:"); + wmove(hw, 2, 0); + + /* Print a list of what is happening. + * If longer than 16 lines, make it two columns. + * Currently, a maximum of 32 (out of 39) "effects" + * can be happening all at once to a player. + */ + + /* 1 - Sense gold */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + ((player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER) && + pstats.s_lvl >= 12)) { + wprintw(hw, "You can sense gold\n"); + i++; + } + /* 2 - Sense traps */ + if (player.t_ctype == C_THIEF || ((player.t_ctype == C_ASSASSIN || + player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK) && + pstats.s_lvl >= 14)) { + wprintw(hw, "You can sense traps\n"); + i++; + } + /* 3 - Steal */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + (player.t_ctype == C_FIGHTER && pstats.s_lvl >= 15)) { + wprintw(hw, "You can steal\n"); + i++; + } + /* 4 - Cast spells */ + if (player.t_ctype == C_MAGICIAN || + (player.t_ctype == C_RANGER && pstats.s_lvl > 1)) { + wprintw(hw, "You can cast spells\n"); + i++; + } + /* 5 - Make chants */ + if (player.t_ctype == C_DRUID || + (player.t_ctype == C_MONK && pstats.s_lvl > 1)) { + wprintw(hw, "You can chant\n"); + i++; + } + /* 6 - Give prayers */ + if (cur_relic[HEIL_ANKH] != 0 || player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 1)) { + wprintw(hw, "You can pray\n"); + i++; + } + /* 7 - Affect the undead */ + if (cur_relic[HEIL_ANKH] != 0 || player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 4)) { + wprintw(hw, "You can affect the undead\n"); + i++; + } + /* 8 - Cause fear */ + if (ISWEARING(R_FEAR) != 0 || ((player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN || player.t_ctype == C_MONK) && + pstats.s_lvl > 1)) { + wprintw(hw, "You are fearful\n"); + i++; + } + /* 9 - Confuse monster */ + if (on(player, CANHUH) != 0) { + wprintw(hw, "You have multi-colored hands\n"); + i++; + } + /* 10 - Confused yourself */ + if (on(player, ISHUH) != 0) { + wprintw(hw, "You are confused\n"); + i++; + } /* really ISHUH or ISCLEAR */ + /* 11 - Clear thought */ + if (on(player, ISCLEAR) != 0) { + wprintw(hw, "You are clear headed\n"); + i++; + } + /* 12 - Slow */ + if (on(player, ISSLOW) != 0) { + wprintw(hw, "You are moving slow\n"); + i++; + } /* really ISSLOW or ISHASTE */ + /* 13 - Haste */ + if (on(player, ISHASTE) != 0) { + wprintw(hw, "You are moving fast\n"); + i++; + } + /* 14 - Flying */ + if (on(player, ISFLY) != 0) { + wprintw(hw, "You are flying\n"); + i++; + } + /* 15 - Blind */ + if (on(player, ISBLIND) != 0) { + wprintw(hw, "You are blind\n"); + i++; + } /* really ISBLIND or CANSEE */ + /* 16 - Extra sight */ + if (on(player, CANSEE) != 0) { + wprintw(hw, "You have extra sight\n"); + i++; + } + /* 17 - Invisibility */ + if (on(player, ISINVIS) != 0) { + /* Okay, start a second column of effects to the screen. */ + if (i > 16) { + mvwaddstr(hw, j, 37, "You are invisible"); + j++; + } + else { + wprintw(hw, "You are invisible\n"); + i++; + } + } + /* 18 - Regeneration and vampiric regen */ + if (ISWEARING(R_VAMPREGEN) != 0 || ISWEARING(R_REGEN) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have regenerative powers"); + j++; + } + else { + wprintw(hw, "You have regenerative powers\n"); + i++; + } + } + /* 19 - Phasing */ + if (on(player, CANINWALL) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You can walk through walls"); + j++; + } + else { + wprintw(hw, "You can walk through walls\n"); + i++; + } + } + /* 20 - Skill (good or bad, it won't last) */ + if (find_slot(unskill) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You feel skillful"); + j++; + } + else { + wprintw(hw, "You feel skillful\n"); + i++; + } + } + /* 21 - Stealthy */ + if (ISWEARING(R_STEALTH) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have stealth"); + j++; + } + else { + wprintw(hw, "You have stealth\n"); + i++; + } + } + /* 22 - Alertness */ + if (ISWEARING(R_ALERT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are awake and alert"); + j++; + } + else { + wprintw(hw, "You are awake and alert\n"); + i++; + } + } + /* 23 - Free action */ + if (ISWEARING(R_FREEDOM) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You feel free"); + j++; + } + else { + wprintw(hw, "You feel free\n"); + i++; + } + } + /* 24 - Heroism */ + if (ISWEARING(R_HEROISM) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are brave"); + j++; + } + else { + wprintw(hw, "You are brave\n"); + i++; + } + } + /* 25 - Ice protection */ + if (on(player, NOCOLD) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from ice"); + j++; + } + else { + wprintw(hw, "You are protected from ice\n"); + i++; + } + } + /* 26 - Fire protection */ + if (on(player, NOFIRE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from fire"); + j++; + } + else { + wprintw(hw, "You are protected from fire\n"); + i++; + } + } + /* 27 - Lightning protection */ + if (on(player, NOBOLT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from lightning"); + j++; + } + else { + wprintw(hw, "You are protected from lightning\n"); + i++; + } + } + /* 28 - Gas protection */ + if (on(player, NOGAS) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from gas"); + j++; + } + else { + wprintw(hw, "You are protected from gas\n"); + i++; + } + } + /* 29 - Acid protection */ + if (on(player, NOACID) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from acid"); + j++; + } + else { + wprintw(hw, "You are protected from acid\n"); + i++; + } + } + /* 30 - Breath protection */ + if (cur_relic[YENDOR_AMULET] != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from monster breath"); + j++; + } + else { + wprintw(hw, "You are protected from monster breath\n"); + i++; + } /* really only YENDOR or STONEBONES */ + } + /* 31 - Magic missile protection */ + if (cur_relic[STONEBONES_AMULET] != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from magic missiles"); + j++; + } + else { + wprintw(hw, "You are protected from magic missiles\n"); + i++; + } + } + /* 32 - Sustain health */ + if (ISWEARING(R_HEALTH) != 0 && (off(player, HASDISEASE) && + off(player, HASINFEST) && off(player, DOROT))) { + if (i > 16) { /* he's really healthy */ + mvwaddstr(hw, j, 37, "You are in good health"); + j++; + } + else { + wprintw(hw, "You are in good health\n"); + i++; + } + } + /* 33 - Being held */ + if (on(player, ISHELD) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are being held"); + j++; + } + else { + wprintw(hw, "You are being held\n"); + i++; + } + } + /* 34 - Stinks */ + if (on(player, HASSTINK) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are affronted by a bad smell"); + j++; + } + else { + wprintw(hw, "You are affronted by a bad smell\n"); + i++; + } + } + /* 35 - Any attribute that is down */ + if (pstats.s_intel < max_stats.s_intel || + pstats.s_str < max_stats.s_str || + pstats.s_wisdom < max_stats.s_wisdom || + pstats.s_dext < max_stats.s_dext || + pstats.s_const < max_stats.s_const || + pstats.s_charisma < max_stats.s_charisma) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are afflicted"); + j++; + } + else { + wprintw(hw, "You are afflicted\n"); + i++; + } + } + /* 36 - Diseased */ + if (on(player, HASDISEASE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have a disease"); + j++; + } + else { + wprintw(hw, "You have a disease\n"); + i++; + } + } + /* 37 - Infested */ + if (on(player, HASINFEST) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have an infestation"); + j++; + } + else { + wprintw(hw, "You have an infestation\n"); + i++; + } + } + /* 38 - Body rot */ + if (on(player, DOROT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have body rot"); + j++; + } + else { + wprintw(hw, "You have body rot\n"); + i++; + } + } + /* 39 - Dancing */ + if (on(player, ISDANCE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are a dancing fool"); + j++; + } + else { + wprintw(hw, "You are a dancing fool\n"); + i++; + } + } + if (i == 1) { + wclear(hw); + msg("No player effects. "); + return; + } + else { + if (i > 1 && i < 17) { + j = 39; + if (menu_overlay) { /* Print the list. */ + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + over_win(cw, hw, i+3, j, i+2, 27, NULL); + } + else { + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + draw(hw); + } + } + else { + i = 17; + if (menu_overlay) { /* Print the list. */ + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + if (j > 2) j = 78; + else j = 39; + over_win(cw, hw, i+3, j, i+2, 27, NULL); + } + else { + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + draw(hw); + } + } + wait_for(' '); + wclear(hw); + status(FALSE); + touchwin(cw); + return; + } +} +