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