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