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