1 /* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
2 /* aux1.c */
3 /* auxiliary functions for those in com.c, also see aux2.c and aux3.c */
4 
5 #include "glob.h"
6 
7 
8 
9 /* check to see if too much tunneling has been done in this level */
tunnelcheck()10 void tunnelcheck()
11 {
12   if ((Level->depth == 0 && Current_Environment != E_DLAIR) ||
13       Current_Environment == E_ASTRAL)
14     return;
15   Level->tunnelled++;
16   if ((Level->tunnelled) > LENGTH/4)
17     mprint("Dust and stone fragments fall on you from overhead.");
18   if ((Level->tunnelled) > LENGTH/2)
19     mprint("You hear groaning and creaking noises.");
20   if ((Level->tunnelled) > 3*LENGTH/4)
21     mprint("The floor trembles and you hear a loud grinding screech.");
22   if ((Level->tunnelled) > LENGTH) {
23     mprint("With a scream of tortured stone, the entire dungeon caves in!!!");
24     gain_experience(5000);
25     if (Player.status[SHADOWFORM]) {
26       change_environment(E_COUNTRYSIDE);
27       switch (Country[Player.x][Player.y].base_terrain_type)
28       {
29 	case CASTLE:
30 	case STARPEAK:
31 	case CAVES:
32 	case VOLCANO:
33 	  Country[Player.x][Player.y].current_terrain_type = MOUNTAINS;
34 	  break;
35 	case DRAGONLAIR:
36 	  Country[Player.x][Player.y].current_terrain_type = DESERT;
37 	  break;
38 	case MAGIC_ISLE:
39 	  Country[Player.x][Player.y].current_terrain_type = CHAOS_SEA;
40 	  break;
41       }
42       Country[Player.x][Player.y].base_terrain_type =
43 	  Country[Player.x][Player.y].current_terrain_type;
44       c_set(Player.x, Player.y, CHANGED);
45       print1("In your shadowy state, you float back up to the surface.");
46       return;
47     }
48     mprint("You are flattened into an unpleasant jellylike substance.");
49     p_death("dungeon cave-in");
50   }
51 }
52 
53 /* displays a room's name */
showroom(i)54 void showroom(i)
55 int i;
56 {
57   strcpy(Str1,"");
58   strcpy(Str2,"");
59   switch(Current_Environment) {
60     case E_MANSION:
61       strcpy(Str2,"A luxurious mansion: ");
62       break;
63     case E_HOUSE:
64       strcpy(Str2,"A house: ");
65       break;
66     case E_HOVEL:
67       strcpy(Str2,"A hovel: ");
68       break;
69     case E_CITY:
70       strcpy(Str2,"The City of Rampart");
71       break;
72     case E_VILLAGE:
73       switch(Villagenum) {
74       case 1: strcpy(Str2,"The Village of Star View"); break;
75       case 2: strcpy(Str2,"The Village of Woodmere"); break;
76       case 3: strcpy(Str2,"The Village of Stormwatch"); break;
77       case 4: strcpy(Str2,"The Village of Thaumaris"); break;
78       case 5: strcpy(Str2,"The Village of Skorch"); break;
79       case 6: strcpy(Str2,"The Village of Whorfen"); break;
80       }
81       break;
82     case E_CAVES:
83       strcpy(Str2,"The Goblin Caves: ");
84       break;
85     case E_CASTLE:
86       strcpy(Str2,"The Archmage's Castle: ");
87       break;
88     case E_ASTRAL:
89       strcpy(Str2,"The Astral Plane: ");
90       break;
91     case E_VOLCANO:
92       strcpy(Str2,"The Volcano: ");
93       break;
94     case E_SEWERS:
95       strcpy(Str2,"The Sewers: ");
96       break;
97     case E_TACTICAL_MAP:
98       strcpy(Str2,"The Tactical Map ");
99       break;
100     default:
101       strcpy(Str2,"");
102       break;
103   }
104   if (Current_Environment == Current_Dungeon) {
105     strcpy(Str1,"Level ");
106     if (Level->depth < 10) {
107       Str1[6] = Level->depth + '0';
108       Str1[7] = 0;
109     }
110     else {
111       Str1[6] = (Level->depth / 10) + '0';
112       Str1[7] = (Level->depth % 10) + '0';
113       Str1[8] = 0;
114     }
115     strcat(Str1," (");
116     strcat(Str1,roomname(i));
117     strcat(Str1,")");
118   }
119   else if (strlen(Str2) == 0 || Current_Environment == E_MANSION ||
120       Current_Environment == E_HOUSE || Current_Environment == E_HOVEL)
121     strcpy(Str1,roomname(i));
122   strcat(Str2,Str1);
123   locprint(Str2);
124 }
125 
126 
player_on_sanctuary()127 int player_on_sanctuary()
128 {
129   if ((Player.x==Player.sx) &&
130       (Player.y==Player.sy))
131     return(TRUE);
132   else {
133     if (Player.patron) {
134       if ((Level->site[Player.x][Player.y].locchar == ALTAR) &&
135 	  (Level->site[Player.x][Player.y].aux == Player.patron))
136 	return(TRUE);
137       else return(FALSE);
138     }
139     else return(FALSE);
140   }
141 }
142 
143 
144 /* check a move attempt, maybe attack something, return TRUE if ok to move. */
145 /* x y is the proposed place to move to */
p_moveable(x,y)146 int p_moveable(x,y)
147 int x,y;
148 {
149   setgamestatus(SKIP_MONSTERS);
150   if (! inbounds(x,y)) return (FALSE);
151   else if (Player.status[SHADOWFORM]) {
152     switch(Level->site[x][y].p_locf) {
153       case L_CHAOS: case L_ABYSS: case L_VOID:
154 	return confirmation();
155       default:
156 	resetgamestatus(SKIP_MONSTERS);
157 	return(TRUE);
158     }
159   }
160   else if (loc_statusp(x,y,SECRET)) {
161     if (!gamestatusp(FAST_MOVE)) print3("Ouch!");
162     return(FALSE);
163   }
164   else if (Level->site[x][y].creature != NULL) {
165     if (! gamestatusp(FAST_MOVE)) {
166       fight_monster(Level->site[x][y].creature);
167       resetgamestatus(SKIP_MONSTERS);
168       return(FALSE);
169     }
170     else return(FALSE);
171   }
172   else if ((Level->site[x][y].locchar == WALL) ||
173 	   (Level->site[x][y].locchar == STATUE) ||
174 	   (Level->site[x][y].locchar == PORTCULLIS) ||
175 	   (Level->site[x][y].locchar == CLOSED_DOOR) ||
176 	   (gamestatusp(FAST_MOVE) &&
177 	    ((Level->site[x][y].locchar == HEDGE) ||
178 	     (Level->site[x][y].locchar == LAVA) ||
179 	     (Level->site[x][y].locchar == ABYSS) ||
180 	     (Level->site[x][y].locchar == VOID_CHAR) ||
181 	     (Level->site[x][y].locchar == FIRE) ||
182 	     (Level->site[x][y].locchar == WHIRLWIND) ||
183 	     (Level->site[x][y].locchar == WATER) ||
184 	     (Level->site[x][y].locchar == LIFT) ||
185 	     (Level->site[x][y].locchar == TRAP)))) {
186     if (! gamestatusp(FAST_MOVE)) print3("Ouch!");
187     return(FALSE);
188   }
189   else if (optionp(CONFIRM)) {
190     if ((Level->site[x][y].locchar == HEDGE) ||
191 	(Level->site[x][y].locchar == LAVA) ||
192 	(Level->site[x][y].locchar == FIRE) ||
193 	(Level->site[x][y].locchar == WHIRLWIND) ||
194 	(Level->site[x][y].locchar == ABYSS) ||
195 	(Level->site[x][y].locchar == VOID_CHAR) ||
196 	(Level->site[x][y].locchar == WATER) ||
197 	(Level->site[x][y].locchar == RUBBLE) ||
198 	(Level->site[x][y].locchar == LIFT) ||
199 	(Level->site[x][y].locchar == TRAP)) {
200       /* horses WILL go into water... */
201       if (gamestatusp(MOUNTED)) {
202 	if (Level->site[x][y].locchar != WATER ||
203 	  Level->site[x][y].p_locf != L_WATER) {
204 	  print1("You can't convince your steed to continue.");
205 	  setgamestatus(SKIP_MONSTERS);
206 	  return(FALSE);
207 	}
208 	else return(TRUE);
209       }
210       else if (confirmation()) resetgamestatus(SKIP_MONSTERS);
211       else setgamestatus(SKIP_MONSTERS);
212       return(!gamestatusp(SKIP_MONSTERS));
213     }
214     else {
215       resetgamestatus(SKIP_MONSTERS);
216       return(TRUE);
217     }
218   }
219   else {
220     resetgamestatus(SKIP_MONSTERS);
221     return(TRUE);
222   }
223 }
224 
225 
226 
227 /* check a move attempt in the countryside */
p_country_moveable(x,y)228 int p_country_moveable(x,y)
229 int x,y;
230 {
231   if (! inbounds(x,y)) return (FALSE);
232   else if (optionp(CONFIRM)) {
233     if ((Country[x][y].current_terrain_type == CHAOS_SEA) ||
234 	(Country[x][y].current_terrain_type == MOUNTAINS))
235       return(confirmation());
236     else return(TRUE);
237   }
238   else return(TRUE);
239 }
240 
241 
242 
243 
244 
245 /* search once particular spot */
searchat(x,y)246 void searchat(x,y)
247 int x,y;
248 {
249   int i;
250   if (inbounds(x,y) && (random_range(3) || Player.status[ALERT])) {
251     if (loc_statusp(x,y,SECRET)) {
252       lreset(x,y,SECRET);
253       lset(x, y, CHANGED);
254       if ((Level->site[x][y].locchar==OPEN_DOOR) ||
255 	  (Level->site[x][y].locchar==CLOSED_DOOR)) {
256 	mprint("You find a secret door!");
257 	for(i=0;i<=8;i++) { /* FIXED! 12/25/98 */
258 	  lset(x+Dirs[0][i],y+Dirs[1][i],STOPS);
259 	  lset(x+Dirs[0][i], y+Dirs[1][i], CHANGED);
260 	}
261       }
262       else mprint("You find a secret passage!");
263       drawvision(Player.x,Player.y);
264     }
265     if ((Level->site[x][y].p_locf >= TRAP_BASE) &&
266 	(Level->site[x][y].locchar != TRAP) &&
267 	(Level->site[x][y].p_locf <= TRAP_BASE+NUMTRAPS)) {
268       Level->site[x][y].locchar = TRAP;
269       lset(x, y, CHANGED);
270       mprint("You find a trap!");
271       drawvision(Player.x,Player.y);
272       resetgamestatus(FAST_MOVE);
273     }
274   }
275 }
276 
277 
278 
279 /* This is to be called whenever anything might change player performance in
280    melee, such as changing weapon, statistics, etc. */
calc_melee()281 void calc_melee()
282 {
283   calc_weight();
284 
285   Player.maxweight = (Player.str * Player.agi * 10);
286   Player.absorption = Player.status[PROTECTION];
287   Player.defense = 2 * statmod(Player.agi)+(Player.level/2);
288   Player.hit = Player.level + statmod(Player.dex)+1;
289   Player.dmg = statmod(Player.str)+3;
290   Player.speed = 5 - min(4,(statmod(Player.agi)/2));
291   if (Player.status[HASTED] > 0) Player.speed = Player.speed / 2;
292   if (Player.status[SLOWED] > 0) Player.speed = Player.speed * 2;
293   if (Player.itemweight > 0)
294     switch(Player.maxweight / Player.itemweight) {
295     case 0: Player.speed+=6; break;
296     case 1: Player.speed+=3; break;
297     case 2: Player.speed+=2; break;
298     case 3: Player.speed+=1; break;
299     }
300 
301   if (Player.status[ACCURATE]) Player.hit+=20;
302   if (Player.status[HERO]) Player.hit+=Player.dex;
303   if (Player.status[HERO]) Player.dmg+=Player.str;
304   if (Player.status[HERO]) Player.defense+=Player.agi;
305   if (Player.status[HERO]) Player.speed=Player.speed / 2;
306 
307   Player.speed = max(1,min(25,Player.speed));
308 
309   if (gamestatusp(MOUNTED)) {
310     Player.speed = 3;
311     Player.hit += 10;
312     Player.dmg += 10;
313   }
314 
315   /* weapon */
316   /* have to check for used since it could be a 2h weapon just carried
317      in one hand */
318   if (Player.possessions[O_WEAPON_HAND] != NULL)
319     if (Player.possessions[O_WEAPON_HAND]->used &&
320 	((Player.possessions[O_WEAPON_HAND]->objchar==WEAPON)||
321 	 (Player.possessions[O_WEAPON_HAND]->objchar==MISSILEWEAPON))) {
322       Player.hit +=
323 	Player.possessions[O_WEAPON_HAND]->hit +
324 	  Player.possessions[O_WEAPON_HAND]->plus;
325       Player.dmg +=
326 	Player.possessions[O_WEAPON_HAND]->dmg +
327 	  Player.possessions[O_WEAPON_HAND]->plus;
328     }
329 
330   /* shield or defensive weapon */
331   if (Player.possessions[O_SHIELD] != NULL) {
332     Player.defense +=
333       Player.possessions[O_SHIELD]->aux +
334 	Player.possessions[O_SHIELD]->plus;
335   }
336 
337   /* armor */
338   if (Player.possessions[O_ARMOR] != NULL) {
339     Player.absorption += Player.possessions[O_ARMOR]->dmg;
340     Player.defense +=
341       Player.possessions[O_ARMOR]->plus -
342 	Player.possessions[O_ARMOR]->aux;
343   }
344 
345   if (strlen(Player.meleestr) > 2*maneuvers())
346     default_maneuvers();
347   comwinprint();
348   showflags();
349   dataprint();
350 }
351 
352 
353 /* player attacks monster m */
fight_monster(m)354 void fight_monster(m)
355 struct monster *m;
356 {
357   int hitmod = 0;
358   int reallyfight = TRUE;
359 
360   if (Player.status[AFRAID]) {
361     print3("You are much too afraid to fight!");
362     reallyfight = FALSE;
363   }
364   else if (player_on_sanctuary()) {
365     print3("You restrain yourself from desecrating this holy place.");
366     reallyfight = FALSE;
367   }
368   else if (Player.status[SHADOWFORM]) {
369     print3("Your attack has no effect in your shadowy state.");
370     reallyfight = FALSE;
371   }
372   else if ((Player.status[BERSERK]<1) && (! m_statusp(m,HOSTILE))) {
373     if (optionp(BELLICOSE)) reallyfight = TRUE;
374     else reallyfight = confirmation();
375   }
376   else reallyfight = TRUE;
377 
378   if (reallyfight) {
379 
380     if (Lunarity == 1) hitmod += Player.level;
381     else if (Lunarity == -1) hitmod -= (Player.level / 2);
382 
383     if (! m->attacked) Player.alignment -= 2; /* chaotic action */
384     m_status_set(m,AWAKE);
385     m_status_set(m,HOSTILE);
386     m->attacked = TRUE;
387     Player.hit += hitmod;
388     tacplayer(m);
389     Player.hit -= hitmod;
390   }
391 }
392 
393 
394 
395 
396 /* Attempt to break an object o */
damage_item(o)397 int damage_item(o)
398 pob o;
399 {
400   int i;
401   /* special case -- break star gem */
402   if (o->id == ARTIFACTID+21) {
403     print1("The Star Gem shatters into a million glistening shards....");
404     if (Current_Environment == E_STARPEAK) {
405       if (! gamestatusp(KILLED_LAWBRINGER))
406 	print2("You hear an agonizing scream of anguish and despair.");
407       morewait();
408       print1("A raging torrent of energy escapes in an explosion of magic!");
409       print2("The energy flows to the apex of Star Peak where there is");
410       morewait();
411       clearmsg();
412       print1("an enormous explosion!");
413       morewait();
414       annihilate(1);
415       print3("You seem to gain strength in the chaotic glare of magic!");
416       Player.str = max(Player.str, Player.maxstr + 5); /* FIXED! 12/25/98 */
417       Player.pow = max(Player.pow, Player.maxpow + 5); /* ditto */
418       Player.alignment -= 200;
419       dispose_lost_objects(1,o);
420     }
421     else {
422       morewait();
423       print1("The shards coalesce back together again, and vanish");
424       print2("with a muted giggle.");
425       dispose_lost_objects(1,o);
426       Objects[o->id].uniqueness = UNIQUE_UNMADE; /* FIXED! 12/30/98 */
427       /* WDT HACK: the above is correct only if UNIQUE_UNMADE means that
428        * the artifact hasn't been generated yet.  (Clearly, Omega is a
429        * little buggy in that regard with respect to artifacts in general
430        * -- it's almost trivial to force two identical artefacts to be
431        * generated right now.) */
432     }
433     return 1;
434   }
435   else {
436     if (o->fragility < random_range(30)) {
437       if (o->objchar == STICK) {
438 	strcpy(Str1,"Your ");
439 	strcat(Str1,(o->blessing >= 0 ? o->truename : o->cursestr));
440 	strcat(Str1," explodes!");
441 	print1(Str1);
442 	morewait();
443 	if (o->charge < 1)
444 	  nprint1(" Fzzz... Out of Power... Oh well...");
445 	else {
446 	  nprint1(" Ka-Blamm!!!");
447 	  /* general case. Some sticks will eventually do special things */
448 	  morewait();
449 	  manastorm(Player.x, Player.y, o->charge*o->level*10);
450 	  dispose_lost_objects(1,o);
451 	}
452 	return 1;
453       }
454       else if ((o->blessing > 0) && (o->level > random_range(10))) {
455 	strcpy(Str1,"Your ");
456 	strcat(Str1,itemid(o));
457 	strcat(Str1," glows strongly.");
458 	print1(Str1);
459 	return 0;
460       }
461       else if ((o->blessing < -1) && (o->level > random_range(10))) {
462 	strcpy(Str1,"You hear an evil giggle from your ");
463 	strcat(Str1,itemid(o));
464 	print1(Str1);
465 	return 0;
466       }
467       else if (o->plus > 0) {
468 	strcpy(Str1,"Your ");
469 	strcat(Str1,itemid(o));
470 	strcat(Str1," glows and then fades.");
471 	print1(Str1);
472 	o->plus--;
473 	return 0;
474       }
475       else {
476 	if (o->blessing > 0) print1("You hear a faint despairing cry!");
477 	else if (o->blessing < 0) print1("You hear an agonized scream!");
478 	strcpy(Str1,"Your ");
479 	strcat(Str1,itemid(o));
480 	strcat(Str1," shatters in a thousand lost fragments!");
481 	print2(Str1);
482 	morewait();
483 	dispose_lost_objects(1,o);
484 	return 1;
485       }
486     }
487     return 0;
488   }
489 }
490 
491 
492 
493 
494 
495 
496 
497 /* do dmg points of damage of type dtype, from source fromstring */
p_damage(dmg,dtype,fromstring)498 void p_damage(dmg,dtype,fromstring)
499 int dmg,dtype;
500 char *fromstring;
501 {
502   if (! p_immune(dtype)) {
503     if (gamestatusp(FAST_MOVE)) {
504       drawvision(Player.x,Player.y);
505       resetgamestatus(FAST_MOVE);
506     }
507     if (dtype == NORMAL_DAMAGE) Player.hp -= max(1,(dmg-Player.absorption));
508     else Player.hp -= dmg;
509     if (Player.hp < 1) p_death(fromstring);
510   }
511   else mprint("You resist the effects!");
512   dataprint();
513 }
514 
515 /* game over, you lose! */
p_death(fromstring)516 void p_death(fromstring)
517 char *fromstring;
518 {
519   Player.hp = -1;
520   print3("You died!");
521   morewait();
522   display_death(fromstring);
523 #ifdef SAVE_LEVELS
524   kill_all_levels();
525 #endif
526   endgraf();
527   exit(0);
528 }
529 
530 
531 /* move the cursor around, like for firing a wand, sets x and y to target */
setspot(x,y)532 void setspot(x,y)
533 int *x,*y;
534 {
535   char c = ' ';
536   mprint("Targeting.... ? for help");
537   omshowcursor(*x,*y);
538   while ((c != '.') && (c != ESCAPE)) {
539     c = lgetc();
540     switch(c) {
541       case 'h':case '4': movecursor(x,y,-1,0);  break;
542       case 'j':case '2': movecursor(x,y,0,1);  break;
543       case 'k':case '8': movecursor(x,y,0,-1);  break;
544       case 'l':case '6': movecursor(x,y,1,0);  break;
545       case 'b':case '1': movecursor(x,y,-1,1);  break;
546       case 'n':case '3': movecursor(x,y,1,1);  break;
547       case 'y':case '7': movecursor(x,y,-1,-1);  break;
548       case 'u':case '9': movecursor(x,y,1,-1);  break;
549       case '?':
550 	clearmsg();
551 	mprint("Use vi keys or numeric keypad to move cursor to target.");
552 	mprint("Hit the '.' key when done, or ESCAPE to abort.");
553 	break;
554     }
555   }
556   if (c==ESCAPE) *x = *y= ABORT;
557   screencheck(Player.y);
558 }
559 
560 
561 /* get a direction: return index into Dirs array corresponding to direction */
getdir()562 int getdir()
563 {
564   while (1) {
565     mprint("Select direction [hjklyubn, ESCAPE to quit]: ");
566     switch (mgetc()) {
567     case '4':
568     case 'h':
569     case 'H': return(5);
570     case '2':
571     case 'j':
572     case 'J': return(6);
573     case '8':
574     case 'k':
575     case 'K': return(7);
576     case '6':
577     case 'l':
578     case 'L': return(4);
579     case '7':
580     case 'y':
581     case 'Y': return(3);
582     case '9':
583     case 'u':
584     case 'U': return(1);
585     case '1':
586     case 'b':
587     case 'B': return(2);
588     case '3':
589     case 'n':
590     case 'N': return(0);
591     case ESCAPE: return(ABORT);
592     default: print3("That's not a direction! ");
593     }
594   }
595 }
596 
597 
598 
599 /* functions describes monster m's state for examine function */
mstatus_string(m)600 char *mstatus_string(m)
601 struct monster *m;
602 {
603   if (m_statusp(m, M_INVISIBLE) && !Player.status[TRUESIGHT])
604     strcpy(Str2, "Some invisible creature");
605   else if (m->uniqueness == COMMON) {
606     if (m->hp < Monsters[m->id].hp / 3)
607       strcpy(Str2,"a grievously injured ");
608     else if (m->hp < Monsters[m->id].hp / 2)
609       strcpy(Str2,"a severely injured ");
610     else if (m->hp < Monsters[m->id].hp)
611       strcpy(Str2,"an injured ");
612     else strcpy(Str2,getarticle(m->monstring));
613     if (m->level > Monsters[m->id].level) {
614       strcat(Str2," (level ");
615       strcat(Str2,wordnum(m->level+1-Monsters[m->id].level));
616       strcat(Str2,") ");
617     }
618     strcat(Str2,m->monstring);
619   }
620   else {
621     strcpy(Str2,m->monstring);
622     if (m->hp < Monsters[m->id].hp / 3)
623       strcat(Str2," who is grievously injured ");
624     else if (m->hp < Monsters[m->id].hp / 2)
625       strcat(Str2," who is severely injured ");
626     else if (m->hp < Monsters[m->id].hp)
627       strcat(Str2," who is injured ");
628   }
629   return(Str2);
630 }
631 
632 
633 
634 
635 /* for the examine function */
describe_player()636 void describe_player()
637 {
638   if (Player.hp < (Player.maxhp /5))
639     print1("A grievously injured ");
640   else if (Player.hp < (Player.maxhp /2))
641     print1("A seriously wounded ");
642   else if (Player.hp < Player.maxhp)
643     print1("A somewhat bruised ");
644   else print1("A fit ");
645 
646   if (Player.status[SHADOWFORM])
647     nprint1("shadow");
648   else
649     nprint1(levelname(Player.level));
650   nprint1(" named ");
651   nprint1(Player.name);
652   if (gamestatusp(MOUNTED))
653     nprint1(" (riding a horse.)");
654 }
655 
656 
657 /* access to player experience... */
658 /* share out experience among guild memberships */
gain_experience(amount)659 void gain_experience(amount)
660 int amount;
661 {
662   int i,count=0,share;
663   Player.xp += (long) amount;
664   gain_level(); /* actually, check to see if should gain level */
665   for(i=0;i<NUMRANKS;i++)
666     if (Player.guildxp[i] > 0) count++;
667   share = amount/(max(count,1));
668   for(i=0;i<NUMRANKS;i++)
669     if (Player.guildxp[i] > 0) Player.guildxp[i]+=share;
670 }
671 
672 /* try to hit a monster in an adjacent space. If there are none
673    return FALSE. Note if you're berserk you get to attack ALL
674    adjacent monsters! */
goberserk()675 int goberserk()
676 {
677   int wentberserk=FALSE,i;
678   char meleestr[80];
679   strcpy(meleestr,Player.meleestr);
680   strcpy(Player.meleestr,"lLlClH");
681   for(i=0;i<8;i++)
682     if (Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature
683 	!= NULL) {
684       wentberserk=TRUE;
685       fight_monster(Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature);
686       morewait();
687     }
688   strcpy(Player.meleestr,meleestr);
689   return(wentberserk);
690 }
691 
692 /* identifies a trap for examine() by its aux value */
trapid(trapno)693 char *trapid(trapno)
694 int trapno;
695 {
696   switch (trapno) {
697   case L_TRAP_SIREN:return("A siren trap");
698   case L_TRAP_DART:return("A dart trap");
699   case L_TRAP_PIT:return("A pit");
700   case L_TRAP_SNARE:return("A snare");
701   case L_TRAP_BLADE:return("A blade trap");
702   case L_TRAP_FIRE:return("A fire trap");
703   case L_TRAP_TELEPORT:return("A teleport trap");
704   case L_TRAP_DISINTEGRATE:return("A disintegration trap");
705   case L_TRAP_DOOR:return("A trap door");
706   case L_TRAP_MANADRAIN:return("A manadrain trap");
707   case L_TRAP_ACID:return("An acid shower trap");
708   case L_TRAP_SLEEP_GAS:return("A sleep gas trap");
709   case L_TRAP_ABYSS:return("A concealed entrance to the abyss");
710   default: return("A completely inoperative trap.");
711   }
712 }
713 
714 
715 /* checks current food status of player, every hour, and when food is eaten */
foodcheck()716 void foodcheck()
717 {
718   if (Player.food > 48) {
719     print3("You vomit up your huge meal.");
720     Player.food = 12;
721   }
722   else if (Player.food == 30)
723     print3("Time for a smackerel of something.");
724   else if (Player.food == 20)
725     print3("You feel hungry.");
726   else if (Player.food == 12)
727     print3("You are ravenously hungry.");
728   else if (Player.food == 3) {
729     print3("You feel weak.");
730     if (gamestatusp(FAST_MOVE)) {
731       drawvision(Player.x,Player.y);
732       resetgamestatus(FAST_MOVE);
733     }
734   }
735   else if (Player.food < 0) {
736     if (gamestatusp(FAST_MOVE)) {
737       drawvision(Player.x,Player.y);
738       resetgamestatus(FAST_MOVE);
739     }
740     print3("You're starving!");
741     p_damage(-5*Player.food,UNSTOPPABLE,"starvation");
742   }
743   showflags();
744 }
745 
746 
747 
748 
749 /* see whether room should be illuminated */
roomcheck()750 void roomcheck()
751 {
752   static int oldroomno = -1;
753 #ifdef MSDOS_SUPPORTED_ANTIQUE
754   static int oldlevel = -1;
755 #else
756   static plv oldlevel = NULL;
757 #endif
758   int roomno = Level->site[Player.x][Player.y].roomnumber;
759 
760   if ((roomno == RS_CAVERN) ||
761       (roomno == RS_SEWER_DUCT) ||
762       (roomno == RS_KITCHEN) ||
763       (roomno == RS_BATHROOM) ||
764       (roomno == RS_BEDROOM) ||
765       (roomno == RS_DININGROOM) ||
766       (roomno == RS_CLOSET) ||
767       (roomno > ROOMBASE))
768     if ((! loc_statusp(Player.x,Player.y,LIT)) &&
769 	(! Player.status[BLINDED]) &&
770 	(Player.status[ILLUMINATION] || (difficulty() < 6))) {
771       showroom(Level->site[Player.x][Player.y].roomnumber);
772       spreadroomlight(Player.x,Player.y,roomno);
773       levelrefresh();
774     }
775   if ((oldroomno != roomno) ||
776 #ifdef MSDOS_SUPPORTED_ANTIQUE
777       (oldlevel != Level->depth)) {
778 #else
779       (oldlevel != Level)) {
780 #endif
781     showroom(roomno);
782     oldroomno = roomno;
783 #ifdef MSDOS_SUPPORTED_ANTIQUE
784     oldlevel = Level->depth;
785 #else
786     oldlevel = Level;
787 #endif
788   }
789 }
790 
791 
792 
793 
794 
795 /* ask for mercy */
796 void surrender(m)
797 struct monster *m;
798 {
799   int i;
800   long bestitem,bestvalue;
801 
802   switch(random_range(4)) {
803   case 0: print1("You grovel at the monster's feet..."); break;
804   case 1: print1("You cry 'uncle'!"); break;
805   case 2: print1("You beg for mercy."); break;
806   case 3: print1("You yield to the monster."); break;
807   }
808   if (m->id == GUARD) {
809     if (m_statusp(m,HOSTILE))
810       monster_talk(m);
811     else {
812       print2("The guard (bored): Have you broken a law? [yn] ");
813       if (ynq2() == 'y') {
814 	print2("The guard grabs you, and drags you to court.");
815 	morewait();
816 	send_to_jail();
817       }
818       else print2("Then don't bother me. Scat!");
819     }
820   }
821   else if ((m->talkf==M_NO_OP) ||
822 	   (m->talkf==M_TALK_STUPID))
823     print3("Your plea is ignored.");
824   else  {
825     morewait();
826     print1("Your surrender is accepted.");
827     if (Player.cash > 0) nprint1(" All your gold is taken....");
828     Player.cash = 0;
829     bestvalue = 0;
830     bestitem = ABORT;
831     for (i=1;i<MAXITEMS;i++)
832       if (Player.possessions[i] != NULL)
833 	if (bestvalue < true_item_value(Player.possessions[i])) {
834           bestitem = i;
835           bestvalue = true_item_value(Player.possessions[i]);
836         }
837     if (bestitem != ABORT) {
838       print2("You also give away your best item... ");
839       nprint2(itemid(Player.possessions[bestitem]));
840       nprint2(".");
841       morewait();
842       givemonster(m,Player.possessions[bestitem]);
843       morewait(); /* msgs come from givemonster */
844       conform_unused_object(Player.possessions[bestitem]);
845       Player.possessions[bestitem] = NULL;
846     }
847     print2("You feel less experienced... ");
848     Player.xp = max(0,Player.xp - m->xpv);
849     nprint2("The monster seems more experienced!");
850     m->level = (min(10,m->level+1));
851     m->hp += m->level*20;
852     m->hit += m->level;
853     m->dmg += m->level;
854     m->ac += m->level;
855     m->xpv += m->level*10;
856     morewait();
857     clearmsg();
858     if ((m->talkf == M_TALK_EVIL) && random_range(10)) {
859       print1("It continues to attack you, laughing evilly!");
860       m_status_set(m,HOSTILE);
861       m_status_reset(m,GREEDY);
862     }
863     else if (m->id == HORNET || m->id == GUARD)
864       print1("It continues to attack you. ");
865     else {
866       print1("The monster leaves, chuckling to itself....");
867       m_teleport(m);
868     }
869   }
870   dataprint();
871 }
872 
873 
874 /* threaten a monster */
875 void threaten(m)
876 struct monster *m;
877 {
878   char response;
879   switch(random_range(4)) {
880   case 0:mprint("You demand that your opponent surrender!"); break;
881   case 1:mprint("You threaten to do bodily harm to it."); break;
882   case 2:mprint("You attempt to bluster it into submission."); break;
883   case 3:mprint("You try to cow it with your awesome presence."); break;
884   }
885   morewait(); /* FIXED! 12/25/98 */
886   if (! m_statusp(m,HOSTILE)) {
887     print3("You only annoy it with your futile demand.");
888     m_status_set(m,HOSTILE);
889   }
890   else if (((m->level*2 > Player.level) && (m->hp > Player.dmg)) ||
891 	   (m->uniqueness != COMMON))
892     print1("It sneers contemptuously at you.");
893   else if ((m->talkf != M_TALK_GREEDY) &&
894 	   (m->talkf != M_TALK_HUNGRY) &&
895 	   (m->talkf != M_TALK_EVIL) &&
896 	   (m->talkf != M_TALK_MAN) &&
897 	   (m->talkf != M_TALK_BEG) &&
898 	   (m->talkf != M_TALK_THIEF) &&
899 	   (m->talkf != M_TALK_MERCHANT) &&
900 	   (m->talkf != M_TALK_IM))
901     print1("Your demand is ignored");
902   else {
903     print1("It yields to your mercy.");
904     Player.alignment+=3;
905     print2("Kill it, rob it, or free it? [krf] ");
906     do response = (char) mcigetc();
907     while ((response != 'k')&&(response != 'r')&&(response !='f'));
908     if (response == 'k') {
909       m_death(m);
910       print2("You treacherous rogue!");
911       Player.alignment -= 13;
912     }
913     else if (response == 'r') {
914       Player.alignment-=2;
915       print2("It drops its treasure and flees.");
916       m_dropstuff(m);
917       m->hp = -1;
918       Level->site[m->x][m->y].creature = NULL;
919       putspot(m->x,m->y,getspot(m->x,m->y,FALSE));
920     }
921     else {
922       Player.alignment+=2;
923       print2("'If you love something set it free ... '");
924       if (random_range(100)==13) {
925 	morewait();
926 	print2("'...If it doesn't come back, hunt it down and kill it.'");
927       }
928       print3("It departs with a renewed sense of its own mortality.");
929       m->hp = -1;
930       Level->site[m->x][m->y].creature = NULL;
931       putspot(m->x,m->y,getspot(m->x,m->y,FALSE));
932     }
933   }
934 }
935 
936 /* name of the player's experience level */
937 char *levelname(level)
938 int level;
939 {
940   switch(level) {
941   case 0:strcpy(Str3,"neophyte");break;
942   case 1:strcpy(Str3,"beginner");break;
943   case 2:strcpy(Str3,"tourist");break;
944   case 3:strcpy(Str3,"traveller");break;
945   case 4:strcpy(Str3,"wayfarer");break;
946   case 5:strcpy(Str3,"peregrinator");break;
947   case 6:strcpy(Str3,"wanderer");break;
948   case 7:strcpy(Str3,"hunter");break;
949   case 8:strcpy(Str3,"scout");break;
950   case 9:strcpy(Str3,"trailblazer");break;
951   case 10:strcpy(Str3,"discoverer");break;
952   case 11:strcpy(Str3,"explorer");break;
953   case 12:strcpy(Str3,"senior explorer");break;
954   case 13:strcpy(Str3,"ranger");break;
955   case 14:strcpy(Str3,"ranger captain");break;
956   case 15:strcpy(Str3,"ranger knight");break;
957   case 16:strcpy(Str3,"adventurer");break;
958   case 17:strcpy(Str3,"experienced adventurer");break;
959   case 18:strcpy(Str3,"skilled adventurer");break;
960   case 19:strcpy(Str3,"master adventurer");break;
961   case 20:strcpy(Str3,"hero");break;
962   case 21:strcpy(Str3,"superhero");break;
963   case 22:strcpy(Str3,"demigod");break;
964   default:
965     if (level < 100) {
966       strcpy(Str3,"Order ");
967       Str3[6] = ((level/10)-2) + '0';
968       Str3[7] = 0;
969       strcat(Str3," Master of Omega");
970     }
971     else strcpy(Str3,"Ultimate Master of Omega");
972     break;
973   }
974   return(Str3);
975 }
976