// This must be called when any of the following change: // - effects // - bionics // - traits // - underwater // - clothes // With the exception of clothes, all changes to these character attributes must // occur through a function in this class which calls this function. Clothes are // typically added/removed with wear() and takeoff(), but direct access to the // 'wears' vector is still allowed due to refactor exhaustion. void Character::recalc_sight_limits() { sight_max = 9999; sight_boost = 0; sight_boost_cap = 0; // Set sight_max. if (has_effect("blind")) { sight_max = 0; } else if (has_effect("in_pit") || (has_effect("boomered") && (!(has_trait("PER_SLIME_OK")))) || (underwater && !has_bionic("bio_membrane") && !has_trait("MEMBRANE") && !worn_with_flag("SWIM_GOGGLES") && !has_trait("CEPH_EYES") && !has_trait("PER_SLIME_OK") ) ) { sight_max = 1; } else if (has_active_mutation("SHELL2")) { // You can kinda see out a bit. sight_max = 2; } else if ( (has_trait("MYOPIC") || has_trait("URSINE_EYE")) && !is_wearing("glasses_eye") && !is_wearing("glasses_monocle") && !is_wearing("glasses_bifocal") && !has_effect("contacts")) { sight_max = 4; } else if (has_trait("PER_SLIME")) { sight_max = 6; } // Set sight_boost and sight_boost_cap, based on night vision. // (A player will never have more than one night vision trait.) sight_boost_cap = 12; // Debug-only NV, by vache's request if (has_trait("DEBUG_NIGHTVISION")) { sight_boost = 59; sight_boost_cap = 59; } else if (has_nv() || is_wearing("rm13_armor_on") || has_active_mutation("NIGHTVISION3") || has_active_mutation("ELFA_FNV") || (has_active_mutation("CEPH_VISION")) ) { // Yes, I'm breaking the cap. I doubt the reality bubble shrinks at night. // BIRD_EYE represents excellent fine-detail vision so I think it works. if (has_trait("BIRD_EYE")) { sight_boost_cap = 13; } sight_boost = sight_boost_cap; } else if (has_active_mutation("ELFA_NV")) { sight_boost = 6; // Elf-a and Bird eyes shouldn't coexist } else if (has_active_mutation("NIGHTVISION2") || has_active_mutation("FEL_NV") || has_active_mutation("URSINE_EYE")) { if (has_trait("BIRD_EYE")) { sight_boost = 5; } else { sight_boost = 4; } } else if (has_active_mutation("NIGHTVISION")) { if (has_trait("BIRD_EYE")) { sight_boost = 2; } else { sight_boost = 1; } } }
fuse unfly(fuse_arg *arg) { NOOP(arg); turn_off(player, CANFLY); if (!is_wearing(R_LEVITATION)) msg("You float gently to the ground."); }
fuse unbreathe(fuse_arg *arg) { NOOP(arg); turn_off(player, HASOXYGEN); if (!is_wearing(R_BREATHE)) msg("You start huffing and puffing."); }
fuse unhot(fuse_arg *arg) { NOOP(arg); turn_off(player, NOFIRE); if (!is_wearing(R_FIRERESIST)) msg("You feel a flush of warmth."); }
fuse unregen(fuse_arg *arg) { NOOP(arg); turn_off(player, ISREGEN); if (!is_wearing(R_REGEN)) msg("Your metabolism slows down."); }
fuse uncold(fuse_arg *arg) { NOOP(arg); turn_off(player, NOCOLD); if (!is_wearing(R_COLDRESIST)) msg("You feel a slight chill in the air."); }
int int_wis_bonus(void) { int ret_val = -2; int casters_stat; switch (player.t_ctype) { case C_PALADIN: case C_CLERIC: casters_stat = pstats.s_wisdom; break; case C_RANGER: case C_DRUID: casters_stat = pstats.s_wisdom; break; case C_MAGICIAN: casters_stat = pstats.s_intel; break; case C_ILLUSION: casters_stat = pstats.s_intel; break; default: if (is_wearing(R_WIZARD)) casters_stat = pstats.s_intel; else if (is_wearing(R_PIETY)) casters_stat = pstats.s_wisdom; else casters_stat = (rnd(2) ? pstats.s_wisdom : pstats.s_intel); } if (casters_stat > 12) ret_val = casters_stat - 12; else if (casters_stat > 6) ret_val = 0; else if (casters_stat > 3) ret_val = -1; return(ret_val); }
void untruesee(fuse_arg *arg) { NOOP(arg); if (!is_wearing(R_TRUESEE)) { turn_off(player, CANTRUESEE); msg("Your sensory perceptions return to normal."); } }
fuse unsee(fuse_arg *arg) { NOOP(arg); if (!is_wearing(R_SEEINVIS)) { turn_off(player, CANSEE); msg("The tingling feeling leaves your eyes."); } }
struct linked_list * summon_monster(int type, int familiar, int print_message) { struct linked_list *mp; struct thing *tp; int monster; if (familiar && !is_wearing(R_WIZARD) && off(player, CANSUMMON)) { msg("Only spellcasters can summon familiars!"); return(NULL); } if (type == 0) /* Random monster modified by level */ { int ndice = min(pstats.s_lvl, (nummonst - NUMSUMMON) / 8); monster = min(nummonst, roll(ndice, pstats.s_charisma)); /* * if a familiar exists, and it is higher in level, make it * again */ if (fam_ptr != NULL) { struct thing *fp = THINGPTR(fam_ptr); monster = max(fp->t_index, monster); } } else monster = type; turn_on(player, SUMMONING); mp = creat_mons(&player, monster, NOMESSAGE); if (!mp) { msg("Summon failed."); turn_off(player, SUMMONING); return(NULL); } if (print_message == MESSAGE) { msg("A %s appears out of nowhere!", monsters[monster].m_name); if (familiar) msg("I am here to serve %s.", whoami); else { msg("My goodness, are you Yendor?"); ++mons_summoned; debug("%d monsters now summoned.", mons_summoned); } } tp = THINGPTR(mp); turn_on(*tp, ISCHARMED); /* Summoned monsters are always charmed */ if (familiar) { int i; static const unsigned long fam_on[]= {ISREGEN,CANSHOOT,CANWIELD,HASARMOR,ISFAMILIAR,0}; static const unsigned long fam_off[]={ISMEAN, ISHUH, ISINVIS, CANSURPRISE, NOMOVE, ISSLOW, ISSHADOW, ISGREED, ISFAST, CANFLY, ISFLEE, 0}; for (i = 0; fam_on[i]; i++) turn_on(*tp, fam_on[i]); for (i = 0; fam_off[i]; i++) turn_off(*tp, fam_off[i]); if (fam_ptr != NULL) /* Get rid of old familiar */ { struct thing *fp = THINGPTR(fam_ptr); struct linked_list *fpack = fp->t_pack; struct linked_list *item; if (fpack != NULL) /* Transfer pack */ { if (tp->t_pack == NULL) tp->t_pack = fpack; else { for(item=tp->t_pack; item->l_next != NULL; item=next(item)) ; /* find last item in list */ item->l_next = fpack; fpack->l_prev = item; } } fpack = NULL; killed(NULL, fam_ptr, NOMESSAGE, NOPOINTS); } fam_ptr = mp; fam_type = monster; /* improve their abilities a bit */ tp->t_stats.s_hpt += roll(2, pstats.s_lvl); tp->t_stats.s_lvl += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_arm -= roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_str += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_intel += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_wisdom += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_dext += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_const += roll(2, (pstats.s_lvl / 4) + 1); tp->t_stats.s_charisma += roll(2, (pstats.s_lvl / 4) + 1); /* some monsters do no damage by default */ if (strcmp(tp->t_stats.s_dmg, "0d0") == 0) tp->t_stats.s_dmg = "1d8"; tp->maxstats = tp->t_stats; /* structure assignment */ } turn_off(player, SUMMONING); return(mp); }
void new_monster(struct linked_list *item, int type, coord *cp, int max_monster) { struct thing *tp; struct monster *mp; char *ip, *hitp; int i, min_intel, max_intel; int num_dice, num_sides = 8, num_extra = 0; int eff_charisma = pstats.s_charisma; int eff_intel = pstats.s_intel; attach(mlist, item); tp = THINGPTR(item); tp->t_index = type; tp->t_wasshot = FALSE; tp->t_type = monsters[type].m_appear; tp->t_ctype = C_MONSTER; tp->t_no_move = 0; tp->t_doorgoal = -1; tp->t_pos = *cp; tp->t_oldpos = *cp; tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) ); mvwaddch(mw, cp->y, cp->x, tp->t_type); mp = &monsters[tp->t_index]; /* Figure out monster's hit points */ hitp = mp->m_stats.s_hpt; num_dice = atoi(hitp); if ((hitp = strchr(hitp, 'd')) != NULL) { num_sides = atoi(++hitp); if ((hitp = strchr(hitp, '+')) != NULL) num_extra = atoi(++hitp); } if (max_monster == MAXSTATS) tp->t_stats.s_hpt = num_dice * num_sides + num_extra; else tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra; tp->t_stats.s_lvl = mp->m_stats.s_lvl; tp->t_stats.s_arm = mp->m_stats.s_arm; tp->t_stats.s_dmg = mp->m_stats.s_dmg; tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp * tp->t_stats.s_hpt; tp->t_stats.s_str = mp->m_stats.s_str; if (max_level > 30) { tp->t_stats.s_hpt += roll(4, (max_level - 60) * 2); tp->t_stats.s_lvl += roll(4, (max_level - 60) / 8); tp->t_stats.s_arm -= roll(2, (max_level - 60) / 8); tp->t_stats.s_str += roll(2, (max_level - 60) / 12); tp->t_stats.s_exp += roll(4, (max_level - 60) * 2) * mp->m_add_exp; } /* * just initailize others values to something reasonable for now * maybe someday will *really* put these in monster table */ tp->t_stats.s_wisdom = 8 + rnd(4); tp->t_stats.s_dext = 8 + rnd(4); tp->t_stats.s_const = 8 + rnd(4); tp->t_stats.s_charisma = 8 + rnd(4); if (max_level > 45) tp->t_stats.s_dext += roll(2, (max_level - 50) / 8); /* Set the initial flags */ for (i = 0; i < 16; i++) tp->t_flags[i] = 0; for (i = 0; i < 16; i++) turn_on(*tp, mp->m_flags[i]); /* suprising monsters don't always surprise you */ if (!max_monster && on(*tp, CANSURPRISE) && rnd(100) < 20) turn_off(*tp, CANSURPRISE); /* If this monster is unique, genocide it */ if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE; /* gods automatically get special abilities */ if (on(*tp, ISGOD)) { turn_on(*tp, CANFRIGHTEN); turn_on(*tp, CANCAST); turn_on(*tp, CANFLY); turn_on(*tp, CANBARGAIN); turn_on(*tp, ISLARGE); turn_on(*tp, CANTELEPORT); turn_on(*tp, CANSPEAK); turn_on(*tp, CANDARKEN); turn_on(*tp, CANSEE); turn_on(*tp, CANLIGHT); turn_on(*tp, BMAGICHIT); } tp->t_turn = TRUE; tp->t_pack = NULL; /* Figure intelligence */ min_intel = atoi(mp->m_intel); if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL) tp->t_stats.s_intel = min_intel; else { max_intel = atoi(++ip); if (max_monster) tp->t_stats.s_intel = max_intel; else tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel); } tp->t_stats.s_power = (rnd(tp->t_stats.s_lvl / 5) + 1) * tp->t_stats.s_intel; tp->maxstats = tp->t_stats; /* structure assignment */ /* If the monster can shoot, it may have a weapon */ if (on(*tp, CANSHOOT) && (max_monster || rnd(9) < 6)) { struct linked_list *thrower_item, *missile_item; struct object *thrower, *a_missile; thrower_item = new_item(sizeof *thrower); thrower = OBJPTR(thrower_item); carried_weapon(tp, thrower); missile_item = new_item(sizeof *a_missile); a_missile = OBJPTR(missile_item); carried_weapon(tp, a_missile); /* The monster may use a crossbow, sling, footbow, or an arrow */ /* Take racial preferences into account */ if ((strcmp(mp->m_name, "elf") == 0) || (strcmp(mp->m_name, "noldor elf") == 0)) { thrower->o_which = BOW; if (rnd(5) == 0) a_missile->o_which = SILVERARROW; else a_missile->o_which = ARROW; } else if ((strcmp(mp->m_name, "dwarf") == 0) || (strcmp(mp->m_name, "kazad dwarf") == 0)) { thrower->o_which = CROSSBOW; a_missile->o_which = BOLT; } else if (on(*tp, ISSMALL)) { switch (rnd(3)) { case 0: thrower->o_which = SLING; a_missile->o_which = BULLET; break; default: thrower->o_which = SLING; a_missile->o_which = ROCK; } } else if (on(*tp, ISLARGE)) { switch (rnd(4)) { case 0: thrower->o_which = CROSSBOW; a_missile->o_which = BOLT; break; case 1: thrower->o_which = FOOTBOW; a_missile->o_which = FBBOLT; break; default: thrower->o_which = BOW; if (rnd(5) == 0) a_missile->o_which = FLAMEARROW; else a_missile->o_which = ARROW; break; } } else { switch (rnd(6)) { case 1: thrower->o_which = SLING; a_missile->o_which = ROCK; break; case 2: thrower->o_which = CROSSBOW; a_missile->o_which = BOLT; break; case 3: thrower->o_which = FOOTBOW; a_missile->o_which = FBBOLT; break; case 4: thrower->o_which = BOW; a_missile->o_which = ARROW; break; default: thrower->o_which = SLING; a_missile->o_which = BULLET; break; } } init_weapon(thrower, thrower->o_which); init_weapon(a_missile, a_missile->o_which); attach(tp->t_pack, thrower_item); attach(tp->t_pack, missile_item); } /* monsters that wield weapons */ if (on(*tp, CANWIELD)) { if (max_monster || rnd(3)) { struct linked_list *wield_item; struct object *wielded; wield_item = new_item(sizeof *wielded); wielded = OBJPTR(wield_item); carried_weapon(tp, wielded); i = rnd(CLAYMORE - CLUB) + rnd(2 * tp->t_stats.s_lvl); i = min(i, CLAYMORE); wielded->o_which = i; init_weapon(wielded, wielded->o_which); /* Is it too heavy? */ if (itemweight(wielded) > 8 * tp->t_stats.s_str) discard(wield_item); else attach(tp->t_pack, wield_item); } } if (is_wearing(R_AGGR)) chase_it(cp, &player); else { turn_off(*tp, ISRUN); if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE); if (rnd(luck) == 0) switch (player.t_ctype) { case C_MAGICIAN: case C_ILLUSION: eff_intel = 2 * pstats.s_intel; break; case C_DRUID: eff_intel = 2 * pstats.s_intel; case C_RANGER: eff_charisma = 2 * pstats.s_charisma; break; case C_ASSASIN: case C_THIEF: case C_NINJA: eff_charisma = pstats.s_charisma / 2; break; } /* LOWFRIENDLY monsters might be friendly */ i = roll(1,100); if (i == 0 || (on(*tp, LOWFRIENDLY) && i < eff_charisma) || (on(*tp, MEDFRIENDLY) && i < 3 * eff_charisma) || (on(*tp, HIGHFRIENDLY) && i < 5 * eff_charisma)) { turn_on(*tp, ISFRIENDLY); turn_off(*tp, ISMEAN); } i = roll(1,100); if (i == 0 || (on(*tp, LOWCAST) && i < eff_intel) || (on(*tp, MEDCAST) && i < 3 * eff_intel) || (on(*tp, HIGHCAST) && i < 5 * eff_intel)) { turn_on(*tp, CANCAST); } if (on(*tp, ISDISGUISE)) { char mch = 0; if (tp->t_pack != NULL) mch = (OBJPTR(tp->t_pack))->o_type; else switch (rnd(level > arts[0].ar_level ? 10 : 9)) { case 0: mch = GOLD; break; case 1: mch = POTION; break; case 2: mch = SCROLL; break; case 3: mch = FOOD; break; case 4: mch = WEAPON; break; case 5: mch = ARMOR; break; case 6: mch = RING; break; case 7: mch = STICK; break; case 8: mch = monsters[randmonster(NOWANDER, NOGRAB)].m_appear; break; case 9: mch = ARTIFACT; break; } tp->t_disguise = mch; } } }
// This must be called when any of the following change: // - effects // - bionics // - traits // - underwater // - clothes // With the exception of clothes, all changes to these character attributes must // occur through a function in this class which calls this function. Clothes are // typically added/removed with wear() and takeoff(), but direct access to the // 'wears' vector is still allowed due to refactor exhaustion. void Character::recalc_sight_limits() { sight_max = 9999; vision_mode_cache.reset(); // Set sight_max. if (has_effect("blind") || worn_with_flag("BLIND") || has_active_bionic("bio_blindfold")) { sight_max = 0; } else if( has_effect("boomered") && (!(has_trait("PER_SLIME_OK"))) ) { sight_max = 1; vision_mode_cache.set( BOOMERED ); } else if (has_effect("in_pit") || (underwater && !has_bionic("bio_membrane") && !has_trait("MEMBRANE") && !worn_with_flag("SWIM_GOGGLES") && !has_trait("CEPH_EYES") && !has_trait("PER_SLIME_OK") ) ) { sight_max = 1; } else if (has_active_mutation("SHELL2")) { // You can kinda see out a bit. sight_max = 2; } else if ( (has_trait("MYOPIC") || has_trait("URSINE_EYE")) && !is_wearing("glasses_eye") && !is_wearing("glasses_monocle") && !is_wearing("glasses_bifocal") && !has_effect("contacts")) { sight_max = 4; } else if (has_trait("PER_SLIME")) { sight_max = 6; } else if( has_effect( "darkness" ) ) { vision_mode_cache.set( DARKNESS ); sight_max = 10; } // Debug-only NV, by vache's request if( has_trait("DEBUG_NIGHTVISION") ) { vision_mode_cache.set( DEBUG_NIGHTVISION ); } if( has_nv() ) { vision_mode_cache.set( NV_GOGGLES ); } if( has_active_mutation("NIGHTVISION3") || is_wearing("rm13_armor_on") ) { vision_mode_cache.set( NIGHTVISION_3 ); } if( has_active_mutation("ELFA_FNV") ) { vision_mode_cache.set( FULL_ELFA_VISION ); } if( has_active_mutation("CEPH_VISION") ) { vision_mode_cache.set( CEPH_VISION ); } if (has_active_mutation("ELFA_NV")) { vision_mode_cache.set( ELFA_VISION ); } if( has_active_mutation("NIGHTVISION2") ) { vision_mode_cache.set( NIGHTVISION_2 ); } if( has_active_mutation("FEL_NV") ) { vision_mode_cache.set( FELINE_VISION ); } if( has_active_mutation("URSINE_EYE") ) { vision_mode_cache.set( URSINE_VISION ); } if (has_active_mutation("NIGHTVISION")) { vision_mode_cache.set(NIGHTVISION_1); } if( has_trait("BIRD_EYE") ) { vision_mode_cache.set( BIRD_EYE); } }
void death(int monst) { char **dp = (char **) rip, *killer; struct tm *lt; time_t date; char buf[80]; int c; if (is_wearing(R_RESURRECT) || rnd(wizard ? 3 : 67) == 0) { int die = TRUE; if (resurrect-- == 0) msg("You've run out of lives."); else if (!save_resurrect(ring_value(R_RESURRECT))) msg("Your attempt to return from the grave fails."); else { struct linked_list *item; struct linked_list *next_item; struct object *obj; int rm, flags; coord pos; die = FALSE; msg("You feel a sudden warmth and then nothingness."); teleport(); if (ring_value(R_RESURRECT) > 1 && rnd(10)) { pstats.s_hpt = 2 * pstats.s_const; pstats.s_const = max(pstats.s_const - 1, 3); } else { for (item = pack; item != NULL; item = next_item) { obj = OBJPTR(item); if (obj->o_flags & ISOWNED || obj->o_flags & ISPROT) { next_item = next(item); continue; } flags = obj->o_flags; obj->o_flags &= ~ISCURSED; dropcheck(obj); obj->o_flags = flags; next_item = next(item); rem_pack(obj); if (obj->o_type == ARTIFACT) has_artifact &= ~(1 << obj->o_which); do { rm = rnd_room(); rnd_pos(&rooms[rm], &pos); } while(winat(pos.y, pos.x) != FLOOR); obj->o_pos = pos; add_obj(item, obj->o_pos.y, obj->o_pos.x); } pstats.s_hpt = pstats.s_const; pstats.s_const = max(pstats.s_const - roll(2, 2), 3); } chg_str(roll(1, 4), TRUE, FALSE); pstats.s_lvl = max(pstats.s_lvl, 1); no_command += 2 + rnd(4); if (on(player, ISHUH)) lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION); else light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER); turn_on(player, ISHUH); light(&hero); } if (die) { wmove(cw, mpos, 0); waddstr(cw, morestr); wrefresh(cw); wait_for(' '); } else return; } time(&date); lt = localtime(&date); clear(); wclear(cw); move(8, 0); while (*dp) printw("%s\n", *dp++); mvaddstr(14, 28 - ((int)(strlen(whoami) + 1) / 2), whoami); sprintf(buf, "%d+%ld Points", pstats.s_lvl, pstats.s_exp); mvaddstr(15, 28 - ((int)(strlen(buf) + 1) / 2), buf); killer = killname(monst,buf); mvaddstr(17, 28 - ((int)(strlen(killer) + 1) / 2), killer); mvaddstr(18, 28, (sprintf(prbuf, "%2d", lt->tm_year), prbuf)); move(LINES - 1, 0); mvaddstr(LINES - 1, 0, retstr); while ((c = readcharw(stdscr)) != '\n' && c != '\r') continue; idenpack(); wrefresh(cw); refresh(); score(pstats.s_exp, pstats.s_lvl, KILLED, monst); byebye(); }
int player::hit_roll() { int stat = dex_cur; // Some martial arts use something else to determine hits! if(weapon.typeId() == "style_tiger"){ stat = (str_cur * 2 + dex_cur) / 3; } else if(weapon.typeId() == "style_leopard"){ stat = (per_cur + int_cur + dex_cur * 2) / 4; } else if(weapon.typeId() == "style_snake"){ stat = (per_cur + dex_cur) / 2; } int numdice = base_to_hit(stat) + weapon.type->m_to_hit + disease_intensity(DI_ATTACK_BOOST); int sides = 10 - encumb(bp_torso); int best_bonus = 0; if (sides < 2) sides = 2; // Are we unarmed? if (unarmed_attack()) { best_bonus = skillLevel("unarmed"); if (skillLevel("unarmed") > 4) best_bonus += skillLevel("unarmed") - 4; // Extra bonus for high levels } // Using a bashing weapon? if (weapon.is_bashing_weapon()) { int bash_bonus = int(skillLevel("bashing") / 3); if (bash_bonus > best_bonus) best_bonus = bash_bonus; } // Using a cutting weapon? if (weapon.is_cutting_weapon()) { int cut_bonus = int(skillLevel("cutting") / 2); if (cut_bonus > best_bonus) best_bonus = cut_bonus; } // Using a spear? if (weapon.has_flag("SPEAR") || weapon.has_flag("STAB")) { int stab_bonus = int(skillLevel("stabbing") / 2); if (stab_bonus > best_bonus) best_bonus = stab_bonus; } numdice += best_bonus; // Use whichever bonus is best. // Drunken master makes us hit better if (has_trait(PF_DRUNKEN)) { if (unarmed_attack()) numdice += int(disease_level(DI_DRUNK) / 300); else numdice += int(disease_level(DI_DRUNK) / 400); } // Farsightedness makes us hit worse if (has_trait(PF_HYPEROPIC) && !is_wearing("glasses_reading")) { numdice -= 2; } if (numdice < 1) { numdice = 1; sides = 8 - encumb(bp_torso); } return dice(numdice, sides); }
void wanderer(void) { int i, cnt = 0; struct room *hr = roomin(hero); struct linked_list *item; struct thing *tp; coord cp; char *loc; int which; /* Find a place for it -- avoid the player's room */ do { do { cnt++; i = rnd_room(); } while (!(hr != &rooms[i] || levtype == MAZELEV || levtype == THRONE || cnt > 5000)); rnd_pos(&rooms[i], &cp); } while(!step_ok(cp.y, cp.x, NOMONST, NULL)); /* Create a new wandering monster */ item = new_item(sizeof *tp); which = randmonster(TRUE, FALSE); new_monster(item, which, &cp, FALSE); tp = THINGPTR(item); tp->t_pos = cp; /* Assign the position to the monster */ chase_it(&tp->t_pos, &player); i = rnd(7); if (on(*tp, ISSWARM) && i < 5) cnt = roll(2, 4); else if (on(*tp, ISFLOCK) && i < 5) cnt = roll(1, 4); else cnt = 0; for (i = 1; i <= cnt; i++) { struct linked_list *ip = creat_mons(tp, which, NOMESSAGE); if (ip != NULL) { struct thing *mp = THINGPTR(ip); if (on(*tp, ISFRIENDLY)) turn_on(*mp, ISFRIENDLY); else turn_off(*mp, ISFRIENDLY); } } if (cnt > 0) { if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST)) turn_on(*tp, CANCAST); tp->t_stats.s_hpt += roll(2, 8); tp->t_stats.s_lvl += roll(2, 3); tp->t_stats.s_arm -= roll(1, 6); tp->t_stats.s_str += roll(2, 3); tp->t_stats.s_intel += roll(2, 3); tp->t_stats.s_exp += roll(2, 8) * monsters[which].m_add_exp; } i = DISTANCE(cp, hero); if (i < 20) loc = "very close to you"; else if (i < 400) loc = "nearby"; else loc = "in the distance"; if (wizard) msg("Started a wandering %s.", monsters[tp->t_index].m_name); else if (on(*tp, ISUNDEAD) && (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN || is_wearing(R_PIETY))) msg("You sense a new ungodly monster %s.", loc); else if (on(player, CANHEAR) || (player.t_ctype == C_THIEF && rnd(20) == 0)) msg("You hear a new %s moving %s.", monsters[tp->t_index].m_name, loc); else if (on(player, CANSCENT) || (player.t_ctype == C_THIEF && rnd(20) == 0)) msg("You smell a new %s %s.", monsters[tp->t_index].m_name, loc); }
void doctor(daemon_arg *who) { struct thing *tp = who->thingptr; long ohp; /* turn off ISFLEE? */ struct stats *curp; /* current stats pointer */ struct stats *maxp; /* max stats pointer */ int turns_quiet, new_points; curp = &(tp->t_stats); maxp = &(tp->maxstats); if (on(*tp, ISINWALL)) { tp->t_rest_hpt = 0; return; } /* Check for regenerating spell points first */ doctor_spell_points(tp); if (curp->s_hpt == maxp->s_hpt) { tp->t_rest_hpt = 0; return; } tp->t_rest_hpt++; switch (tp->t_ctype) { case C_MAGICIAN: case C_ILLUSION: turns_quiet = 24 - curp->s_lvl; new_points = curp->s_lvl / 2 - 4; break; case C_THIEF: case C_ASSASIN: case C_NINJA: turns_quiet = 16 - curp->s_lvl; new_points = curp->s_lvl / 2 - 1; break; case C_CLERIC: case C_DRUID: turns_quiet = 16 - curp->s_lvl; new_points = curp->s_lvl / 2 - 2; break; case C_FIGHTER: case C_RANGER: case C_PALADIN: turns_quiet = 8 - curp->s_lvl / 2; new_points = curp->s_lvl / 2 - 1; break; case C_MONSTER: turns_quiet = 16 - curp->s_lvl; new_points = curp->s_lvl / 2 - 6; break; default: debug("What a strange character you are!"); return; } ohp = curp->s_hpt; if (off(*tp, HASDISEASE)) { if (curp->s_lvl < 8) { if (tp->t_rest_hpt > turns_quiet) curp->s_hpt++; } else if (tp->t_rest_hpt >= 15) curp->s_hpt += rnd(new_points) + 1; } if (tp == &player) { if (curp->s_lvl > 10) turns_quiet = 2; else turns_quiet = rnd(turns_quiet / 6) + 1; if (is_wearing(R_REGEN)) curp->s_hpt += ring_value(R_REGEN); } if (on(*tp, ISREGEN)) curp->s_hpt += curp->s_lvl / 5 + 1; if (ohp != curp->s_hpt) { if (curp->s_hpt >= maxp->s_hpt) { curp->s_hpt = maxp->s_hpt; if (off(*tp, WASTURNED) && on(*tp, ISFLEE) && tp != &player) { turn_off(*tp, ISFLEE); tp->t_oldpos = tp->t_pos; /* Start our trek over */ } } tp->t_rest_hpt = 0; } return; }
void doctor_spell_points(struct thing *tp) { int turns_quiet, new_points; struct stats *curp; /* current stats pointer */ struct stats *maxp; /* max stats pointer */ int opower; /* current power */ curp = &(tp->t_stats); maxp = &(tp->maxstats); opower = curp->s_power; /* The right ring will let you regenerate while wearing bad armor */ if (off(*tp, CANCAST) || ((tp == &player) && (cur_armor && wear_ok(tp, cur_armor, NOMESSAGE) == FALSE) && !(is_wearing(R_WIZARD) || is_wearing(R_PIETY)))) { tp->t_rest_pow = 0; return; } tp->t_rest_pow++; switch (tp->t_ctype) { case C_MAGICIAN: case C_ILLUSION: turns_quiet = 18 - curp->s_lvl / 2; new_points = curp->s_lvl / 2; break; case C_CLERIC: case C_DRUID: turns_quiet = 24 - curp->s_lvl; new_points = curp->s_lvl / 2 - 2; break; case C_THIEF: case C_ASSASIN: case C_NINJA: turns_quiet = 32 - curp->s_lvl; new_points = curp->s_lvl / 3 - 3; break; case C_FIGHTER: case C_RANGER: case C_PALADIN: turns_quiet = 32 - curp->s_lvl; new_points = curp->s_lvl / 3 - 4; break; case C_MONSTER: turns_quiet = 24 - curp->s_lvl; new_points = curp->s_lvl - 6; break; default: return; } if (curp->s_lvl < 8) { if (tp->t_rest_pow > turns_quiet) curp->s_power++; } else if (tp->t_rest_pow >= 15) curp->s_power += rnd(new_points) + 1; if (tp == &player && (is_wearing(R_WIZARD) || is_wearing(R_PIETY))) curp->s_power += ring_value(R_WIZARD) + ring_value(R_PIETY); curp->s_power = min(max(0, curp->s_power), maxp->s_power); if (curp->s_power != opower) tp->t_rest_pow = 0; return; }
void player::complete_craft() { const recipe *making = &recipe_dict[ activity.name ]; // Which recipe is it? int batch_size = activity.values.front(); if( making == nullptr ) { debugmsg( "no recipe with id %s found", activity.name.c_str() ); activity.set_to_null(); return; } int secondary_dice = 0; int secondary_difficulty = 0; for( const auto &pr : making->required_skills ) { secondary_dice += get_skill_level( pr.first ); secondary_difficulty += pr.second; } // # of dice is 75% primary skill, 25% secondary (unless secondary is null) int skill_dice; if( secondary_difficulty > 0 ) { skill_dice = get_skill_level( making->skill_used ) * 3 + secondary_dice; } else { skill_dice = get_skill_level( making->skill_used ) * 4; } auto helpers = g->u.get_crafting_helpers(); for( const npc *np : helpers ) { if( np->get_skill_level( making->skill_used ) >= get_skill_level( making->skill_used ) ) { // NPC assistance is worth half a skill level skill_dice += 2; add_msg( m_info, _( "%s helps with crafting..." ), np->name.c_str() ); break; } } // farsightedness can impose a penalty on electronics and tailoring success // it's equivalent to a 2-rank electronics penalty, 1-rank tailoring if( has_trait( trait_id( "HYPEROPIC" ) ) && !is_wearing( "glasses_reading" ) && !is_wearing( "glasses_bifocal" ) && !has_effect( effect_contacts ) ) { int main_rank_penalty = 0; if( making->skill_used == skill_id( "electronics" ) ) { main_rank_penalty = 2; } else if( making->skill_used == skill_id( "tailor" ) ) { main_rank_penalty = 1; } skill_dice -= main_rank_penalty * 4; } // It's tough to craft with paws. Fortunately it's just a matter of grip and fine-motor, // not inability to see what you're doing if( has_trait( trait_PAWS ) || has_trait( trait_PAWS_LARGE ) ) { int paws_rank_penalty = 0; if( has_trait( trait_PAWS_LARGE ) ) { paws_rank_penalty += 1; } if( making->skill_used == skill_id( "electronics" ) || making->skill_used == skill_id( "tailor" ) || making->skill_used == skill_id( "mechanics" ) ) { paws_rank_penalty += 1; } skill_dice -= paws_rank_penalty * 4; } // Sides on dice is 16 plus your current intelligence ///\EFFECT_INT increases crafting success chance int skill_sides = 16 + int_cur; int diff_dice; if( secondary_difficulty > 0 ) { diff_dice = making->difficulty * 3 + secondary_difficulty; } else { // Since skill level is * 4 also diff_dice = making->difficulty * 4; } int diff_sides = 24; // 16 + 8 (default intelligence) int skill_roll = dice( skill_dice, skill_sides ); int diff_roll = dice( diff_dice, diff_sides ); if( making->skill_used ) { const double batch_mult = 1 + time_to_craft( *making, batch_size ) / 30000.0; //normalize experience gain to crafting time, giving a bonus for longer crafting practice( making->skill_used, ( int )( ( making->difficulty * 15 + 10 ) * batch_mult ), ( int )making->difficulty * 1.25 ); //NPCs assisting or watching should gain experience... for( auto &elem : helpers ) { //If the NPC can understand what you are doing, they gain more exp if( elem->get_skill_level( making->skill_used ) >= making->difficulty ) { elem->practice( making->skill_used, ( int )( ( making->difficulty * 15 + 10 ) * batch_mult * .50 ), ( int )making->difficulty * 1.25 ); if( batch_size > 1 ) { add_msg( m_info, _( "%s assists with crafting..." ), elem->name.c_str() ); } if( batch_size == 1 ) { add_msg( m_info, _( "%s could assist you with a batch..." ), elem->name.c_str() ); } //NPCs around you understand the skill used better } else { elem->practice( making->skill_used, ( int )( ( making->difficulty * 15 + 10 ) * batch_mult * .15 ), ( int )making->difficulty * 1.25 ); add_msg( m_info, _( "%s watches you craft..." ), elem->name.c_str() ); } } } // Messed up badly; waste some components. if( making->difficulty != 0 && diff_roll > skill_roll * ( 1 + 0.1 * rng( 1, 5 ) ) ) { add_msg( m_bad, _( "You fail to make the %s, and waste some materials." ), item::nname( making->result ).c_str() ); if( last_craft->has_cached_selections() ) { last_craft->consume_components(); } else { // @todo Guarantee that selections are cached const auto &req = making->requirements(); for( const auto &it : req.get_components() ) { consume_items( it, batch_size ); } for( const auto &it : req.get_tools() ) { consume_tools( it, batch_size ); } } activity.set_to_null(); return; // Messed up slightly; no components wasted. } else if( diff_roll > skill_roll ) { add_msg( m_neutral, _( "You fail to make the %s, but don't waste any materials." ), item::nname( making->result ).c_str() ); //this method would only have been called from a place that nulls activity.type, //so it appears that it's safe to NOT null that variable here. //rationale: this allows certain contexts (e.g. ACT_LONGCRAFT) to distinguish major and minor failures return; } // If we're here, the craft was a success! // Use up the components and tools std::list<item> used; if( !last_craft->has_cached_selections() ) { // This should fail and return, but currently crafting_command isn't saved // Meaning there are still cases where has_cached_selections will be false // @todo Allow saving last_craft and debugmsg+fail craft if selection isn't cached if( !has_trait( trait_id( "DEBUG_HS" ) ) ) { const auto &req = making->requirements(); for( const auto &it : req.get_components() ) { std::list<item> tmp = consume_items( it, batch_size ); used.splice( used.end(), tmp ); } for( const auto &it : req.get_tools() ) { consume_tools( it, batch_size ); } } } else if( !has_trait( trait_id( "DEBUG_HS" ) ) ) { used = last_craft->consume_components(); if( used.empty() ) { return; } } // Set up the new item, and assign an inventory letter if available std::vector<item> newits = making->create_results( batch_size ); bool first = true; float used_age_tally = 0; int used_age_count = 0; size_t newit_counter = 0; for( item &newit : newits ) { // messages, learning of recipe, food spoilage calc only once if( first ) { first = false; if( knows_recipe( making ) ) { add_msg( _( "You craft %s from memory." ), newit.type_name( 1 ).c_str() ); } else { add_msg( _( "You craft %s using a book as a reference." ), newit.type_name( 1 ).c_str() ); // If we made it, but we don't know it, // we're making it from a book and have a chance to learn it. // Base expected time to learn is 1000*(difficulty^4)/skill/int moves. // This means time to learn is greatly decreased with higher skill level, // but also keeps going up as difficulty goes up. // Worst case is lvl 10, which will typically take // 10^4/10 (1,000) minutes, or about 16 hours of crafting it to learn. int difficulty = has_recipe( making, crafting_inventory(), helpers ); ///\EFFECT_INT increases chance to learn recipe when crafting from a book if( x_in_y( making->time, ( 1000 * 8 * ( difficulty * difficulty * difficulty * difficulty ) ) / ( std::max( get_skill_level( making->skill_used ).level(), 1 ) * std::max( get_int(), 1 ) ) ) ) { learn_recipe( ( recipe * )making ); add_msg( m_good, _( "You memorized the recipe for %s!" ), newit.type_name( 1 ).c_str() ); } } for( auto &elem : used ) { if( elem.goes_bad() ) { used_age_tally += elem.get_relative_rot(); ++used_age_count; } } } // Don't store components for things made by charges, // don't store components for things that can't be uncrafted. if( recipe_dictionary::get_uncraft( making->result ) && !newit.count_by_charges() ) { // Setting this for items counted by charges gives only problems: // those items are automatically merged everywhere (map/vehicle/inventory), // which would either loose this information or merge it somehow. set_components( newit.components, used, batch_size, newit_counter ); newit_counter++; } finalize_crafted_item( newit, used_age_tally, used_age_count ); set_item_inventory( newit ); } if( making->has_byproducts() ) { std::vector<item> bps = making->create_byproducts( batch_size ); for( auto &bp : bps ) { finalize_crafted_item( bp, used_age_tally, used_age_count ); set_item_inventory( bp ); } } inv.restack( this ); }
struct linked_list * wake_monster(int y, int x) { struct thing *tp; struct linked_list *it; struct room *trp; char *mname; if ((it = find_mons(y, x)) == NULL) { debug("Can't find monster in show."); return(NULL); } tp = THINGPTR(it); if ((good_monster(*tp)) || on(player, SUMMONING)) { chase_it(&tp->t_pos, &player); turn_off(*tp, ISINVIS); turn_off(*tp, CANSURPRISE); return(it); } trp = roomin(tp->t_pos); /* Current room for monster */ mname = monsters[tp->t_index].m_name; /* Let greedy ones guard gold */ if (on(*tp, ISGREED) && off(*tp, ISRUN)) if ((trp != NULL) && (lvl_obj != NULL)) { struct linked_list *item; struct object *cur; for (item = lvl_obj; item != NULL; item = next(item)) { cur = OBJPTR(item); if ((cur->o_type == GOLD) && (roomin(cur->o_pos) == trp)) { /* Run to the gold */ tp->t_horde = cur; turn_on(*tp, ISRUN); turn_off(*tp, ISDISGUISE); tp->t_ischasing = FALSE; /* Make it worth protecting */ cur->o_count += roll(2, 3) * GOLDCALC; break; } } } /* * Every time he sees mean monster, it might start chasing him unique * monsters always do */ if ( (on(*tp, ISUNIQUE)) || ( (rnd(100) > 33) && on(*tp, ISMEAN) && off(*tp, ISHELD) && off(*tp, ISRUN) && !is_stealth(&player) && (off(player, ISINVIS) || on(*tp, CANSEE)) ) ) { chase_it(&tp->t_pos, &player); } /* Handle gaze attacks */ if (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x) && off(player, ISINVIS)) { if (on(*tp, CANHUH)) /* Confusion */ { if (on(player, CANREFLECT)) { msg("You reflect the bewildering stare of the %s.", mname); if (save_throw(VS_MAGIC, tp)) { msg("The %s is confused!", mname); turn_on(*tp, ISHUH); } else msg("The %s staggers for a moment.", mname); } else if (save(VS_MAGIC)) { msg("You feel dizzy for a moment, but it quickly passes."); if (rnd(100) < 67) turn_off(*tp, CANHUH); } else if (off(player, ISCLEAR)) { if (off(player, ISHUH)) { light_fuse(FUSE_UNCONFUSE, 0, rnd(20) + HUHDURATION, AFTER); msg("The %s's gaze has confused you.", mname); turn_on(player, ISHUH); } else lengthen_fuse(FUSE_UNCONFUSE, rnd(20) + HUHDURATION); } } if (on(*tp, CANSNORE)) /* Sleep */ { if (on(player, CANREFLECT)) { msg("You reflect the lethargic glance of the %s", mname); if (save_throw(VS_PARALYZATION, tp)) { msg("The %s falls asleep!", mname); tp->t_no_move += SLEEPTIME; } } else if (no_command == 0 && !save(VS_PARALYZATION)) { if (is_wearing(R_ALERT)) msg("You feel slightly drowsy for a moment."); else { msg("The %s's gaze puts you to sleep.", mname); no_command = SLEEPTIME; if (rnd(100) < 50) turn_off(*tp, CANSNORE); } } } if (on(*tp, CANFRIGHTEN)) /* Fear */ { turn_off(*tp, CANFRIGHTEN); if (on(player, CANREFLECT)) { msg("The %s sees its reflection. ", mname); if (save_throw(VS_MAGIC,tp)) { msg("The %s is terrified by its reflection!", mname); turn_on(*tp, ISFLEE); } } else { if (!save(VS_WAND) && !(on(player, ISFLEE) && (player.t_chasee==tp))) { if ((player.t_ctype != C_PALADIN) && off(player, SUPERHERO)) { turn_on(player, ISFLEE); player.t_ischasing = FALSE; player.t_chasee = tp; msg("The sight of the %s terrifies you.", mname); } else msg("My, the %s looks ugly.", mname); } } } if (on(*tp, LOOKSLOW)) /* Slow */ { turn_off(*tp, LOOKSLOW); if (on(player, CANREFLECT)) { msg("You reflect the mournful glare of the %s.", mname); if (save_throw(VS_MAGIC,tp)) { msg("The %s is slowing down!", mname); turn_on(*tp, ISSLOW); } } else if (is_wearing(R_FREEDOM) || save(VS_MAGIC)) msg("You feel run-down for a moment."); else { if (on(player, ISHASTE)) /* Already sped up */ { extinguish_fuse(FUSE_NOHASTE); nohaste(NULL); } else { msg("You feel yourself moving %sslower.", on(player, ISSLOW) ? "even " : ""); if (on(player, ISSLOW)) lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4); else { turn_on(player, ISSLOW); player.t_turn = TRUE; light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER); } } } } if (on(*tp, CANBLIND)) /* Blinding */ { turn_off(*tp, CANBLIND); if (on(player, CANREFLECT)) { msg("You reflect the blinding stare of the %s.", mname); if (save_throw(VS_WAND, tp)) { msg("The %s is blinded!", mname); turn_on(*tp, ISHUH); } } else if (off(player, ISBLIND)) if (save(VS_WAND) || is_wearing(R_TRUESEE) || is_wearing(R_SEEINVIS)) msg("Your eyes film over for a moment."); else { msg("The gaze of the %s blinds you.", mname); turn_on(player, ISBLIND); light_fuse(FUSE_SIGHT, 0, rnd(30) + 20, AFTER); look(FALSE); } } if (on(*tp, LOOKSTONE)) /* Stoning */ { turn_off(*tp, LOOKSTONE); if (on(player, CANREFLECT)) { msg("You reflect the flinty look of the %s.", mname); if (save_throw(VS_PETRIFICATION,tp)) { msg("The %s suddenly stiffens", mname); tp->t_no_move += STONETIME; } else { msg("The %s is turned to stone!", mname); killed(&player, it, NOMESSAGE, POINTS); } } else { if (on(player, CANINWALL)) msg("The %s cannot focus on you.", mname); else { msg("The gaze of the %s stiffens your limbs.", mname); if (save(VS_PETRIFICATION)) no_command = STONETIME; else if (rnd(100)) no_command = STONETIME * 3; else { msg("The gaze of the %s petrifies you.", mname); msg("You are turned to stone!!! --More--"); wait_for(' '); death(D_PETRIFY); return(it); } } } } } /* * True Sight sees all Never see ISINWALL or CANSURPRISE See ISSHADOW * 80% See ISINVIS with See Invisibilty */ if (off(player, CANTRUESEE) && on(*tp, ISINWALL) || on(*tp, CANSURPRISE) || (on(*tp, ISSHADOW) && rnd(100) < 80) || (on(*tp, ISINVIS) && off(player, CANSEE))) { /* TODO: incomplete - need to finish logic int ch = mvwinch(stdscr, y, x); */ } /* hero might be able to hear or smell monster if he can't see it */ if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || on(player, CANHEAR)) && !cansee(tp->t_pos.y, tp->t_pos.x)) msg("You hear a %s nearby.", mname); else if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || on(player, CANSCENT)) && !cansee(tp->t_pos.y, tp->t_pos.x)) msg("You smell a %s nearby.", mname); return(it); }
void teleport(void) { struct room *new_rp = NULL, *old_rp = roomin(hero); int rm, which; coord c; int is_lit = FALSE; /* For saving room light state */ int rand_position = TRUE; c = hero; mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x)); if (is_wearing(R_TELCONTROL)) { msg("Where do you wish to teleport to? (* for help)"); wmove(cw, hero.y, hero.x); wrefresh(cw); which = (short) (readchar() & 0177); while (which != (short) ESCAPE && which != (short) LINEFEED && which != (short) CARRIAGE_RETURN) { switch(which) { case 'h': c.x--; break; case 'j': c.y++; break; case 'k': c.y--; break; case 'l': c.x++; break; case 'y': c.x--; c.y--; break; case 'u': c.x++; c.y--; break; case 'b': c.x--; c.y++; break; case 'n': c.x++; c.y++; break; case '*': msg("Use h,j,k,l,y,u,b,n to position cursor, then hit" "return."); } c.y = max(c.y, 1); c.y = min(c.y, LINES - 3); c.x = max(c.x, 1); c.x = min(c.x, COLS - 1); wmove(cw, c.y, c.x); wrefresh(cw); which = (short) (readchar() & 0177); } which = winat(c.y, c.x); if ((which == FLOOR || which == PASSAGE || which == DOOR) && ((ring_value(R_TELCONTROL) == 0 && rnd(10) < 6) || (ring_value(R_TELCONTROL) > 0 && rnd(10) < 9))) { rand_position = FALSE; msg("You attempt succeeds."); hero = c; new_rp = roomin(hero); } else msg("Your attempt fails."); } if (rand_position) { do { rm = rnd_room(); rnd_pos(&rooms[rm], &hero); } while (winat(hero.y, hero.x) != FLOOR); new_rp = &rooms[rm]; } /* If hero gets moved, darken old room */ if (old_rp && old_rp != new_rp) { if (!(old_rp->r_flags & ISDARK)) is_lit = TRUE; old_rp->r_flags |= ISDARK; /* Fake darkness */ light(&c); if (is_lit) old_rp->r_flags &= ~ISDARK; /* Restore light state */ } light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); /* turn off ISHELD in case teleportation was done while fighting */ if (on(player, ISHELD)) { struct linked_list *ip, *nip; struct thing *mp; turn_off(player, ISHELD); hold_count = 0; for (ip = mlist; ip; ip = nip) { mp = THINGPTR(ip); nip = next(ip); if (on(*mp, DIDHOLD)) { turn_off(*mp, DIDHOLD); turn_on(*mp, CANHOLD); } turn_off(*mp, DIDSUFFOCATE); } } extinguish_fuse(FUSE_SUFFOCATE); player.t_no_move = 0; /* not trapped anymore */ count = 0; running = FALSE; return; }