Mercurial > hg > early-roguelike
view xrogue/player.c @ 265:7fcb2f9f57e6
Mention UltraRogue in the top-level README.
author | John "Elwin" Edwards |
---|---|
date | Sun, 19 Feb 2017 19:54:17 -0500 |
parents | 2236ef808bcb |
children |
line wrap: on
line source
/* 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 <string.h> #include <curses.h> #include "rogue.h" bool pick_spell(struct spells spells[], int ability, int num_spells, int power, const char *prompt, const char *type); /* * affect: * cleric affecting undead */ void affect(void) { 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 */ void pray(void) { 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, 0, 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 */ void cast(void) { 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, 0, 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 */ void chant(void) { 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, 0, 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 */ int const_bonus(void) /* 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. */ void give(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, &hero); 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, &hero); 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. */ void fright(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 */ void gsense(void) { /* 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, 0, FALSE); } else msg("You seem to have no gold sense."); return; } /* * xsense: Sense traps */ void xsense(void) { /* 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, 0, FALSE); } else msg("You seem not to be able to sense traps."); return; } /* * steal: * Steal in direction given in delta */ void steal(void) { 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)