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;