Mercurial > hg > early-roguelike
comparison rogue4/monsters.c @ 12:9535a08ddc39
Import Rogue 5.2 from the Roguelike Restoration Project (r1490)
| author | edwarj4 | 
|---|---|
| date | Sat, 24 Oct 2009 16:52:52 +0000 | 
| parents | |
| children | 1b73a8641b37 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 11:949d558c2162 | 12:9535a08ddc39 | 
|---|---|
| 1 /* | |
| 2 * File with various monster functions in it | |
| 3 * | |
| 4 * @(#)monsters.c 4.24 (Berkeley) 4/6/82 | |
| 5 * | |
| 6 * Rogue: Exploring the Dungeons of Doom | |
| 7 * Copyright (C) 1980, 1981, 1982 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 <ctype.h> | |
| 16 #include "rogue.h" | |
| 17 | |
| 18 /* | |
| 19 * List of monsters in rough order of vorpalness | |
| 20 * | |
| 21 * NOTE: This not initialized using strings so that xstr doesn't set up | |
| 22 * the string not to be saved. Otherwise genocide is lost through | |
| 23 * saving a game. | |
| 24 */ | |
| 25 char lvl_mons[] = { | |
| 26 'K', 'J', 'B', 'S', 'H', 'E', 'A', 'O', 'Z', 'G', 'L', 'C', 'R', | |
| 27 'Q', 'N', 'Y', 'T', 'W', 'F', 'I', 'X', 'U', 'M', 'V', 'P', 'D', | |
| 28 '\0' | |
| 29 }; | |
| 30 | |
| 31 char wand_mons[] = { | |
| 32 'K', 'J', 'B', 'S', 'H', ' ', 'A', 'O', 'Z', 'G', ' ', 'C', 'R', | |
| 33 'Q', ' ', 'Y', 'T', 'W', ' ', 'I', 'X', 'U', ' ', 'V', 'P', ' ', | |
| 34 '\0' | |
| 35 }; | |
| 36 | |
| 37 /* | |
| 38 * randmonster: | |
| 39 * Pick a monster to show up. The lower the level, | |
| 40 * the meaner the monster. | |
| 41 */ | |
| 42 randmonster(wander) | |
| 43 bool wander; | |
| 44 { | |
| 45 register int d; | |
| 46 register char *mons; | |
| 47 | |
| 48 mons = wander ? wand_mons : lvl_mons; | |
| 49 do | |
| 50 { | |
| 51 d = level + (rnd(10) - 5); | |
| 52 if (d < 1) | |
| 53 d = rnd(5) + 1; | |
| 54 if (d > 26) | |
| 55 d = rnd(5) + 22; | |
| 56 } while (mons[--d] == ' '); | |
| 57 return mons[d]; | |
| 58 } | |
| 59 | |
| 60 /* | |
| 61 * new_monster: | |
| 62 * Pick a new monster and add it to the list | |
| 63 */ | |
| 64 new_monster(tp, type, cp) | |
| 65 register THING *tp; | |
| 66 char type; | |
| 67 register coord *cp; | |
| 68 { | |
| 69 register struct monster *mp; | |
| 70 register int lev_add; | |
| 71 | |
| 72 if ((lev_add = level - AMULETLEVEL) < 0) | |
| 73 lev_add = 0; | |
| 74 attach(mlist, tp); | |
| 75 tp->t_type = type; | |
| 76 tp->t_disguise = type; | |
| 77 tp->t_pos = *cp; | |
| 78 tp->t_oldch = mvinch(cp->y, cp->x); | |
| 79 tp->t_room = roomin(cp); | |
| 80 moat(cp->y, cp->x) = tp; | |
| 81 mp = &monsters[tp->t_type-'A']; | |
| 82 tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add; | |
| 83 tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8); | |
| 84 tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add; | |
| 85 strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,16); | |
| 86 tp->t_stats.s_str = mp->m_stats.s_str; | |
| 87 tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp); | |
| 88 tp->t_flags = mp->m_flags; | |
| 89 tp->t_turn = TRUE; | |
| 90 tp->t_pack = NULL; | |
| 91 if (ISWEARING(R_AGGR)) | |
| 92 runto(cp, &hero); | |
| 93 if (type == 'M') | |
| 94 switch (rnd(level > 25 ? 9 : 8)) | |
| 95 { | |
| 96 case 0: tp->t_disguise = GOLD; | |
| 97 when 1: tp->t_disguise = POTION; | |
| 98 when 2: tp->t_disguise = SCROLL; | |
| 99 when 3: tp->t_disguise = STAIRS; | |
| 100 when 4: tp->t_disguise = WEAPON; | |
| 101 when 5: tp->t_disguise = ARMOR; | |
| 102 when 6: tp->t_disguise = RING; | |
| 103 when 7: tp->t_disguise = STICK; | |
| 104 when 8: tp->t_disguise = AMULET; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 /* | |
| 109 * expadd: | |
| 110 * Experience to add for this monster's level/hit points | |
| 111 */ | |
| 112 exp_add(tp) | |
| 113 register THING *tp; | |
| 114 { | |
| 115 register int mod; | |
| 116 | |
| 117 if (tp->t_stats.s_lvl == 1) | |
| 118 mod = tp->t_stats.s_maxhp / 8; | |
| 119 else | |
| 120 mod = tp->t_stats.s_maxhp / 6; | |
| 121 if (tp->t_stats.s_lvl > 9) | |
| 122 mod *= 20; | |
| 123 else if (tp->t_stats.s_lvl > 6) | |
| 124 mod *= 4; | |
| 125 return mod; | |
| 126 } | |
| 127 | |
| 128 /* | |
| 129 * wanderer: | |
| 130 * Create a new wandering monster and aim it at the player | |
| 131 */ | |
| 132 wanderer() | |
| 133 { | |
| 134 register int i; | |
| 135 register struct room *rp; | |
| 136 register THING *tp; | |
| 137 coord cp = {0,0}; | |
| 138 register int cnt = 0; | |
| 139 | |
| 140 tp = new_item(); | |
| 141 do | |
| 142 { | |
| 143 /* Avoid endless loop when all rooms are filled with monsters | |
| 144 * and the player room is not accessible to the monsters. | |
| 145 */ | |
| 146 if (cnt++ >= 500) | |
| 147 { | |
| 148 discard(tp); | |
| 149 return; | |
| 150 } | |
| 151 i = rnd_room(); | |
| 152 if ((rp = &rooms[i]) == proom) | |
| 153 continue; | |
| 154 rnd_pos(rp, &cp); | |
| 155 } until (rp != proom && step_ok(winat(cp.y, cp.x))); | |
| 156 new_monster(tp, randmonster(TRUE), &cp); | |
| 157 runto(&tp->t_pos, &hero); | |
| 158 #ifdef WIZARD | |
| 159 if (wizard) | |
| 160 msg("started a wandering %s", monsters[tp->t_type-'A'].m_name); | |
| 161 #endif | |
| 162 } | |
| 163 | |
| 164 /* | |
| 165 * wake_monster: | |
| 166 * What to do when the hero steps next to a monster | |
| 167 */ | |
| 168 THING * | |
| 169 wake_monster(y, x) | |
| 170 int y, x; | |
| 171 { | |
| 172 register THING *tp; | |
| 173 register struct room *rp; | |
| 174 register char ch; | |
| 175 | |
| 176 #ifdef WIZARD | |
| 177 if ((tp = moat(y, x)) == NULL) | |
| 178 msg("can't find monster in wake_monster"); | |
| 179 #else | |
| 180 tp = moat(y, x); | |
| 181 #endif | |
| 182 ch = tp->t_type; | |
| 183 /* | |
| 184 * Every time he sees mean monster, it might start chasing him | |
| 185 */ | |
| 186 if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD) | |
| 187 && !ISWEARING(R_STEALTH)) | |
| 188 { | |
| 189 tp->t_dest = &hero; | |
| 190 tp->t_flags |= ISRUN; | |
| 191 } | |
| 192 if (ch == 'U' && !on(player, ISBLIND) && !on(*tp, ISFOUND) | |
| 193 && !on(*tp, ISCANC) && on(*tp, ISRUN)) | |
| 194 { | |
| 195 rp = proom; | |
| 196 if ((rp != NULL && !(rp->r_flags & ISDARK)) | |
| 197 || DISTANCE(y, x, hero.y, hero.x) < LAMPDIST) | |
| 198 { | |
| 199 tp->t_flags |= ISFOUND; | |
| 200 if (!save(VS_MAGIC)) | |
| 201 { | |
| 202 if (on(player, ISHUH)) | |
| 203 lengthen(unconfuse, rnd(20) + HUHDURATION); | |
| 204 else | |
| 205 fuse(unconfuse, 0, rnd(20) + HUHDURATION, AFTER); | |
| 206 player.t_flags |= ISHUH; | |
| 207 msg("the umber hulk's gaze has confused you"); | |
| 208 } | |
| 209 } | |
| 210 } | |
| 211 /* | |
| 212 * Let greedy ones guard gold | |
| 213 */ | |
| 214 if (on(*tp, ISGREED) && !on(*tp, ISRUN)) | |
| 215 { | |
| 216 tp->t_flags |= ISRUN; | |
| 217 if (proom->r_goldval) | |
| 218 tp->t_dest = &proom->r_gold; | |
| 219 else | |
| 220 tp->t_dest = &hero; | |
| 221 } | |
| 222 return tp; | |
| 223 } | |
| 224 | |
| 225 /* | |
| 226 * genocide: | |
| 227 * Wipe one monster out of existence (for now...) | |
| 228 */ | |
| 229 genocide() | |
| 230 { | |
| 231 register THING *mp; | |
| 232 register char c; | |
| 233 register int i; | |
| 234 register THING *nmp; | |
| 235 | |
| 236 addmsg("which monster"); | |
| 237 if (!terse) | |
| 238 addmsg(" do you wish to wipe out"); | |
| 239 msg("? "); | |
| 240 while (!isalpha(c = readchar())) | |
| 241 if (c == ESCAPE) | |
| 242 return; | |
| 243 else | |
| 244 { | |
| 245 mpos = 0; | |
| 246 msg("please specifiy a letter between 'A' and 'Z'"); | |
| 247 } | |
| 248 mpos = 0; | |
| 249 if (islower(c)) | |
| 250 c = toupper(c); | |
| 251 for (mp = mlist; mp; mp = nmp) | |
| 252 { | |
| 253 nmp = next(mp); | |
| 254 if (mp->t_type == c) | |
| 255 remove_monster(&mp->t_pos, mp, FALSE); | |
| 256 } | |
| 257 for (i = 0; i < 26; i++) | |
| 258 if (lvl_mons[i] == c) | |
| 259 { | |
| 260 lvl_mons[i] = ' '; | |
| 261 wand_mons[i] = ' '; | |
| 262 break; | |
| 263 } | |
| 264 if (!terse) | |
| 265 addmsg("there will be "); | |
| 266 msg("no more %ss", monsters[c - 'A'].m_name); | |
| 267 } | |
| 268 | |
| 269 /* | |
| 270 * give_pack: | |
| 271 * Give a pack to a monster if it deserves one | |
| 272 */ | |
| 273 give_pack(tp) | |
| 274 register THING *tp; | |
| 275 { | |
| 276 if (rnd(100) < monsters[tp->t_type-'A'].m_carry) | |
| 277 attach(tp->t_pack, new_thing()); | |
| 278 } | 
