1 1.20 rillig /* $NetBSD: monster.c,v 1.20 2021/05/02 12:50:45 rillig Exp $ */ 2 1.2 mycroft 3 1.1 cgd /* 4 1.5 christos * monster.c Larn is copyrighted 1986 by Noah Morgan. 5 1.1 cgd * 6 1.5 christos * This file contains the following functions: 7 1.5 christos * ---------------------------------------------------------------------------- 8 1.1 cgd * 9 1.5 christos * createmonster(monstno) Function to create a monster next to the player 10 1.5 christos * int monstno; 11 1.1 cgd * 12 1.5 christos * int cgood(x,y,itm,monst)Function to check location for emptiness 13 1.5 christos * int x,y,itm,monst; 14 1.1 cgd * 15 1.5 christos * createitem(it,arg) Routine to place an item next to the player 16 1.5 christos * int it,arg; 17 1.1 cgd * 18 1.5 christos * cast() Subroutine called by parse to cast a spell for the user 19 1.1 cgd * 20 1.5 christos * speldamage(x) Function to perform spell functions cast by the player 21 1.5 christos * int x; 22 1.1 cgd * 23 1.5 christos * loseint() Routine to decrement your int (intelligence) if > 3 24 1.1 cgd * 25 1.5 christos * isconfuse() Routine to check to see if player is confused 26 1.1 cgd * 27 1.5 christos * nospell(x,monst)Routine to return 1 if a spell doesn't affect a monster 28 1.5 christos * int x,monst; 29 1.1 cgd * 30 1.5 christos * fullhit(xx) Function to return full damage against a monst (aka web) 31 1.5 christos * int xx; 32 1.1 cgd * 33 1.5 christos * direct(spnum,dam,str,arg)Routine to direct spell damage 1 square in 1 dir 34 1.5 christos * int spnum,dam,arg; 35 1.5 christos * char *str; 36 1.1 cgd * 37 1.5 christos * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks 38 1.5 christos * int spnum,dam,delay; 39 1.5 christos * char *str,cshow; 40 1.1 cgd * 41 1.5 christos * ifblind(x,y)Routine to put "monster" or the monster name into lastmosnt 42 1.5 christos * int x,y; 43 1.1 cgd * 44 1.5 christos * tdirect(spnum) Routine to teleport away a monster 45 1.5 christos * int spnum; 46 1.1 cgd * 47 1.5 christos * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player 48 1.5 christos * int sp,dam; 49 1.5 christos * char *str; 50 1.1 cgd * 51 1.5 christos * dirsub(x,y) Routine to ask for direction, then modify x,y for it 52 1.5 christos * int *x,*y; 53 1.1 cgd * 54 1.5 christos * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds 55 1.5 christos * int *x,*y; 56 1.1 cgd * 57 1.5 christos * dirpoly(spnum) Routine to ask for a direction and polymorph a monst 58 1.5 christos * int spnum; 59 1.1 cgd * 60 1.5 christos * hitmonster(x,y) Function to hit a monster at the designated coordinates 61 1.5 christos * int x,y; 62 1.1 cgd * 63 1.5 christos * hitm(x,y,amt) Function to just hit a monster at a given coordinates 64 1.5 christos * int x,y,amt; 65 1.1 cgd * 66 1.5 christos * hitplayer(x,y) Function for the monster to hit the player from (x,y) 67 1.5 christos * int x,y; 68 1.1 cgd * 69 1.5 christos * dropsomething(monst) Function to create an object when a monster dies 70 1.5 christos * int monst; 71 1.1 cgd * 72 1.5 christos * dropgold(amount) Function to drop some gold around player 73 1.5 christos * int amount; 74 1.1 cgd * 75 1.5 christos * something(level) Function to create a random item around player 76 1.5 christos * int level; 77 1.1 cgd * 78 1.5 christos * newobject(lev,i) Routine to return a randomly selected new object 79 1.5 christos * int lev,*i; 80 1.1 cgd * 81 1.5 christos * spattack(atckno,xx,yy) Function to process special attacks from monsters 82 1.5 christos * int atckno,xx,yy; 83 1.1 cgd * 84 1.5 christos * checkloss(x) Routine to subtract hp from user and flag bottomline display 85 1.5 christos * int x; 86 1.1 cgd * 87 1.5 christos * annihilate() Routine to annihilate monsters around player, playerx,playery 88 1.1 cgd * 89 1.5 christos * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation 90 1.5 christos * int x,y,dir,lifetime; 91 1.1 cgd * 92 1.5 christos * rmsphere(x,y) Function to delete a sphere of annihilation from list 93 1.5 christos * int x,y; 94 1.1 cgd * 95 1.5 christos * sphboom(x,y) Function to perform the effects of a sphere detonation 96 1.5 christos * int x,y; 97 1.1 cgd * 98 1.5 christos * genmonst() Function to ask for monster and genocide from game 99 1.1 cgd * 100 1.1 cgd */ 101 1.5 christos #include <sys/cdefs.h> 102 1.5 christos #ifndef lint 103 1.20 rillig __RCSID("$NetBSD: monster.c,v 1.20 2021/05/02 12:50:45 rillig Exp $"); 104 1.5 christos #endif /* not lint */ 105 1.5 christos 106 1.5 christos #include <string.h> 107 1.5 christos #include <stdlib.h> 108 1.15 dholland #include <ctype.h> 109 1.1 cgd #include "header.h" 110 1.5 christos #include "extern.h" 111 1.1 cgd 112 1.5 christos struct isave { /* used for altar reality */ 113 1.5 christos char type; /* 0=item, 1=monster */ 114 1.5 christos char id; /* item number or monster number */ 115 1.5 christos short arg; /* the type of item or hitpoints of monster */ 116 1.5 christos }; 117 1.1 cgd 118 1.14 dholland static int cgood(int, int, int, int); 119 1.17 dholland static void speldamage(int); 120 1.17 dholland static void loseint(void); 121 1.17 dholland static int isconfuse(void); 122 1.17 dholland static int nospell(int, int); 123 1.17 dholland static int fullhit(int); 124 1.17 dholland static void direct(int, int, const char *, int); 125 1.17 dholland static void ifblind(int, int); 126 1.17 dholland static void tdirect(int); 127 1.17 dholland static void omnidirect(int, int, const char *); 128 1.8 jsm static int dirsub(int *, int *); 129 1.17 dholland static void dirpoly(int); 130 1.17 dholland static int hitm(int, int, int); 131 1.14 dholland static void dropsomething(int); 132 1.14 dholland static int spattack(int, int, int); 133 1.17 dholland static void sphboom(int, int); 134 1.17 dholland static void genmonst(void); 135 1.14 dholland 136 1.1 cgd /* 137 1.5 christos * createmonster(monstno) Function to create a monster next to the player 138 1.5 christos * int monstno; 139 1.1 cgd * 140 1.5 christos * Enter with the monster number (1 to MAXMONST+8) 141 1.5 christos * Returns no value. 142 1.1 cgd */ 143 1.5 christos void 144 1.18 dholland createmonster(int mon) 145 1.5 christos { 146 1.5 christos int x, y, k, i; 147 1.5 christos if (mon < 1 || mon > MAXMONST + 8) { /* check for monster number 148 1.5 christos * out of bounds */ 149 1.5 christos beep(); 150 1.12 dholland lprintf("\ncan't createmonst(%ld)\n", (long) mon); 151 1.5 christos nap(3000); 152 1.5 christos return; 153 1.5 christos } 154 1.5 christos while (monster[mon].genocided && mon < MAXMONST) 155 1.5 christos mon++; /* genocided? */ 156 1.5 christos for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction, 157 1.5 christos * then try all */ 158 1.5 christos if (k > 8) 159 1.5 christos k = 1; /* wraparound the diroff arrays */ 160 1.5 christos x = playerx + diroffx[k]; 161 1.5 christos y = playery + diroffy[k]; 162 1.5 christos if (cgood(x, y, 0, 1)) { /* if we can create here */ 163 1.1 cgd mitem[x][y] = mon; 164 1.1 cgd hitp[x][y] = monster[mon].hitpoints; 165 1.5 christos stealth[x][y] = know[x][y] = 0; 166 1.5 christos switch (mon) { 167 1.5 christos case ROTHE: 168 1.5 christos case POLTERGEIST: 169 1.5 christos case VAMPIRE: 170 1.5 christos stealth[x][y] = 1; 171 1.5 christos }; 172 1.1 cgd return; 173 1.1 cgd } 174 1.1 cgd } 175 1.5 christos } 176 1.1 cgd 177 1.1 cgd /* 178 1.5 christos * int cgood(x,y,itm,monst) Function to check location for emptiness 179 1.5 christos * int x,y,itm,monst; 180 1.1 cgd * 181 1.5 christos * Routine to return TRUE if a location does not have itm or monst there 182 1.5 christos * returns FALSE (0) otherwise 183 1.5 christos * Enter with itm or monst TRUE or FALSE if checking it 184 1.5 christos * Example: if itm==TRUE check for no item at this location 185 1.5 christos * if monst==TRUE check for no monster at this location 186 1.5 christos * This routine will return FALSE if at a wall or the dungeon exit on level 1 187 1.5 christos */ 188 1.20 rillig static int 189 1.13 dholland cgood(int x, int y, int theitem, int monst) 190 1.5 christos { 191 1.13 dholland #define itm __lose 192 1.5 christos if ((y >= 0) && (y <= MAXY - 1) && (x >= 0) && (x <= MAXX - 1)) 193 1.5 christos /* within bounds? */ 194 1.5 christos if (item[x][y] != OWALL) /* can't make anything on walls */ 195 1.5 christos /* is it free of items? */ 196 1.13 dholland if (theitem == 0 || (item[x][y] == 0)) 197 1.5 christos /* is it free of monsters? */ 198 1.5 christos if (monst == 0 || (mitem[x][y] == 0)) 199 1.5 christos if ((level != 1) || (x != 33) || 200 1.5 christos (y != MAXY - 1)) 201 1.5 christos /* not exit to level 1 */ 202 1.5 christos return (1); 203 1.5 christos return (0); 204 1.5 christos } 205 1.5 christos 206 1.5 christos /* 207 1.5 christos * createitem(it,arg) Routine to place an item next to the player 208 1.5 christos * int it,arg; 209 1.5 christos * 210 1.5 christos * Enter with the item number and its argument (iven[], ivenarg[]) 211 1.5 christos * Returns no value, thus we don't know about createitem() failures. 212 1.5 christos */ 213 1.5 christos void 214 1.18 dholland createitem(int it, int arg) 215 1.5 christos { 216 1.5 christos int x, y, k, i; 217 1.5 christos if (it >= MAXOBJ) 218 1.5 christos return; /* no such object */ 219 1.5 christos for (k = rnd(8), i = -8; i < 0; i++, k++) { /* choose direction, 220 1.5 christos * then try all */ 221 1.5 christos if (k > 8) 222 1.5 christos k = 1; /* wraparound the diroff arrays */ 223 1.5 christos x = playerx + diroffx[k]; 224 1.5 christos y = playery + diroffy[k]; 225 1.5 christos if (cgood(x, y, 1, 0)) { /* if we can create here */ 226 1.5 christos item[x][y] = it; 227 1.5 christos know[x][y] = 0; 228 1.5 christos iarg[x][y] = arg; 229 1.5 christos return; 230 1.1 cgd } 231 1.1 cgd } 232 1.5 christos } 233 1.1 cgd 234 1.1 cgd /* 235 1.5 christos * cast() Subroutine called by parse to cast a spell for the user 236 1.1 cgd * 237 1.5 christos * No arguments and no return value. 238 1.1 cgd */ 239 1.5 christos static char eys[] = "\nEnter your spell: "; 240 1.5 christos void 241 1.18 dholland cast(void) 242 1.5 christos { 243 1.5 christos int i, j, a, b, d; 244 1.1 cgd cursors(); 245 1.5 christos if (c[SPELLS] <= 0) { 246 1.5 christos lprcat("\nYou don't have any spells!"); 247 1.5 christos return; 248 1.5 christos } 249 1.5 christos lprcat(eys); 250 1.5 christos --c[SPELLS]; 251 1.16 dholland while ((a = ttgetch()) == 'D') { 252 1.5 christos seemagic(-1); 253 1.5 christos cursors(); 254 1.5 christos lprcat(eys); 255 1.5 christos } 256 1.5 christos if (a == '\33') 257 1.5 christos goto over; /* to escape casting a spell */ 258 1.16 dholland if ((b = ttgetch()) == '\33') 259 1.5 christos goto over; /* to escape casting a spell */ 260 1.16 dholland if ((d = ttgetch()) == '\33') { 261 1.5 christos over: lprcat(aborted); 262 1.5 christos c[SPELLS]++; 263 1.5 christos return; 264 1.5 christos } /* to escape casting a spell */ 265 1.1 cgd #ifdef EXTRA 266 1.1 cgd c[SPELLSCAST]++; 267 1.1 cgd #endif 268 1.5 christos for (lprc('\n'), j = -1, i = 0; i < SPNUM; i++) /* seq search for his 269 1.5 christos * spell, hash? */ 270 1.5 christos if ((spelcode[i][0] == a) && (spelcode[i][1] == b) && (spelcode[i][2] == d)) 271 1.5 christos if (spelknow[i]) { 272 1.5 christos speldamage(i); 273 1.5 christos j = 1; 274 1.5 christos i = SPNUM; 275 1.5 christos } 276 1.5 christos if (j == -1) 277 1.5 christos lprcat(" Nothing Happened "); 278 1.1 cgd bottomline(); 279 1.5 christos } 280 1.1 cgd 281 1.1 cgd /* 282 1.5 christos * speldamage(x) Function to perform spell functions cast by the player 283 1.5 christos * int x; 284 1.1 cgd * 285 1.5 christos * Enter with the spell number, returns no value. 286 1.5 christos * Please insure that there are 2 spaces before all messages here 287 1.1 cgd */ 288 1.17 dholland static void 289 1.13 dholland speldamage(int x) 290 1.5 christos { 291 1.5 christos int i, j, clev; 292 1.5 christos int xl, xh, yl, yh; 293 1.13 dholland u_char *p, *kn, *pm; 294 1.13 dholland 295 1.5 christos if (x >= SPNUM) 296 1.5 christos return; /* no such spell */ 297 1.5 christos if (c[TIMESTOP]) { 298 1.5 christos lprcat(" It didn't seem to work"); 299 1.5 christos return; 300 1.5 christos } /* not if time stopped */ 301 1.1 cgd clev = c[LEVEL]; 302 1.5 christos if ((rnd(23) == 7) || (rnd(18) > c[INTELLIGENCE])) { 303 1.5 christos lprcat(" It didn't work!"); 304 1.5 christos return; 305 1.5 christos } 306 1.5 christos if (clev * 3 + 2 < x) { 307 1.5 christos lprcat(" Nothing happens. You seem inexperienced at this"); 308 1.5 christos return; 309 1.5 christos } 310 1.5 christos switch (x) { 311 1.5 christos /* ----- LEVEL 1 SPELLS ----- */ 312 1.5 christos 313 1.5 christos case 0: 314 1.5 christos if (c[PROTECTIONTIME] == 0) 315 1.5 christos c[MOREDEFENSES] += 2; /* protection field +2 */ 316 1.5 christos c[PROTECTIONTIME] += 250; 317 1.5 christos return; 318 1.5 christos 319 1.5 christos case 1: 320 1.5 christos i = rnd(((clev + 1) << 1)) + clev + 3; 321 1.5 christos godirect(x, i, (clev >= 2) ? " Your missiles hit the %s" : " Your missile hit the %s", 100, '+'); /* magic missile */ 322 1.5 christos 323 1.5 christos return; 324 1.5 christos 325 1.5 christos case 2: 326 1.5 christos if (c[DEXCOUNT] == 0) 327 1.5 christos c[DEXTERITY] += 3; /* dexterity */ 328 1.5 christos c[DEXCOUNT] += 400; 329 1.5 christos return; 330 1.5 christos 331 1.13 dholland case 3: /* sleep */ 332 1.5 christos i = rnd(3) + 1; 333 1.13 dholland direct(x, fullhit(i), 334 1.13 dholland " While the %s slept, you smashed it %ld times", i); 335 1.5 christos return; 336 1.1 cgd 337 1.5 christos case 4: /* charm monster */ 338 1.5 christos c[CHARMCOUNT] += c[CHARISMA] << 1; 339 1.5 christos return; 340 1.5 christos 341 1.5 christos case 5: 342 1.5 christos godirect(x, rnd(10) + 15 + clev, " The sound damages the %s", 70, '@'); /* sonic spear */ 343 1.5 christos return; 344 1.5 christos 345 1.5 christos /* ----- LEVEL 2 SPELLS ----- */ 346 1.1 cgd 347 1.13 dholland case 6: /* web */ 348 1.5 christos i = rnd(3) + 2; 349 1.13 dholland direct(x, fullhit(i), 350 1.13 dholland " While the %s is entangled, you hit %ld times", i); 351 1.13 dholland return; 352 1.5 christos 353 1.5 christos case 7: 354 1.5 christos if (c[STRCOUNT] == 0) 355 1.5 christos c[STREXTRA] += 3; /* strength */ 356 1.5 christos c[STRCOUNT] += 150 + rnd(100); 357 1.5 christos return; 358 1.1 cgd 359 1.5 christos case 8: 360 1.5 christos yl = playery - 5; /* enlightenment */ 361 1.5 christos yh = playery + 6; 362 1.5 christos xl = playerx - 15; 363 1.5 christos xh = playerx + 16; 364 1.5 christos vxy(&xl, &yl); 365 1.5 christos vxy(&xh, &yh); /* check bounds */ 366 1.5 christos for (i = yl; i <= yh; i++) /* enlightenment */ 367 1.5 christos for (j = xl; j <= xh; j++) 368 1.5 christos know[j][i] = 1; 369 1.5 christos draws(xl, xh + 1, yl, yh + 1); 370 1.5 christos return; 371 1.1 cgd 372 1.5 christos case 9: 373 1.5 christos raisehp(20 + (clev << 1)); 374 1.5 christos return; /* healing */ 375 1.5 christos 376 1.5 christos case 10: 377 1.5 christos c[BLINDCOUNT] = 0; 378 1.5 christos return; /* cure blindness */ 379 1.1 cgd 380 1.5 christos case 11: 381 1.5 christos createmonster(makemonst(level + 1) + 8); 382 1.5 christos return; 383 1.1 cgd 384 1.5 christos case 12: 385 1.5 christos if (rnd(11) + 7 <= c[WISDOM]) 386 1.5 christos direct(x, rnd(20) + 20 + clev, " The %s believed!", 0); 387 1.5 christos else 388 1.5 christos lprcat(" It didn't believe the illusions!"); 389 1.5 christos return; 390 1.1 cgd 391 1.5 christos case 13: /* if he has the amulet of invisibility then 392 1.5 christos * add more time */ 393 1.5 christos for (j = i = 0; i < 26; i++) 394 1.5 christos if (iven[i] == OAMULET) 395 1.5 christos j += 1 + ivenarg[i]; 396 1.5 christos c[INVISIBILITY] += (j << 7) + 12; 397 1.5 christos return; 398 1.1 cgd 399 1.5 christos /* ----- LEVEL 3 SPELLS ----- */ 400 1.1 cgd 401 1.5 christos case 14: 402 1.5 christos godirect(x, rnd(25 + clev) + 25 + clev, " The fireball hits the %s", 40, '*'); 403 1.5 christos return; /* fireball */ 404 1.1 cgd 405 1.5 christos case 15: 406 1.5 christos godirect(x, rnd(25) + 20 + clev, " Your cone of cold strikes the %s", 60, 'O'); /* cold */ 407 1.5 christos return; 408 1.1 cgd 409 1.5 christos case 16: 410 1.5 christos dirpoly(x); 411 1.5 christos return; /* polymorph */ 412 1.5 christos 413 1.5 christos case 17: 414 1.5 christos c[CANCELLATION] += 5 + clev; 415 1.5 christos return; /* cancellation */ 416 1.5 christos 417 1.5 christos case 18: 418 1.5 christos c[HASTESELF] += 7 + clev; 419 1.5 christos return; /* haste self */ 420 1.1 cgd 421 1.5 christos case 19: 422 1.5 christos omnidirect(x, 30 + rnd(10), " The %s gasps for air"); /* cloud kill */ 423 1.5 christos return; 424 1.1 cgd 425 1.5 christos case 20: 426 1.5 christos xh = min(playerx + 1, MAXX - 2); 427 1.5 christos yh = min(playery + 1, MAXY - 2); 428 1.5 christos for (i = max(playerx - 1, 1); i <= xh; i++) /* vaporize rock */ 429 1.5 christos for (j = max(playery - 1, 1); j <= yh; j++) { 430 1.5 christos kn = &know[i][j]; 431 1.5 christos pm = &mitem[i][j]; 432 1.5 christos switch (*(p = &item[i][j])) { 433 1.5 christos case OWALL: 434 1.5 christos if (level < MAXLEVEL + MAXVLEVEL - 1) 435 1.5 christos *p = *kn = 0; 436 1.5 christos break; 437 1.1 cgd 438 1.5 christos case OSTATUE: 439 1.5 christos if (c[HARDGAME] < 3) { 440 1.5 christos *p = OBOOK; 441 1.5 christos iarg[i][j] = level; 442 1.5 christos *kn = 0; 443 1.5 christos } 444 1.5 christos break; 445 1.1 cgd 446 1.5 christos case OTHRONE: 447 1.5 christos *pm = GNOMEKING; 448 1.5 christos *kn = 0; 449 1.5 christos *p = OTHRONE2; 450 1.5 christos hitp[i][j] = monster[GNOMEKING].hitpoints; 451 1.5 christos break; 452 1.1 cgd 453 1.5 christos case OALTAR: 454 1.5 christos *pm = DEMONPRINCE; 455 1.5 christos *kn = 0; 456 1.5 christos hitp[i][j] = monster[DEMONPRINCE].hitpoints; 457 1.5 christos break; 458 1.5 christos }; 459 1.5 christos switch (*pm) { 460 1.5 christos case XORN: 461 1.5 christos ifblind(i, j); 462 1.5 christos hitm(i, j, 200); 463 1.5 christos break; /* Xorn takes damage from vpr */ 464 1.5 christos } 465 1.5 christos } 466 1.5 christos return; 467 1.1 cgd 468 1.5 christos /* ----- LEVEL 4 SPELLS ----- */ 469 1.1 cgd 470 1.5 christos case 21: 471 1.5 christos direct(x, 100 + clev, " The %s shrivels up", 0); /* dehydration */ 472 1.5 christos return; 473 1.1 cgd 474 1.5 christos case 22: 475 1.5 christos godirect(x, rnd(25) + 20 + (clev << 1), " A lightning bolt hits the %s", 1, '~'); /* lightning */ 476 1.5 christos return; 477 1.1 cgd 478 1.5 christos case 23: 479 1.5 christos i = min(c[HP] - 1, c[HPMAX] / 2); /* drain life */ 480 1.5 christos direct(x, i + i, "", 0); 481 1.5 christos c[HP] -= i; 482 1.5 christos return; 483 1.1 cgd 484 1.5 christos case 24: 485 1.5 christos if (c[GLOBE] == 0) 486 1.5 christos c[MOREDEFENSES] += 10; 487 1.5 christos c[GLOBE] += 200; 488 1.5 christos loseint(); /* globe of invulnerability */ 489 1.5 christos return; 490 1.1 cgd 491 1.5 christos case 25: 492 1.5 christos omnidirect(x, 32 + clev, " The %s struggles for air in your flood!"); /* flood */ 493 1.5 christos return; 494 1.1 cgd 495 1.5 christos case 26: 496 1.5 christos if (rnd(151) == 63) { 497 1.5 christos beep(); 498 1.5 christos lprcat("\nYour heart stopped!\n"); 499 1.5 christos nap(4000); 500 1.5 christos died(270); 501 1.5 christos return; 502 1.5 christos } 503 1.5 christos if (c[WISDOM] > rnd(10) + 10) 504 1.5 christos direct(x, 2000, " The %s's heart stopped", 0); /* finger of death */ 505 1.5 christos else 506 1.5 christos lprcat(" It didn't work"); 507 1.5 christos return; 508 1.1 cgd 509 1.5 christos /* ----- LEVEL 5 SPELLS ----- */ 510 1.1 cgd 511 1.5 christos case 27: 512 1.5 christos c[SCAREMONST] += rnd(10) + clev; 513 1.5 christos return; /* scare monster */ 514 1.5 christos 515 1.5 christos case 28: 516 1.5 christos c[HOLDMONST] += rnd(10) + clev; 517 1.5 christos return; /* hold monster */ 518 1.5 christos 519 1.5 christos case 29: 520 1.5 christos c[TIMESTOP] += rnd(20) + (clev << 1); 521 1.5 christos return; /* time stop */ 522 1.5 christos 523 1.5 christos case 30: 524 1.5 christos tdirect(x); 525 1.5 christos return; /* teleport away */ 526 1.1 cgd 527 1.5 christos case 31: 528 1.5 christos omnidirect(x, 35 + rnd(10) + clev, " The %s cringes from the flame"); /* magic fire */ 529 1.5 christos return; 530 1.1 cgd 531 1.5 christos /* ----- LEVEL 6 SPELLS ----- */ 532 1.5 christos 533 1.5 christos case 32: 534 1.5 christos if ((rnd(23) == 5) && (wizard == 0)) { /* sphere of 535 1.5 christos * annihilation */ 536 1.5 christos beep(); 537 1.5 christos lprcat("\nYou have been enveloped by the zone of nothingness!\n"); 538 1.5 christos nap(4000); 539 1.5 christos died(258); 540 1.5 christos return; 541 1.5 christos } 542 1.5 christos xl = playerx; 543 1.5 christos yl = playery; 544 1.5 christos loseint(); 545 1.5 christos i = dirsub(&xl, &yl); /* get direction of sphere */ 546 1.5 christos newsphere(xl, yl, i, rnd(20) + 11); /* make a sphere */ 547 1.5 christos return; 548 1.5 christos 549 1.5 christos case 33: 550 1.5 christos genmonst(); 551 1.5 christos spelknow[33] = 0; /* genocide */ 552 1.5 christos loseint(); 553 1.5 christos return; 554 1.5 christos 555 1.5 christos case 34: /* summon demon */ 556 1.5 christos if (rnd(100) > 30) { 557 1.5 christos direct(x, 150, " The demon strikes at the %s", 0); 558 1.5 christos return; 559 1.5 christos } 560 1.5 christos if (rnd(100) > 15) { 561 1.5 christos lprcat(" Nothing seems to have happened"); 562 1.5 christos return; 563 1.5 christos } 564 1.5 christos lprcat(" The demon turned on you and vanished!"); 565 1.5 christos beep(); 566 1.5 christos i = rnd(40) + 30; 567 1.5 christos lastnum = 277; 568 1.5 christos losehp(i); /* must say killed by a demon */ 569 1.5 christos return; 570 1.5 christos 571 1.5 christos case 35: /* walk through walls */ 572 1.5 christos c[WTW] += rnd(10) + 5; 573 1.5 christos return; 574 1.5 christos 575 1.5 christos case 36: /* alter reality */ 576 1.5 christos { 577 1.5 christos struct isave *save; /* pointer to item save 578 1.5 christos * structure */ 579 1.5 christos int sc; 580 1.5 christos sc = 0; /* # items saved */ 581 1.5 christos save = (struct isave *) malloc(sizeof(struct isave) * MAXX * MAXY * 2); 582 1.5 christos for (j = 0; j < MAXY; j++) 583 1.5 christos for (i = 0; i < MAXX; i++) { /* save all items and 584 1.5 christos * monsters */ 585 1.5 christos xl = item[i][j]; 586 1.5 christos if (xl && xl != OWALL && xl != OANNIHILATION) { 587 1.5 christos save[sc].type = 0; 588 1.5 christos save[sc].id = item[i][j]; 589 1.5 christos save[sc++].arg = iarg[i][j]; 590 1.5 christos } 591 1.5 christos if (mitem[i][j]) { 592 1.5 christos save[sc].type = 1; 593 1.5 christos save[sc].id = mitem[i][j]; 594 1.5 christos save[sc++].arg = hitp[i][j]; 595 1.5 christos } 596 1.5 christos item[i][j] = OWALL; 597 1.5 christos mitem[i][j] = 0; 598 1.5 christos if (wizard) 599 1.5 christos know[i][j] = 1; 600 1.5 christos else 601 1.5 christos know[i][j] = 0; 602 1.5 christos } 603 1.5 christos eat(1, 1); 604 1.5 christos if (level == 1) 605 1.5 christos item[33][MAXY - 1] = 0; 606 1.5 christos for (j = rnd(MAXY - 2), i = 1; i < MAXX - 1; i++) 607 1.5 christos item[i][j] = 0; 608 1.5 christos while (sc > 0) { /* put objects back in level */ 609 1.5 christos --sc; 610 1.5 christos if (save[sc].type == 0) { 611 1.5 christos int trys; 612 1.5 christos for (trys = 100, i = j = 1; --trys > 0 && item[i][j]; i = rnd(MAXX - 1), j = rnd(MAXY - 1)); 613 1.5 christos if (trys) { 614 1.5 christos item[i][j] = save[sc].id; 615 1.5 christos iarg[i][j] = save[sc].arg; 616 1.5 christos } 617 1.5 christos } else { /* put monsters back in */ 618 1.5 christos int trys; 619 1.5 christos for (trys = 100, i = j = 1; --trys > 0 && (item[i][j] == OWALL || mitem[i][j]); i = rnd(MAXX - 1), j = rnd(MAXY - 1)); 620 1.5 christos if (trys) { 621 1.5 christos mitem[i][j] = save[sc].id; 622 1.5 christos hitp[i][j] = save[sc].arg; 623 1.1 cgd } 624 1.5 christos } 625 1.5 christos } 626 1.5 christos loseint(); 627 1.5 christos draws(0, MAXX, 0, MAXY); 628 1.5 christos if (wizard == 0) 629 1.5 christos spelknow[36] = 0; 630 1.5 christos free((char *) save); 631 1.5 christos positionplayer(); 632 1.5 christos return; 633 1.5 christos } 634 1.1 cgd 635 1.5 christos case 37: /* permanence */ 636 1.5 christos adjusttime(-99999L); 637 1.5 christos spelknow[37] = 0; /* forget */ 638 1.5 christos loseint(); 639 1.5 christos return; 640 1.1 cgd 641 1.5 christos default: 642 1.12 dholland lprintf(" spell %ld not available!", (long) x); 643 1.5 christos beep(); 644 1.5 christos return; 645 1.5 christos }; 646 1.5 christos } 647 1.1 cgd 648 1.1 cgd /* 649 1.5 christos * loseint() Routine to subtract 1 from your int (intelligence) if > 3 650 1.1 cgd * 651 1.5 christos * No arguments and no return value 652 1.1 cgd */ 653 1.17 dholland static void 654 1.18 dholland loseint(void) 655 1.5 christos { 656 1.5 christos if (--c[INTELLIGENCE] < 3) 657 1.5 christos c[INTELLIGENCE] = 3; 658 1.5 christos } 659 1.1 cgd 660 1.1 cgd /* 661 1.5 christos * isconfuse() Routine to check to see if player is confused 662 1.1 cgd * 663 1.5 christos * This routine prints out a message saying "You can't aim your magic!" 664 1.5 christos * returns 0 if not confused, non-zero (time remaining confused) if confused 665 1.1 cgd */ 666 1.17 dholland static int 667 1.18 dholland isconfuse(void) 668 1.5 christos { 669 1.5 christos if (c[CONFUSE]) { 670 1.5 christos lprcat(" You can't aim your magic!"); 671 1.5 christos beep(); 672 1.5 christos } 673 1.5 christos return (c[CONFUSE]); 674 1.5 christos } 675 1.5 christos 676 1.5 christos /* 677 1.5 christos * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster 678 1.5 christos * int x,monst; 679 1.5 christos * 680 1.5 christos * Subroutine to return 1 if the spell can't affect the monster 681 1.5 christos * otherwise returns 0 682 1.5 christos * Enter with the spell number in x, and the monster number in monst. 683 1.5 christos */ 684 1.17 dholland static int 685 1.18 dholland nospell(int x, int monst) 686 1.5 christos { 687 1.5 christos int tmp; 688 1.5 christos if (x >= SPNUM || monst >= MAXMONST + 8 || monst < 0 || x < 0) 689 1.5 christos return (0); /* bad spell or monst */ 690 1.5 christos if ((tmp = spelweird[monst - 1][x]) == 0) 691 1.5 christos return (0); 692 1.5 christos cursors(); 693 1.5 christos lprc('\n'); 694 1.5 christos lprintf(spelmes[tmp], monster[monst].name); 695 1.5 christos return (1); 696 1.5 christos } 697 1.1 cgd 698 1.1 cgd /* 699 1.5 christos * fullhit(xx) Function to return full damage against a monster (aka web) 700 1.5 christos * int xx; 701 1.1 cgd * 702 1.5 christos * Function to return hp damage to monster due to a number of full hits 703 1.5 christos * Enter with the number of full hits being done 704 1.1 cgd */ 705 1.17 dholland static int 706 1.18 dholland fullhit(int xx) 707 1.5 christos { 708 1.5 christos int i; 709 1.5 christos if (xx < 0 || xx > 20) 710 1.5 christos return (0); /* fullhits are out of range */ 711 1.5 christos if (c[LANCEDEATH]) 712 1.5 christos return (10000); /* lance of death */ 713 1.5 christos i = xx * ((c[WCLASS] >> 1) + c[STRENGTH] + c[STREXTRA] - c[HARDGAME] - 12 + c[MOREDAM]); 714 1.5 christos return ((i >= 1) ? i : xx); 715 1.5 christos } 716 1.5 christos 717 1.5 christos /* 718 1.5 christos * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir 719 1.5 christos * int spnum,dam,arg; 720 1.5 christos * char *str; 721 1.5 christos * 722 1.5 christos * Routine to ask for a direction to a spell and then hit the monster 723 1.5 christos * Enter with the spell number in spnum, the damage to be done in dam, 724 1.5 christos * lprintf format string in str, and lprintf's argument in arg. 725 1.5 christos * Returns no value. 726 1.5 christos */ 727 1.17 dholland static void 728 1.18 dholland direct(int spnum, int dam, const char *str, int arg) 729 1.5 christos { 730 1.5 christos int x, y; 731 1.5 christos int m; 732 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0) 733 1.5 christos return; /* bad arguments */ 734 1.5 christos if (isconfuse()) 735 1.5 christos return; 736 1.5 christos dirsub(&x, &y); 737 1.1 cgd m = mitem[x][y]; 738 1.5 christos if (item[x][y] == OMIRROR) { 739 1.5 christos if (spnum == 3) { /* sleep */ 740 1.5 christos lprcat("You fall asleep! "); 741 1.5 christos beep(); 742 1.5 christos fool: 743 1.1 cgd arg += 2; 744 1.5 christos while (arg-- > 0) { 745 1.5 christos parse2(); 746 1.5 christos nap(1000); 747 1.5 christos } 748 1.1 cgd return; 749 1.5 christos } else if (spnum == 6) { /* web */ 750 1.5 christos lprcat("You get stuck in your own web! "); 751 1.5 christos beep(); 752 1.1 cgd goto fool; 753 1.5 christos } else { 754 1.5 christos lastnum = 278; 755 1.11 mouse lprintf(str, "spell caster (that's you)", (long) arg); 756 1.5 christos beep(); 757 1.5 christos losehp(dam); 758 1.5 christos return; 759 1.1 cgd } 760 1.1 cgd } 761 1.5 christos if (m == 0) { 762 1.5 christos lprcat(" There wasn't anything there!"); 763 1.5 christos return; 764 1.5 christos } 765 1.5 christos ifblind(x, y); 766 1.5 christos if (nospell(spnum, m)) { 767 1.5 christos lasthx = x; 768 1.5 christos lasthy = y; 769 1.5 christos return; 770 1.5 christos } 771 1.5 christos lprintf(str, lastmonst, (long) arg); 772 1.5 christos hitm(x, y, dam); 773 1.5 christos } 774 1.5 christos 775 1.5 christos /* 776 1.5 christos * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks 777 1.5 christos * int spnum,dam,delay; 778 1.5 christos * char *str,cshow; 779 1.5 christos * 780 1.5 christos * Function to hit in a direction from a missile weapon and have it keep 781 1.5 christos * on going in that direction until its power is exhausted 782 1.5 christos * Enter with the spell number in spnum, the power of the weapon in hp, 783 1.5 christos * lprintf format string in str, the # of milliseconds to delay between 784 1.5 christos * locations in delay, and the character to represent the weapon in cshow. 785 1.5 christos * Returns no value. 786 1.5 christos */ 787 1.5 christos void 788 1.18 dholland godirect(int spnum, int dam, const char *str, int delay, int cshow_i) 789 1.5 christos { 790 1.13 dholland u_char *p; 791 1.5 christos int x, y, m; 792 1.5 christos int dx, dy; 793 1.18 dholland char cshow; 794 1.18 dholland 795 1.18 dholland /* truncate to char width in case it matters */ 796 1.18 dholland cshow = (char)cshow_i; 797 1.18 dholland 798 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0 || delay < 0) 799 1.5 christos return; /* bad args */ 800 1.5 christos if (isconfuse()) 801 1.5 christos return; 802 1.5 christos dirsub(&dx, &dy); 803 1.5 christos x = dx; 804 1.5 christos y = dy; 805 1.5 christos dx = x - playerx; 806 1.5 christos dy = y - playery; 807 1.5 christos x = playerx; 808 1.5 christos y = playery; 809 1.5 christos while (dam > 0) { 810 1.5 christos x += dx; 811 1.5 christos y += dy; 812 1.5 christos if ((x > MAXX - 1) || (y > MAXY - 1) || (x < 0) || (y < 0)) { 813 1.5 christos dam = 0; 814 1.5 christos break; /* out of bounds */ 815 1.5 christos } 816 1.5 christos if ((x == playerx) && (y == playery)) { /* if energy hits player */ 817 1.5 christos cursors(); 818 1.11 mouse lprcat("\nYou are hit by your own magic!"); 819 1.5 christos beep(); 820 1.5 christos lastnum = 278; 821 1.5 christos losehp(dam); 822 1.5 christos return; 823 1.5 christos } 824 1.5 christos if (c[BLINDCOUNT] == 0) { /* if not blind show effect */ 825 1.5 christos cursor(x + 1, y + 1); 826 1.5 christos lprc(cshow); 827 1.5 christos nap(delay); 828 1.5 christos show1cell(x, y); 829 1.5 christos } 830 1.5 christos if ((m = mitem[x][y])) { /* is there a monster there? */ 831 1.5 christos ifblind(x, y); 832 1.5 christos if (nospell(spnum, m)) { 833 1.5 christos lasthx = x; 834 1.5 christos lasthy = y; 835 1.5 christos return; 836 1.1 cgd } 837 1.5 christos cursors(); 838 1.5 christos lprc('\n'); 839 1.5 christos lprintf(str, lastmonst); 840 1.5 christos dam -= hitm(x, y, dam); 841 1.5 christos show1cell(x, y); 842 1.5 christos nap(1000); 843 1.5 christos x -= dx; 844 1.5 christos y -= dy; 845 1.5 christos } else 846 1.5 christos switch (*(p = &item[x][y])) { 847 1.5 christos case OWALL: 848 1.5 christos cursors(); 849 1.5 christos lprc('\n'); 850 1.5 christos lprintf(str, "wall"); 851 1.5 christos if (dam >= 50 + c[HARDGAME]) /* enough damage? */ 852 1.5 christos if (level < MAXLEVEL + MAXVLEVEL - 1) /* not on V3 */ 853 1.5 christos if ((x < MAXX - 1) && (y < MAXY - 1) && (x) && (y)) { 854 1.1 cgd lprcat(" The wall crumbles"); 855 1.5 christos god3: *p = 0; 856 1.5 christos god: know[x][y] = 0; 857 1.5 christos show1cell(x, y); 858 1.5 christos } 859 1.5 christos god2: dam = 0; 860 1.5 christos break; 861 1.5 christos 862 1.5 christos case OCLOSEDDOOR: 863 1.5 christos cursors(); 864 1.5 christos lprc('\n'); 865 1.5 christos lprintf(str, "door"); 866 1.5 christos if (dam >= 40) { 867 1.5 christos lprcat(" The door is blasted apart"); 868 1.5 christos goto god3; 869 1.5 christos } 870 1.5 christos goto god2; 871 1.5 christos 872 1.5 christos case OSTATUE: 873 1.5 christos cursors(); 874 1.5 christos lprc('\n'); 875 1.5 christos lprintf(str, "statue"); 876 1.5 christos if (c[HARDGAME] < 3) 877 1.5 christos if (dam > 44) { 878 1.5 christos lprcat(" The statue crumbles"); 879 1.5 christos *p = OBOOK; 880 1.5 christos iarg[x][y] = level; 881 1.1 cgd goto god; 882 1.5 christos } 883 1.5 christos goto god2; 884 1.1 cgd 885 1.5 christos case OTHRONE: 886 1.5 christos cursors(); 887 1.5 christos lprc('\n'); 888 1.5 christos lprintf(str, "throne"); 889 1.5 christos if (dam > 39) { 890 1.5 christos mitem[x][y] = GNOMEKING; 891 1.5 christos hitp[x][y] = monster[GNOMEKING].hitpoints; 892 1.5 christos *p = OTHRONE2; 893 1.5 christos goto god; 894 1.5 christos } 895 1.5 christos goto god2; 896 1.5 christos 897 1.5 christos case OMIRROR: 898 1.5 christos dx *= -1; 899 1.5 christos dy *= -1; 900 1.5 christos break; 901 1.1 cgd }; 902 1.5 christos dam -= 3 + (c[HARDGAME] >> 1); 903 1.1 cgd } 904 1.5 christos } 905 1.1 cgd 906 1.1 cgd /* 907 1.5 christos * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt 908 1.5 christos * int x,y; 909 1.1 cgd * 910 1.5 christos * Subroutine to copy the word "monster" into lastmonst if the player is blind 911 1.5 christos * Enter with the coordinates (x,y) of the monster 912 1.5 christos * Returns no value. 913 1.1 cgd */ 914 1.17 dholland static void 915 1.13 dholland ifblind(int x, int y) 916 1.5 christos { 917 1.13 dholland const char *p; 918 1.13 dholland 919 1.5 christos vxy(&x, &y); /* verify correct x,y coordinates */ 920 1.5 christos if (c[BLINDCOUNT]) { 921 1.5 christos lastnum = 279; 922 1.5 christos p = "monster"; 923 1.5 christos } else { 924 1.5 christos lastnum = mitem[x][y]; 925 1.5 christos p = monster[lastnum].name; 926 1.1 cgd } 927 1.5 christos strcpy(lastmonst, p); 928 1.5 christos } 929 1.1 cgd 930 1.1 cgd /* 931 1.5 christos * tdirect(spnum) Routine to teleport away a monster 932 1.5 christos * int spnum; 933 1.1 cgd * 934 1.5 christos * Routine to ask for a direction to a spell and then teleport away monster 935 1.5 christos * Enter with the spell number that wants to teleport away 936 1.5 christos * Returns no value. 937 1.1 cgd */ 938 1.17 dholland static void 939 1.18 dholland tdirect(int spnum) 940 1.5 christos { 941 1.5 christos int x, y; 942 1.5 christos int m; 943 1.5 christos if (spnum < 0 || spnum >= SPNUM) 944 1.5 christos return; /* bad args */ 945 1.5 christos if (isconfuse()) 946 1.5 christos return; 947 1.5 christos dirsub(&x, &y); 948 1.5 christos if ((m = mitem[x][y]) == 0) { 949 1.5 christos lprcat(" There wasn't anything there!"); 950 1.5 christos return; 951 1.1 cgd } 952 1.5 christos ifblind(x, y); 953 1.5 christos if (nospell(spnum, m)) { 954 1.5 christos lasthx = x; 955 1.5 christos lasthy = y; 956 1.5 christos return; 957 1.1 cgd } 958 1.5 christos fillmonst(m); 959 1.5 christos mitem[x][y] = know[x][y] = 0; 960 1.5 christos } 961 1.5 christos 962 1.5 christos /* 963 1.5 christos * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player 964 1.5 christos * int sp,dam; 965 1.5 christos * char *str; 966 1.5 christos * 967 1.5 christos * Routine to cast a spell and then hit the monster in all directions 968 1.5 christos * Enter with the spell number in sp, the damage done to wach square in dam, 969 1.5 christos * and the lprintf string to identify the spell in str. 970 1.5 christos * Returns no value. 971 1.5 christos */ 972 1.17 dholland static void 973 1.13 dholland omnidirect(int spnum, int dam, const char *str) 974 1.5 christos { 975 1.5 christos int x, y, m; 976 1.13 dholland 977 1.5 christos if (spnum < 0 || spnum >= SPNUM || str == 0) 978 1.5 christos return; /* bad args */ 979 1.5 christos for (x = playerx - 1; x < playerx + 2; x++) 980 1.5 christos for (y = playery - 1; y < playery + 2; y++) { 981 1.6 veego if ((m = mitem[x][y]) != 0) { 982 1.5 christos if (nospell(spnum, m) == 0) { 983 1.5 christos ifblind(x, y); 984 1.5 christos cursors(); 985 1.5 christos lprc('\n'); 986 1.5 christos lprintf(str, lastmonst); 987 1.5 christos hitm(x, y, dam); 988 1.5 christos nap(800); 989 1.5 christos } else { 990 1.5 christos lasthx = x; 991 1.5 christos lasthy = y; 992 1.5 christos } 993 1.6 veego } 994 1.5 christos } 995 1.5 christos } 996 1.5 christos 997 1.5 christos /* 998 1.5 christos * static dirsub(x,y) Routine to ask for direction, then modify x,y for it 999 1.5 christos * int *x,*y; 1000 1.5 christos * 1001 1.5 christos * Function to ask for a direction and modify an x,y for that direction 1002 1.5 christos * Enter with the origination coordinates in (x,y). 1003 1.5 christos * Returns index into diroffx[] (0-8). 1004 1.1 cgd */ 1005 1.1 cgd static int 1006 1.18 dholland dirsub(int *x, int *y) 1007 1.5 christos { 1008 1.5 christos int i; 1009 1.1 cgd lprcat("\nIn What Direction? "); 1010 1.5 christos for (i = 0;;) 1011 1.16 dholland switch (ttgetch()) { 1012 1.5 christos case 'b': 1013 1.5 christos i++; 1014 1.19 mrg /* FALLTHROUGH */ 1015 1.5 christos case 'n': 1016 1.5 christos i++; 1017 1.19 mrg /* FALLTHROUGH */ 1018 1.5 christos case 'y': 1019 1.5 christos i++; 1020 1.19 mrg /* FALLTHROUGH */ 1021 1.5 christos case 'u': 1022 1.5 christos i++; 1023 1.19 mrg /* FALLTHROUGH */ 1024 1.5 christos case 'h': 1025 1.5 christos i++; 1026 1.19 mrg /* FALLTHROUGH */ 1027 1.5 christos case 'k': 1028 1.5 christos i++; 1029 1.19 mrg /* FALLTHROUGH */ 1030 1.5 christos case 'l': 1031 1.5 christos i++; 1032 1.19 mrg /* FALLTHROUGH */ 1033 1.5 christos case 'j': 1034 1.5 christos i++; 1035 1.19 mrg /* FALLTHROUGH */ 1036 1.5 christos goto out; 1037 1.5 christos }; 1038 1.1 cgd out: 1039 1.5 christos *x = playerx + diroffx[i]; 1040 1.5 christos *y = playery + diroffy[i]; 1041 1.5 christos vxy(x, y); 1042 1.5 christos return (i); 1043 1.5 christos } 1044 1.5 christos 1045 1.5 christos /* 1046 1.5 christos * vxy(x,y) Routine to verify/fix coordinates for being within bounds 1047 1.5 christos * int *x,*y; 1048 1.5 christos * 1049 1.5 christos * Function to verify x & y are within the bounds for a level 1050 1.5 christos * If *x or *y is not within the absolute bounds for a level, fix them so that 1051 1.5 christos * they are on the level. 1052 1.5 christos * Returns TRUE if it was out of bounds, and the *x & *y in the calling 1053 1.5 christos * routine are affected. 1054 1.5 christos */ 1055 1.5 christos int 1056 1.18 dholland vxy(int *x, int *y) 1057 1.5 christos { 1058 1.5 christos int flag = 0; 1059 1.5 christos if (*x < 0) { 1060 1.5 christos *x = 0; 1061 1.5 christos flag++; 1062 1.5 christos } 1063 1.5 christos if (*y < 0) { 1064 1.5 christos *y = 0; 1065 1.5 christos flag++; 1066 1.5 christos } 1067 1.5 christos if (*x >= MAXX) { 1068 1.5 christos *x = MAXX - 1; 1069 1.5 christos flag++; 1070 1.5 christos } 1071 1.5 christos if (*y >= MAXY) { 1072 1.5 christos *y = MAXY - 1; 1073 1.5 christos flag++; 1074 1.5 christos } 1075 1.5 christos return (flag); 1076 1.5 christos } 1077 1.5 christos 1078 1.5 christos /* 1079 1.5 christos * dirpoly(spnum) Routine to ask for a direction and polymorph a monst 1080 1.5 christos * int spnum; 1081 1.5 christos * 1082 1.5 christos * Subroutine to polymorph a monster and ask for the direction its in 1083 1.5 christos * Enter with the spell number in spmun. 1084 1.5 christos * Returns no value. 1085 1.5 christos */ 1086 1.17 dholland static void 1087 1.18 dholland dirpoly(int spnum) 1088 1.5 christos { 1089 1.5 christos int x, y, m; 1090 1.5 christos if (spnum < 0 || spnum >= SPNUM) 1091 1.5 christos return; /* bad args */ 1092 1.5 christos if (isconfuse()) 1093 1.5 christos return; /* if he is confused, he can't aim his magic */ 1094 1.5 christos dirsub(&x, &y); 1095 1.5 christos if (mitem[x][y] == 0) { 1096 1.5 christos lprcat(" There wasn't anything there!"); 1097 1.5 christos return; 1098 1.1 cgd } 1099 1.5 christos ifblind(x, y); 1100 1.5 christos if (nospell(spnum, mitem[x][y])) { 1101 1.5 christos lasthx = x; 1102 1.5 christos lasthy = y; 1103 1.5 christos return; 1104 1.1 cgd } 1105 1.5 christos while (monster[m = mitem[x][y] = rnd(MAXMONST + 7)].genocided); 1106 1.1 cgd hitp[x][y] = monster[m].hitpoints; 1107 1.5 christos show1cell(x, y); /* show the new monster */ 1108 1.5 christos } 1109 1.1 cgd 1110 1.1 cgd /* 1111 1.5 christos * hitmonster(x,y) Function to hit a monster at the designated coordinates 1112 1.5 christos * int x,y; 1113 1.1 cgd * 1114 1.5 christos * This routine is used for a bash & slash type attack on a monster 1115 1.5 christos * Enter with the coordinates of the monster in (x,y). 1116 1.5 christos * Returns no value. 1117 1.5 christos */ 1118 1.5 christos void 1119 1.18 dholland hitmonster(int x, int y) 1120 1.5 christos { 1121 1.5 christos int tmp, monst, damag = 0, flag; 1122 1.5 christos if (c[TIMESTOP]) 1123 1.5 christos return; /* not if time stopped */ 1124 1.5 christos vxy(&x, &y); /* verify coordinates are within range */ 1125 1.5 christos if ((monst = mitem[x][y]) == 0) 1126 1.5 christos return; 1127 1.5 christos hit3flag = 1; 1128 1.5 christos ifblind(x, y); 1129 1.5 christos tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + 1130 1.5 christos c[WCLASS] / 4 - 12; 1131 1.1 cgd cursors(); 1132 1.5 christos /* need at least random chance to hit */ 1133 1.5 christos if ((rnd(20) < tmp - c[HARDGAME]) || (rnd(71) < 5)) { 1134 1.5 christos lprcat("\nYou hit"); 1135 1.5 christos flag = 1; 1136 1.5 christos damag = fullhit(1); 1137 1.5 christos if (damag < 9999) 1138 1.5 christos damag = rnd(damag) + 1; 1139 1.5 christos } else { 1140 1.5 christos lprcat("\nYou missed"); 1141 1.5 christos flag = 0; 1142 1.5 christos } 1143 1.5 christos lprcat(" the "); 1144 1.5 christos lprcat(lastmonst); 1145 1.5 christos if (flag) /* if the monster was hit */ 1146 1.5 christos if ((monst == RUSTMONSTER) || (monst == DISENCHANTRESS) || (monst == CUBE)) 1147 1.5 christos if (c[WIELD] > 0) 1148 1.5 christos if (ivenarg[c[WIELD]] > -10) { 1149 1.5 christos lprintf("\nYour weapon is dulled by the %s", lastmonst); 1150 1.5 christos beep(); 1151 1.5 christos --ivenarg[c[WIELD]]; 1152 1.5 christos } 1153 1.5 christos if (flag) 1154 1.5 christos hitm(x, y, damag); 1155 1.5 christos if (monst == VAMPIRE) 1156 1.5 christos if (hitp[x][y] < 25) { 1157 1.5 christos mitem[x][y] = BAT; 1158 1.5 christos know[x][y] = 0; 1159 1.5 christos } 1160 1.5 christos } 1161 1.5 christos 1162 1.5 christos /* 1163 1.5 christos * hitm(x,y,amt) Function to just hit a monster at a given coordinates 1164 1.5 christos * int x,y,amt; 1165 1.5 christos * 1166 1.5 christos * Returns the number of hitpoints the monster absorbed 1167 1.5 christos * This routine is used to specifically damage a monster at a location (x,y) 1168 1.5 christos * Called by hitmonster(x,y) 1169 1.5 christos */ 1170 1.17 dholland static int 1171 1.18 dholland hitm(int x, int y, int amt) 1172 1.5 christos { 1173 1.5 christos int monst; 1174 1.5 christos int hpoints, amt2; 1175 1.5 christos vxy(&x, &y); /* verify coordinates are within range */ 1176 1.1 cgd amt2 = amt; /* save initial damage so we can return it */ 1177 1.1 cgd monst = mitem[x][y]; 1178 1.5 christos if (c[HALFDAM]) 1179 1.5 christos amt >>= 1; /* if half damage curse adjust damage points */ 1180 1.5 christos if (amt <= 0) 1181 1.5 christos amt2 = amt = 1; 1182 1.5 christos lasthx = x; 1183 1.5 christos lasthy = y; 1184 1.5 christos stealth[x][y] = 1; /* make sure hitting monst breaks stealth 1185 1.5 christos * condition */ 1186 1.5 christos c[HOLDMONST] = 0; /* hit a monster breaks hold monster spell */ 1187 1.5 christos switch (monst) { /* if a dragon and orb(s) of dragon slaying */ 1188 1.5 christos case WHITEDRAGON: 1189 1.5 christos case REDDRAGON: 1190 1.5 christos case GREENDRAGON: 1191 1.5 christos case BRONZEDRAGON: 1192 1.5 christos case PLATINUMDRAGON: 1193 1.5 christos case SILVERDRAGON: 1194 1.5 christos amt *= 1 + (c[SLAYING] << 1); 1195 1.5 christos break; 1196 1.5 christos } 1197 1.5 christos /* invincible monster fix is here */ 1198 1.1 cgd if (hitp[x][y] > monster[monst].hitpoints) 1199 1.1 cgd hitp[x][y] = monster[monst].hitpoints; 1200 1.5 christos if ((hpoints = hitp[x][y]) <= amt) { 1201 1.1 cgd #ifdef EXTRA 1202 1.1 cgd c[MONSTKILLED]++; 1203 1.1 cgd #endif 1204 1.5 christos lprintf("\nThe %s died!", lastmonst); 1205 1.5 christos raiseexperience((long) monster[monst].experience); 1206 1.5 christos amt = monster[monst].gold; 1207 1.5 christos if (amt > 0) 1208 1.5 christos dropgold(rnd(amt) + amt); 1209 1.5 christos dropsomething(monst); 1210 1.5 christos disappear(x, y); 1211 1.5 christos bottomline(); 1212 1.5 christos return (hpoints); 1213 1.5 christos } 1214 1.5 christos hitp[x][y] = hpoints - amt; 1215 1.5 christos return (amt2); 1216 1.5 christos } 1217 1.5 christos 1218 1.5 christos /* 1219 1.5 christos * hitplayer(x,y) Function for the monster to hit the player from (x,y) 1220 1.5 christos * int x,y; 1221 1.5 christos * 1222 1.5 christos * Function for the monster to hit the player with monster at location x,y 1223 1.5 christos * Returns nothing of value. 1224 1.5 christos */ 1225 1.5 christos void 1226 1.18 dholland hitplayer(int x, int y) 1227 1.5 christos { 1228 1.5 christos int dam, tmp, mster, bias; 1229 1.5 christos vxy(&x, &y); /* verify coordinates are within range */ 1230 1.5 christos lastnum = mster = mitem[x][y]; 1231 1.5 christos /* 1232 1.11 mouse * spirit nagas and poltergeists do nothing if scarab of negate 1233 1.5 christos * spirit 1234 1.5 christos */ 1235 1.5 christos if (c[NEGATESPIRIT] || c[SPIRITPRO]) 1236 1.5 christos if ((mster == POLTERGEIST) || (mster == SPIRITNAGA)) 1237 1.5 christos return; 1238 1.5 christos /* if undead and cube of undead control */ 1239 1.5 christos if (c[CUBEofUNDEAD] || c[UNDEADPRO]) 1240 1.5 christos if ((mster == VAMPIRE) || (mster == WRAITH) || (mster == ZOMBIE)) 1241 1.5 christos return; 1242 1.5 christos if ((know[x][y] & 1) == 0) { 1243 1.5 christos know[x][y] = 1; 1244 1.5 christos show1cell(x, y); 1245 1.1 cgd } 1246 1.1 cgd bias = (c[HARDGAME]) + 1; 1247 1.1 cgd hitflag = hit2flag = hit3flag = 1; 1248 1.5 christos yrepcount = 0; 1249 1.5 christos cursors(); 1250 1.5 christos ifblind(x, y); 1251 1.5 christos if (c[INVISIBILITY]) 1252 1.5 christos if (rnd(33) < 20) { 1253 1.5 christos lprintf("\nThe %s misses wildly", lastmonst); 1254 1.5 christos return; 1255 1.1 cgd } 1256 1.5 christos if (c[CHARMCOUNT]) 1257 1.5 christos if (rnd(30) + 5 * monster[mster].level - c[CHARISMA] < 30) { 1258 1.5 christos lprintf("\nThe %s is awestruck at your magnificence!", lastmonst); 1259 1.5 christos return; 1260 1.1 cgd } 1261 1.5 christos if (mster == BAT) 1262 1.5 christos dam = 1; 1263 1.5 christos else { 1264 1.1 cgd dam = monster[mster].damage; 1265 1.5 christos dam += rnd((int) ((dam < 1) ? 1 : dam)) + monster[mster].level; 1266 1.5 christos } 1267 1.1 cgd tmp = 0; 1268 1.5 christos if (monster[mster].attack > 0) 1269 1.5 christos if (((dam + bias + 8) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) { 1270 1.5 christos if (spattack(monster[mster].attack, x, y)) { 1271 1.5 christos flushall(); 1272 1.5 christos return; 1273 1.5 christos } 1274 1.5 christos tmp = 1; 1275 1.5 christos bias -= 2; 1276 1.5 christos cursors(); 1277 1.5 christos } 1278 1.5 christos if (((dam + bias) > c[AC]) || (rnd((int) ((c[AC] > 0) ? c[AC] : 1)) == 1)) { 1279 1.5 christos lprintf("\n The %s hit you ", lastmonst); 1280 1.5 christos tmp = 1; 1281 1.5 christos if ((dam -= c[AC]) < 0) 1282 1.5 christos dam = 0; 1283 1.5 christos if (dam > 0) { 1284 1.5 christos losehp(dam); 1285 1.5 christos bottomhp(); 1286 1.5 christos flushall(); 1287 1.5 christos } 1288 1.5 christos } 1289 1.5 christos if (tmp == 0) 1290 1.5 christos lprintf("\n The %s missed ", lastmonst); 1291 1.5 christos } 1292 1.5 christos 1293 1.5 christos /* 1294 1.5 christos * dropsomething(monst) Function to create an object when a monster dies 1295 1.5 christos * int monst; 1296 1.5 christos * 1297 1.5 christos * Function to create an object near the player when certain monsters are killed 1298 1.5 christos * Enter with the monster number 1299 1.5 christos * Returns nothing of value. 1300 1.1 cgd */ 1301 1.14 dholland static void 1302 1.18 dholland dropsomething(int monst) 1303 1.5 christos { 1304 1.5 christos switch (monst) { 1305 1.5 christos case ORC: 1306 1.5 christos case NYMPH: 1307 1.5 christos case ELF: 1308 1.5 christos case TROGLODYTE: 1309 1.5 christos case TROLL: 1310 1.5 christos case ROTHE: 1311 1.5 christos case VIOLETFUNGI: 1312 1.5 christos case PLATINUMDRAGON: 1313 1.5 christos case GNOMEKING: 1314 1.5 christos case REDDRAGON: 1315 1.5 christos something(level); 1316 1.5 christos return; 1317 1.1 cgd 1318 1.5 christos case LEPRECHAUN: 1319 1.5 christos if (rnd(101) >= 75) 1320 1.5 christos creategem(); 1321 1.5 christos if (rnd(5) == 1) 1322 1.5 christos dropsomething(LEPRECHAUN); 1323 1.5 christos return; 1324 1.1 cgd } 1325 1.5 christos } 1326 1.1 cgd 1327 1.1 cgd /* 1328 1.5 christos * dropgold(amount) Function to drop some gold around player 1329 1.5 christos * int amount; 1330 1.1 cgd * 1331 1.5 christos * Enter with the number of gold pieces to drop 1332 1.5 christos * Returns nothing of value. 1333 1.1 cgd */ 1334 1.5 christos void 1335 1.18 dholland dropgold(int amount) 1336 1.5 christos { 1337 1.5 christos if (amount > 250) 1338 1.5 christos createitem(OMAXGOLD, amount / 100); 1339 1.5 christos else 1340 1.5 christos createitem(OGOLDPILE, amount); 1341 1.5 christos } 1342 1.1 cgd 1343 1.1 cgd /* 1344 1.5 christos * something(level) Function to create a random item around player 1345 1.5 christos * int level; 1346 1.1 cgd * 1347 1.5 christos * Function to create an item from a designed probability around player 1348 1.5 christos * Enter with the cave level on which something is to be dropped 1349 1.5 christos * Returns nothing of value. 1350 1.1 cgd */ 1351 1.5 christos void 1352 1.13 dholland something(int cavelevel) 1353 1.5 christos { 1354 1.5 christos int j; 1355 1.5 christos int i; 1356 1.13 dholland if (cavelevel < 0 || cavelevel > MAXLEVEL + MAXVLEVEL) 1357 1.5 christos return; /* correct level? */ 1358 1.5 christos if (rnd(101) < 8) 1359 1.13 dholland something(cavelevel); /* possibly more than one item */ 1360 1.13 dholland j = newobject(cavelevel, &i); 1361 1.5 christos createitem(j, i); 1362 1.5 christos } 1363 1.5 christos 1364 1.5 christos /* 1365 1.5 christos * newobject(lev,i) Routine to return a randomly selected new object 1366 1.5 christos * int lev,*i; 1367 1.5 christos * 1368 1.5 christos * Routine to return a randomly selected object to be created 1369 1.5 christos * Returns the object number created, and sets *i for its argument 1370 1.5 christos * Enter with the cave level and a pointer to the items arg 1371 1.5 christos */ 1372 1.5 christos static char nobjtab[] = { 1373 1.5 christos 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION, OPOTION, 1374 1.5 christos OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 1375 1.5 christos OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, 1376 1.5 christos OLEATHER, OLEATHER, OLEATHER, OREGENRING, OPROTRING, 1377 1.5 christos OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT, ORING, 1378 1.5 christos OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE, 1379 1.5 christos OLONGSWORD}; 1380 1.5 christos 1381 1.5 christos int 1382 1.18 dholland newobject(int lev, int *i) 1383 1.5 christos { 1384 1.5 christos int tmp = 32, j; 1385 1.5 christos if (level < 0 || level > MAXLEVEL + MAXVLEVEL) 1386 1.5 christos return (0); /* correct level? */ 1387 1.5 christos if (lev > 6) 1388 1.5 christos tmp = 37; 1389 1.5 christos else if (lev > 4) 1390 1.5 christos tmp = 35; 1391 1.5 christos j = nobjtab[tmp = rnd(tmp)]; /* the object type */ 1392 1.5 christos switch (tmp) { 1393 1.5 christos case 1: 1394 1.5 christos case 2: 1395 1.5 christos case 3: 1396 1.5 christos case 4: 1397 1.5 christos *i = newscroll(); 1398 1.5 christos break; 1399 1.5 christos case 5: 1400 1.5 christos case 6: 1401 1.5 christos case 7: 1402 1.5 christos case 8: 1403 1.5 christos *i = newpotion(); 1404 1.5 christos break; 1405 1.5 christos case 9: 1406 1.5 christos case 10: 1407 1.5 christos case 11: 1408 1.5 christos case 12: 1409 1.5 christos *i = rnd((lev + 1) * 10) + lev * 10 + 10; 1410 1.5 christos break; 1411 1.5 christos case 13: 1412 1.5 christos case 14: 1413 1.5 christos case 15: 1414 1.5 christos case 16: 1415 1.5 christos *i = lev; 1416 1.5 christos break; 1417 1.5 christos case 17: 1418 1.5 christos case 18: 1419 1.5 christos case 19: 1420 1.5 christos if (!(*i = newdagger())) 1421 1.5 christos return (0); 1422 1.5 christos break; 1423 1.5 christos case 20: 1424 1.5 christos case 21: 1425 1.5 christos case 22: 1426 1.5 christos if (!(*i = newleather())) 1427 1.5 christos return (0); 1428 1.5 christos break; 1429 1.5 christos case 23: 1430 1.5 christos case 32: 1431 1.5 christos case 35: 1432 1.5 christos *i = rund(lev / 3 + 1); 1433 1.5 christos break; 1434 1.5 christos case 24: 1435 1.5 christos case 26: 1436 1.5 christos *i = rnd(lev / 4 + 1); 1437 1.5 christos break; 1438 1.5 christos case 25: 1439 1.5 christos *i = rund(lev / 4 + 1); 1440 1.5 christos break; 1441 1.5 christos case 27: 1442 1.5 christos *i = rnd(lev / 2 + 1); 1443 1.5 christos break; 1444 1.5 christos case 30: 1445 1.5 christos case 33: 1446 1.5 christos *i = rund(lev / 2 + 1); 1447 1.5 christos break; 1448 1.5 christos case 28: 1449 1.5 christos *i = rund(lev / 3 + 1); 1450 1.5 christos if (*i == 0) 1451 1.5 christos return (0); 1452 1.5 christos break; 1453 1.5 christos case 29: 1454 1.5 christos case 31: 1455 1.5 christos *i = rund(lev / 2 + 1); 1456 1.5 christos if (*i == 0) 1457 1.5 christos return (0); 1458 1.5 christos break; 1459 1.5 christos case 34: 1460 1.5 christos *i = newchain(); 1461 1.5 christos break; 1462 1.5 christos case 36: 1463 1.5 christos *i = newplate(); 1464 1.5 christos break; 1465 1.5 christos case 37: 1466 1.5 christos *i = newsword(); 1467 1.5 christos break; 1468 1.1 cgd } 1469 1.5 christos return (j); 1470 1.5 christos } 1471 1.1 cgd 1472 1.1 cgd /* 1473 1.5 christos * spattack(atckno,xx,yy) Function to process special attacks from monsters 1474 1.1 cgd * int atckno,xx,yy; 1475 1.1 cgd * 1476 1.5 christos * Enter with the special attack number, and the coordinates (xx,yy) 1477 1.5 christos * of the monster that is special attacking 1478 1.5 christos * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise 1479 1.1 cgd * 1480 1.1 cgd * atckno monster effect 1481 1.1 cgd * --------------------------------------------------- 1482 1.5 christos * 0 none 1483 1.5 christos * 1 rust monster eat armor 1484 1.5 christos * 2 hell hound breathe light fire 1485 1.5 christos * 3 dragon breathe fire 1486 1.5 christos * 4 giant centipede weakening sing 1487 1.5 christos * 5 white dragon cold breath 1488 1.5 christos * 6 wraith drain level 1489 1.5 christos * 7 waterlord water gusher 1490 1.5 christos * 8 leprechaun steal gold 1491 1.5 christos * 9 disenchantress disenchant weapon or armor 1492 1.5 christos * 10 ice lizard hits with barbed tail 1493 1.5 christos * 11 umber hulk confusion 1494 1.5 christos * 12 spirit naga cast spells taken from special attacks 1495 1.5 christos * 13 platinum dragon psionics 1496 1.5 christos * 14 nymph steal objects 1497 1.5 christos * 15 bugbear bite 1498 1.5 christos * 16 osequip bite 1499 1.5 christos * 1500 1.5 christos * char rustarm[ARMORTYPES][2]; 1501 1.5 christos * special array for maximum rust damage to armor from rustmonster 1502 1.5 christos * format is: { armor type , minimum attribute 1503 1.1 cgd */ 1504 1.1 cgd #define ARMORTYPES 6 1505 1.5 christos static char rustarm[ARMORTYPES][2] = { 1506 1.5 christos { OSTUDLEATHER, -2 }, 1507 1.5 christos { ORING, -4 }, 1508 1.5 christos { OCHAIN, -5 }, 1509 1.5 christos { OSPLINT, -6 }, 1510 1.5 christos { OPLATE, -8 }, 1511 1.5 christos { OPLATEARMOR, -9} 1512 1.5 christos }; 1513 1.5 christos static char spsel[] = {1, 2, 3, 5, 6, 8, 9, 11, 13, 14}; 1514 1.14 dholland static int 1515 1.18 dholland spattack(int x, int xx, int yy) 1516 1.5 christos { 1517 1.5 christos int i, j = 0, k, m; 1518 1.13 dholland const char *p = NULL; 1519 1.13 dholland 1520 1.5 christos if (c[CANCELLATION]) 1521 1.5 christos return (0); 1522 1.5 christos vxy(&xx, &yy); /* verify x & y coordinates */ 1523 1.5 christos switch (x) { 1524 1.5 christos case 1: /* rust your armor, j=1 when rusting has occurred */ 1525 1.5 christos m = k = c[WEAR]; 1526 1.6 veego if ((i = c[SHIELD]) != -1) { 1527 1.5 christos if (--ivenarg[i] < -1) 1528 1.5 christos ivenarg[i] = -1; 1529 1.5 christos else 1530 1.5 christos j = 1; 1531 1.6 veego } 1532 1.5 christos if ((j == 0) && (k != -1)) { 1533 1.5 christos m = iven[k]; 1534 1.5 christos for (i = 0; i < ARMORTYPES; i++) 1535 1.5 christos /* find his armor in table */ 1536 1.5 christos if (m == rustarm[i][0]) { 1537 1.5 christos if (--ivenarg[k] < rustarm[i][1]) 1538 1.5 christos ivenarg[k] = rustarm[i][1]; 1539 1.5 christos else 1540 1.5 christos j = 1; 1541 1.5 christos break; 1542 1.5 christos } 1543 1.5 christos } 1544 1.5 christos if (j == 0) /* if rusting did not occur */ 1545 1.5 christos switch (m) { 1546 1.5 christos case OLEATHER: 1547 1.11 mouse p = "\nThe %s hit you -- You're lucky you have leather on"; 1548 1.1 cgd break; 1549 1.5 christos case OSSPLATE: 1550 1.11 mouse p = "\nThe %s hit you -- You're fortunate to have stainless steel armor!"; 1551 1.1 cgd break; 1552 1.5 christos } 1553 1.5 christos else { 1554 1.5 christos beep(); 1555 1.5 christos p = "\nThe %s hit you -- your armor feels weaker"; 1556 1.5 christos } 1557 1.5 christos break; 1558 1.5 christos 1559 1.5 christos case 2: 1560 1.5 christos i = rnd(15) + 8 - c[AC]; 1561 1.5 christos spout: p = "\nThe %s breathes fire at you!"; 1562 1.5 christos if (c[FIRERESISTANCE]) 1563 1.11 mouse p = "\nThe %s's flame doesn't faze you!"; 1564 1.5 christos else 1565 1.5 christos spout2: if (p) { 1566 1.5 christos lprintf(p, lastmonst); 1567 1.5 christos beep(); 1568 1.5 christos } 1569 1.5 christos checkloss(i); 1570 1.5 christos return (0); 1571 1.5 christos 1572 1.5 christos case 3: 1573 1.5 christos i = rnd(20) + 25 - c[AC]; 1574 1.5 christos goto spout; 1575 1.5 christos 1576 1.5 christos case 4: 1577 1.5 christos if (c[STRENGTH] > 3) { 1578 1.5 christos p = "\nThe %s stung you! You feel weaker"; 1579 1.5 christos beep(); 1580 1.5 christos --c[STRENGTH]; 1581 1.5 christos } else 1582 1.5 christos p = "\nThe %s stung you!"; 1583 1.5 christos break; 1584 1.5 christos 1585 1.5 christos case 5: 1586 1.5 christos p = "\nThe %s blasts you with his cold breath"; 1587 1.5 christos i = rnd(15) + 18 - c[AC]; 1588 1.5 christos goto spout2; 1589 1.5 christos 1590 1.5 christos case 6: 1591 1.5 christos lprintf("\nThe %s drains you of your life energy!", lastmonst); 1592 1.5 christos loselevel(); 1593 1.5 christos beep(); 1594 1.5 christos return (0); 1595 1.5 christos 1596 1.5 christos case 7: 1597 1.5 christos p = "\nThe %s got you with a gusher!"; 1598 1.5 christos i = rnd(15) + 25 - c[AC]; 1599 1.5 christos goto spout2; 1600 1.5 christos 1601 1.5 christos case 8: 1602 1.5 christos if (c[NOTHEFT]) 1603 1.5 christos return (0); /* he has a device of no theft */ 1604 1.5 christos if (c[GOLD]) { 1605 1.5 christos p = "\nThe %s hit you -- Your purse feels lighter"; 1606 1.5 christos if (c[GOLD] > 32767) 1607 1.5 christos c[GOLD] >>= 1; 1608 1.5 christos else 1609 1.5 christos c[GOLD] -= rnd((int) (1 + (c[GOLD] >> 1))); 1610 1.5 christos if (c[GOLD] < 0) 1611 1.5 christos c[GOLD] = 0; 1612 1.5 christos } else 1613 1.5 christos p = "\nThe %s couldn't find any gold to steal"; 1614 1.5 christos lprintf(p, lastmonst); 1615 1.5 christos disappear(xx, yy); 1616 1.5 christos beep(); 1617 1.5 christos bottomgold(); 1618 1.5 christos return (1); 1619 1.5 christos 1620 1.5 christos case 9: 1621 1.5 christos for (j = 50;;) {/* disenchant */ 1622 1.5 christos i = rund(26); 1623 1.5 christos m = iven[i]; /* randomly select item */ 1624 1.5 christos if (m > 0 && ivenarg[i] > 0 && m != OSCROLL && m != OPOTION) { 1625 1.5 christos if ((ivenarg[i] -= 3) < 0) 1626 1.5 christos ivenarg[i] = 0; 1627 1.5 christos lprintf("\nThe %s hits you -- you feel a sense of loss", lastmonst); 1628 1.5 christos srcount = 0; 1629 1.5 christos beep(); 1630 1.5 christos show3(i); 1631 1.5 christos bottomline(); 1632 1.5 christos return (0); 1633 1.5 christos } 1634 1.5 christos if (--j <= 0) { 1635 1.5 christos p = "\nThe %s nearly misses"; 1636 1.1 cgd break; 1637 1.5 christos } 1638 1.5 christos break; 1639 1.5 christos } 1640 1.5 christos break; 1641 1.1 cgd 1642 1.5 christos case 10: 1643 1.5 christos p = "\nThe %s hit you with his barbed tail"; 1644 1.5 christos i = rnd(25) - c[AC]; 1645 1.5 christos goto spout2; 1646 1.5 christos 1647 1.5 christos case 11: 1648 1.5 christos p = "\nThe %s has confused you"; 1649 1.5 christos beep(); 1650 1.5 christos c[CONFUSE] += 10 + rnd(10); 1651 1.5 christos break; 1652 1.5 christos 1653 1.5 christos case 12: /* performs any number of other special 1654 1.5 christos * attacks */ 1655 1.5 christos return (spattack(spsel[rund(10)], xx, yy)); 1656 1.5 christos 1657 1.5 christos case 13: 1658 1.5 christos p = "\nThe %s flattens you with his psionics!"; 1659 1.5 christos i = rnd(15) + 30 - c[AC]; 1660 1.5 christos goto spout2; 1661 1.5 christos 1662 1.5 christos case 14: 1663 1.5 christos if (c[NOTHEFT]) 1664 1.5 christos return (0); /* he has device of no theft */ 1665 1.5 christos if (emptyhanded() == 1) { 1666 1.5 christos p = "\nThe %s couldn't find anything to steal"; 1667 1.5 christos break; 1668 1.5 christos } 1669 1.5 christos lprintf("\nThe %s picks your pocket and takes:", lastmonst); 1670 1.5 christos beep(); 1671 1.5 christos if (stealsomething() == 0) 1672 1.5 christos lprcat(" nothing"); 1673 1.5 christos disappear(xx, yy); 1674 1.5 christos bottomline(); 1675 1.5 christos return (1); 1676 1.5 christos 1677 1.5 christos case 15: 1678 1.5 christos i = rnd(10) + 5 - c[AC]; 1679 1.5 christos spout3: p = "\nThe %s bit you!"; 1680 1.5 christos goto spout2; 1681 1.5 christos 1682 1.5 christos case 16: 1683 1.5 christos i = rnd(15) + 10 - c[AC]; 1684 1.5 christos goto spout3; 1685 1.5 christos }; 1686 1.5 christos if (p) { 1687 1.5 christos lprintf(p, lastmonst); 1688 1.5 christos bottomline(); 1689 1.1 cgd } 1690 1.5 christos return (0); 1691 1.5 christos } 1692 1.1 cgd 1693 1.1 cgd /* 1694 1.5 christos * checkloss(x) Routine to subtract hp from user and flag bottomline display 1695 1.5 christos * int x; 1696 1.1 cgd * 1697 1.5 christos * Routine to subtract hitpoints from the user and flag the bottomline display 1698 1.5 christos * Enter with the number of hit points to lose 1699 1.5 christos * Note: if x > c[HP] this routine could kill the player! 1700 1.1 cgd */ 1701 1.5 christos void 1702 1.18 dholland checkloss(int x) 1703 1.5 christos { 1704 1.5 christos if (x > 0) { 1705 1.5 christos losehp(x); 1706 1.5 christos bottomhp(); 1707 1.1 cgd } 1708 1.5 christos } 1709 1.1 cgd 1710 1.1 cgd /* 1711 1.5 christos * annihilate() Routine to annihilate all monsters around player (playerx,playery) 1712 1.1 cgd * 1713 1.5 christos * Gives player experience, but no dropped objects 1714 1.5 christos * Returns the experience gained from all monsters killed 1715 1.1 cgd */ 1716 1.5 christos int 1717 1.18 dholland annihilate(void) 1718 1.5 christos { 1719 1.5 christos int i, j; 1720 1.5 christos long k; 1721 1.5 christos u_char *p; 1722 1.5 christos for (k = 0, i = playerx - 1; i <= playerx + 1; i++) 1723 1.5 christos for (j = playery - 1; j <= playery + 1; j++) 1724 1.6 veego if (!vxy(&i, &j)) { /* if not out of bounds */ 1725 1.6 veego if (*(p = &mitem[i][j])) { /* if a monster there */ 1726 1.5 christos if (*p < DEMONLORD + 2) { 1727 1.5 christos k += monster[*p].experience; 1728 1.5 christos *p = know[i][j] = 0; 1729 1.5 christos } else { 1730 1.5 christos lprintf("\nThe %s barely escapes being annihilated!", monster[*p].name); 1731 1.5 christos hitp[i][j] = (hitp[i][j] >> 1) + 1; /* lose half hit points */ 1732 1.1 cgd } 1733 1.6 veego } 1734 1.6 veego } 1735 1.5 christos if (k > 0) { 1736 1.5 christos lprcat("\nYou hear loud screams of agony!"); 1737 1.5 christos raiseexperience((long) k); 1738 1.5 christos } 1739 1.5 christos return (k); 1740 1.5 christos } 1741 1.5 christos 1742 1.5 christos /* 1743 1.5 christos * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation 1744 1.5 christos * int x,y,dir,lifetime; 1745 1.5 christos * 1746 1.5 christos * Enter with the coordinates of the sphere in x,y 1747 1.5 christos * the direction (0-8 diroffx format) in dir, and the lifespan of the 1748 1.5 christos * sphere in lifetime (in turns) 1749 1.5 christos * Returns the number of spheres currently in existence 1750 1.5 christos */ 1751 1.5 christos int 1752 1.18 dholland newsphere(int x, int y, int dir, int life) 1753 1.5 christos { 1754 1.5 christos int m; 1755 1.5 christos struct sphere *sp; 1756 1.5 christos if (((sp = (struct sphere *) malloc(sizeof(struct sphere)))) == 0) 1757 1.5 christos return (c[SPHCAST]); /* can't malloc, therefore failure */ 1758 1.5 christos if (dir >= 9) 1759 1.5 christos dir = 0; /* no movement if direction not found */ 1760 1.5 christos if (level == 0) 1761 1.5 christos vxy(&x, &y); /* don't go out of bounds */ 1762 1.5 christos else { 1763 1.5 christos if (x < 1) 1764 1.5 christos x = 1; 1765 1.5 christos if (x >= MAXX - 1) 1766 1.5 christos x = MAXX - 2; 1767 1.5 christos if (y < 1) 1768 1.5 christos y = 1; 1769 1.5 christos if (y >= MAXY - 1) 1770 1.5 christos y = MAXY - 2; 1771 1.5 christos } 1772 1.5 christos if ((m = mitem[x][y]) >= DEMONLORD + 4) { /* demons dispel spheres */ 1773 1.5 christos know[x][y] = 1; 1774 1.5 christos show1cell(x, y);/* show the demon (ha ha) */ 1775 1.5 christos cursors(); 1776 1.5 christos lprintf("\nThe %s dispels the sphere!", monster[m].name); 1777 1.5 christos beep(); 1778 1.5 christos rmsphere(x, y); /* remove any spheres that are here */ 1779 1.10 christos free(sp); 1780 1.5 christos return (c[SPHCAST]); 1781 1.5 christos } 1782 1.5 christos if (m == DISENCHANTRESS) { /* disenchantress cancels spheres */ 1783 1.5 christos cursors(); 1784 1.5 christos lprintf("\nThe %s causes cancellation of the sphere!", monster[m].name); 1785 1.5 christos beep(); 1786 1.5 christos boom: sphboom(x, y); /* blow up stuff around sphere */ 1787 1.5 christos rmsphere(x, y); /* remove any spheres that are here */ 1788 1.10 christos free(sp); 1789 1.5 christos return (c[SPHCAST]); 1790 1.1 cgd } 1791 1.5 christos if (c[CANCELLATION]) { /* cancellation cancels spheres */ 1792 1.5 christos cursors(); 1793 1.5 christos lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); 1794 1.5 christos beep(); 1795 1.1 cgd goto boom; 1796 1.5 christos } 1797 1.5 christos if (item[x][y] == OANNIHILATION) { /* collision of spheres 1798 1.5 christos * detonates spheres */ 1799 1.5 christos cursors(); 1800 1.5 christos lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); 1801 1.5 christos beep(); 1802 1.5 christos rmsphere(x, y); 1803 1.1 cgd goto boom; 1804 1.5 christos } 1805 1.5 christos if (playerx == x && playery == y) { /* collision of sphere and 1806 1.5 christos * player! */ 1807 1.1 cgd cursors(); 1808 1.1 cgd lprcat("\nYou have been enveloped by the zone of nothingness!\n"); 1809 1.5 christos beep(); 1810 1.5 christos rmsphere(x, y); /* remove any spheres that are here */ 1811 1.5 christos nap(4000); 1812 1.5 christos died(258); 1813 1.5 christos } 1814 1.5 christos item[x][y] = OANNIHILATION; 1815 1.5 christos mitem[x][y] = 0; 1816 1.5 christos know[x][y] = 1; 1817 1.5 christos show1cell(x, y); /* show the new sphere */ 1818 1.5 christos sp->x = x; 1819 1.5 christos sp->y = y; 1820 1.5 christos sp->lev = level; 1821 1.5 christos sp->dir = dir; 1822 1.5 christos sp->lifetime = life; 1823 1.5 christos sp->p = 0; 1824 1.5 christos if (spheres == 0) 1825 1.5 christos spheres = sp; /* if first node in the sphere list */ 1826 1.5 christos else { /* add sphere to beginning of linked list */ 1827 1.5 christos sp->p = spheres; 1828 1.5 christos spheres = sp; 1829 1.5 christos } 1830 1.5 christos return (++c[SPHCAST]); /* one more sphere in the world */ 1831 1.5 christos } 1832 1.5 christos 1833 1.5 christos /* 1834 1.5 christos * rmsphere(x,y) Function to delete a sphere of annihilation from list 1835 1.5 christos * int x,y; 1836 1.5 christos * 1837 1.5 christos * Enter with the coordinates of the sphere (on current level) 1838 1.5 christos * Returns the number of spheres currently in existence 1839 1.5 christos */ 1840 1.5 christos int 1841 1.18 dholland rmsphere(int x, int y) 1842 1.5 christos { 1843 1.5 christos struct sphere *sp, *sp2 = 0; 1844 1.5 christos for (sp = spheres; sp; sp2 = sp, sp = sp->p) 1845 1.5 christos if (level == sp->lev) /* is sphere on this level? */ 1846 1.5 christos if ((x == sp->x) && (y == sp->y)) { /* locate sphere at this 1847 1.5 christos * location */ 1848 1.5 christos item[x][y] = mitem[x][y] = 0; 1849 1.5 christos know[x][y] = 1; 1850 1.5 christos show1cell(x, y); /* show the now missing 1851 1.5 christos * sphere */ 1852 1.5 christos --c[SPHCAST]; 1853 1.5 christos if (sp == spheres) { 1854 1.5 christos sp2 = sp; 1855 1.5 christos spheres = sp->p; 1856 1.5 christos free((char *) sp2); 1857 1.5 christos } else { 1858 1.9 christos if (sp2) 1859 1.9 christos sp2->p = sp->p; 1860 1.5 christos free((char *) sp); 1861 1.5 christos } 1862 1.5 christos break; 1863 1.1 cgd } 1864 1.5 christos return (c[SPHCAST]); /* return number of spheres in the world */ 1865 1.5 christos } 1866 1.1 cgd 1867 1.1 cgd /* 1868 1.5 christos * sphboom(x,y) Function to perform the effects of a sphere detonation 1869 1.5 christos * int x,y; 1870 1.1 cgd * 1871 1.5 christos * Enter with the coordinates of the blast, Returns no value 1872 1.1 cgd */ 1873 1.17 dholland static void 1874 1.18 dholland sphboom(int x, int y) 1875 1.5 christos { 1876 1.5 christos int i, j; 1877 1.5 christos if (c[HOLDMONST]) 1878 1.5 christos c[HOLDMONST] = 1; 1879 1.5 christos if (c[CANCELLATION]) 1880 1.5 christos c[CANCELLATION] = 1; 1881 1.5 christos for (j = max(1, x - 2); j < min(x + 3, MAXX - 1); j++) 1882 1.5 christos for (i = max(1, y - 2); i < min(y + 3, MAXY - 1); i++) { 1883 1.5 christos item[j][i] = mitem[j][i] = 0; 1884 1.5 christos show1cell(j, i); 1885 1.5 christos if (playerx == j && playery == i) { 1886 1.5 christos cursors(); 1887 1.5 christos beep(); 1888 1.5 christos lprcat("\nYou were too close to the sphere!"); 1889 1.5 christos nap(3000); 1890 1.5 christos died(283); /* player killed in explosion */ 1891 1.1 cgd } 1892 1.1 cgd } 1893 1.5 christos } 1894 1.1 cgd 1895 1.1 cgd /* 1896 1.5 christos * genmonst() Function to ask for monster and genocide from game 1897 1.1 cgd * 1898 1.5 christos * This is done by setting a flag in the monster[] structure 1899 1.1 cgd */ 1900 1.17 dholland static void 1901 1.18 dholland genmonst(void) 1902 1.5 christos { 1903 1.5 christos int i, j; 1904 1.5 christos cursors(); 1905 1.5 christos lprcat("\nGenocide what monster? "); 1906 1.16 dholland for (i = 0; (!isalpha(i)) && (i != ' '); i = ttgetch()); 1907 1.1 cgd lprc(i); 1908 1.5 christos for (j = 0; j < MAXMONST; j++) /* search for the monster type */ 1909 1.5 christos if (monstnamelist[j] == i) { /* have we found it? */ 1910 1.5 christos monster[j].genocided = 1; /* genocided from game */ 1911 1.5 christos lprintf(" There will be no more %s's", monster[j].name); 1912 1.1 cgd /* now wipe out monsters on this level */ 1913 1.5 christos newcavelevel(level); 1914 1.5 christos draws(0, MAXX, 0, MAXY); 1915 1.5 christos bot_linex(); 1916 1.1 cgd return; 1917 1.5 christos } 1918 1.1 cgd lprcat(" You sense failure!"); 1919 1.5 christos } 1920