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