Mercurial > hg > early-roguelike
comparison rogue5/monsters.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Mon, 24 May 2010 20:10:59 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 32:2dcd75e6a736 | 33:f502bf60e6e4 |
|---|---|
| 1 /* | |
| 2 * File with various monster functions in it | |
| 3 * | |
| 4 * @(#)monsters.c 4.46 (Berkeley) 02/05/99 | |
| 5 * | |
| 6 * Rogue: Exploring the Dungeons of Doom | |
| 7 * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman | |
| 8 * All rights reserved. | |
| 9 * | |
| 10 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 11 */ | |
| 12 | |
| 13 #include <curses.h> | |
| 14 #include <string.h> | |
| 15 #include "rogue.h" | |
| 16 #include <ctype.h> | |
| 17 | |
| 18 /* | |
| 19 * List of monsters in rough order of vorpalness | |
| 20 */ | |
| 21 static const int lvl_mons[] = { | |
| 22 'K', 'E', 'B', 'S', 'H', 'I', 'R', 'O', 'Z', 'L', 'C', 'Q', 'A', | |
| 23 'N', 'Y', 'F', 'T', 'W', 'P', 'X', 'U', 'M', 'V', 'G', 'J', 'D' | |
| 24 }; | |
| 25 | |
| 26 static const int wand_mons[] = { | |
| 27 'K', 'E', 'B', 'S', 'H', 0, 'R', 'O', 'Z', 0, 'C', 'Q', 'A', | |
| 28 0, 'Y', 0, 'T', 'W', 'P', 0, 'U', 'M', 'V', 'G', 'J', 0 | |
| 29 }; | |
| 30 | |
| 31 /* | |
| 32 * randmonster: | |
| 33 * Pick a monster to show up. The lower the level, | |
| 34 * the meaner the monster. | |
| 35 */ | |
| 36 int | |
| 37 randmonster(int wander) | |
| 38 { | |
| 39 int d; | |
| 40 const int *mons; | |
| 41 | |
| 42 mons = (wander ? wand_mons : lvl_mons); | |
| 43 do | |
| 44 { | |
| 45 d = level + (rnd(10) - 6); | |
| 46 if (d < 0) | |
| 47 d = rnd(5); | |
| 48 if (d > 25) | |
| 49 d = rnd(5) + 21; | |
| 50 } while (mons[d] == 0); | |
| 51 return mons[d]; | |
| 52 } | |
| 53 | |
| 54 /* | |
| 55 * new_monster: | |
| 56 * Pick a new monster and add it to the list | |
| 57 */ | |
| 58 | |
| 59 void | |
| 60 new_monster(THING *tp, int type, const coord *cp) | |
| 61 { | |
| 62 struct monster *mp; | |
| 63 int lev_add; | |
| 64 | |
| 65 if ((lev_add = level - AMULETLEVEL) < 0) | |
| 66 lev_add = 0; | |
| 67 attach(mlist, tp); | |
| 68 tp->t_type = type; | |
| 69 tp->t_disguise = type; | |
| 70 tp->t_pos = *cp; | |
| 71 move(cp->y, cp->x); | |
| 72 tp->t_oldch = CCHAR( inch() ); | |
| 73 tp->t_room = roomin(cp); | |
| 74 moat(cp->y, cp->x) = tp; | |
| 75 mp = &monsters[tp->t_type-'A']; | |
| 76 tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add; | |
| 77 tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8); | |
| 78 tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add; | |
| 79 strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg); | |
| 80 tp->t_stats.s_str = mp->m_stats.s_str; | |
| 81 tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp); | |
| 82 tp->t_flags = mp->m_flags; | |
| 83 if (level > 29) | |
| 84 tp->t_flags |= ISHASTE; | |
| 85 tp->t_turn = TRUE; | |
| 86 tp->t_pack = NULL; | |
| 87 if (ISWEARING(R_AGGR)) | |
| 88 runto(cp); | |
| 89 if (type == 'X') | |
| 90 tp->t_disguise = rnd_thing(); | |
| 91 } | |
| 92 | |
| 93 /* | |
| 94 * expadd: | |
| 95 * Experience to add for this monster's level/hit points | |
| 96 */ | |
| 97 int | |
| 98 exp_add(const THING *tp) | |
| 99 { | |
| 100 int mod; | |
| 101 | |
| 102 if (tp->t_stats.s_lvl == 1) | |
| 103 mod = tp->t_stats.s_maxhp / 8; | |
| 104 else | |
| 105 mod = tp->t_stats.s_maxhp / 6; | |
| 106 if (tp->t_stats.s_lvl > 9) | |
| 107 mod *= 20; | |
| 108 else if (tp->t_stats.s_lvl > 6) | |
| 109 mod *= 4; | |
| 110 return mod; | |
| 111 } | |
| 112 | |
| 113 /* | |
| 114 * wanderer: | |
| 115 * Create a new wandering monster and aim it at the player | |
| 116 */ | |
| 117 | |
| 118 void | |
| 119 wanderer(void) | |
| 120 { | |
| 121 THING *tp; | |
| 122 coord cp; | |
| 123 int cnt = 0; | |
| 124 | |
| 125 tp = new_item(); | |
| 126 do | |
| 127 { | |
| 128 /* Avoid endless loop when all rooms are filled with monsters | |
| 129 * and the player room is not accessible to the monsters. | |
| 130 */ | |
| 131 if (cnt++ >= 500) | |
| 132 { | |
| 133 discard(tp); | |
| 134 return; | |
| 135 } | |
| 136 find_floor(NULL, &cp, FALSE, TRUE); | |
| 137 } while (roomin(&cp) == proom && moat(cp.y, cp.x) == NULL); | |
| 138 new_monster(tp, randmonster(TRUE), &cp); | |
| 139 if (on(player, SEEMONST)) | |
| 140 { | |
| 141 standout(); | |
| 142 if (!on(player, ISHALU)) | |
| 143 addch(tp->t_type); | |
| 144 else | |
| 145 addch(rnd(26) + 'A'); | |
| 146 standend(); | |
| 147 } | |
| 148 runto(&tp->t_pos); | |
| 149 #ifdef MASTER | |
| 150 if (wizard) | |
| 151 msg("started a wandering %s", monsters[tp->t_type-'A'].m_name); | |
| 152 #endif | |
| 153 } | |
| 154 | |
| 155 /* | |
| 156 * wake_monster: | |
| 157 * What to do when the hero steps next to a monster | |
| 158 */ | |
| 159 const THING * | |
| 160 wake_monster(int y, int x) | |
| 161 { | |
| 162 THING *tp; | |
| 163 struct room *rp; | |
| 164 int ch; | |
| 165 const char *mname; | |
| 166 | |
| 167 if ((tp = moat(y, x)) == NULL) { | |
| 168 #ifdef MASTER | |
| 169 msg("can't find monster in wake_monster"); | |
| 170 #endif | |
| 171 return NULL; | |
| 172 } | |
| 173 | |
| 174 ch = tp->t_type; | |
| 175 /* | |
| 176 * Every time he sees mean monster, it might start chasing him | |
| 177 */ | |
| 178 if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD) | |
| 179 && !ISWEARING(R_STEALTH) && !on(player, ISLEVIT)) | |
| 180 { | |
| 181 tp->t_dest = &hero; | |
| 182 tp->t_flags |= ISRUN; | |
| 183 } | |
| 184 if (ch == 'M' && !on(player, ISBLIND) && !on(player, ISHALU) | |
| 185 && !on(*tp, ISFOUND) && !on(*tp, ISCANC) && on(*tp, ISRUN)) | |
| 186 { | |
| 187 rp = proom; | |
| 188 if ((rp != NULL && !(rp->r_flags & ISDARK)) | |
| 189 || dist(y, x, hero.y, hero.x) < LAMPDIST) | |
| 190 { | |
| 191 tp->t_flags |= ISFOUND; | |
| 192 if (!save(VS_MAGIC)) | |
| 193 { | |
| 194 if (on(player, ISHUH)) | |
| 195 lengthen(unconfuse, spread(HUHDURATION)); | |
| 196 else | |
| 197 fuse(unconfuse, 0, spread(HUHDURATION), AFTER); | |
| 198 player.t_flags |= ISHUH; | |
| 199 mname = set_mname(tp); | |
| 200 addmsg("%s", mname); | |
| 201 if (strcmp(mname, "it") != 0) | |
| 202 addmsg("'"); | |
| 203 msg("s gaze has confused you"); | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 /* | |
| 208 * Let greedy ones guard gold | |
| 209 */ | |
| 210 if (on(*tp, ISGREED) && !on(*tp, ISRUN)) | |
| 211 { | |
| 212 tp->t_flags |= ISRUN; | |
| 213 if (proom->r_goldval) | |
| 214 tp->t_dest = &proom->r_gold; | |
| 215 else | |
| 216 tp->t_dest = &hero; | |
| 217 } | |
| 218 return tp; | |
| 219 } | |
| 220 | |
| 221 /* | |
| 222 * give_pack: | |
| 223 * Give a pack to a monster if it deserves one | |
| 224 */ | |
| 225 | |
| 226 void | |
| 227 give_pack(THING *tp) | |
| 228 { | |
| 229 if (level >= max_level && rnd(100) < monsters[tp->t_type-'A'].m_carry) | |
| 230 attach(tp->t_pack, new_thing()); | |
| 231 } | |
| 232 | |
| 233 /* | |
| 234 * save_throw: | |
| 235 * See if a creature save against something | |
| 236 */ | |
| 237 int | |
| 238 save_throw(int which, const THING *tp) | |
| 239 { | |
| 240 int need; | |
| 241 | |
| 242 need = 14 + which - tp->t_stats.s_lvl / 2; | |
| 243 return (roll(1, 20) >= need); | |
| 244 } | |
| 245 | |
| 246 /* | |
| 247 * save: | |
| 248 * See if he saves against various nasty things | |
| 249 */ | |
| 250 int | |
| 251 save(int which) | |
| 252 { | |
| 253 if (which == VS_MAGIC) | |
| 254 { | |
| 255 if (ISRING(LEFT, R_PROTECT)) | |
| 256 which -= cur_ring[LEFT]->o_arm; | |
| 257 if (ISRING(RIGHT, R_PROTECT)) | |
| 258 which -= cur_ring[RIGHT]->o_arm; | |
| 259 } | |
| 260 return save_throw(which, &player); | |
| 261 } |
