/* * All the fighting gets done here * * @(#)fight.c 9.0 (rdk) 7/17/84 * * Super-Rogue * Copyright (C) 1984 Robert D. Kindelberger * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include #include #include #include "rogue.h" #include "rogue.ext" bool roll_em(struct stats *att, struct stats *def, struct object *weap, bool hurl); char *mindex(char *cp, char c); char *prname(char *who, bool upper); void hit(char *er); void miss(char *er); void thunk(struct object *weap, char *mname); void bounce(struct object *weap, char *mname); /* * fight: * The player attacks the monster. */ bool fight(struct coord *mp, struct object *weap, bool thrown) { reg struct thing *tp; reg struct stats *st; reg struct linked_list *item; bool did_hit = TRUE; if (pl_on(ISETHER)) /* cant fight when ethereal */ return 0; if ((item = find_mons(mp->y, mp->x)) == NULL) { mvaddch(mp->y, mp->x, FLOOR); mvwaddch(mw, mp->y, mp->x, ' '); look(FALSE); msg("That monster must have been an illusion."); return 0; } tp = THINGPTR(item); st = &tp->t_stats; /* * Since we are fighting, things are not quiet so * no healing takes place. */ quiet = 0; isfight = TRUE; runto(mp, &hero); /* * Let him know it was really a mimic (if it was one). */ if(tp->t_type == 'M' && tp->t_disguise != 'M' && pl_off(ISBLIND)) { msg("Wait! That's a mimic!"); tp->t_disguise = 'M'; did_hit = thrown; } if (did_hit) { reg char *mname; did_hit = FALSE; if (pl_on(ISBLIND)) mname = "it"; else mname = monsters[tp->t_indx].m_name; /* * If the hero can see the invisibles, then * make it easier to hit. */ if (pl_on(CANSEE) && on(*tp, ISINVIS) && off(*tp, WASHIT)) { tp->t_flags |= WASHIT; st->s_arm += 3; } if (roll_em(him, st, weap, thrown)) { did_hit = TRUE; if (thrown) thunk(weap, mname); else hit(NULL); if (pl_on(CANHUH)) { msg("Your hands stop glowing red"); msg("The %s appears confused.", mname); tp->t_flags |= ISHUH; player.t_flags &= ~CANHUH; /* * If our hero was stuck by a bone devil, * release him now because the devil is * confused. */ if (pl_on(ISHELD)) unhold(tp->t_type); } if (st->s_hpt <= 0) killed(item, TRUE); else if (monhurt(tp) && off(*tp, ISWOUND)) { if (levtype != MAZELEV && tp->t_room != NULL && !rf_on(tp->t_room, ISTREAS)) { tp->t_flags |= ISWOUND; msg("You wounded %s.",prname(mname,FALSE)); unhold(tp->t_type); } } } else { if (thrown) bounce(weap, mname); else miss(NULL); } } count = 0; return did_hit; } /* * attack: * The monster attacks the player */ int attack(struct thing *mp) { reg char *mname; if (pl_on(ISETHER)) /* ethereal players cant be hit */ return(0); if (mp->t_flags & ISPARA) /* paralyzed monsters */ return(0); running = FALSE; quiet = 0; isfight = TRUE; if (mp->t_type == 'F') fung_hit = atoi(mp->t_stats.s_dmg); if (mp->t_type == 'M' && pl_off(ISBLIND)) mp->t_disguise = 'M'; if (pl_on(ISBLIND)) mname = "it"; else mname = monsters[mp->t_indx].m_name; if (roll_em(&mp->t_stats, him, NULL, FALSE)) { if (pl_on(ISINVINC)) { msg("%s does not harm you.",prname(mname,TRUE)); } else { nochange = FALSE; if (mp->t_type != 'E') hit(mname); if (him->s_hpt <= 0) death(mp->t_indx); if (off(*mp, ISCANC)) switch (mp->t_type) { case 'R': if (hurt_armor(cur_armor)) { msg("Your armor weakens."); cur_armor->o_ac++; } when 'E': /* * The gaze of the floating eye hypnotizes you */ if (pl_off(ISBLIND) && player.t_nocmd <= 0) { player.t_nocmd = rnd(16) + 25; msg("You are transfixed."); } when 'Q': if (!save(VS_POISON) && !iswearing(R_SUSAB)) { if (him->s_ef.a_dex > MINABIL) { chg_abil(DEX, -1, TRUE); msg("You feel less agile."); } } when 'A': if (!save(VS_POISON) && herostr() > MINABIL) { if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) { if (levcount > 0) { chg_abil(STR, -1, TRUE); msg("A sting has weakened you"); } } else msg("Sting has no effect."); } when 'W': if (rnd(100) < 15 && !iswearing(R_SUSAB)) { if (him->s_exp <= 0) death(mp->t_indx); msg("You suddenly feel weaker."); if (--him->s_lvl == 0) { him->s_exp = 0; him->s_lvl = 1; } else him->s_exp = e_levels[him->s_lvl - 1] + 1; chg_hpt(-roll(1,10),TRUE,mp->t_indx); } when 'F': player.t_flags |= ISHELD; sprintf(mp->t_stats.s_dmg,"%dd1",++fung_hit); when 'L': { long lastpurse; struct linked_list *lep; lastpurse = purse; purse -= GOLDCALC; if (!save(VS_MAGIC)) purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; if (purse < 0) purse = 0; if (purse != lastpurse) msg("Your purse feels lighter."); lep = find_mons(mp->t_pos.y,mp->t_pos.x); if (lep != NULL) { remove_monster(&mp->t_pos, lep); mp = NULL; } } when 'N': { struct linked_list *steal, *list; struct object *sobj; int stworth = 0, wo; /* * Nymph's steal a magic item, look through the pack * and pick out one we like, namely the object worth * the most bucks. */ steal = NULL; for (list = pack; list != NULL; list = next(list)) { wo = get_worth(OBJPTR(list)); if (wo > stworth) { stworth = wo; steal = list; } } if (steal != NULL) { sobj = OBJPTR(steal); if (o_off(sobj, ISPROT)) { struct linked_list *nym; nym = find_mons(mp->t_pos.y, mp->t_pos.x); if (nym != NULL) { remove_monster(&mp->t_pos, nym); mp = NULL; } msg("She stole %s!", inv_name(sobj, TRUE)); detach(pack, steal); discard(steal); cur_null(sobj); updpack(); } } } when 'c': if (!save(VS_PETRIFICATION)) { msg("Your body begins to solidify."); msg("You are turned to stone !!! --More--"); wait_for(cw, ' '); death(mp->t_indx); } when 'd': if (rnd(100) < 50 && !(mp->t_flags & ISHUH)) player.t_flags |= ISHELD; if (!save(VS_POISON)) { if (iswearing(R_SUSAB) || iswearing(R_SUSTSTR)) msg("Sting has no effect."); else { int fewer, ostr; fewer = roll(1,4); ostr = herostr(); chg_abil(STR,-fewer,TRUE); if (herostr() < ostr) { fewer = ostr - herostr(); fuse(rchg_str, fewer - 1, 10); } msg("You feel weaker now."); } } when 'g': if (!save(VS_BREATH) && !iswearing(R_BREATH)) { msg("You feel singed."); chg_hpt(-roll(1,8),FALSE,mp->t_indx); } when 'h': if (!save(VS_BREATH) && !iswearing(R_BREATH)) { msg("You are seared."); chg_hpt(-roll(1,4),FALSE,mp->t_indx); } when 'p': if (!save(VS_POISON) && herostr() > MINABIL) { if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) { msg("You are gnawed."); chg_abil(STR,-1,TRUE); } } when 'u': if (!save(VS_POISON) && herostr() > MINABIL) { if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) { msg("You are bitten."); chg_abil(STR, -1, TRUE); fuse(rchg_str, 1, roll(5,10)); } } when 'w': if (!save(VS_POISON) && !iswearing(R_SUSAB)) { msg("You feel devitalized."); chg_hpt(-1,TRUE,mp->t_indx); } when 'i': if (!save(VS_PARALYZATION) && !iswearing(R_SUSAB)) { if (pl_on(ISSLOW)) lengthen(notslow,roll(3,10)); else { msg("You feel impaired."); player.t_flags |= ISSLOW; fuse(notslow,TRUE,roll(5,10)); } } otherwise: break; } } } else if (mp->t_type != 'E') { if (mp->t_type == 'F') { him->s_hpt -= fung_hit; if (him->s_hpt <= 0) death(mp->t_indx); } miss(mname); } flushinp(); /* flush type ahead */ count = 0; if (mp == NULL) return(-1); else return(0); } /* * swing: * Returns true if the swing hits */ bool swing(int at_lvl, int op_arm, int wplus) { reg int res = rnd(20)+1; reg int need = (21 - at_lvl) - op_arm; return (res + wplus >= need); } /* * check_level: * Check to see if the guy has gone up a level. */ void check_level(void) { reg int lev, add, dif; for (lev = 0; e_levels[lev] != 0; lev++) if (e_levels[lev] > him->s_exp) break; lev += 1; if (lev > him->s_lvl) { dif = lev - him->s_lvl; add = roll(dif, 10) + (dif * getpcon(him)); him->s_maxhp += add; if ((him->s_hpt += add) > him->s_maxhp) him->s_hpt = him->s_maxhp; msg("Welcome to level %d", lev); } him->s_lvl = lev; } /* * roll_em: * Roll several attacks */ bool roll_em(struct stats *att, struct stats *def, struct object *weap, bool hurl) { reg char *cp; reg int ndice, nsides, def_arm, prop_hplus, prop_dplus; reg bool did_hit = FALSE; prop_hplus = prop_dplus = 0; if (weap == NULL) { cp = att->s_dmg; } else if (hurl) { if (o_on(weap,ISMISL) && cur_weapon != NULL && cur_weapon->o_which == weap->o_launch) { cp = weap->o_hurldmg; prop_hplus = cur_weapon->o_hplus; prop_dplus = cur_weapon->o_dplus; } else cp = (o_on(weap,ISMISL) ? weap->o_damage : weap->o_hurldmg); } else { cp = weap->o_damage; /* * Drain a staff of striking */ if (weap->o_type == STICK && weap->o_which == WS_HIT && weap->o_charges == 0) { strcpy(weap->o_damage, "0d0"); weap->o_hplus = weap->o_dplus = 0; } } while(1) { int damage; int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus); int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus); if (att == him && weap == cur_weapon) { if (isring(LEFT, R_ADDDAM)) dplus += cur_ring[LEFT]->o_ac; else if (isring(LEFT, R_ADDHIT)) hplus += cur_ring[LEFT]->o_ac; if (isring(RIGHT, R_ADDDAM)) dplus += cur_ring[RIGHT]->o_ac; else if (isring(RIGHT, R_ADDHIT)) hplus += cur_ring[RIGHT]->o_ac; } ndice = atoi(cp); if ((cp = mindex(cp, 'd')) == NULL) break; nsides = atoi(++cp); if (def == him) { /* defender is hero */ if (cur_armor != NULL) def_arm = cur_armor->o_ac; else def_arm = def->s_arm; if (isring(LEFT, R_PROTECT)) def_arm -= cur_ring[LEFT]->o_ac; if (isring(RIGHT, R_PROTECT)) def_arm -= cur_ring[RIGHT]->o_ac; } else /* defender is monster */ def_arm = def->s_arm; if (hurl) hplus += getpdex(att,TRUE); if (swing(att->s_lvl, def_arm + getpdex(def, FALSE), hplus + str_plus(att))) { reg int proll; proll = roll(ndice, nsides); damage = dplus + proll + add_dam(att); if (pl_off(ISINVINC) || def != him) def->s_hpt -= max(0, damage); did_hit = TRUE; } if ((cp = mindex(cp, '/')) == NULL) break; cp++; } return did_hit; } /* * mindex: * Look for char 'c' in string pointed to by 'cp' */ char * mindex(char *cp, char c) { reg int i; for (i = 0; i < 3; i++) if (*cp != c) cp++; if (*cp == c) return cp; else return NULL; } /* * prname: * The print name of a combatant */ char * prname(char *who, bool upper) { static char tbuf[LINLEN]; *tbuf = '\0'; if (who == 0) strcpy(tbuf, "you"); else if (pl_on(ISBLIND)) strcpy(tbuf, "it"); else { strcpy(tbuf, "the "); strcat(tbuf, who); } if (upper) *tbuf = toupper(*tbuf); return tbuf; } /* * hit: * Print a message to indicate a succesful hit */ void hit(char *er) { msg("%s hit.",prname(er, TRUE)); } /* * miss: * Print a message to indicate a poor swing */ void miss(char *er) { msg("%s miss%s.",prname(er, TRUE),(er == 0 ? "":"es")); } /* * save_throw: * See if a creature saves against something */ bool save_throw(int which, struct thing *tp) { reg int need; reg struct stats *st; st = &tp->t_stats; need = 14 + which - (st->s_lvl / 2) - getpwis(st); return (roll(1, 20) >= need); } /* * save: * See if he saves against various nasty things */ bool save(int which) { return save_throw(which, &player); } /* * raise_level: * The guy just magically went up a level. */ void raise_level(void) { him->s_exp = e_levels[him->s_lvl-1] + 1L; check_level(); } /* * thunk: * A missile hits a monster */ void thunk(struct object *weap, char *mname) { if (weap->o_type == WEAPON) msg("The %s hits the %s.",w_magic[weap->o_which].mi_name,mname); else msg("You hit the %s.", mname); } /* * bounce: * A missile misses a monster */ void bounce(struct object *weap, char *mname) { if (weap->o_type == WEAPON) msg("The %s misses the %s.", w_magic[weap->o_which].mi_name,mname); else msg("You missed the %s.", mname); } /* * remove: * Remove a monster from the screen */ void remove_monster(struct coord *mp, struct linked_list *item) { reg char what; mvwaddch(mw, mp->y, mp->x, ' '); if (pl_on(ISBLIND)) what = ' '; /* if blind, then a blank */ else what = (THINGPTR(item))->t_oldch; /* normal char */ mvwaddch(cw, mp->y, mp->x, what); detach(mlist, item); discard(item); } /* * is_magic: * Returns true if an object radiates magic */ bool is_magic(struct object *obj) { switch (obj->o_type) { case ARMOR: return obj->o_ac != armors[obj->o_which].a_class; case WEAPON: return obj->o_hplus != 0 || obj->o_dplus != 0; case POTION: case SCROLL: case STICK: case RING: case AMULET: return TRUE; } return FALSE; } /* * killed: * Called to put a monster to death */ void killed(struct linked_list *item, bool pr) { reg struct thing *tp; reg struct object *obj; struct linked_list *pitem, *nexti, *itspack; struct coord here; nochange = FALSE; tp = THINGPTR(item); here = tp->t_pos; if (pr) { addmsg("Defeated "); if (pl_on(ISBLIND)) msg("it."); else msg("%s.", monsters[tp->t_indx].m_name); } him->s_exp += tp->t_stats.s_exp; isfight = FALSE; check_level(); unhold(tp->t_type); /* free player if held */ if (tp->t_type == 'L') { reg struct room *rp; rp = roomin(&here); if (rp != NULL) { if (rp->r_goldval!=0 || fallpos(&here, &rp->r_gold, FALSE)) { rp->r_goldval += GOLDCALC; if (!save_throw(VS_MAGIC,tp)) rp->r_goldval += GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; mvaddch(rp->r_gold.y, rp->r_gold.x, GOLD); if (!rf_on(rp,ISDARK)) { light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } } } } pitem = tp->t_pack; itspack = tp->t_pack; remove_monster(&here, item); while (pitem != NULL) { nexti = next(pitem); obj = OBJPTR(pitem); obj->o_pos = here; detach(itspack, pitem); fall(pitem, FALSE); pitem = nexti; } }