1 /* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
2 /* command3.c */
3 
4 /* This file contains some more top level command functions
5    called from command1.c */
6 
7 #ifndef MSDOS_SUPPORTED_ANTIQUE
8 #include <pwd.h>
9 #include <unistd.h>
10 #endif
11 
12 #include "glob.h"
13 #include "date.h"
14 
15 /* look at some spot */
examine()16 void examine()
17 {
18   pol ol;
19   int x=Player.x,y=Player.y,drewmenu=FALSE;
20 
21   clearmsg();
22 
23   /* WDT HACK: I'm not sure I buy that one shouldn't be able to examine
24    * when one is blind.  However, the 'right' way to do it is certainly
25    * too difficult (I would expect to be able to examine only the items
26    * I actually recall).  So, for now I'll use David Given's compromise.
27    * 12/30/98
28    */
29   if (Player.status[BLINDED] > 0)
30   {
31     mprint("You're blind - you can't examine things.");
32     return;
33   }
34   setgamestatus(SKIP_MONSTERS);
35   mprint("Examine --");
36   setspot(&x,&y);
37   if (inbounds(x,y)) {
38     clearmsg();
39     if (Current_Environment == E_COUNTRYSIDE) {
40       if (! c_statusp(x, y, SEEN))
41 	print3("How should I know what that is?");
42       else {
43 	mprint("That terrain is:");
44 	mprint(countryid(Country[x][y].current_terrain_type));
45       }
46     }
47     else if (! view_los_p(Player.x,Player.y,x,y))
48       print3("I refuse to examine something I can't see.");
49     else {
50       clearmsg();
51       if (Level->site[x][y].creature != NULL)
52 	mprint(mstatus_string(Level->site[x][y].creature));
53       else if ((Player.x == x) && (Player.y ==y))
54 	describe_player();
55       if (loc_statusp(x,y,SECRET))
56 	print2("An age-worn stone wall.");
57       else
58 	switch (Level->site[x][y].locchar) {
59 	case SPACE: print2("An infinite void."); break;
60 	case PORTCULLIS: print2("A heavy steel portcullis"); break;
61 	case ABYSS: print2("An entrance to the infinite abyss"); break;
62 	case FLOOR:
63 	  if (Current_Dungeon == Current_Environment)
64 	    print2("A dirty stone floor.");
65 	  else print2("The ground.");
66 	  break;
67 	case WALL:
68 	  if (Level->site[x][y].aux == 0)
69 	    print2("A totally impervious wall.");
70 	  else if (Level->site[x][y].aux < 10)
71 	    print2("A pitted concrete wall.");
72 	  else if (Level->site[x][y].aux < 30)
73 	    print2("An age-worn sandstone wall.");
74 	  else if (Level->site[x][y].aux < 50)
75 	    print2("A smooth basalt wall.");
76 	  else if (Level->site[x][y].aux < 70)
77 	    print2("A solid granite wall.");
78 	  else if (Level->site[x][y].aux < 90)
79 	    print2("A wall of steel.");
80 	  else if (Level->site[x][y].aux < 210) {
81 	    if (Current_Environment == E_CITY)
82 	      print2("A thick wall of Rampart bluestone");
83 	    else print2("A magically reinforced wall.");
84 	  }
85 	  else print2("An almost totally impervious wall.");
86 	  break;
87 	case RUBBLE:print2("A dangerous-looking pile of rubble."); break;
88 	case SAFE:print2("A steel safe inset into the floor."); break;
89 	case CLOSED_DOOR:print2("A solid oaken door, now closed."); break;
90 	case OPEN_DOOR:print2("A solid oaken door, now open."); break;
91 	case STATUE:print2("A strange-looking statue."); break;
92 	case STAIRS_UP:print2("A stairway leading up."); break;
93 	case STAIRS_DOWN:print2("A stairway leading down...."); break;
94 	case TRAP:print2(trapid(Level->site[x][y].p_locf)); break;
95 	case HEDGE:
96 	  if (Level->site[x][y].p_locf == L_EARTH_STATION)
97 	    print2("A weird fibrillation of oozing tendrils.");
98 	  else print2("A brambly, thorny hedge.");
99 	  break;
100 	case LAVA:print2("A bubbling pool of lava."); break;
101 	case LIFT:print2("A strange glowing disk."); break;
102 	case ALTAR:print2("An (un?)holy altar."); break;
103 	case CHAIR:print2("A chair."); break;
104 	case WHIRLWIND:print2("A strange cyclonic electrical storm."); break;
105 	case WATER:
106 	  if (Level->site[x][y].p_locf == L_WATER)
107 	    print2("A deep pool of water.");
108 	  else if (Level->site[x][y].p_locf == L_CHAOS)
109 	    print2("A pool of primal chaos.");
110 	  else if (Level->site[x][y].p_locf == L_WATER_STATION)
111 	    print2("A bubbling pool of acid.");
112 	  else print2("An eerie pool of water.");
113 	  break;
114 	case FIRE:print2("A curtain of fire."); break;
115 	default:print2("Wow, I haven't the faintest idea!"); break;
116 	}
117       if ((ol = Level->site[x][y].things) != NULL && !loc_statusp(x,y,SECRET)) {
118 	if (ol->next == NULL)
119 	  print3(itemid(ol->thing));
120 	else {
121 	  drewmenu = TRUE;
122 	  menuclear();
123 	  menuprint("Things on floor:\n");
124 	  while (ol != NULL) {
125 	    menuprint("\n");
126 	    menuprint(itemid(ol->thing));
127 	    ol = ol->next;
128 	  }
129 	  showmenu();
130 	}
131       }
132       morewait();
133       sign_print(x,y,TRUE);
134     }
135   }
136   if (drewmenu) xredraw();
137 }
138 
help()139 void help()
140 {
141   char c;
142   char filestr[80];
143   FILE *in, *out;
144   int n;
145 
146   clearmsg();
147   print1("Please enter the letter indicating what topic you want help on.");
148   menuclear();
149   menuprint("a: Overview\n");
150   menuprint("b: Characters\n");
151   menuprint("c: Inventories\n");
152   menuprint("d: Movement\n");
153   menuprint("e: Combat\n");
154   menuprint("f: Bugs\n");
155   menuprint("g: Magic\n");
156   menuprint("h: The Countryside\n");
157   menuprint("i: The Screen Display\n");
158   menuprint("j: Saving and Restoring\n");
159   menuprint("k: Options Settings\n");
160   menuprint("l: Dungeon/City/Other Command List\n");
161   menuprint("m: Countryside Command List\n");
162 #if !defined(MSDOS) && !defined(AMIGA)
163   menuprint("n: Everything\n");
164 #endif
165   menuprint("ESCAPE: Forget the whole thing.");
166   showmenu();
167   do
168     c = (char) mcigetc();
169 #if defined(MSDOS) || defined(AMIGA)
170   while ((c < 'a' || c > 'm') && c != ESCAPE);
171   if (c != ESCAPE) {
172     sprintf(filestr, "%shelp%d.txt", Omegalib, c+1-'a');
173     displayfile(filestr);
174   }
175 #else
176   while ((c < 'a' || c > 'n') && c != ESCAPE);
177   if (c == 'n') {
178     print1("Trying to copy all help files to ./omega.doc ");
179     nprint1("Confirm [yn]");
180     if (ynq1()=='y') {
181       change_to_user_perms();
182       out = checkfopen("omega.doc", "w");
183       print2("Copying");
184       for (n = 1; n <= 13; n++)
185       {
186 	nprint2(".");
187 	sprintf(Str1, "%shelp%d.txt", Omegalib, n);
188 	in = checkfopen(Str1, "r");
189 	while (fgets(Str1, STRING_LEN, in))
190 	  fputs(Str1, out);
191 	fclose(in);
192       }
193       fclose(out);
194       change_to_game_perms();
195       nprint2(" Done.");
196     }
197   }
198   else if (c != ESCAPE) {
199     sprintf(filestr, "%shelp%d.txt", Omegalib, c+1-'a');
200     print1("Display help file, or Copy help file to file in wd. [dc] ");
201     do
202       c = (char) mcigetc();
203     while ((c != 'd') && (c != 'c')&& (c!=ESCAPE));
204     if (c == 'd')
205       displayfile(filestr);
206     else if (c == 'c') copyfile(filestr);
207   }
208 #endif
209   xredraw();
210 }
211 
version()212 void version()
213 {
214   setgamestatus(SKIP_MONSTERS);
215   print3(VERSIONSTRING);
216   nprint3(":");
217   nprint3(" Last Edited: ");
218   nprint3(LAST_OMEGA_EDIT_DATE);
219 }
220 
fire()221 void fire()
222 {
223   int index,x1,y1,x2,y2;
224   pob obj;
225   struct monster *m;
226 
227   clearmsg();
228 
229   print1("Fire/Throw --");
230   index = getitem(NULL_ITEM);
231   if (index == ABORT)
232     setgamestatus(SKIP_MONSTERS);
233   else if (index == CASHVALUE) print3("Can't fire money at something!");
234   else if (cursed(Player.possessions[index]) &&
235 	   Player.possessions[index]->used)
236     print3("You can't seem to get rid of it!");
237   /* load a crossbow */
238   else if ((Player.possessions[O_WEAPON_HAND] != NULL) &&
239 	   (Player.possessions[O_WEAPON_HAND]->id == WEAPONID+27) &&
240 	   (Player.possessions[O_WEAPON_HAND]->aux != LOADED) &&
241 	   (Player.possessions[index]->id == WEAPONID+29)) {
242 	     mprint("You crank back the crossbow and load a bolt.");
243 	     Player.possessions[O_WEAPON_HAND]->aux = LOADED;
244 	   }
245   else {
246     if (Player.possessions[index]->used) {
247       Player.possessions[index]->used = FALSE;
248       item_use(Player.possessions[index]);
249     }
250     obj = Player.possessions[index];
251     x1 = x2 = Player.x;
252     y1 = y2 = Player.y;
253     setspot(&x2,&y2);
254     if ((x2 == Player.x) && (y2 == Player.y))
255       mprint("You practice juggling for a moment or two.");
256     else {
257       do_object_los(obj->objchar,&x1,&y1,x2,y2);
258       if ((m=Level->site[x1][y1].creature) != NULL) {
259 	if (obj->dmg == 0) {
260 	  if (m->treasure > 0) { /* the monster can have treasure/objects */
261 	    mprint("Your gift is caught!");
262 	    givemonster(m,split_item(1,obj));
263 	    conform_lost_objects(1,obj);
264 	  }
265 	  else {
266 	    mprint("Your thrown offering is ignored.");
267 	    setgamestatus(SUPPRESS_PRINTING);
268 	    p_drop_at(x1,y1,1,obj);
269 	    resetgamestatus(SUPPRESS_PRINTING);
270 	    conform_lost_objects(1,obj);
271 	  }
272 	}
273 	else if (obj->aux == I_SCYTHE) {
274 	  mprint("It isn't very aerodynamic... you miss.");
275 	  setgamestatus(SUPPRESS_PRINTING);
276 	  p_drop_at(x1,y1,1,obj);
277 	  resetgamestatus(SUPPRESS_PRINTING);
278 	  conform_lost_objects(1,obj);
279 	}
280 	else if (hitp(Player.hit,m->ac)) {/* ok already, hit the damn thing */
281 	  weapon_use(2*statmod(Player.str),obj,m);
282 	  if ((obj->id == WEAPONID+28 || obj->id == WEAPONID+29) &&
283 	    !random_range(4))
284 	    dispose_lost_objects(1,obj);
285 	  else {
286 	    setgamestatus(SUPPRESS_PRINTING);
287 	    p_drop_at(x1,y1,1,obj);
288 	    resetgamestatus(SUPPRESS_PRINTING);
289 	    conform_lost_objects(1,obj);
290 	  }
291 	}
292 	else {
293 	  mprint("You miss it.");
294 	  setgamestatus(SUPPRESS_PRINTING);
295 	  p_drop_at(x1,y1,1,obj);
296 	  resetgamestatus(SUPPRESS_PRINTING);
297 	  conform_lost_objects(1,obj);
298 	}
299       }
300       else {
301 	setgamestatus(SUPPRESS_PRINTING);
302 	p_drop_at(x1,y1,1,obj);
303 	resetgamestatus(SUPPRESS_PRINTING);
304 	conform_lost_objects(1,obj);
305 	plotspot(x1,y1,TRUE);
306       }
307     }
308   }
309 }
310 
311 
312 
quit()313 void quit()
314 {
315   clearmsg();
316   change_to_game_perms();
317   mprint("Quit: Are you sure? [yn] ");
318   if (ynq()=='y') {
319     if (Player.rank[ADEPT] == 0) display_quit();
320     else display_bigwin();
321 #ifdef SAVE_LEVELS
322     kill_all_levels();
323 #endif
324     endgraf();
325     exit(0);
326   }
327   else resetgamestatus(SKIP_MONSTERS);
328 }
329 
330 
331 
332 /* rest in 10 second segments so if woken up by monster won't
333 die automatically.... */
nap()334 void nap()
335 {
336   static int naptime;
337   if (gamestatusp(FAST_MOVE)) {
338     if (naptime-- < 1) {
339       clearmsg();
340       mprint("Yawn. You wake up.");
341       resetgamestatus(FAST_MOVE);
342       drawvision(Player.x,Player.y);
343     }
344   }
345   else {
346     clearmsg();
347     mprint("Rest for how long? (in minutes) ");
348     naptime = (int) parsenum();
349     if (naptime > 600) {
350       print3("You can only sleep up to 10 hours (600 minutes)");
351       naptime = 3600;
352     }
353     else naptime *= 6;
354     if (naptime > 1) {
355       clearmsg();
356       setgamestatus(FAST_MOVE);
357       mprint("Resting.... ");
358     }
359   }
360 }
361 
362 
charid()363 void charid()
364 {
365   char id;
366   int countryside=FALSE;
367   char cstr[80];
368 
369   clearmsg();
370   mprint("Character to identify: ");
371   id = mgetc();
372   if (Current_Environment == E_COUNTRYSIDE) {
373     countryside = TRUE;
374     strcpy(cstr,countryid(id));
375     if (strcmp(cstr,"I have no idea.")==0)
376       countryside = FALSE;
377     else mprint(cstr);
378   }
379   if (! countryside) {
380     if ((id >= 'a' && id <= 'z') || (id >= 'A' && id <= 'Z') || id == '@')
381       mprint("A monster or NPC -- examine (x) to find out exactly.");
382     else switch(id) {
383     case (SPACE&0xff):
384       mprint(" : An airless void (if seen) or unknown region (if unseen)");
385       break;
386     case (WALL&0xff):
387       mprint(" : An (impenetrable?) wall");
388       break;
389     case (OPEN_DOOR&0xff):
390       mprint(" : An open door");
391       break;
392     case (CLOSED_DOOR&0xff):
393       mprint(" : A closed (possibly locked) door");
394       break;
395     case (LAVA&0xff):
396       mprint(" : A pool of lava");
397       break;
398     case (HEDGE&0xff):
399       mprint(" : A dense hedge");
400       break;
401     case (WATER&0xff):
402       mprint(" : A deep body of water");
403       break;
404     case (FIRE&0xff):
405       mprint(" : A curtain of fire");
406       break;
407     case (TRAP&0xff):
408       mprint(" : An uncovered trap");
409       break;
410     case (STAIRS_UP&0xff):
411       mprint(" : A stairway leading up");
412       break;
413     case (STAIRS_DOWN&0xff):
414       mprint(" : A stairway leading down");
415       break;
416     case (FLOOR&0xff):
417       mprint(" : The dungeon floor");
418       break;
419     case (PORTCULLIS&0xff):
420       mprint(" : A heavy steel portcullis");
421       break;
422     case (ABYSS&0xff):
423       mprint(" : An entrance to the infinite abyss");
424       break;
425     case (PLAYER&0xff):
426       mprint(" : You, the player");
427       break;
428     case (CORPSE&0xff):
429       mprint(" : The remains of some creature");
430       break;
431     case (THING&0xff):
432       mprint(" : Some random miscellaneous object");
433       break;
434     case (SAFE&0xff):
435       mprint(" : A steel safe inset into the floor");
436       break;
437     case (RUBBLE&0xff):
438       mprint(" : A dangerous-looking pile of rubble");
439       break;
440     case (STATUE&0xff):
441       mprint(" : A statue");
442       break;
443     case (ALTAR&0xff):
444       mprint(" : A (un?)holy altar");
445       break;
446     case (CASH&0xff):
447       mprint(" : Bills, specie, gems: cash");
448       break;
449     case (PILE&0xff):
450       mprint(" : A pile of objects");
451       break;
452     case (FOOD&0xff):
453       mprint(" : Something edible");
454       break;
455     case (WEAPON&0xff):
456       mprint(" : Some kind of weapon");
457       break;
458     case (MISSILEWEAPON&0xff):
459       mprint(" : Some kind of missile weapon");
460       break;
461     case (SCROLL&0xff):
462       mprint(" : Something readable");
463       break;
464     case (POTION&0xff):
465       mprint(" : Something drinkable");
466       break;
467     case (ARMOR&0xff):
468       mprint(" : A suit of armor");
469       break;
470     case (SHIELD&0xff):
471       mprint(" : A shield");
472       break;
473     case (CLOAK&0xff):
474       mprint(" : A cloak");
475       break;
476     case (BOOTS&0xff):
477       mprint(" : A pair of boots");
478       break;
479     case (STICK&0xff):
480       mprint(" : A stick");
481       break;
482     case (RING&0xff):
483       mprint(" : A ring");
484       break;
485     case (ARTIFACT&0xff):
486       mprint(" : An artifact");
487       break;
488     case (CHAIR&0xff):
489       mprint(" : A chair");
490       break;
491     case (WHIRLWIND&0xff):
492       mprint(" : A whirlwind");
493       break;
494     default:
495       mprint("That character is unused.");
496       break;
497     }
498   }
499 }
500 
501 
wizard()502 void wizard()
503 {
504   char *lname;
505 #ifndef MSDOS_SUPPORTED_ANTIQUE
506   struct passwd *dastuff;
507 #endif
508 
509   setgamestatus(SKIP_MONSTERS);
510   if (gamestatusp(CHEATED)) mprint("You're already in wizard mode!");
511   else {
512     clearmsg();
513     mprint("Really try to enter wizard mode? [yn] ");
514     if (ynq()=='y') {
515        lname = getlogin();
516 #ifndef MSDOS_SUPPORTED_ANTIQUE
517        if (!lname || strlen(lname) == 0)
518        {
519 	    dastuff = getpwuid(getuid());
520 	    lname = dastuff->pw_name;
521        }
522 #endif
523        if (strcmp(lname,WIZARD)==0) {
524 	 setgamestatus(CHEATED);
525 	 mprint("Wizard mode set.");
526       }
527       else {
528 	mprint("There is a shrieking sound, as of reality being distorted.");
529 	strcpy(Str1,WIZARD);
530 	strcat(Str1,", the Wizard of Omega appears before you....");
531 	if (Str1[0] >= 'a' && Str1[0] <= 'z')
532 	    Str1[0] += 'A'-'a'; /* capitalise 1st letter */
533 	mprint(Str1);
534 	mprint("'Do not meddle in the affairs of Wizards --");
535 	if (random_range(2)) mprint("it makes them soggy and hard to light.'");
536 	else mprint("for they are subtle, and swift to anger!'");
537       }
538     }
539   }
540 }
541 
542 /* Jump, that is */
vault()543 void vault()
544 {
545   int x=Player.x,y=Player.y,jumper=0;
546 
547   clearmsg();
548 
549   if (Player.possessions[O_BOOTS] != NULL)
550     if (Player.possessions[O_BOOTS]->usef == I_BOOTS_JUMPING)
551       jumper = 2;
552   if (Player.status[IMMOBILE] > 0) {
553     resetgamestatus(FAST_MOVE);
554     print3("You are unable to move");
555   }
556   else {
557     setgamestatus(SKIP_MONSTERS);
558     mprint("Jump where?");
559     setspot(&x,&y);
560     if (! los_p(Player.x,Player.y,x,y))
561       print3("The way is obstructed.");
562     else if (Player.itemweight > Player.maxweight)
563       print3("You are too burdened to jump anywhere.");
564     else if (distance(x,y,Player.x,Player.y) >
565 	     max(2,statmod(Player.agi)+2)+jumper)
566       print3("The jump is too far for you.");
567     else if (Level->site[x][y].creature != NULL)
568       print3("You can't jump on another creature.");
569     else if (! p_moveable(x,y))
570       print3("You can't jump there.");
571     else {
572       resetgamestatus(SKIP_MONSTERS);
573       Player.x = x;
574       Player.y = y;
575       if ((! jumper) && (random_range(30) > Player.agi)) {
576 	mprint("Oops -- took a tumble.");
577 	setgamestatus(SKIP_PLAYER);
578 	p_damage((Player.itemweight/250),UNSTOPPABLE,"clumsiness");
579       }
580       p_movefunction(Level->site[Player.x][Player.y].p_locf);
581       if (Current_Environment != E_COUNTRYSIDE)
582 	if ((Level->site[Player.x][Player.y].things != NULL) &&
583 	    (optionp(PICKUP)))
584 	  pickup();
585     }
586   }
587 }
588 
589 
590 /* Sets sequence of combat maneuvers. */
tacoptions()591 void tacoptions()
592 {
593   int actionsleft,done,place;
594   char defatt, *attstr, *defstr; /* for the default setting */
595   int draw_again = 1;
596 
597   setgamestatus(SKIP_MONSTERS);
598 
599   done = FALSE;
600   actionsleft = maneuvers();
601   place = 0;
602   do {
603     if (draw_again) {
604       menuclear();
605       menuprint("Enter a combat maneuvers sequence.\n");
606       menuprint("? for help, ! for default, backspace to start again,\n");
607       menuprint(" RETURN to save sequence\n");
608       showmenu();
609       draw_again = 0;
610     }
611     clearmsg();
612     mprint("Maneuvers Left:");
613     mnumprint(actionsleft);
614     switch(mgetc()) {
615     case '?':
616       combat_help();
617       draw_again = 1;
618       break;
619     case 'a': case 'A':
620       if (actionsleft < 1) print3("No more maneuvers!");
621       else {
622 	if (Player.possessions[O_WEAPON_HAND] == NULL) {
623 	  Player.meleestr[place] = 'C';
624 	  menuprint("\nPunch:");
625 	}
626 	else if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING) {
627 	  Player.meleestr[place] = 'T';
628 	  menuprint("\nThrust:");
629 	}
630 	else if (Player.possessions[O_WEAPON_HAND]->type == STRIKING) {
631 	  Player.meleestr[place] = 'C';
632 	  menuprint("\nStrike:");
633 	}
634 	else {
635 	  menuprint("\nCut:");
636 	  Player.meleestr[place] = 'C';
637 	}
638 	place++;
639 	Player.meleestr[place]=getlocation();
640 	place++;
641 	actionsleft--;
642       }
643       break;
644     case 'b': case 'B':
645       if (actionsleft<1) print3("No more maneuvers!");
646       else {
647 	Player.meleestr[place] = 'B';
648 	if (Player.possessions[O_WEAPON_HAND] == NULL)
649 	  menuprint("\nDodge (from):");
650 	else if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING)
651 	  menuprint("\nParry:");
652 	else menuprint("\nBlock:");
653 	place++;
654 	Player.meleestr[place]= getlocation();
655 	place++;
656 	actionsleft--;
657       }
658       break;
659     case 'l': case 'L':
660       if (actionsleft<2) print3("Not enough maneuvers to lunge!");
661       else {
662 	if (Player.possessions[O_WEAPON_HAND] != NULL) {
663 	  if (Player.possessions[O_WEAPON_HAND]->type != MISSILE) {
664 	    menuprint("\nLunge:");
665 	    Player.meleestr[place] = 'L';
666 	    place++;
667 	    Player.meleestr[place]=getlocation();
668 	    place++;
669 	    actionsleft -= 2;
670 	  }
671 	  else {
672 	    print3("Can't lunge with a missile weapon!");
673 	    morewait();
674 	  }
675 	}
676 	else {
677 	  print3("Can't lunge without a weapon!");
678 	  morewait();
679 	}
680       }
681       break;
682     case 'r': case 'R':
683       if (actionsleft<2) print3("Not enough maneuvers to riposte!");
684       else {
685 	if (Player.possessions[O_WEAPON_HAND] != NULL) {
686 	  if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING) {
687 	    Player.meleestr[place++] = 'R';
688 	    menuprint("\nRiposte:");
689 	    Player.meleestr[place++]=getlocation();
690 	    actionsleft -= 2;
691 	  }
692 	  else {
693 	    print3("Can't riposte without a thrusting weapon!");
694 	    morewait();
695 	  }
696 	}
697 	else {
698 	  print3("Can't riposte without a thrusting weapon!");
699 	  morewait();
700 	}
701       }
702       break;
703     case BACKSPACE:
704     case DELETE:
705       place = 0;
706       actionsleft=maneuvers();
707       draw_again = 1;
708       break;
709     case '!':
710       if (Player.possessions[O_WEAPON_HAND] == NULL) {
711 	defatt = 'C';
712 	attstr = "Punch";
713       }
714       else if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING) {
715 	defatt = 'T';
716 	attstr = "Thrust";
717       }
718       else if (Player.possessions[O_WEAPON_HAND]->type == STRIKING) {
719 	defatt = 'C';
720 	attstr = "Strike";
721       }
722       else {
723 	defatt = 'C';
724 	attstr = "Cut";
725       }
726       if (Player.possessions[O_WEAPON_HAND] == NULL)
727 	defstr = "Dodge";
728       else if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING)
729 	defstr = "Parry";
730       else defstr = "Block";
731       menuclear();
732       menuprint("Enter a combat maneuvers sequence.\n");
733       menuprint("? for help, ! for default, backspace to start again,\n");
734       menuprint(" RETURN to save sequence\n\n");
735       for(place=0;place<maneuvers();place++)
736 	if (place&1) { /* every 2nd time around */
737 	    Player.meleestr[place*2] = 'B';
738 	    Player.meleestr[(place*2)+1] = 'C';
739 	    menuprint(defstr);
740 	    menuprint(" Center.\n");
741 	}
742 	else {
743 	    Player.meleestr[place*2] = defatt;
744 	    Player.meleestr[(place*2)+1] = 'C';
745 	    menuprint(attstr);
746 	    menuprint(" Center.\n");
747 	}
748       actionsleft = 0;
749       showmenu();
750       Player.meleestr[place*2]='\0';
751       break;
752     case RETURN:
753     case LINEFEED:
754     case ESCAPE:
755       done = TRUE;
756       break;
757     }
758 /*    if (actionsleft < 1) morewait(); */ /* FIXED 12/30/98 */
759   } while (! done);
760   xredraw();
761   Player.meleestr[place] = 0;
762 }
763 
764 
765 
766 
767 /* Do the Artful Dodger trick */
pickpocket()768 void pickpocket()
769 {
770   int dx,dy,index=0;
771   struct monster *m;
772 
773   clearmsg();
774 
775   mprint("Pickpocketing --");
776 
777   index = getdir();
778 
779   if (index == ABORT)
780     setgamestatus(SKIP_MONSTERS);
781   else {
782     dx = Dirs[0][index];
783     dy = Dirs[1][index];
784 
785     if ((! inbounds(Player.x+dx, Player.y+dy)) ||
786 	(Level->site[Player.x+dx][Player.y+dy].creature == NULL)) {
787       print3("There's nothing there to steal from!!!");
788       setgamestatus(SKIP_MONSTERS);
789     }
790     else {
791       m = Level->site[Player.x+dx][Player.y+dy].creature;
792       if (m->id == GUARD) {
793 	mprint("Trying to steal from a guardsman, eh?");
794 	mprint("Not a clever idea.");
795 	if (Player.cash > 0) {
796 	  mprint("As a punitive fine, the guard takes all your money.");
797 	  Player.cash = 0;
798 	  dataprint();
799 	}
800 	else {
801 	  mprint("The guardsman places you under arrest.");
802 	  morewait();
803 	  send_to_jail();
804 	}
805       }
806       else if (m->possessions == NULL) {
807 	mprint("You couldn't find anything worth taking!");
808 	mprint("But you managed to annoy it...");
809 	m_status_set(m,HOSTILE);
810       }
811       else if (Player.dex*5+Player.rank[THIEVES]*20+random_range(100) >
812 	       random_range(100)+m->level*20) {
813 	mprint("You successfully complete your crime!");
814 	mprint("You stole:");
815 	mprint(itemid(m->possessions->thing));
816 	Player.alignment--;
817 	gain_experience(m->level*m->level);
818 	gain_item(m->possessions->thing);
819 	m->possessions = m->possessions->next;
820       }
821     }
822   }
823 }
824 
825 
826 
rename_player()827 void rename_player()
828 {
829   setgamestatus(SKIP_MONSTERS);
830   clearmsg();
831   mprint("Rename Character: ");
832   strcpy(Str1,msgscanstring());
833   if (strlen(Str1) == 0)
834     mprint(Player.name);
835   else {
836     if (Str1[0] >= 'a' && Str1[0] <= 'z')
837       Str1[0] += 'A' - 'a';
838     strcpy(Player.name, Str1);
839   }
840   sprintf(Str1, "Henceforth, you shall be known as %s", Player.name);
841   print2(Str1);
842 }
843 
844 
abortshadowform()845 void abortshadowform()
846 {
847   setgamestatus(SKIP_MONSTERS);
848   if (Player.status[SHADOWFORM] && (Player.status[SHADOWFORM]<1000)) {
849     mprint("You abort your spell of Shadow Form.");
850     Player.immunity[NORMAL_DAMAGE]--;
851     Player.immunity[ACID]--;
852     Player.immunity[THEFT]--;
853     Player.immunity[INFECTION]--;
854     mprint("You feel less shadowy now.");
855     Player.status[SHADOWFORM] = 0;
856   }
857 }
858 
tunnel()859 void tunnel()
860 {
861   int dir,ox,oy,aux;
862 
863   clearmsg();
864   mprint("Tunnel -- ");
865   dir = getdir();
866   if (dir == ABORT)
867     setgamestatus(SKIP_MONSTERS);
868   else {
869     ox = Player.x + Dirs[0][dir];
870     oy = Player.y + Dirs[1][dir];
871     if (loc_statusp(ox,oy,SECRET))
872       mprint("You have no success as yet.");
873     else if (Level->site[ox][oy].locchar != WALL) {
874       print3("You can't tunnel through that!");
875       setgamestatus(SKIP_MONSTERS);
876     }
877     else {
878       aux = Level->site[ox][oy].aux;
879       if (random_range(20)==1){
880 	if (Player.possessions[O_WEAPON_HAND] == NULL) {
881 	  mprint("Ouch! broke a fingernail...");
882 	  p_damage(Player.str / 6,UNSTOPPABLE,"a broken fingernail");
883 	}
884 	else if ((Player.possessions[O_WEAPON_HAND]->type == THRUSTING) ||
885 		 ((Player.possessions[O_WEAPON_HAND]->type != STRIKING) &&
886 		  (Player.possessions[O_WEAPON_HAND]->fragility <
887 		   random_range(20)))) {
888 	  mprint("Clang! Uh oh...");
889 	  (void) damage_item(Player.possessions[O_WEAPON_HAND]);
890 	}
891 	else mprint("Your digging implement shows no sign of breaking.");
892       }
893       if (Player.possessions[O_WEAPON_HAND] == NULL) {
894 	if ((aux > 0) && ((Player.str/3)+random_range(100) > aux)) {
895 	  mprint("You carve a tunnel through the stone!");
896 	  tunnelcheck();
897 	  Level->site[ox][oy].locchar = RUBBLE;
898 	  Level->site[ox][oy].p_locf = L_RUBBLE;
899 	  lset(ox, oy, CHANGED);
900 	}
901 	else mprint("No joy.");
902       }
903       else if (Player.possessions[O_WEAPON_HAND]->type == THRUSTING) {
904 	if ((aux > 0) &&
905 	    (Player.possessions[O_WEAPON_HAND]->dmg*2+random_range(100) >
906 	     aux)) {
907 	  mprint("You carve a tunnel through the stone!");
908 	  tunnelcheck();
909 	  Level->site[ox][oy].locchar = RUBBLE;
910 	  Level->site[ox][oy].p_locf = L_RUBBLE;
911 	  lset(ox, oy, CHANGED);
912 	}
913 	else mprint("No luck.");
914       }
915       else if ((aux > 0) &&
916 	       (Player.possessions[O_WEAPON_HAND]->dmg+random_range(100)
917 		> aux)) {
918 	mprint("You carve a tunnel through the stone!");
919 	tunnelcheck();
920 	Level->site[ox][oy].locchar = RUBBLE;
921 	Level->site[ox][oy].p_locf = L_RUBBLE;
922 	lset(ox, oy, CHANGED);
923       }
924       else mprint("You have no success as yet.");
925     }
926   }
927 }
928 
929 
930 
931 
hunt(terrain)932 void hunt(terrain)
933 Symbol terrain;
934 {
935   int fertility=0;
936   switch(terrain) {
937   case SWAMP:
938     mprint("You hesitate to hunt for food in the marshy wasteland.");
939     break;
940   case VOLCANO:
941   case CASTLE:
942   case TEMPLE:
943   case CAVES:
944   case STARPEAK:
945   case MAGIC_ISLE:
946   case DRAGONLAIR:
947     mprint("There is nothing alive here (or so it seems)");
948     break;
949   case VILLAGE:
950   case CITY:
951     mprint("You can find no food here; perhaps if you went inside....");
952     break;
953   case ROAD:
954     mprint("You feel it would be a better idea to hunt off the road.");
955     break;
956   case CHAOS_SEA:
957     mprint("Food in the Sea of Chaos? Go on!");
958     break;
959   case DESERT:
960     mprint("You wander off into the trackless desert in search of food...");
961     Time += 100;
962     hourly_check();
963     fertility = 10;
964     break;
965   case JUNGLE:
966     mprint("You search the lush and verdant jungle for game....");
967     Time += 100;
968     hourly_check();
969     fertility = 80;
970     break;
971   case PLAINS:
972     mprint("You set off through the tall grass; the game is afoot.");
973     Time += 100;
974     hourly_check();
975     fertility = 50;
976     break;
977   case TUNDRA:
978     mprint("You blaze a trail through the frozen wasteland....");
979     Time += 100;
980     hourly_check();
981     fertility = 30;
982     break;
983   case FOREST:
984     mprint("You try to follow the many tracks through the forest loam....");
985     Time += 100;
986     hourly_check();
987     fertility = 70;
988     break;
989   case MOUNTAINS: case PASS:
990     mprint("You search the cliff walls looking for something to eat....");
991     Time += 100;
992     hourly_check();
993     fertility = 30;
994     break;
995   case RIVER:
996     mprint("The halcyon river is your hopeful food source...");
997     Time += 100;
998     hourly_check();
999     fertility = 80;
1000     break;
1001   }
1002   if (((Date % 360 < 60) || (Date % 360 > 300)) &&
1003       (terrain != DESERT) &&
1004       (terrain != JUNGLE)) {
1005     mprint("The cold weather impedes your hunt....");
1006     fertility = fertility / 2;
1007   }
1008   if (fertility > random_range(100)) {
1009     mprint("You have an encounter...");
1010     change_environment(E_TACTICAL_MAP);
1011   }
1012   else mprint("Your hunt is fruitless.");
1013 }
1014 
dismount_steed()1015 void dismount_steed()
1016 {
1017   pml ml;
1018   if (! gamestatusp(MOUNTED))
1019     print3("You're on foot already!");
1020   else if (Current_Environment == E_COUNTRYSIDE) {
1021     mprint("If you leave your steed here he will wander away!");
1022     mprint("Do it anyway? [yn] ");
1023     if (ynq()=='y') resetgamestatus(MOUNTED);
1024   }
1025   else {
1026     resetgamestatus(MOUNTED);;
1027     ml = ((pml) checkmalloc(sizeof(mltype)));
1028     ml->m = ((pmt) checkmalloc(sizeof(montype)));
1029     *(ml->m) = Monsters[HORSE];
1030     ml->m->x = Player.x;
1031     ml->m->y = Player.y;
1032     ml->m->status = MOBILE+SWIMMING;
1033     ml->next = Level->mlist;
1034     Level->site[Player.x][Player.y].creature = ml->m;
1035     Level->mlist = ml;
1036   }
1037   calc_melee();
1038 }
1039 
1040 
city_move()1041 void city_move()
1042 {
1043   int site,x=Player.x,y=Player.y,toggle=FALSE;
1044   clearmsg();
1045   if (Current_Environment != E_CITY) {
1046     print3("This command only works in the city!");
1047     setgamestatus(SKIP_MONSTERS);
1048   }
1049   else if (Player.status[IMMOBILE] > 0)
1050     print3("You can't even move!");
1051   else if (hostilemonstersnear()) {
1052     setgamestatus(SKIP_MONSTERS);
1053     print3("You can't move this way with hostile monsters around!");
1054   }
1055   else if (Level->site[Player.x][Player.y].aux == NOCITYMOVE)
1056     print3("You can't use the 'M' command from this location.");
1057   else {
1058     print1("Move to which establishment [? for help, ESCAPE to quit]");
1059     site = parsecitysite();
1060     if (site != ABORT) {
1061       mprint("You're on your way...");
1062       morewait();
1063       while ((x != CitySiteList[site][1]) || (y != CitySiteList[site][2])) {
1064 	toggle = ! toggle;
1065 	if (toggle) {
1066 	  Time++;
1067 	  if (Time % 10 == 0) tenminute_check();
1068 	  else minute_status_check();
1069 	}
1070 	x += sign(CitySiteList[site][1] - x);
1071 	y += sign(CitySiteList[site][2] - y);
1072 	screencheck(y);
1073 	omshowcursor(x,y);
1074       }
1075       Player.x = x;
1076       Player.y = y;
1077       screencheck(Player.y);
1078       mprint("Made it!");
1079       drawvision(Player.x, Player.y);
1080       morewait();
1081       p_movefunction(Level->site[x][y].p_locf);
1082     }
1083   }
1084 }
1085 
1086 
1087 
frobgamestatus()1088 void frobgamestatus()
1089 {
1090   char response;
1091   long num;
1092   mprint("Set or Reset or Forget it [s,r,ESCAPE]:");
1093   do response = (char) mcigetc();
1094   while ((response != 'r') && (response != 's') && (response != ESCAPE));
1095   if (response != ESCAPE) {
1096     mprint("Enter log2 of flag:");
1097     num = (int) parsenum();
1098     if (num > -1) {
1099       num = pow2(num);
1100       if (num == CHEATED) {
1101 	mprint("Can't alter Wizard flag.");
1102 	return;
1103       }
1104       if (response == 's') setgamestatus(num);
1105       else resetgamestatus(num);
1106       mprint("Done....");
1107     }
1108   }
1109 }
1110 
1111