/** * Check if a monster should stagger or not. Always stagger when confused, * but also deal with random movement for RAND_25 and _50 monsters. */ static bool monster_turn_should_stagger(struct monster *mon) { struct monster_lore *lore = get_lore(mon->race); int chance = 0; /* Increase chance of being erratic for every level of confusion */ int conf_level = monster_effect_level(mon, MON_TMD_CONF); while (conf_level) { int accuracy = 100 - chance; accuracy *= (100 - CONF_ERRATIC_CHANCE); accuracy /= 100; chance = 100 - accuracy; conf_level--; } /* RAND_25 and RAND_50 are cumulative */ if (rf_has(mon->race->flags, RF_RAND_25)) { chance += 25; if (monster_is_visible(mon)) rf_on(lore->flags, RF_RAND_25); } if (rf_has(mon->race->flags, RF_RAND_50)) { chance += 50; if (monster_is_visible(mon)) rf_on(lore->flags, RF_RAND_50); } return randint0(100) < chance; }
/** * Check if a monster should stagger or not. Always stagger when confused, * but also deal with random movement for RAND_25 and _50 monsters. */ static bool process_monster_should_stagger(struct monster *mon) { struct monster_lore *lore = get_lore(mon->race); int chance = 0; /* Confused */ if (mon->m_timed[MON_TMD_CONF]) return true; /* RAND_25 and RAND_50 are cumulative */ if (rf_has(mon->race->flags, RF_RAND_25)) { chance += 25; if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_RAND_25); } if (rf_has(mon->race->flags, RF_RAND_50)) { chance += 50; if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_RAND_50); } return randint0(100) < chance; }
/** * Extract the multiplier from a given object hitting a given monster. * * \param o_ptr is the object being used to attack * \param m_ptr is the monster being attacked * \param best_s_ptr is the best applicable slay_table entry, or NULL if no * slay already known * \param real is whether this is a real attack (where we update lore) or a * simulation (where we don't) * \param known_only is whether we are using all the object flags, or only * the ones we *already* know about */ void improve_attack_modifier(object_type *o_ptr, const monster_type *m_ptr, const struct slay **best_s_ptr, bool real, bool known_only) { monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; bitflag f[OF_SIZE], known_f[OF_SIZE], note_f[OF_SIZE]; int i; object_flags(o_ptr, f); object_flags_known(o_ptr, known_f); for (i = 0; i < SL_MAX; i++) { const struct slay *s_ptr = &slay_table[i]; if ((known_only && !of_has(known_f, s_ptr->object_flag)) || (!known_only && !of_has(f, s_ptr->object_flag))) continue; /* Disallow forbidden off-weapon slays/brands */ if (wield_slot(o_ptr) > INVEN_BOW && wield_slot(o_ptr) < INVEN_TOTAL && !s_ptr->nonweap) continue; /* In a real attack, learn about monster resistance or slay match if: * EITHER the slay flag on the object is known, * OR the monster is vulnerable to the slay/brand */ if (real && (of_has(known_f, s_ptr->object_flag) || (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) || (s_ptr->resist_flag && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || (s_ptr->vuln_flag && rf_has(r_ptr->flags, s_ptr->vuln_flag)))) { /* notice any brand or slay that would affect monster */ of_wipe(note_f); of_on(note_f, s_ptr->object_flag); object_notice_slays(o_ptr, note_f); if (m_ptr->ml && s_ptr->monster_flag) rf_on(l_ptr->flags, s_ptr->monster_flag); if (m_ptr->ml && s_ptr->resist_flag) rf_on(l_ptr->flags, s_ptr->resist_flag); if (m_ptr->ml && s_ptr->vuln_flag) rf_on(l_ptr->flags, s_ptr->vuln_flag); } /* If the monster doesn't resist or the slay flag matches */ if ((s_ptr->brand && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) || (s_ptr->vuln_flag && rf_has(r_ptr->flags, s_ptr->vuln_flag))) { /* compare multipliers to determine best attack */ if ((*best_s_ptr == NULL) || ((*best_s_ptr)->mult < s_ptr->mult)) *best_s_ptr = s_ptr; } } }
/** * Extract the multiplier from a given object hitting a given monster. * * If there is a slay or brand in effect, change the verb for hitting * to something interesting ('burn', 'smite', etc.). Also, note which * flags had an effect in o_ptr->known_flags[]. * * \param o_ptr is the object being used to attack * \param m_ptr is the monster being attacked * \param best_s_ptr is the best applicable slay_table entry, or NULL if no * slay already known * */ void improve_attack_modifier(object_type *o_ptr, const monster_type *m_ptr, const slay_t **best_s_ptr) { const slay_t *s_ptr; monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; bitflag f[OF_SIZE], known_f[OF_SIZE]; object_flags(o_ptr, f); object_flags_known(o_ptr, known_f); for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++) { if (!of_has(f, s_ptr->slay_flag)) continue; /* Learn about monster resistance/vulnerability IF: * 1) The slay flag on the object is known OR * 2) The monster does not possess the appropriate resistance flag OR * 3) The monster does possess the appropriate vulnerability flag */ if (of_has(known_f, s_ptr->slay_flag) || (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) || (s_ptr->resist_flag && !rf_has(r_ptr->flags, s_ptr->resist_flag))) { if (m_ptr->ml && s_ptr->monster_flag) { rf_on(l_ptr->flags, s_ptr->monster_flag); } if (m_ptr->ml && s_ptr->resist_flag) { rf_on(l_ptr->flags, s_ptr->resist_flag); } } /* If the monster doesn't match or the slay flag does */ if ((s_ptr->brand && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || rf_has(r_ptr->flags, s_ptr->monster_flag)) { /* notice any brand or slay that would affect the monster */ object_notice_slay(o_ptr, s_ptr->slay_flag); /* compare multipliers to determine best attack, would be more complex for O-style brands */ if ((*best_s_ptr == NULL) || ((*best_s_ptr)->mult < s_ptr->mult)) *best_s_ptr = s_ptr; } } }
/** * Try to push past / kill another monster. Returns true on success. */ static bool process_monster_try_push(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny) { struct monster *mon1 = square_monster(c, ny, nx); struct monster_lore *lore = get_lore(mon->race); /* Kill weaker monsters */ int kill_ok = rf_has(mon->race->flags, RF_KILL_BODY); /* Move weaker monsters if they can swap places */ /* (not in a wall) */ int move_ok = (rf_has(mon->race->flags, RF_MOVE_BODY) && square_ispassable(c, mon->fy, mon->fx)); if (compare_monsters(mon, mon1) > 0) { /* Learn about pushing and shoving */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_KILL_BODY); rf_on(lore->flags, RF_MOVE_BODY); } if (kill_ok || move_ok) { /* Get the names of the monsters involved */ char n_name[80]; monster_desc(n_name, sizeof(n_name), mon1, MDESC_IND_HID); /* Reveal mimics */ if (is_mimicking(mon1)) become_aware(mon1); /* Note if visible */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && mflag_has(mon->mflag, MFLAG_VIEW)) msg("%s %s %s.", m_name, kill_ok ? "tramples over" : "pushes past", n_name); /* Monster ate another monster */ if (kill_ok) delete_monster(ny, nx); monster_swap(mon->fy, mon->fx, ny, nx); return true; } } return false; }
/** * React to slays which hurt a monster * * \param obj_flags is the set of flags we're testing for slays * \param mon_flags is the set of flags we're adjusting as a result */ void react_to_slay(bitflag *obj_flags, bitflag *mon_flags) { int i; for (i = 0; i < SL_MAX; i++) { const struct slay *s_ptr = &slay_table[i]; if (of_has(obj_flags, s_ptr->object_flag) && s_ptr->monster_flag) rf_on(mon_flags, s_ptr->monster_flag); } }
/** * Attempt to reproduce, if possible. All monsters are checked here for * lore purposes, the unfit fail. */ static bool process_monster_multiply(struct chunk *c, struct monster *m_ptr) { int oy = m_ptr->fy; int ox = m_ptr->fx; int k = 0, y, x; monster_lore *l_ptr = get_lore(m_ptr->race); /* Too many breeders on the level already */ if (num_repro >= z_info->repro_monster_max) return FALSE; /* Count the adjacent monsters */ for (y = oy - 1; y <= m_ptr->fy + 1; y++) for (x = ox - 1; x <= m_ptr->fx + 1; x++) if (c->squares[y][x].mon > 0) k++; /* Multiply slower in crowded areas */ if ((k < 4) && (k == 0 || one_in_(k * z_info->repro_monster_rate))) { /* Successful breeding attempt, learn about that now */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) rf_on(l_ptr->flags, RF_MULTIPLY); /* Leave now if not a breeder */ if (!rf_has(m_ptr->race->flags, RF_MULTIPLY)) return FALSE; /* Try to multiply */ if (multiply_monster(m_ptr)) { /* Make a sound */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) sound(MSG_MULTIPLY); /* Multiplying takes energy */ return TRUE; } } return FALSE; }
/** * Attempt to reproduce, if possible. All monsters are checked here for * lore purposes, the unfit fail. */ static bool monster_turn_multiply(struct chunk *c, struct monster *mon) { int k = 0, y, x; struct monster_lore *lore = get_lore(mon->race); /* Too many breeders on the level already */ if (num_repro >= z_info->repro_monster_max) return false; /* Count the adjacent monsters */ for (y = mon->fy - 1; y <= mon->fy + 1; y++) for (x = mon->fx - 1; x <= mon->fx + 1; x++) if (c->squares[y][x].mon > 0) k++; /* Multiply slower in crowded areas */ if ((k < 4) && (k == 0 || one_in_(k * z_info->repro_monster_rate))) { /* Successful breeding attempt, learn about that now */ if (monster_is_visible(mon)) rf_on(lore->flags, RF_MULTIPLY); /* Leave now if not a breeder */ if (!rf_has(mon->race->flags, RF_MULTIPLY)) return false; /* Try to multiply */ if (multiply_monster(c, mon)) { /* Make a sound */ if (monster_is_visible(mon)) sound(MSG_MULTIPLY); /* Multiplying takes energy */ return true; } } return false; }
/** * Grab all objects from the grid. */ void process_monster_grab_objects(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny) { struct monster_lore *lore = get_lore(mon->race); struct object *obj; bool visible = mflag_has(mon->mflag, MFLAG_VISIBLE); /* Learn about item pickup behavior */ for (obj = square_object(c, ny, nx); obj; obj = obj->next) { if (!tval_is_money(obj) && visible) { rf_on(lore->flags, RF_TAKE_ITEM); rf_on(lore->flags, RF_KILL_ITEM); break; } } /* Abort if can't pickup/kill */ if (!rf_has(mon->race->flags, RF_TAKE_ITEM) && !rf_has(mon->race->flags, RF_KILL_ITEM)) { return; } /* Take or kill objects on the floor */ obj = square_object(c, ny, nx); while (obj) { char o_name[80]; bool safe = obj->artifact ? true : false; struct object *next = obj->next; /* Skip gold */ if (tval_is_money(obj)) { obj = next; continue; } /* Skip mimicked objects */ if (obj->mimicking_m_idx) { obj = next; continue; } /* Get the object name */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* React to objects that hurt the monster */ if (react_to_slay(obj, mon)) safe = true; /* Try to pick up, or crush */ if (safe) { /* Only give a message for "take_item" */ if (rf_has(mon->race->flags, RF_TAKE_ITEM) && visible && square_isview(c, ny, nx) && !ignore_item_ok(obj)) { /* Dump a message */ msg("%s tries to pick up %s, but fails.", m_name, o_name); } } else if (rf_has(mon->race->flags, RF_TAKE_ITEM)) { /* Describe observable situations */ if (square_isseen(c, ny, nx) && !ignore_item_ok(obj)) msg("%s picks up %s.", m_name, o_name); /* Carry the object */ square_excise_object(c, ny, nx, obj); monster_carry(c, mon, obj); square_note_spot(c, ny, nx); square_light_spot(c, ny, nx); } else { /* Describe observable situations */ if (square_isseen(c, ny, nx) && !ignore_item_ok(obj)) msgt(MSG_DESTROY, "%s crushes %s.", m_name, o_name); /* Delete the object */ square_excise_object(c, ny, nx, obj); delist_object(c, obj); object_delete(&obj); square_note_spot(c, ny, nx); square_light_spot(c, ny, nx); } /* Next object */ obj = next; } }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns true if the monster is able to move through the grid. */ static bool monster_turn_can_move(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny, bool *did_something) { struct monster_lore *lore = get_lore(mon->race); /* Dangerous terrain in the way */ if (monster_hates_grid(c, mon, ny, nx)) { return false; } /* Floor is open? */ if (square_ispassable(c, ny, nx)) { return true; } /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) { return false; } /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (monster_is_visible(mon)) { rf_on(lore->flags, RF_PASS_WALL); rf_on(lore->flags, RF_KILL_WALL); } /* Monster may be able to deal with walls and doors */ if (rf_has(mon->race->flags, RF_PASS_WALL)) { return true; } else if (rf_has(mon->race->flags, RF_KILL_WALL)) { /* Remove the wall */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); return true; } else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool can_open = rf_has(mon->race->flags, RF_OPEN_DOOR); bool can_bash = rf_has(mon->race->flags, RF_BASH_DOOR); bool will_bash = false; /* Take a turn */ *did_something = true; /* Learn about door abilities */ if (monster_is_visible(mon)) { rf_on(lore->flags, RF_OPEN_DOOR); rf_on(lore->flags, RF_BASH_DOOR); } /* If creature can open or bash doors, make a choice */ if (can_open) { /* Sometimes bash anyway (impatient) */ if (can_bash) { will_bash = one_in_(2) ? true : false; } } else if (can_bash) { /* Only choice */ will_bash = true; } else { /* Door is an insurmountable obstacle */ return false; } /* Now outcome depends on type of door */ if (square_islockeddoor(c, ny, nx)) { /* Locked door -- test monster strength against door strength */ int k = square_door_power(c, ny, nx); if (randint0(mon->hp / 10) > k) { if (will_bash) { msg("%s slams against the door.", m_name); } else { msg("%s fiddles with the lock.", m_name); } /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Closed or secret door -- always open or bash */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); if (will_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return true; } else { square_open_door(c, ny, nx); } } } return false; }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns true if the monster is able to move through the grid. */ static bool process_monster_can_move(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny, bool *did_something) { struct monster_lore *lore = get_lore(mon->race); /* Only fiery creatures can handle lava */ if (square_isfiery(c, ny, nx) && !rf_has(mon->race->flags, RF_IM_FIRE)) return false; /* Floor is open? */ if (square_ispassable(c, ny, nx)) return true; /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) return false; /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_PASS_WALL); rf_on(lore->flags, RF_KILL_WALL); } /* Monster may be able to deal with walls and doors */ if (rf_has(mon->race->flags, RF_PASS_WALL)) { return true; } else if (rf_has(mon->race->flags, RF_KILL_WALL)) { /* Remove the wall */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow since terrain changed */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); return true; } else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool may_bash = rf_has(mon->race->flags, RF_BASH_DOOR) && one_in_(2); /* Take a turn */ *did_something = true; /* Learn about door abilities */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_OPEN_DOOR); rf_on(lore->flags, RF_BASH_DOOR); } /* Creature can open or bash doors */ if (!rf_has(mon->race->flags, RF_OPEN_DOOR) && !rf_has(mon->race->flags, RF_BASH_DOOR)) return false; /* Stuck door -- try to unlock it */ if (square_islockeddoor(c, ny, nx)) { int k = square_door_power(c, ny, nx); if (randint0(mon->hp / 10) > k) { if (may_bash) msg("%s slams against the door.", m_name); else msg("%s fiddles with the lock.", m_name); /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Handle viewable doors */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Closed or secret door -- open or bash if allowed */ if (may_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return true; } else if (rf_has(mon->race->flags, RF_OPEN_DOOR)) { square_open_door(c, ny, nx); } } } return false; }
/* * Attack the monster at the given location * * If no "weapon" is available, then "punch" the monster one time. * * We get blows until energy drops below that required for another blow, or * until the target monster dies. We use a wrapper to work out the number of * blows. We don't allow @ to spend more than 100 energy in one go, to avoid * slower monsters getting double moves. */ bool py_attack_real(int y, int x) { int bonus, chance; monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; object_type *o_ptr; char m_name[80]; bool fear = FALSE; bool do_quake = FALSE; bool dead = FALSE; u32b msg_type = 0; bool success = FALSE; const char *hit_verb = "ERROR"; int dmg = 1; /* Default to punching for one damage */ /* Maybe handle monster melee here -Simon */ if(!rp_ptr->p_monster_index) { hit_verb = "punch"; msg_type = MSG_HIT; } /* * Hack -- if advanced innate attacks are disabled for this race, fall back * on defaults <player>'s 1d1. */ /* TODO: this -Simon */ /* if (p_ptr->flags[NO_INNATE]) { p_ptr = &r_info[0]; } */ /* Extract monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Auto-Recall if possible and visible */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Track a new monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); /* Handle player fear (only for invisible monsters) */ if (p_ptr->state.afraid) { message_format(MSG_AFRAID, 0, "You are too afraid to attack %s!", m_name); return (FALSE); } /* Disturb the monster */ wake_monster(m_ptr); /* Get the weapon */ o_ptr = &p_ptr->inventory[INVEN_WIELD]; /* Calculate the "attack quality" */ bonus = p_ptr->state.to_h + o_ptr->to_h; chance = (p_ptr->state.skills[SKILL_TO_HIT_MELEE] + (bonus * BTH_PLUS_ADJ)); /* Handle innate melee -Simon */ if(!o_ptr->k_idx && rp_ptr->p_monster_index) { for (int num = 0; (num < MONSTER_BLOW_MAX) && !dead; num++) { const slay_t *best_s_ptr = NULL; int type = GF_ARROW, type2 = 0, i; int flg = PROJECT_KILL | PROJECT_STOP | PROJECT_HIDE; // | PROJECT_PASS; TODO: figure out what this is and implement it -Simon char *p = ""; if (!r_info[rp_ptr->p_monster_index].blow[num].method && !dead) continue; /* Test for hit */ if (test_hit(chance, r_info[m_ptr->r_idx].ac, m_ptr->ml)) { int mul = 1; int k = 0; /* Get the method */ switch (r_info[rp_ptr->p_monster_index].blow[num].method) { case RBM_HIT: p = "hit"; break; case RBM_TOUCH: p = "touch"; break; case RBM_PUNCH: p = "punch"; break; case RBM_KICK: p = "kick"; break; case RBM_CLAW: p = "claw"; break; case RBM_BITE: p = "bite"; break; case RBM_STING: p = "sting"; break; case RBM_BUTT: p = "butt"; break; case RBM_CRUSH: p = "crush"; break; case RBM_ENGULF:p = "engulf"; break; case RBM_PECK: p = "peck"; break; case RBM_CRAWL: p = "crawl on"; break; case RBM_DROOL: p = "drool on"; break; case RBM_SPIT: p = "spit on"; break; case RBM_SLIME: p = "slime"; break; case RBM_GAZE: p = "gaze at"; break; case RBM_WAIL: p = "wail at"; break; case RBM_SPORE: p = "release spores at"; break; case RBM_BEG: p = "beg for money"; break; case RBM_INSULT: p = "insult"; break; default: p = "attack"; } /* Get the effect */ switch (r_info[rp_ptr->p_monster_index].blow[num].effect) { case RBE_HURT: type = GF_ARROW; break; case RBE_DISEASE: type = GF_POIS; mul = 2; break; case RBE_POISON: type = GF_POIS; mul = 2; break; case RBE_LOSE_MANA: type = GF_DISENCHANT; break; case RBE_UN_BONUS: type = GF_DISENCHANT; mul = 2; break; case RBE_UN_POWER: type = GF_DISENCHANT; mul = 2; break; /* ? */ case RBE_EAT_LIGHT: type = GF_DARK; mul = 2; break; case RBE_ACID: type = GF_ACID; mul = 2; break; case RBE_ELEC: type = GF_ELEC; mul = 2; break; case RBE_FIRE: type = GF_FIRE; mul = 2; break; case RBE_COLD: type = GF_COLD; mul = 2; break; case RBE_BLIND: type2 = GF_OLD_CONF; break; /* ? */ case RBE_CONFUSE: type2 = GF_OLD_CONF; break; case RBE_TERRIFY: type2 = GF_TURN_ALL; break; /* ? */ case RBE_PARALYZE: type2 = GF_OLD_SLEEP; break; /* ? */ /* Earthquake would be natural, but all monsters * with RBE_SHATTER are already humanoids */ case RBE_SHATTER: type = GF_ARROW; break; case RBE_EXP_10: type = GF_NETHER; mul = 2; break; case RBE_EXP_20: type = GF_NETHER; mul = 2; break; case RBE_EXP_40: type = GF_NETHER; mul = 2; break; case RBE_EXP_80: type = GF_NETHER; mul = 2; break; /* GF_CHAOS will polymorph, so it is bad */ case RBE_HALLU: type = GF_DISENCHANT; mul = 2; break; default: type = GF_ARROW; } k = damroll(r_info[rp_ptr->p_monster_index].blow[num].d_dice, r_info[rp_ptr->p_monster_index].blow[num].d_side); /* Get the best attack from all slays or * brands on all non-launcher equipment */ for (i = INVEN_FINGER; i < INVEN_TOTAL; i++) improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr); if (best_s_ptr != NULL) { if (best_s_ptr->mult > mul) { p = best_s_ptr->melee_verb; mul = best_s_ptr->mult; if (best_s_ptr->resist_flag == RF_IM_ACID) type = GF_ACID; else if (best_s_ptr->resist_flag == RF_IM_ELEC) type = GF_ELEC; else if (best_s_ptr->resist_flag == RF_IM_FIRE) type = GF_FIRE; else if (best_s_ptr->resist_flag == RF_IM_COLD) type = GF_COLD; else if (best_s_ptr->resist_flag == RF_IM_POIS) type = GF_POIS; } } k *= mul; message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", p, m_name); /* Add to-dam bonus only if did some damage */ if (k) k += p_ptr->state.to_d; if (k < 0) k = 0; /* Learn by use for other equipped items */ wieldeds_notice_on_attack(); /* If there is an extra effect, project it also, using 4*level as power */ if (type2) { project(-1, 0, y, x, 4 * p_ptr->lev, type2, flg); } /* Confusion attack */ if (p_ptr->confusing) { /* Message */ if (p_ptr->confusing) msg_print("Your limbs stop glowing."); /* Cancel glowing hands */ p_ptr->confusing = FALSE; /* Confuse the monster */ if (rf_has(r_ptr->flags, RF_NO_CONF)) { if (m_ptr->ml) { rf_on(l_ptr->flags, RF_NO_CONF); } msg_format("%^s is unaffected.", m_name); } else if (randint0(100) < r_ptr->level) { msg_format("%^s appears slightly perplexed.", m_name); } else { msg_format("%^s appears confused.", m_name); m_ptr->confused += 10 + randint0(p_ptr->lev) / 5; } } /* Damage, check for fear and death */ /* Makes elemental attacks do half their damage physically -Simon */ if (type != GF_ARROW) { project(-1, 0, y, x, (k + 1)/2, type, flg); /* Make the physical portion TOP SECRET -Simon */ flg &= ~(PROJECT_AWARE); project(-1, 0, y, x, k/2, GF_ARROW, flg); } else project(-1, 0, y, x, k, type, flg); /* Hack: check if the square is empty after we project the attack into it -Simon */ dead = (cave_m_idx[y][x] == 0); /* Hack -- delay fear messages */ if (fear && m_ptr->ml && !dead) message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } /* Player misses */ else { /* Message */ message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name); } } return (TRUE); } else { /* See if the player hit */ success = test_hit(chance, r_ptr->ac, m_ptr->ml); /* If a miss, skip this hit */ if (!success) { message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name); return (FALSE); } /* Handle normal weapon */ if (o_ptr->k_idx) { int i; const slay_t *best_s_ptr = NULL; hit_verb = "hit"; /* Get the best attack from all slays or * brands on all non-launcher equipment */ for (i = INVEN_FINGER; i < INVEN_TOTAL; i++) improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr); improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) hit_verb = best_s_ptr->melee_verb; dmg = damroll(o_ptr->dd, o_ptr->ds); dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult; if (p_ptr->state.impact && (dmg > 50)) do_quake = TRUE; dmg += o_ptr->to_d; dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type); /* Learn by use for the weapon */ object_notice_attack_plusses(o_ptr); if (do_quake) wieldeds_notice_flag(OF_IMPACT); } /* Learn by use for other equipped items */ wieldeds_notice_on_attack(); /* Apply the player damage bonuses */ dmg += p_ptr->state.to_d; /* No negative damage */ if (dmg <= 0) dmg = 0; /* Tell the player what happened */ if (dmg <= 0) message_format(MSG_MISS, m_ptr->r_idx, "You fail to harm %s.", m_name); else if (msg_type == MSG_HIT) message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) message_format(MSG_HIT_GOOD, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a good hit!"); else if (msg_type == MSG_HIT_GREAT) message_format(MSG_HIT_GREAT, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a great hit!"); else if (msg_type == MSG_HIT_SUPERB) message_format(MSG_HIT_SUPERB, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a superb hit!"); else if (msg_type == MSG_HIT_HI_GREAT) message_format(MSG_HIT_HI_GREAT, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a *GREAT* hit!"); else if (msg_type == MSG_HIT_HI_SUPERB) message_format(MSG_HIT_HI_SUPERB, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a *SUPERB* hit!"); /* Complex message */ if (p_ptr->wizard) msg_format("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Confusion attack */ if (p_ptr->confusing) { /* Cancel glowing hands */ p_ptr->confusing = FALSE; /* Message */ msg_print("Your limbs stop glowing."); /* Update the lore */ if (m_ptr->ml) rf_on(l_ptr->flags, RF_NO_CONF); /* Confuse the monster */ if (rf_has(r_ptr->flags, RF_NO_CONF)) msg_format("%^s is unaffected.", m_name); else if (randint0(100) < r_ptr->level) msg_format("%^s is unaffected.", m_name); else { msg_format("%^s appears confused.", m_name); m_ptr->confused += 10 + randint0(p_ptr->lev) / 5; } } /* Damage, check for fear and death */ dead = mon_take_hit(cave_m_idx[y][x], dmg, &fear, NULL); /* Hack -- delay fear messages */ if (fear && m_ptr->ml) message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); /* Mega-Hack -- apply earthquake brand */ if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10); return (dead); } }
/** * Determines whether the given monster successfully resists the given effect. * * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns false. * Then we determine if the monster resists the effect for some racial * reason. For example, the monster might have the NO_SLEEP flag, in which * case it always resists sleep. Or if it breathes chaos, it always resists * confusion. If the given monster doesn't resist for any of these reasons, * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`, * indicating that another monster caused this effect, then the chance of * success on the saving throw just depends on the monster's native depth. * Otherwise, the chance of success decreases as `timer` increases. * * Also marks the lore for any appropriate resists. */ static bool mon_resist_effect(const struct monster *mon, int ef_idx, int timer, u16b flag) { struct mon_timed_effect *effect; int resist_chance; struct monster_lore *lore; assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX); assert(mon); effect = &effects[ef_idx]; lore = get_lore(mon->race); /* Hasting never fails */ if (ef_idx == MON_TMD_FAST) return (false); /* Some effects are marked to never fail */ if (flag & MON_TMD_FLG_NOFAIL) return (false); /* A sleeping monster resists further sleeping */ if (ef_idx == MON_TMD_SLEEP && mon->m_timed[ef_idx]) return (true); /* If the monster resists innately, learn about it */ if (rf_has(mon->race->flags, effect->flag_resist)) { if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, effect->flag_resist); return (true); } /* Monsters with specific breaths resist stunning */ if (ef_idx == MON_TMD_STUN && (rsf_has(mon->race->spell_flags, RSF_BR_SOUN) || rsf_has(mon->race->spell_flags, RSF_BR_WALL))) { /* Add the lore */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { if (rsf_has(mon->race->spell_flags, RSF_BR_SOUN)) rsf_on(lore->spell_flags, RSF_BR_SOUN); if (rsf_has(mon->race->spell_flags, RSF_BR_WALL)) rsf_on(lore->spell_flags, RSF_BR_WALL); } return (true); } /* Monsters with specific breaths resist confusion */ if ((ef_idx == MON_TMD_CONF) && rsf_has(mon->race->spell_flags, RSF_BR_CHAO)) { /* Add the lore */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) if (rsf_has(mon->race->spell_flags, RSF_BR_CHAO)) rsf_on(lore->spell_flags, RSF_BR_CHAO); return (true); } /* Inertia breathers resist slowing */ if (ef_idx == MON_TMD_SLOW && rsf_has(mon->race->spell_flags, RSF_BR_INER)){ rsf_on(lore->spell_flags, RSF_BR_INER); return (true); } /* Calculate the chance of the monster making its saving throw. */ if (ef_idx == MON_TMD_SLEEP) timer /= 25; /* Hack - sleep uses much bigger numbers */ if (flag & MON_TMD_MON_SOURCE) resist_chance = mon->race->level; else resist_chance = mon->race->level + 40 - (timer / 2); if (randint0(100) < resist_chance) return (true); /* Uniques are doubly hard to affect */ if (rf_has(mon->race->flags, RF_UNIQUE)) if (randint0(100) < resist_chance) return (true); return (false); }
/** * Determines whether the given monster successfully resists the given effect. * * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns FALSE. * Then we determine if the monster resists the effect for some racial * reason. For example, the monster might have the NO_SLEEP flag, in which * case it always resists sleep. Or if it breathes chaos, it always resists * confusion. If the given monster doesn't resist for any of these reasons, * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`, * indicating that another monster caused this effect, then the chance of * success on the saving throw just depends on the monster's native depth. * Otherwise, the chance of success decreases as `timer` increases. * * Also marks the lore for any appropriate resists. */ static bool mon_resist_effect(const monster_type *m_ptr, int ef_idx, int timer, u16b flag) { mon_timed_effect *effect; int resist_chance; const monster_race *r_ptr; monster_lore *l_ptr; assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX); effect = &effects[ef_idx]; assert(m_ptr); r_ptr = &r_info[m_ptr->r_idx]; l_ptr = &l_list[m_ptr->r_idx]; /* Hasting never fails */ if (ef_idx == MON_TMD_FAST) return (FALSE); /* Some effects are marked to never fail */ if (flag & MON_TMD_FLG_NOFAIL) return (FALSE); /* A sleeping monster resists further sleeping */ if (ef_idx == MON_TMD_SLEEP && m_ptr->m_timed[ef_idx]) return (TRUE); /* If the monster resists innately, learn about it */ if (rf_has(r_ptr->flags, effect->flag_resist)) { if (m_ptr->ml) rf_on(l_ptr->flags, effect->flag_resist); return (TRUE); } /* Monsters with specific breaths resist stunning*/ if (ef_idx == MON_TMD_STUN && (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN) || rsf_has(r_ptr->spell_flags, RSF_BR_WALL))) { /* Add the lore */ if (m_ptr->ml) { if (rsf_has(r_ptr->spell_flags, RSF_BR_SOUN)) rsf_on(l_ptr->spell_flags, RSF_BR_SOUN); if (rsf_has(r_ptr->spell_flags, RSF_BR_WALL)) rsf_on(l_ptr->spell_flags, RSF_BR_WALL); } return (TRUE); } /* Monsters with specific breaths resist confusion */ if ((ef_idx == MON_TMD_CONF) && ((rsf_has(r_ptr->spell_flags, RSF_BR_CHAO)) || (rsf_has(r_ptr->spell_flags, RSF_BR_CONF))) ) { /* Add the lore */ if (m_ptr->ml) { if (rsf_has(r_ptr->spell_flags, RSF_BR_CHAO)) rsf_on(l_ptr->spell_flags, RSF_BR_CHAO); if (rsf_has(r_ptr->spell_flags, RSF_BR_CONF)) rsf_on(l_ptr->spell_flags, RSF_BR_CONF); } return (TRUE); } /* Inertia breathers resist slowing */ if (ef_idx == MON_TMD_SLOW && rsf_has(r_ptr->spell_flags, RSF_BR_INER)) { rsf_on(l_ptr->spell_flags, RSF_BR_INER); return (TRUE); } /* Calculate the chance of the monster making its saving throw. */ if (ef_idx == MON_TMD_SLEEP) timer /= 25; /* Hack - sleep uses much bigger numbers */ if (flag & MON_TMD_MON_SOURCE) resist_chance = r_ptr->level; else resist_chance = r_ptr->level + 40 - (timer / 2); if (randint0(100) < resist_chance) return (TRUE); /* Uniques are doubly hard to affect */ if (rf_has(r_ptr->flags, RF_UNIQUE)) if (randint0(100) < resist_chance) return (TRUE); return (FALSE); }
/** * Grab all objects from the grid. */ void process_monster_grab_objects(struct chunk *c, struct monster *m_ptr, const char *m_name, int nx, int ny) { monster_lore *l_ptr = get_lore(m_ptr->race); struct object *obj = square_object(c, ny, nx); bool is_item = obj ? TRUE : FALSE;; if (is_item && mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) { rf_on(l_ptr->flags, RF_TAKE_ITEM); rf_on(l_ptr->flags, RF_KILL_ITEM); } /* Abort if can't pickup/kill */ if (!rf_has(m_ptr->race->flags, RF_TAKE_ITEM) && !rf_has(m_ptr->race->flags, RF_KILL_ITEM)) { return; } /* Take or kill objects on the floor */ while (obj) { char o_name[80]; bool safe = obj->artifact ? TRUE : FALSE; struct object *next = obj->next; /* Skip gold */ if (tval_is_money(obj)) { obj = next; continue; } /* Get the object name */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* React to objects that hurt the monster */ if (react_to_slay(obj, m_ptr)) safe = TRUE; /* The object cannot be picked up by the monster */ if (safe) { /* Only give a message for "take_item" */ if (rf_has(m_ptr->race->flags, RF_TAKE_ITEM) && mflag_has(m_ptr->mflag, MFLAG_VISIBLE) && player_has_los_bold(ny, nx) && !ignore_item_ok(obj)) { /* Dump a message */ msg("%s tries to pick up %s, but fails.", m_name, o_name); } /* Pick up the item */ } else if (rf_has(m_ptr->race->flags, RF_TAKE_ITEM)) { /* Describe observable situations */ if (player_has_los_bold(ny, nx) && !ignore_item_ok(obj)) msg("%s picks up %s.", m_name, o_name); /* Carry the object */ square_excise_object(c, ny, nx, obj); monster_carry(c, m_ptr, obj); /* Destroy the item */ } else { /* Describe observable situations */ if (player_has_los_bold(ny, nx) && !ignore_item_ok(obj)) msgt(MSG_DESTROY, "%s crushes %s.", m_name, o_name); /* Delete the object */ square_excise_object(c, ny, nx, obj); object_delete(obj); } /* Next object */ obj = next; } }
/** * Process a monster * * In several cases, we directly update the monster lore * * Note that a monster is only allowed to "reproduce" if there * are a limited number of "reproducing" monsters on the current * level. This should prevent the level from being "swamped" by * reproducing monsters. It also allows a large mass of mice to * prevent a louse from multiplying, but this is a small price to * pay for a simple multiplication method. * * XXX Monster fear is slightly odd, in particular, monsters will * fixate on opening a door even if they cannot open it. Actually, * the same thing happens to normal monsters when they hit a door * * In addition, monsters which *cannot* open or bash down a door * will still stand there trying to open it... XXX XXX XXX * * Technically, need to check for monster in the way combined * with that monster being in a wall (or door?) XXX */ static void process_monster(struct chunk *c, struct monster *mon) { struct monster_lore *lore = get_lore(mon->race); bool did_something = false; int i; int dir = 0; bool stagger = false; char m_name[80]; /* Get the monster name */ monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID); /* Try to multiply - this can use up a turn */ if (process_monster_multiply(c, mon)) return; /* Attempt to cast a spell */ if (make_attack_spell(mon)) return; /* Work out what kind of movement to use - AI or staggered movement */ if (!process_monster_should_stagger(mon)) { if (!get_moves(c, mon, &dir)) return; } else { stagger = true; } /* Process moves */ for (i = 0; i < 5 && !did_something; i++) { int oy = mon->fy; int ox = mon->fx; /* Get the direction (or stagger) */ int d = (stagger ? ddd[randint0(8)] : side_dirs[dir][i]); /* Get the destination */ int ny = oy + ddy[d]; int nx = ox + ddx[d]; /* Check if we can move */ if (!process_monster_can_move(c, mon, m_name, nx, ny, &did_something)) continue; /* Try to break the glyph if there is one. This can happen multiple * times per turn because failure does not break the loop */ if (square_iswarded(c, ny, nx) && !process_monster_glyph(c, mon, nx, ny)) continue; /* The player is in the way. */ if (square_isplayer(c, ny, nx)) { /* Learn about if the monster attacks */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_NEVER_BLOW); /* Some monsters never attack */ if (rf_has(mon->race->flags, RF_NEVER_BLOW)) continue; /* Otherwise, attack the player */ make_attack_normal(mon, player); did_something = true; break; } else { /* Some monsters never move */ if (rf_has(mon->race->flags, RF_NEVER_MOVE)) { /* Learn about lack of movement */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_NEVER_MOVE); return; } } /* A monster is in the way, try to push past/kill */ if (square_monster(c, ny, nx)) { did_something = process_monster_try_push(c, mon, m_name, nx, ny); } else { /* Otherwise we can just move */ monster_swap(oy, ox, ny, nx); did_something = true; } /* Scan all objects in the grid, if we reached it */ if (mon == square_monster(c, ny, nx)) { monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID); process_monster_grab_objects(c, mon, m_name, nx, ny); } } if (did_something) { /* Learn about no lack of movement */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_NEVER_MOVE); /* Possible disturb */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && mflag_has(mon->mflag, MFLAG_VIEW) && OPT(player, disturb_near)) disturb(player, 0); } /* Hack -- get "bold" if out of options */ if (!did_something && mon->m_timed[MON_TMD_FEAR]) mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOTIFY, false); /* If we see an unaware monster do something, become aware of it */ if (did_something && mflag_has(mon->mflag, MFLAG_UNAWARE)) become_aware(mon); }
/* * read_scroll: * Let the hero read a scroll */ int read_scroll() { struct object *obj; struct linked_list *item; int i, j, wh; unsigned long ch, nch; struct room *rp; struct linked_list *titem; char buf[LINLEN]; bool bless, curse; if ((item = get_item("read", SCROLL)) == NULL) return 0; obj = OBJPTR(item); if (obj->o_type != SCROLL) { msg("Nothing to read."); after = FALSE; return 0; } msg("As you read the scroll, it vanishes."); wh = obj->o_which; bless = o_on(obj, ISBLESS); curse = o_on(obj, ISCURSED); del_pack(item); /* Get rid of the thing */ /* * Calculate the effect it has on the hero */ switch(wh) { case S_KNOWALL: if (!curse) { idenpack(); /* identify all the pack */ msg("You feel more knowledgable."); chg_abil(WIS,1,TRUE); s_know[S_KNOWALL] = TRUE; } when S_CONFUSE: if (!curse) { /* * Scroll of monster confusion. Give him that power. */ msg("Your hands begin to glow red."); player.t_flags |= CANHUH; s_know[S_CONFUSE] = TRUE; } when S_LIGHT: rp = player.t_room; if (!curse) { if (rp == NULL) { s_know[S_LIGHT] = TRUE; msg("The corridor glows and then fades."); } else { if (rf_on(rp,ISDARK)) { s_know[S_LIGHT] = TRUE; msg("The room is lit."); rp->r_flags &= ~ISDARK; } light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } } when S_ARMOR: if (!curse) { if (cur_armor != NULL && o_off(cur_armor,ISPROT)) { s_know[S_ARMOR] = TRUE; msg("Your armor glows faintly for a moment."); if (o_on(cur_armor,ISCURSED)) cur_armor->o_ac = armors[cur_armor->o_which].a_class; else cur_armor->o_ac--; resoflg(cur_armor,ISCURSED); } } when S_HOLD: if (!curse) { /* * Hold monster scroll. Stop all monsters within 3 spaces * from chasing after the hero. */ int x,y; struct linked_list *mon; for (x = hero.x - 3; x <= hero.x + 3; x++) { for (y = hero.y - 3; y <= hero.y + 3; y++) { if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) { if ((mon = find_mons(y, x)) != NULL) { struct thing *th; th = THINGPTR(mon); th->t_flags &= ~ISRUN; th->t_flags |= ISHELD; th->t_flags |= ISSTUCK; } } } } } when S_SLEEP: /* * Scroll which makes you fall asleep */ if (!bless) { s_know[S_SLEEP] = TRUE; msg("You fall asleep."); player.t_nocmd += 4 + rnd(SLEEPTIME); } when S_CREATE: if (!bless) { if (makemons(mtlev[rnd(levcount)]->m_show)) s_know[S_CREATE] = TRUE; else msg("You hear a faint cry of anguish in the distance."); } when S_IDENT: if (!curse) { msg("This scroll is an identify scroll"); s_know[S_IDENT] = TRUE; whatis(NULL); } when S_MAP: if (curse) break; s_know[S_MAP] = TRUE; addmsg("Oh, now this scroll has a "); if (rnd(100) < 10 || bless) { addmsg("very detailed map on it."); endmsg(); displevl(); } else { addmsg("map on it."); endmsg(); overwrite(stdscr, hw); for (i = 1; i < LINES - 2; i++) { for (j = 0; j < COLS; j++) { switch (nch = ch = mvwinch(hw, i, j)) { case SECRETDOOR: nch = DOOR; mvaddch(i, j, nch); case '-': case '|': case DOOR: case PASSAGE: case ' ': case STAIRS: if (mvwinch(mw, i, j) != ' ') { struct thing *it; struct linked_list *blah; blah = find_mons(i, j); if (blah != NULL) { it = THINGPTR(blah); if (it->t_oldch == ' ') it->t_oldch = nch; } } break; default: nch = ' '; } if (nch != ch) waddch(hw, nch); } } overlay(cw, hw); overwrite(hw, cw); } when S_GFIND: if (!curse) { int gtotal = 0; struct room *rp; wclear(hw); for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) { gtotal += rp->r_goldval; if (rp->r_goldval != 0 && mvinch(rp->r_gold.y,rp->r_gold.x) == GOLD) mvwaddch(hw,rp->r_gold.y,rp->r_gold.x,GOLD); } if (gtotal) { s_know[S_GFIND] = TRUE; msg("You begin to feel greedy and sense gold."); overlay(hw,cw); } else msg("You begin to feel a pull downward."); } when S_TELEP: if (!curse) { int rm; struct room *cur_room; cur_room = player.t_room; rm = teleport(rndspot, &player); if (cur_room != &rooms[rm]) s_know[S_TELEP] = TRUE; } when S_ENCH: if (!curse) { if (cur_weapon == NULL || (cur_weapon != NULL && (o_on(cur_weapon,ISPROT) || cur_weapon->o_type != WEAPON))) msg("You feel a strange sense of loss."); else { s_know[S_ENCH] = TRUE; if (o_on(cur_weapon,ISCURSED)) { resoflg(cur_weapon,ISCURSED); cur_weapon->o_hplus = rnd(2); cur_weapon->o_dplus = rnd(2); } else { /* weapon was not cursed here */ if (rnd(100) < 50) cur_weapon->o_hplus += 1; else cur_weapon->o_dplus += 1; } setoflg(cur_weapon, ISKNOW); msg("Your %s glows blue for a moment.", w_magic[cur_weapon->o_which].mi_name); } } when S_SCARE: /* * A monster will refuse to step on a scare monster scroll * if it is dropped. Thus reading it is a mistake and produces * laughter at the poor rogue's boo boo. */ msg("You hear maniacal laughter in the distance."); when S_REMOVE: if (!curse) { if (cur_armor != NULL && o_off(cur_armor,ISPROT)) resoflg(cur_armor,ISCURSED); if (cur_weapon != NULL && o_off(cur_weapon,ISPROT)) resoflg(cur_weapon,ISCURSED); if (cur_ring[LEFT]!=NULL && o_off(cur_ring[LEFT],ISPROT)) resoflg(cur_ring[LEFT],ISCURSED); if (cur_ring[RIGHT]!=NULL && o_off(cur_ring[RIGHT],ISPROT)) resoflg(cur_ring[RIGHT],ISCURSED); msg("You feel as if somebody is watching over you."); s_know[S_REMOVE] = TRUE; } when S_AGGR: if (!bless) { if (mlist != NULL) { aggravate(); msg("You hear a high pitched humming noise."); s_know[S_AGGR] = TRUE; } } when S_NOP: msg("This scroll seems to be blank."); when S_GENOCIDE: if (!curse) { msg("You have been granted the boon of genocide."); genocide(); s_know[S_GENOCIDE] = TRUE; } when S_DCURSE: if (!bless) { struct linked_list *ll; struct object *lb; msg("Your pack shudders."); for (ll = pack ; ll != NULL ; ll = next(ll)) { lb = OBJPTR(ll); if (o_off(lb,ISPROT)) { resoflg(lb, ISBLESS); setoflg(lb, ISCURSED); } } } when S_DLEVEL: if (!bless) { int much = rnd(9) - 4; if (much != 0) { level += much; if (level < 1) level = 1; mpos = 0; new_level(NORMLEV); /* change levels */ msg("You are whisked away to another region."); s_know[S_DLEVEL] = TRUE; } } when S_PROTECT: if (!curse) { struct linked_list *ll; struct object *lb; msg("You are granted the power of protection."); if ((ll = get_item("protect",0)) != NULL) { lb = OBJPTR(ll); setoflg(lb,ISPROT); mpos = 0; msg("Protected %s.",inv_name(lb,TRUE)); } s_know[S_PROTECT] = TRUE; } when S_ALLENCH: if (!curse) { struct linked_list *ll; struct object *lb; int howmuch, ac, good; msg("You are granted the power of enchantment."); good = TRUE; if ((ll = get_item("enchant",0)) != NULL) { lb = OBJPTR(ll); resoflg(lb,ISCURSED); resoflg(lb,ISPROT); howmuch = rnd(3) + 1; switch(lb->o_type) { case RING: if (lb->o_ac < 0) lb->o_ac = 0; lb->o_ac += howmuch; when ARMOR: ac = armors[lb->o_which].a_class; if (lb->o_ac > ac) lb->o_ac = ac; lb->o_ac -= howmuch; when STICK: lb->o_charges += howmuch + 10; when WEAPON: if (lb->o_dplus < 0) lb->o_dplus = 0; if (lb->o_hplus < 0) lb->o_hplus = 0; lb->o_hplus += howmuch; lb->o_dplus += howmuch; otherwise: msg("You are injured as the scroll flashes & bursts into flames !!!"); chg_hpt(-roll(6,6),FALSE,K_SCROLL); good = FALSE; } if (good) { mpos = 0; msg("Enchanted %s.",inv_name(lb,TRUE)); } } s_know[S_ALLENCH] = TRUE; } when S_BLESS: if (!curse) { struct linked_list *ll; struct object *lb; msg("Your pack glistens brightly."); for (ll = pack ; ll != NULL ; ll = next(ll)) { whatis(ll); lb = OBJPTR(ll); resoflg(lb,ISCURSED); setoflg(lb,ISBLESS); } } when S_MAKEIT: if (!curse) { msg("You have been endowed with the power of creation."); s_know[S_MAKEIT] = TRUE; create_obj(TRUE); } when S_BAN: { int howdeep; char *ptr; if (bless) { if (level > 6) { howdeep = 1 + rnd(5); ptr = "elevated to the upper"; } else { howdeep = -1; bless = FALSE; } } else { howdeep = level + 10 + rnd(20) + (curse * 20); ptr = "banished to the lower"; } if ((!bless && level < howdeep) || bless) { level = howdeep; new_level(NORMLEV); mpos = 0; msg("You are %s regions.", ptr); s_know[S_BAN] = TRUE; } } when S_CWAND: if (!curse) { struct linked_list *ll; struct object *lb; bool wands = FALSE; for (ll = pack ; ll != NULL ; ll = next(ll)) { lb = OBJPTR(ll); if (lb->o_type == STICK) { whatis(ll); setoflg(lb, ISKNOW); resoflg(lb, ISCURSED); lb->o_charges += rnd(11) + 5; wands = TRUE; } } if (wands) { msg("Your sticks gleam."); s_know[wh] = TRUE; } } when S_LOCTRAP: { struct trap *trp; if (ntraps > 0) { for (trp = &traps[0]; trp < &traps[ntraps]; trp++) trp->tr_flags |= ISFOUND; look(FALSE); msg("You now recognize pitfalls."); s_know[S_LOCTRAP] = TRUE; } } otherwise: msg("What a puzzling scroll!"); return 0; }
/** * Attack the player via physical attacks. */ bool make_attack_normal(struct monster *mon, struct player *p) { struct monster_lore *lore = get_lore(mon->race); int ap_cnt; int k, tmp, ac, rlev; char m_name[80]; char ddesc[80]; bool blinked; /* Not allowed to attack */ if (rf_has(mon->race->flags, RF_NEVER_BLOW)) return (false); /* Total armor */ ac = p->state.ac + p->state.to_a; /* Extract the effective monster level */ rlev = ((mon->race->level >= 1) ? mon->race->level : 1); /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD); /* Get the "died from" information (i.e. "a kobold") */ monster_desc(ddesc, sizeof(ddesc), mon, MDESC_SHOW | MDESC_IND_VIS); /* Assume no blink */ blinked = false; /* Scan through all blows */ for (ap_cnt = 0; ap_cnt < z_info->mon_blows_max; ap_cnt++) { bool visible = false; bool obvious = false; bool do_break = false; int power = 0; int damage = 0; int do_cut = 0; int do_stun = 0; int sound_msg = MSG_GENERIC; const char *act = NULL; /* Extract the attack infomation */ int effect = mon->race->blow[ap_cnt].effect; int method = mon->race->blow[ap_cnt].method; random_value dice = mon->race->blow[ap_cnt].dice; /* Hack -- no more attacks */ if (!method) break; /* Handle "leaving" */ if (p->is_dead || p->upkeep->generate_level) break; /* Extract visibility (before blink) */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) visible = true; /* Extract visibility from carrying light */ if (rf_has(mon->race->flags, RF_HAS_LIGHT)) visible = true; /* Extract the attack "power" */ power = monster_blow_effect_power(effect); /* Monster hits player */ if (!effect || check_hit(p, power, rlev)) { melee_effect_handler_f effect_handler; /* Always disturbing */ disturb(p, 1); /* Hack -- Apply "protection from evil" */ if (p->timed[TMD_PROTEVIL] > 0) { /* Learn about the evil flag */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) rf_on(lore->flags, RF_EVIL); if (rf_has(mon->race->flags, RF_EVIL) && p->lev >= rlev && randint0(100) + p->lev > 50) { /* Message */ msg("%s is repelled.", m_name); /* Hack -- Next attack */ continue; } } /* Describe the attack method */ act = monster_blow_method_action(method); do_cut = monster_blow_method_cut(method); do_stun = monster_blow_method_stun(method); sound_msg = monster_blow_method_message(method); /* Message */ if (act) msgt(sound_msg, "%s %s", m_name, act); /* Hack -- assume all attacks are obvious */ obvious = true; /* Roll dice */ damage = randcalc(dice, rlev, RANDOMISE); /* Perform the actual effect. */ effect_handler = melee_handler_for_blow_effect(effect); if (effect_handler != NULL) { melee_effect_handler_context_t context = { p, mon, rlev, method, ac, ddesc, obvious, blinked, do_break, damage, }; effect_handler(&context); /* Save any changes made in the handler for later use. */ obvious = context.obvious; blinked = context.blinked; damage = context.damage; do_break = context.do_break; } else { msg("ERROR: Effect handler not found for %d.", effect); } /* Don't cut or stun if player is dead */ if (p->is_dead) { do_cut = false; do_stun = false; } /* Hack -- only one of cut or stun */ if (do_cut && do_stun) { /* Cancel cut */ if (randint0(100) < 50) do_cut = 0; /* Cancel stun */ else do_stun = 0; } /* Handle cut */ if (do_cut) { /* Critical hit (zero if non-critical) */ tmp = monster_critical(dice, rlev, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint1(5); break; case 2: k = randint1(5) + 5; break; case 3: k = randint1(20) + 20; break; case 4: k = randint1(50) + 50; break; case 5: k = randint1(100) + 100; break; case 6: k = 300; break; default: k = 500; break; } /* Apply the cut */ if (k) (void)player_inc_timed(p, TMD_CUT, k, true, true); } /* Handle stun */ if (do_stun) { /* Critical hit (zero if non-critical) */ tmp = monster_critical(dice, rlev, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint1(5); break; case 2: k = randint1(10) + 10; break; case 3: k = randint1(20) + 20; break; case 4: k = randint1(30) + 30; break; case 5: k = randint1(40) + 40; break; case 6: k = 100; break; default: k = 200; break; } /* Apply the stun */ if (k) (void)player_inc_timed(p, TMD_STUN, k, true, true); } } else { /* Visible monster missed player, so notify if appropriate. */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && monster_blow_method_miss(method)) { /* Disturbing */ disturb(p, 1); msg("%s misses you.", m_name); } } /* Analyze "visible" monsters only */ if (visible) { /* Count "obvious" attacks (and ones that cause damage) */ if (obvious || damage || (lore->blows[ap_cnt].times_seen > 10)) { /* Count attacks of this type */ if (lore->blows[ap_cnt].times_seen < UCHAR_MAX) lore->blows[ap_cnt].times_seen++; } } /* Skip the other blows if necessary */ if (do_break) break; } /* Blink away */ if (blinked) { char dice[5]; msg("There is a puff of smoke!"); strnfmt(dice, sizeof(dice), "%d", z_info->max_sight * 2 + 5); effect_simple(EF_TELEPORT, dice, 0, 0, 0, NULL); } /* Always notice cause of death */ if (p->is_dead && (lore->deaths < SHRT_MAX)) lore->deaths++; /* Learn lore */ lore_update(mon->race, lore); /* Assume we attacked */ return (true); }
/* * \brief Function sets the RF in RX state. * * \param none * * \return none */ void rf_receive(void) { uint16_t while_counter = 0; if(rf_flags_check(RFF_ON) == 0) { rf_on(); } /*If not yet in RX state set it*/ if(rf_flags_check(RFF_RX) == 0) { platform_enter_critical(); /*Wait while receiving data*/ while(rf_if_read_trx_state() == BUSY_RX_AACK) { while_counter++; if(while_counter == 0xffff) { break; } } //TODO: rf_if_delay_function(50); /*Wake up from sleep state*/ if(rf_if_read_trx_state() == 0x00 || rf_if_read_trx_state() == 0x1f) { rf_if_disable_slptr(); rf_poll_trx_state_change(TRX_OFF); } rf_if_change_trx_state(PLL_ON); if(rf_mode == RF_MODE_SNIFFER) { rf_if_change_trx_state(RX_ON); } else { /*ACK is always received in promiscuous mode to bypass address filters*/ if(rf_rx_mode) { rf_rx_mode = 0; rf_if_enable_promiscuous_mode(); } else { rf_if_disable_promiscuous_mode(); } rf_if_change_trx_state(RX_AACK_ON); } /*If calibration timer was unable to calibrate the RF, run calibration now*/ if(!rf_tuned) { /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/ rf_if_calibration(); /*RF is tuned now*/ rf_tuned = 1; } rf_channel_set(rf_phy_channel); rf_flags_set(RFF_RX); rf_if_enable_rx_end_interrupt(); platform_exit_critical(); } /*Stop the running CCA process*/ if(rf_flags_check(RFF_CCA)) rf_cca_abort(); }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns TRUE if the monster is able to move through the grid. */ static bool process_monster_can_move(struct chunk *c, struct monster *m_ptr, const char *m_name, int nx, int ny, bool *did_something) { monster_lore *l_ptr = get_lore(m_ptr->race); /* Floor is open? */ if (square_ispassable(c, ny, nx)) return TRUE; /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) return FALSE; /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) { rf_on(l_ptr->flags, RF_PASS_WALL); rf_on(l_ptr->flags, RF_KILL_WALL); } /* Monster moves through walls (and doors) */ if (rf_has(m_ptr->race->flags, RF_PASS_WALL)) return TRUE; /* Monster destroys walls (and doors) */ else if (rf_has(m_ptr->race->flags, RF_KILL_WALL)) { /* Forget the wall */ sqinfo_off(c->squares[ny][nx].info, SQUARE_MARK); /* Notice */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (player_has_los_bold(ny, nx)) player->upkeep->update |= PU_UPDATE_VIEW; /* Update the flow, since walls affect flow */ player->upkeep->update |= PU_UPDATE_FLOW; return TRUE; } /* Handle doors and secret doors */ else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool may_bash = rf_has(m_ptr->race->flags, RF_BASH_DOOR) && one_in_(2); /* Take a turn */ *did_something = TRUE; /* Learn about door abilities */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) { rf_on(l_ptr->flags, RF_OPEN_DOOR); rf_on(l_ptr->flags, RF_BASH_DOOR); } /* Creature can open or bash doors */ if (!rf_has(m_ptr->race->flags, RF_OPEN_DOOR) && !rf_has(m_ptr->race->flags, RF_BASH_DOOR)) return FALSE; /* Stuck door -- try to unlock it */ if (square_islockeddoor(c, ny, nx)) { int k = square_door_power(c, ny, nx); if (randint0(m_ptr->hp / 10) > k) { if (may_bash) msg("%s slams against the door.", m_name); else msg("%s fiddles with the lock.", m_name); /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Handle viewable doors */ if (player_has_los_bold(ny, nx)) player->upkeep->update |= PU_UPDATE_VIEW; /* Closed or secret door -- open or bash if allowed */ if (may_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return TRUE; } else if (rf_has(m_ptr->race->flags, RF_OPEN_DOOR)) { square_open_door(c, ny, nx); } } } return FALSE; }