1 /* copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
2 /* utils.c */
3 
4 /* Random utility functions called from all over */
5 
6 #ifndef MSDOS_SUPPORTED_ANTIQUE
7 #include <sys/types.h>
8 #include <sys/time.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #endif
13 
14 #include "glob.h"
15 
16 /* x and y on level? */
inbounds(x,y)17 int inbounds(x,y)
18 int x,y;
19 {
20   return((x>=0)&&(y>=0)&&(x<WIDTH)&&(y<LENGTH));
21 }
22 
23 /* RANDFUNCTION is defined in odefs.h */
random_range(k)24 int random_range(k)
25 int k;
26 {
27   /*return( k==0 ? 0 : (int) RANDFUNCTION() % k ) ;*/
28   return( k==0 ? 0 : (int) ((RANDFUNCTION()%10000)*k)/10000);
29 }
30 
31 
32 /* modify absolute y coord relative to which part of level we are on */
screenmod(y)33 int screenmod(y)
34 int y;
35 {
36   return(y-ScreenOffset);
37 }
38 
39 
offscreen(y)40 int offscreen(y)
41 int y;
42 {
43   return((y<0)||
44 	 (y<ScreenOffset) ||
45 	 (y>ScreenOffset+ScreenLength-1) ||
46 	 (y>LENGTH));
47 }
48 
49 
50 /* always hit on a natural 0; never hit on a natural 19 */
hitp(hit,ac)51 int hitp(hit,ac)
52 int hit,ac;
53 {
54   int roll = random_range(20);
55   if (roll == 0) return(TRUE);
56   else if (roll == 19) return(FALSE);
57   else return((roll < (hit - ac)) ? TRUE : FALSE );
58 }
59 
60 
61 
62 
63 /* number of moves from x1,y1 to x2,y2 */
distance(x1,y1,x2,y2)64 int distance(x1,y1,x2,y2)
65 int x1,y1,x2,y2;
66 {
67   return(max(abs(x2-x1),abs(y2-y1)));
68 }
69 
70 
71 /* can you shoot, or move monsters through a spot? */
unblocked(x,y)72 int unblocked(x,y)
73 int x,y;
74 {
75   if ((! inbounds(x,y)) ||
76       (Level->site[x][y].creature != NULL) ||
77       (Level->site[x][y].locchar == WALL) ||
78       (Level->site[x][y].locchar == PORTCULLIS) ||
79       (Level->site[x][y].locchar == STATUE) ||
80       (Level->site[x][y].locchar == HEDGE) ||
81       (Level->site[x][y].locchar == CLOSED_DOOR) ||
82       loc_statusp(x,y,SECRET) ||
83       ((x==Player.x) && (y==Player.y)))
84     return(FALSE);
85   else
86     return(TRUE);
87 }
88 
89 
90 /* do monsters want to move through a spot */
m_unblocked(m,x,y)91 int m_unblocked(m,x,y)
92 struct monster *m;
93 int x,y;
94 {
95   if ((! inbounds(x,y)) || ((x==Player.x) && (y==Player.y)))
96     return(FALSE);
97   else if ((Level->site[x][y].creature != NULL) ||
98 	   (Level->site[x][y].locchar == SPACE)) return(FALSE);
99   else if (m_statusp(m,ONLYSWIM))
100     return(Level->site[x][y].locchar == WATER);
101   else if (loc_statusp(x,y,SECRET)) {
102     if (m->movef == M_MOVE_SMART) {
103       if (los_p(x, y, Player.x, Player.y)) {
104 	mprint("You see a secret door swing open!");
105 	lreset(x, y, SECRET);
106 	lset(x, y, CHANGED);
107       }
108       else
109 	mprint("You hear a door creak open, and then close again.");
110 	/* smart monsters would close secret doors behind them if the */
111 	/* player didn't see them using it */
112       return(TRUE);
113     }
114     else
115       return(m_statusp(m,INTANGIBLE));
116   }
117   else if ((Level->site[x][y].locchar == FLOOR) ||
118 	   (Level->site[x][y].locchar == OPEN_DOOR))
119     return(TRUE);
120   else if ((Level->site[x][y].locchar == PORTCULLIS) ||
121 	   (Level->site[x][y].locchar == WALL) ||
122 	   (Level->site[x][y].locchar == STATUE))
123     return(m_statusp(m,INTANGIBLE));
124   else if (Level->site[x][y].locchar==WATER)
125     return(m_statusp(m,SWIMMING) ||
126 	   m_statusp(m,ONLYSWIM) ||
127 	   m_statusp(m,INTANGIBLE) ||
128 	   m_statusp(m,FLYING));
129   else if (Level->site[x][y].locchar == CLOSED_DOOR) {
130     if (m->movef==M_MOVE_SMART) {
131       mprint("You hear a door creak open.");
132       Level->site[x][y].locchar = OPEN_DOOR;
133       lset(x, y, CHANGED);
134       return(TRUE);
135     }
136     else if (random_range(m->dmg) > random_range(100)) {
137       mprint("You hear a door shattering.");
138       Level->site[x][y].locchar = RUBBLE;
139       lset(x, y, CHANGED);
140       return(TRUE);
141     }
142     else return(m_statusp(m,INTANGIBLE));
143   }
144   else if (Level->site[x][y].locchar == LAVA)
145     return((m_immunityp(m,FLAME) &&
146 	    m_statusp(m,SWIMMING)) ||
147 	   m_statusp(m,INTANGIBLE) ||
148 	   m_statusp(m,FLYING));
149   else if (Level->site[x][y].locchar == FIRE)
150     return(m_statusp(m,INTANGIBLE) ||
151 	   m_immunityp(m,FLAME));
152   else if ((Level->site[x][y].locchar == TRAP) ||
153 	   (Level->site[x][y].locchar == HEDGE) ||
154 	   (Level->site[x][y].locchar == ABYSS))
155     return((m->movef == M_MOVE_CONFUSED) ||
156 	   m_statusp(m,INTANGIBLE) ||
157 	   m_statusp(m,FLYING));
158   else return(TRUE);
159 }
160 
161 
162 
163 /* can you see through a spot? */
view_unblocked(x,y)164 int view_unblocked(x,y)
165 int x,y;
166 {
167   if (! inbounds(x,y)) return(FALSE);
168   else if ((Level->site[x][y].locchar == WALL) ||
169 	   (Level->site[x][y].locchar == STATUE) ||
170 	   (Level->site[x][y].locchar == HEDGE) ||
171 	   (Level->site[x][y].locchar == FIRE) ||
172 	   (Level->site[x][y].locchar == CLOSED_DOOR) ||
173 	   loc_statusp(x,y,SECRET))
174     return(FALSE);
175   else
176     return(TRUE);
177 }
178 
179 
180 #ifndef MSDOS_SUPPORTED_ANTIQUE
181 /* 8 moves in Dirs */
initdirs()182 void initdirs()
183 {
184   Dirs[0][0] = 1;
185   Dirs[0][1] = 1;
186   Dirs[0][2] = -1;
187   Dirs[0][3] = -1;
188   Dirs[0][4] = 1;
189   Dirs[0][5] = -1;
190   Dirs[0][6] = 0;
191   Dirs[0][7] = 0;
192   Dirs[0][8] = 0;
193   Dirs[1][0] = 1;
194   Dirs[1][1] = -1;
195   Dirs[1][2] = 1;
196   Dirs[1][3] = -1;
197   Dirs[1][4] = 0;
198   Dirs[1][5] = 0;
199   Dirs[1][6] = 1;
200   Dirs[1][7] = -1;
201   Dirs[1][8] = 0;
202 }
203 #endif
204 
205 
206 
207 
208 
209 /* do_los moves pyx along a lineofsight from x1 to x2 */
210 /* x1 and x2 are pointers because as a side effect they are changed */
211 /* to the final location of the pyx */
do_los(pyx,x1,y1,x2,y2)212 void do_los(pyx,x1,y1,x2,y2)
213 Symbol pyx;
214 int *x1,*y1,x2,y2;
215 {
216   int dx,dy,ox,oy;
217   int major, minor;
218   int error, delta, step;
219   int blocked;
220 
221   if (x2 - *x1 < 0) dx = 5;
222   else if (x2 - *x1 > 0) dx = 4;
223   else dx = -1;
224   if (y2 - *y1 < 0) dy = 7;
225   else if (y2 - *y1 > 0) dy = 6;
226   else dy = -1;
227   if (abs(x2 - *x1) > abs(y2 - *y1)) {
228     major = dx;
229     minor = dy;
230     step = abs(x2 - *x1);
231     delta = 2*abs(y2 - *y1);
232   }
233   else {
234     major = dy;
235     minor = dx;
236     step = abs(y2 - *y1);
237     delta = 2*abs(x2 - *x1);
238   }
239   if (major == -1)	/* x1,y2 already == x2,y2 */
240     return;
241   error = 0;
242   do {
243     ox = *x1; oy = *y1;
244     *x1 += Dirs[0][major];
245     *y1 += Dirs[1][major];
246     error += delta;
247     if (error > step) {	/* don't need to check that minor >= 0 */
248       *x1 += Dirs[0][minor];
249       *y1 += Dirs[1][minor];
250       error -= 2*step;
251     }
252     blocked = !unblocked(*x1,*y1);
253     if (error < 0 && (*x1 != x2 || *y1 != y2) && blocked) {
254       *x1 -= Dirs[0][minor];
255       *y1 -= Dirs[1][minor];
256       error += 2*step;
257       blocked = !unblocked(*x1,*y1);
258     }
259     Level->site[*x1][*y1].showchar = pyx;
260     plotchar(pyx,*x1,*y1);
261     plotspot(ox,oy,TRUE);
262     usleep(50000);
263   } while ((*x1 != x2 || *y1 != y2) && !blocked);
264   plotspot(*x1,*y1,TRUE);
265   levelrefresh();
266 }
267 
268 
269 /* This is the same as do_los, except we stop before hitting nonliving
270 obstructions */
do_object_los(pyx,x1,y1,x2,y2)271 void do_object_los(pyx,x1,y1,x2,y2)
272 Symbol pyx;
273 int *x1,*y1,x2,y2;
274 {
275   int dx,dy,ox,oy;
276   int major, minor;
277   int error, delta, step;
278   int blocked;
279 
280   if (x2 - *x1 < 0) dx = 5;
281   else if (x2 - *x1 > 0) dx = 4;
282   else dx = -1;
283   if (y2 - *y1 < 0) dy = 7;
284   else if (y2 - *y1 > 0) dy = 6;
285   else dy = -1;
286   if (abs(x2 - *x1) > abs(y2 - *y1)) {
287     major = dx;
288     minor = dy;
289     step = abs(x2 - *x1);
290     delta = 2*abs(y2 - *y1);
291   }
292   else {
293     major = dy;
294     minor = dx;
295     step = abs(y2 - *y1);
296     delta = 2*abs(x2 - *x1);
297   }
298   if (major == -1)	/* x1,y2 already == x2,y2 */
299     return;
300   error = 0;
301   do {
302     ox = *x1; oy = *y1;
303     *x1 += Dirs[0][major];
304     *y1 += Dirs[1][major];
305     error += delta;
306     if (error > step) {	/* don't need to check that minor >= 0 */
307       *x1 += Dirs[0][minor];
308       *y1 += Dirs[1][minor];
309       error -= 2*step;
310     }
311     blocked = !unblocked(*x1,*y1);
312     if (error < 0 && (*x1 != x2 || *y1 != y2) && blocked) {
313       *x1 -= Dirs[0][minor];
314       *y1 -= Dirs[1][minor];
315       error += 2*step;
316       blocked = !unblocked(*x1,*y1);
317     }
318     plotspot(ox,oy,TRUE);
319     if (unblocked(*x1,*y1)) {
320       plotchar(pyx,*x1,*y1);
321       Level->site[*x1][*y1].showchar = pyx;
322       usleep(50000);
323     }
324   } while ((*x1 != x2 || *y1 != y2) && !blocked);
325   if (Level->site[*x1][*y1].creature == NULL && blocked) {
326     *x1 = ox;
327     *y1 = oy;
328   }
329   plotspot(*x1,*y1,TRUE);
330   levelrefresh();
331 }
332 
333 
334 /* los_p checks to see whether there is an unblocked los from x1,y1 to x2,y2 */
los_p(x1,y1,x2,y2)335 int los_p(x1,y1,x2,y2)
336 int x1,y1,x2,y2;
337 {
338   int dx,dy;
339   int major, minor;
340   int error, delta, step;
341   int blocked;
342 
343   if (x2-x1 < 0) dx = 5;
344   else if (x2-x1 > 0) dx = 4;
345   else dx = -1;
346   if (y2-y1 < 0) dy = 7;
347   else if (y2-y1 > 0) dy = 6;
348   else dy = -1;
349   if (abs(x2-x1) > abs(y2-y1)) {
350     major = dx;
351     minor = dy;
352     step = abs(x2 - x1);
353     delta = 2*abs(y2 - y1);
354   }
355   else {
356     major = dy;
357     minor = dx;
358     step = abs(y2 - y1);
359     delta = 2*abs(x2 - x1);
360   }
361   if (major == -1)	/* x1,y2 already == x2,y2 */
362     return TRUE;
363   error = 0;
364   do {
365     x1 += Dirs[0][major];
366     y1 += Dirs[1][major];
367     error += delta;
368     if (error > step) {	/* don't need to check that minor >= 0 */
369       x1 += Dirs[0][minor];
370       y1 += Dirs[1][minor];
371       error -= 2*step;
372     }
373     blocked = !unblocked(x1,y1);
374     if (error < 0 && (x1 != x2 || y1 != y2) && blocked) {
375       x1 -= Dirs[0][minor];
376       y1 -= Dirs[1][minor];
377       error += 2*step;
378       blocked = !unblocked(x1,y1);
379     }
380   } while ((x1 != x2 || y1 != y2) && !blocked);
381   return((x1==x2) && (y1==y2));
382 }
383 
384 
385 /* view_los_p sees through monsters */
view_los_p(x1,y1,x2,y2)386 int view_los_p(x1,y1,x2,y2)
387 int x1,y1,x2,y2;
388 {
389   int dx,dy;
390   int major, minor;
391   int error, delta, step;
392   int blocked;
393 
394   if (x2-x1 < 0) dx = 5;
395   else if (x2-x1 > 0) dx = 4;
396   else dx = -1;
397   if (y2-y1 < 0) dy = 7;
398   else if (y2-y1 > 0) dy = 6;
399   else dy = -1;
400   if (abs(x2-x1) > abs(y2-y1)) {
401     major = dx;
402     minor = dy;
403     step = abs(x2 - x1);
404     delta = 2*abs(y2 - y1);
405   }
406   else {
407     major = dy;
408     minor = dx;
409     step = abs(y2 - y1);
410     delta = 2*abs(x2 - x1);
411   }
412   if (major == -1)	/* x1,y2 already == x2,y2 */
413     return TRUE;
414   error = 0;
415   do {
416     x1 += Dirs[0][major];
417     y1 += Dirs[1][major];
418     error += delta;
419     if (error > step) {
420       x1 += Dirs[0][minor];
421       y1 += Dirs[1][minor];
422       error -= 2*step;
423     }
424     blocked = !view_unblocked(x1,y1);
425     if (error < 0 && (x1 != x2 || y1 != y2) && blocked) {
426       x1 -= Dirs[0][minor];
427       y1 -= Dirs[1][minor];
428       error += 2*step;
429       blocked = !view_unblocked(x1,y1);
430     }
431   } while ((x1 != x2 || y1 != y2) && !blocked);
432   return((x1==x2) && (y1==y2));
433 }
434 
435 #ifndef MSDOS_SUPPORTED_ANTIQUE
436 /* returns the command direction from the index into Dirs */
inversedir(dirindex)437 char inversedir(dirindex)
438 int dirindex;
439 {
440   switch (dirindex) {
441     case 0:return('n');
442     case 1:return('u');
443     case 2:return('b');
444     case 3:return('y');
445     case 4:return('l');
446     case 5:return('h');
447     case 6:return('j');
448     case 7:return('k');
449     default:return('\0');
450   }
451 }
452 #endif
453 
454 
calc_points()455 long calc_points()
456 {
457   int i;
458   long points=0;
459 
460   if (gamestatusp(SPOKE_TO_DRUID)) points += 50;
461   if (gamestatusp(COMPLETED_CAVES)) points += 100;
462   if (gamestatusp(COMPLETED_SEWERS)) points += 200;
463   if (gamestatusp(COMPLETED_CASTLE)) points += 300;
464   if (gamestatusp(COMPLETED_ASTRAL)) points += 400;
465   if (gamestatusp(COMPLETED_VOLCANO)) points += 500;
466   if (gamestatusp(KILLED_DRAGONLORD)) points += 100;
467   if (gamestatusp(KILLED_EATER)) points += 100;
468   if (gamestatusp(KILLED_LAWBRINGER)) points += 100;
469 
470   points += Player.xp/50;
471 
472   points += Player.cash/500;
473 
474   for (i=0;i<MAXITEMS;i++)
475     if (Player.possessions[i] != NULL)
476       points += Player.possessions[i]->level*(Player.possessions[i]->known+1);
477 
478   for (i=0;i<MAXPACK;i++)
479     if (Player.pack[i] != NULL)
480       points += Player.pack[i]->level*(Player.pack[i]->known+1);
481 
482   for (i=0;i<NUMRANKS;i++) {
483     if (Player.rank[i] == 5) points += 500;
484     else points += 20*Player.rank[i];
485   }
486 
487   if (Player.hp < 1)
488     points = (points / 2);
489 
490   else if (Player.rank[ADEPT])
491     points *= 10;
492 
493   return(points);
494 }
495 
496 
497 /* returns the 24 hour clock hour */
hour()498 int hour()
499 {
500   return((int)(((Time+720) / 60) % 24));
501 }
502 
503 /* returns 0, 10, 20, 30, 40, or 50 */
showminute()504 int showminute()
505 {
506   return((int)((Time % 60)/10)*10);
507 }
508 
509 /* returns the 12 hour clock hour */
showhour()510 int showhour()
511 {
512   int showtime;
513   if ((hour() == 0) || (hour() == 12)) showtime = 12;
514   else showtime = (hour() % 12);
515   return(showtime);
516 }
517 
518 /* nighttime is defined from 9 PM to 6AM */
nighttime()519 int nighttime()
520 {
521   return((hour() > 20) || (hour() < 7));
522 }
523 
getarticle(str)524 char *getarticle(str)
525 char *str;
526 {
527   if ((str[0]=='a') || (str[0]=='A') ||
528       (str[0]=='e') || (str[0]=='E') ||
529       (str[0]=='i') || (str[0]=='I') ||
530       (str[0]=='o') || (str[0]=='O') ||
531       (str[0]=='u') || (str[0]=='U') ||
532       (((str[0]=='h') || (str[0]=='H')) &&
533        ((str[1]=='i') || (str[1]=='e'))))
534     return("an ");
535   else return("a ");
536 }
537 
day()538 int day()
539 {
540   return ((Date % 30) + 1);
541 }
542 
ordinal(number)543 char *ordinal(number)
544 int number;
545 {
546   if ((number == 11) || (number == 12) || (number == 13)) return("th");
547   else  switch(number % 10) {
548     case 1:return("st");
549     case 2:return("nd");
550     case 3:return("rd");
551     default: return("th");
552   }
553 }
554 
month()555 char *month()
556 {
557   switch((Date % 360) / 30) {
558     case 0: return("Freeze");
559     case 1: return("Ice");
560     case 2: return("Mud");
561     case 3: return("Storm");
562     case 4: return("Breeze");
563     case 5: return("Light");
564     case 6: return("Flame");
565     case 7: return("Broil");
566     case 8: return("Cool");
567     case 9: return("Haunt");
568     case 10: return("Chill");
569     case 11: return("Dark");
570     case 12: return("Twixt");
571     default: return("***Error***");
572   }
573 }
574 
575 
576 /* WDT: code for the following two functions contributed by Sheldon
577  * Simms. */
578 /* finds floor space on level with buildaux not equal to baux,
579 sets x,y there. There must *be* floor space somewhere on level.... */
spaceok(int i,int j,int baux)580 int spaceok( int i, int j, int baux )
581 {
582   return (( Level->site[ i ][ j ].locchar == FLOOR ) &&
583           ( Level->site[ i ][ j ].creature == NULL ) &&
584           ( !loc_statusp( i, j, SECRET )) &&
585           ( Level->site[ i ][ j ].buildaux != baux ));
586 }
587 
findspace(int * x,int * y,int baux)588 void findspace( int *x, int *y, int baux )
589 {
590   int i, j, tog = TRUE, done = FALSE;
591 
592   do {
593     i = random_range( WIDTH );
594     j = random_range( LENGTH );
595     if ( spaceok( i, j, baux ))
596     {
597       done = TRUE;
598     }
599     else
600     {
601       if ( tog )
602       {
603         tog = !tog;
604         while( 1 )
605         {
606           i++;
607           if ( i >= WIDTH )
608             break;
609           else if ( spaceok( i, j, baux ))
610           {
611             done = TRUE;
612             break;
613           }
614         }
615       }
616       else
617       {
618         tog = !tog;
619         while( 1 )
620         {
621           j++;
622           if ( j >= LENGTH )
623             break;
624           else if ( spaceok( i, j, baux ))
625           {
626             done = TRUE;
627             break;
628           }
629         }
630       }
631     }
632   } while ( !done );
633   *x = i;
634   *y = j;
635 }
636 
637 /* is prefix a prefix of s? */
strprefix(prefix,s)638 int strprefix(prefix,s)
639 char *prefix,*s;
640 {
641   int i=0,matched=TRUE;
642   if (strlen(prefix) > strlen(s)) return(FALSE);
643   else {
644     while (matched && (i<strlen(prefix))) {
645       matched = (prefix[i] == s[i]);
646       i++;
647     }
648     return(matched);
649   }
650 }
651 
confirmation()652 int confirmation()
653 {
654   switch(random_range(4)) {
655   case 0:  mprint("Are you sure? [yn] "); break;
656   case 1:  mprint("Certain about that? [yn] "); break;
657   case 2:  mprint("Do you really mean it? [yn] "); break;
658   case 3:  mprint("Confirm that, would you? [yn] "); break;
659   }
660   return(ynq()=='y');
661 }
662 
663 
664 /* is character c a member of string s */
strmem(c,s)665 int strmem(c,s)
666 char c;
667 char *s;
668 {
669   int i,found=FALSE;
670   for(i=0;((i<strlen(s)) && (! found));i++)
671     found = (s[i] == c);
672   return(found);
673 }
674 
calc_weight()675 void calc_weight()
676 {
677   int i,weight=0;
678 
679   for(i=1;i<MAXITEMS;i++)
680     if (Player.possessions[i] != NULL)
681       weight += Player.possessions[i]->weight *
682 	Player.possessions[i]->number;
683   if ((Player.possessions[O_WEAPON_HAND] != NULL) &&
684       (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND]))
685     weight -= Player.possessions[O_READY_HAND]->weight *
686       Player.possessions[O_READY_HAND]->number;
687   for(i=0;i<MAXPACK;i++)
688     if (Player.pack[i] != NULL)
689       weight += Player.pack[i]->weight *
690 	Player.pack[i]->number;
691   Player.itemweight = weight;
692   dataprint();
693 }
694 
695 /* returns true if its ok to get rid of a level */
ok_to_free(level)696 int ok_to_free(level)
697 plv level;
698 {
699   if (level == NULL) return(FALSE);
700   else return((level->environment != E_CITY) &&
701 	      (level->environment != E_VILLAGE) &&
702 	      (level->environment != Current_Dungeon));
703 }
704 
free_objlist(pobjlist)705 void free_objlist(pobjlist)
706 pol pobjlist;
707 {
708   pol tmp;
709 
710   while (pobjlist) {
711     free((tmp = pobjlist)->thing);
712     pobjlist = pobjlist->next;
713     free(tmp);
714   }
715 }
716 
free_mons_and_objs(mlist)717 void free_mons_and_objs(mlist)
718 pml mlist;
719 {
720   pml tmp;
721 
722   while (mlist) {
723     free_objlist((tmp = mlist)->m->possessions);
724     free(tmp->m);
725     mlist = mlist->next;
726     free(tmp);
727   }
728 }
729 
730 /* Free up monsters and items on a level*/
free_level(level)731 void free_level(level)
732 plv level;
733 {
734   int i,j;
735 
736   free_mons_and_objs(level->mlist);
737   for (i = 0; i < MAXWIDTH; i++)
738     for (j = 0; j < MAXLENGTH; j++)
739       if (level->site[i][j].things) {
740 	free_objlist(level->site[i][j].things);
741 	level->site[i][j].things = NULL;
742       }
743 #ifndef SAVE_LEVELS
744   free(level);
745 #endif
746 }
747 
748 /* malloc function that checks its return value - if NULL, tries to free */
749 /* some memory... */
checkmalloc(unsigned int bytes)750 void *checkmalloc(unsigned int bytes)
751 {
752   void *ptr = malloc(bytes);
753   struct level *curr, **prev, **oldest;
754 
755   if (ptr)
756     return ptr;
757   for (curr = Dungeon, oldest = prev = &Dungeon; curr; curr = curr->next) {
758     if ((*oldest)->last_visited > curr->last_visited)
759       oldest = prev;
760     prev = &(curr->next);
761   }
762   if (*oldest && *oldest != Level) {
763     curr = *oldest;
764     *oldest = (*oldest)->next;
765     free_level(curr);
766     ptr = malloc(bytes);
767   }
768   if (ptr)
769     return ptr;
770   else {
771     print1("Out of memory!  Saving and quitting.");
772     morewait();
773     save(FALSE, TRUE);
774     endgraf();
775     exit(0);
776   }
777 }
778 
779 /* alloc just enough string space for str, strcpy, and return pointer */
salloc(str)780 char *salloc(str)
781 char *str;
782 {
783   char *s=checkmalloc((unsigned)(strlen(str)+1));
784   strcpy(s,str);
785   return(s);
786 }
787 
788 #ifdef MSDOS
789 /* ****Moved here from another file**** */
790 /* reads a string from a file. If it is a line with more than 80 char's,
791    then remainder of line to \n is consumed */
filescanstring(fd,fstr)792 void filescanstring(fd,fstr)
793 FILE *fd;
794 char *fstr;
795 {
796   int i= -1;
797   int byte='x';
798   while ((i<80) && (byte != '\n') && (byte != EOF)) {
799     i++;
800     byte=fgetc(fd);
801     fstr[i] = byte;
802   }
803   if (byte != '\n')
804     while((byte!='\n') && (byte != EOF))
805       byte=fgetc(fd);
806   fstr[i]=0;
807 }
808 #endif
809 
810 #ifdef MSDOS_SUPPORTED_ANTIQUE
811 /* ****Moved here from another file**** */
812 /* returns a "level of difficulty" based on current environment
813    and depth in dungeon. Is somewhat arbitrary. value between 1 and 10.
814    May not actually represent real difficulty, but instead level
815    of items, monsters encountered.    */
difficulty()816 int difficulty()
817 {
818   int depth = 1;
819   if (Level != NULL) depth = Level->depth;
820   switch(Current_Environment) {
821   case E_COUNTRYSIDE: return(7);
822   case E_CITY: return(3);
823   case E_VILLAGE: return(1);
824   case E_TACTICAL_MAP: return(7);
825   case E_SEWERS: return(depth/6)+3;
826   case E_CASTLE: return(depth/4)+4;
827   case E_CAVES: return(depth/3)+1;
828   case E_VOLCANO: return(depth/4)+5;
829   case E_ASTRAL: return(8);
830   case E_ARENA: return(5);
831   case E_HOVEL: return(3);
832   case E_MANSION: return(7);
833   case E_HOUSE: return(5);
834   case E_DLAIR: return(9);
835   case E_ABYSS: return(10);
836   case E_STARPEAK: return(9);
837   case E_CIRCLE: return(8);
838   case E_MAGIC_ISLE: return(8);
839   case E_TEMPLE: return(8);
840   default: return(3);
841   }
842 }
843 #endif
844 
cryptkey(fname)845 char cryptkey(fname)
846 char *fname;
847 {
848     int pos, key = 0;
849 
850     for (pos = 0; fname[pos]; pos++)
851 	key += 3*(fname[pos] - ' ');
852     return (key&0xff);
853 }
854 
855 int game_uid;
856 int user_uid;
857 
init_perms()858 void init_perms()
859 {
860 #if (defined(BSD) || defined(SYSV)) && !defined(__DJGPP__)
861     user_uid = getuid();
862     game_uid = geteuid();
863 #endif
864 }
865 
866 /*
867 #ifdef BSD
868 void setreuid(int, int);
869 #endif
870 */
871 
change_to_user_perms()872 void change_to_user_perms()
873 {
874 #if (defined( BSD ) || defined( SYSV )) && !defined(__EMX__) && !defined(__DJGPP__)
875 #ifdef BSD
876     setreuid(game_uid, user_uid);
877 #else /* SYSV */
878     seteuid(user_uid);
879 #endif /* BSD */
880 #endif /* BSD || SYSV */
881 }
882 
change_to_game_perms()883 void change_to_game_perms()
884 {
885 #if (defined( BSD ) || defined( SYSV )) && !defined(__EMX__) && !defined(__DJGPP__)
886 #ifdef BSD
887     setreuid(user_uid, game_uid);
888 #else /* SYSV */
889     seteuid(game_uid);
890 #endif /* BSD */
891 #endif /* BSD || SYSV */
892 }
893 
894 #ifdef NO_USLEEP
usleep(int usecs)895 void usleep(int usecs)
896 {
897   fd_set null;
898   struct timeval timeout;
899 
900   FD_ZERO(&null);
901   timeout.tv_usec = usecs;
902   timeout.tv_sec = 0;
903   select(0, &null, &null, &null, &timeout);
904 }
905 #endif
906