route: ensure RTM_IFINFO is sent first when bring interface down/up
[dragonfly.git] / games / larn / create.c
1 /*      create.c                Larn is copyrighted 1986 by Noah Morgan. */
2 /* $FreeBSD: src/games/larn/create.c,v 1.4 1999/11/16 02:57:20 billf Exp $ */
3 /* $DragonFly: src/games/larn/create.c,v 1.3 2006/08/26 17:05:05 pavalos Exp $ */
4 #include "header.h"
5
6 static void makemaze(int);
7 static int cannedlevel(int);
8 static void treasureroom(int);
9 static void troom(int, int, int, int, int, int);
10 static void makeobject(int);
11 static void fillmroom(int, char, int);
12 static void froom(int, char, int);
13 static void fillroom(char, int);
14 static void sethp(int);
15 static void checkgen(void);
16
17 /*
18         makeplayer()
19
20         subroutine to create the player and the players attributes
21         this is called at the beginning of a game and at no other time
22  */
23 void
24 makeplayer(void)
25 {
26         int i;
27         scbr();
28         clear();
29         c[HPMAX] = c[HP] = 10;          /* start player off with 15 hit points */
30         c[LEVEL] = 1;                   /* player starts at level one */
31         c[SPELLMAX] = c[SPELLS] = 1;    /* total # spells starts off as 3 */
32         c[REGENCOUNTER] = 16;           /* start regeneration correctly */
33         c[ECOUNTER] = 96;
34         c[SHIELD] = c[WEAR] = c[WIELD] = -1;
35         for (i = 0; i < 26; i++)
36                 iven[i] = 0;
37         spelknow[0] = spelknow[1] = 1;  /* he knows protection, magic missile */
38         if (c[HARDGAME] <= 0) {
39                 iven[0] = OLEATHER;
40                 iven[1] = ODAGGER;
41                 ivenarg[1] = ivenarg[0] = c[WEAR] = 0;
42                 c[WIELD] = 1;
43         }
44         playerx = rnd(MAXX - 2);
45         playery = rnd(MAXY - 2);
46         oldx = 0;
47         oldy = 25;
48         gtime = 0;              /* time clock starts at zero */
49         cbak[SPELLS] = -50;
50         for (i = 0; i < 6; i++) /* make the attributes, ie str, int, etc. */
51                 c[i] = 12;
52         recalc();
53 }
54
55 /*
56         newcavelevel(level)
57         int level;
58
59         function to enter a new level.  This routine must be called anytime the
60         player changes levels.  If that level is unknown it will be created.
61         A new set of monsters will be created for a new level, and existing
62         levels will get a few more monsters.
63         Note that it is here we remove genocided monsters from the present level.
64  */
65 void
66 newcavelevel(int x)
67 {
68         int i, j;
69         if (beenhere[(int)level])       /* put the level back into storage */
70                 savelevel();
71         level = x;      /* get the new level and put in working storage */
72         if (beenhere[x] == 0)
73                 for (i = 0; i < MAXY; i++)
74                         for (j = 0; j < MAXX; j++)
75                                 know[j][i] = mitem[j][i] = 0;
76         else {
77                 getlevel();
78                 sethp(0);
79                 goto chgn;
80         }
81         makemaze(x);
82         makeobject(x);
83         beenhere[x] = 1;
84         sethp(1);
85
86 #if WIZID
87         if (wizard || x == 0)
88 #else
89         if (x == 0)
90 #endif
91                 for (j = 0; j < MAXY; j++)
92                         for (i = 0; i < MAXX; i++)
93                                 know[i][j] = 1;
94 chgn:
95         checkgen();       /* wipe out any genocided monsters */
96 }
97
98 /*
99         makemaze(level)
100         int level;
101
102         subroutine to make the caverns for a given level.  only walls are made.
103  */
104 static int mx, mxl, mxh, my, myl, myh, tmp2;
105
106 static void
107 makemaze(int k)
108 {
109         int i, j, tmp;
110         int z;
111         if (k > 1 && (rnd(17) <= 4 || k == MAXLEVEL - 1 || k == MAXLEVEL + MAXVLEVEL - 1))
112                 if (cannedlevel(k))     /* read maze from data file */
113                         return;
114         if (k == 0)
115                 tmp = 0;
116         else
117                 tmp = OWALL;
118         for (i = 0; i < MAXY; i++)
119                 for (j = 0; j < MAXX; j++)
120                         item[j][i] = tmp;
121         if (k == 0)
122                 return;
123         eat(1, 1);
124         if (k == 1)                     /* exit from dungeon */
125                 item[33][MAXY - 1] = 0;
126
127         /* now for open spaces -- not on level 10 */
128         if (k != MAXLEVEL - 1) {
129                 tmp2 = rnd(3) + 3;
130                 for (tmp = 0; tmp < tmp2; tmp++) {
131                         my = rnd(11) + 2;
132                         myl = my - rnd(2);
133                         myh = my + rnd(2);
134                         if (k < MAXLEVEL) {
135                                 mx = rnd(44) + 5;
136                                 mxl = mx - rnd(4);
137                                 mxh = mx + rnd(12) + 3;
138                                 z = 0;
139                         } else {
140                                 mx = rnd(60) + 3;
141                                 mxl = mx - rnd(2);
142                                 mxh = mx + rnd(2);
143                                 z = makemonst(k);
144                         }
145                         for (i = mxl; i < mxh; i++)
146                                 for (j = myl; j < myh; j++) {
147                                         item[i][j] = 0;
148                                         if ((mitem[i][j] = z))
149                                                 hitp[i][j] = monster[z].hitpoints;
150                                 }
151                 }
152         }
153         if (k != MAXLEVEL - 1) {
154                 my = rnd(MAXY - 2);
155                 for (i = 1; i < MAXX - 1; i++)
156                         item[i][my] = 0;
157         }
158         if (k > 1)
159                 treasureroom(k);
160 }
161
162 /*
163         function to eat away a filled in maze
164  */
165 void
166 eat(int xx, int yy)
167 {
168         int dir, try;
169         dir = rnd(4);
170         try = 2;
171         while (try) {
172                 switch (dir) {
173                 case 1:
174                         if (xx <= 2)            /* west */
175                                 break;
176                         if ((item[xx - 1][yy] != OWALL) || (item[xx - 2][yy] != OWALL))
177                                 break;
178                         item[xx - 1][yy] = item[xx - 2][yy] = 0;
179                         eat(xx - 2, yy);
180                         break;
181
182                 case 2:
183                         if (xx >= MAXX - 3)     /* east */
184                                 break;
185                         if ((item[xx + 1][yy] != OWALL) || (item[xx + 2][yy] != OWALL))
186                                 break;
187                         item[xx + 1][yy] = item[xx + 2][yy] = 0;
188                         eat(xx + 2, yy);
189                         break;
190
191                 case 3:
192                         if (yy <= 2)            /* south */
193                                 break;
194                         if ((item[xx][yy - 1] != OWALL) || (item[xx][yy - 2] != OWALL))
195                                 break;
196                         item[xx][yy - 1] = item[xx][yy - 2] = 0;
197                         eat(xx, yy - 2);
198                         break;
199
200                 case 4:
201                         if (yy >= MAXY - 3)     /* north */
202                                 break;
203                         if ((item[xx][yy + 1] != OWALL) || (item[xx][yy + 2] != OWALL))
204                                 break;
205                         item[xx][yy + 1] = item[xx][yy + 2] = 0;
206                         eat(xx, yy + 2);
207                         break;
208                 }
209                 if (++dir > 4) {
210                         dir = 1;
211                         --try;
212                 }
213         }
214 }
215
216 /*
217  *      function to read in a maze from a data file
218  *
219  *      Format of maze data file:  1st character = # of mazes in file (ascii digit)
220  *                              For each maze: 18 lines (1st 17 used) 67 characters per line
221  *
222  *      Special characters in maze data file:
223  *
224  *              #       wall                    D       door                    .       random monster
225  *              ~       eye of larn             !       cure dianthroritis
226  *              -       random object
227  */
228 static int
229 cannedlevel(int k)
230 {
231         char *row;
232         int i, j;
233         int it, arg, mit, marg;
234         if (lopen(larnlevels) < 0) {
235                 write(1, "Can't open the maze data file\n", 30);
236                 died(-282);
237                 return (0);
238         }
239         i = lgetc();
240         if (i <= '0') {
241                 died(-282);
242                 return (0);
243         }
244         for (i = 18 * rund(i - '0'); i > 0; i--)
245                 lgetl();        /* advance to desired maze */
246         for (i = 0; i < MAXY; i++) {
247                 row = lgetl();
248                 for (j = 0; j < MAXX; j++) {
249                         it = mit = arg = marg = 0;
250                         switch (*row++) {
251                         case '#':
252                                 it = OWALL;
253                                 break;
254                         case 'D':
255                                 it = OCLOSEDDOOR;
256                                 arg = rnd(30);
257                                 break;
258                         case '~':
259                                 if (k != MAXLEVEL - 1)
260                                         break;
261                                 it = OLARNEYE;
262                                 mit = rund(8) + DEMONLORD;
263                                 marg = monster[mit].hitpoints;
264                                 break;
265                         case '!':
266                                 if (k != MAXLEVEL + MAXVLEVEL - 1)
267                                         break;
268                                 it = OPOTION;
269                                 arg = 21;
270                                 mit = DEMONLORD + 7;
271                                 marg = monster[mit].hitpoints;
272                                 break;
273                         case '.':
274                                 if (k < MAXLEVEL)
275                                         break;
276                                 mit = makemonst(k + 1);
277                                 marg = monster[mit].hitpoints;
278                                 break;
279                         case '-':
280                                 it = newobject(k + 1, &arg);
281                                 break;
282                         }
283                         item[j][i] = it;
284                         iarg[j][i] = arg;
285                         mitem[j][i] = mit;
286                         hitp[j][i] = marg;
287
288 #if WIZID
289                         know[j][i] = (wizard) ? 1 : 0;
290 #else
291                         know[j][i] = 0;
292 #endif
293                 }
294         }
295         lrclose();
296         return (1);
297 }
298
299 /*
300         function to make a treasure room on a level
301         level 10's treasure room has the eye in it and demon lords
302         level V3 has potion of cure dianthroritis and demon prince
303  */
304 static void
305 treasureroom(int lv)
306 {
307         int tx, ty, xsize, ysize;
308
309         for (tx = 1 + rnd(10); tx < MAXX - 10; tx += 10)
310                 if ((lv == MAXLEVEL - 1) || (lv == MAXLEVEL + MAXVLEVEL - 1) || rnd(13) == 2) {
311                         xsize = rnd(6) + 3;
312                         ysize = rnd(3) + 3;
313                         ty = rnd(MAXY - 9) + 1; /* upper left corner of room */
314                         if (lv == MAXLEVEL - 1 || lv == MAXLEVEL + MAXVLEVEL - 1)
315                                 troom(lv, xsize, ysize, tx = tx + rnd(MAXX - 24), ty, rnd(3) + 6);
316                         else
317                                 troom(lv, xsize, ysize, tx, ty, rnd(9));
318                 }
319 }
320
321 /*
322  *      subroutine to create a treasure room of any size at a given location
323  *      room is filled with objects and monsters
324  *      the coordinate given is that of the upper left corner of the room
325  */
326 static void
327 troom(int lv, int xsize, int ysize, int tx, int ty, int glyph)
328 {
329         int i, j;
330         int tp1, tp2;
331         for (j = ty - 1; j <= ty + ysize; j++)
332                 for (i = tx - 1; i <= tx + xsize; i++)  /* clear out space for room */
333                         item[i][j] = 0;
334         for (j = ty; j < ty + ysize; j++)
335                 for (i = tx; i < tx + xsize; i++) {     /* now put in the walls */
336                         item[i][j] = OWALL;
337                         mitem[i][j] = 0;
338                 }
339         for (j = ty + 1; j < ty + ysize - 1; j++)
340                 for (i = tx + 1; i < tx + xsize - 1; i++)       /* now clear out interior */
341                         item[i][j] = 0;
342
343         switch (rnd(2)) {       /* locate the door on the treasure room */
344         case 1:
345                 item[i = tx + rund(xsize)][j = ty + (ysize - 1) * rund(2)] = OCLOSEDDOOR;
346                 iarg[i][j] = glyph;     /* on horizontal walls */
347                 break;
348         case 2:
349                 item[i = tx + (xsize - 1) * rund(2)][j = ty + rund(ysize)] = OCLOSEDDOOR;
350                 iarg[i][j] = glyph;     /* on vertical walls */
351                 break;
352         }
353
354         tp1 = playerx;
355         tp2 = playery;
356         playery = ty + (ysize >> 1);
357         if (c[HARDGAME] < 2)
358                 for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
359                         for (i = 0, j = rnd(6); i <= j; i++) {
360                                 something(lv + 2);
361                                 createmonster(makemonst(lv + 1));
362                         }
363         else
364                 for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
365                         for (i = 0, j = rnd(4); i <= j; i++) {
366                                 something(lv + 2);
367                                 createmonster(makemonst(lv + 3));
368                         }
369
370         playerx = tp1;
371         playery = tp2;
372 }
373
374 /*
375         ***********
376         MAKE_OBJECT
377         ***********
378         subroutine to create the objects in the maze for the given level
379  */
380 static void
381 makeobject(int j)
382 {
383         int i;
384         if (j == 0) {
385                 fillroom(OENTRANCE, 0); /* entrance to dungeon */
386                 fillroom(ODNDSTORE, 0); /* the DND STORE */
387                 fillroom(OSCHOOL, 0);   /* college of Larn */
388                 fillroom(OBANK, 0);     /* 1st national bank of larn */
389                 fillroom(OVOLDOWN, 0);  /* volcano shaft to temple */
390                 fillroom(OHOME, 0);     /* the players home & family */
391                 fillroom(OTRADEPOST, 0);/* the trading post */
392                 fillroom(OLRS, 0);      /* the larn revenue service */
393                 return;
394         }
395         if (j == MAXLEVEL)  /* volcano shaft up from the temple */
396                 fillroom(OVOLUP, 0);
397
398         /* make the fixed objects in the maze STAIRS */
399         if ((j > 0) && (j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
400                 fillroom(OSTAIRSDOWN, 0);
401         if ((j > 1) && (j != MAXLEVEL))
402                 fillroom(OSTAIRSUP, 0);
403
404         /* make the random objects in the maze */
405
406         fillmroom(rund(3), OBOOK, j);
407         fillmroom(rund(3), OALTAR, 0);
408         fillmroom(rund(3), OSTATUE, 0);
409         fillmroom(rund(3), OPIT, 0);
410         fillmroom(rund(3), OFOUNTAIN, 0);
411         fillmroom(rnd(3) - 2, OIVTELETRAP, 0);
412         fillmroom(rund(2), OTHRONE, 0);
413         fillmroom(rund(2), OMIRROR, 0);
414         fillmroom(rund(2), OTRAPARROWIV, 0);
415         fillmroom(rnd(3) - 2, OIVDARTRAP, 0);
416         fillmroom(rund(3), OCOOKIE, 0);
417         if (j == 1)
418                 fillmroom(1, OCHEST, j);
419         else
420                 fillmroom(rund(2), OCHEST, j);
421         if ((j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
422                 fillmroom(rund(2), OIVTRAPDOOR, 0);
423         if (j <= 10) {
424                 fillmroom((rund(2)), ODIAMOND, rnd(10 * j + 1) + 10);
425                 fillmroom(rund(2), ORUBY, rnd(6 * j + 1) + 6);
426                 fillmroom(rund(2), OEMERALD, rnd(4 * j + 1) + 4);
427                 fillmroom(rund(2), OSAPPHIRE, rnd(3 * j + 1) + 2);
428         }
429         for (i = 0; i < rnd(4) + 3; i++)
430                 fillroom(OPOTION, newpotion()); /* make a POTION */
431         for (i = 0; i < rnd(5) + 3; i++)
432                 fillroom(OSCROLL, newscroll()); /* make a SCROLL */
433         for (i = 0; i < rnd(12) + 11; i++)
434                 fillroom(OGOLDPILE, 12 * rnd(j + 1) + (j << 3) + 10);   /* make GOLD */
435         if (j == 5)
436                 fillroom(OBANK2, 0);    /* branch office of the bank */
437         froom(2, ORING, 0);             /* a ring mail */
438         froom(1, OSTUDLEATHER, 0);      /* a studded leather */
439         froom(3, OSPLINT, 0);           /* a splint mail */
440         froom(5, OSHIELD, rund(3));     /* a shield */
441         froom(2, OBATTLEAXE, rund(3));  /* a battle axe */
442         froom(5, OLONGSWORD, rund(3));  /* a long sword */
443         froom(5, OFLAIL, rund(3));      /* a flail */
444         froom(4, OREGENRING, rund(3));  /* ring of regeneration */
445         froom(1, OPROTRING, rund(3));   /* ring of protection */
446         froom(2, OSTRRING, 4);          /* ring of strength + 4 */
447         froom(7, OSPEAR, rnd(5));       /* a spear */
448         froom(3, OORBOFDRAGON, 0);      /* orb of dragon slaying */
449         froom(4, OSPIRITSCARAB, 0);     /* scarab of negate spirit */
450         froom(4, OCUBEofUNDEAD, 0);     /* cube of undead control */
451         froom(2, ORINGOFEXTRA, 0);      /* ring of extra regen */
452         froom(3, ONOTHEFT, 0);          /* device of antitheft */
453         froom(2, OSWORDofSLASHING, 0);  /* sword of slashing */
454         if (c[BESSMANN] == 0) {
455                 froom(4, OHAMMER, 0);   /* Bessman's flailing hammer */
456                 c[BESSMANN] = 1;
457         }
458         if (c[HARDGAME] < 3 || (rnd(4) == 3)) {
459                 if (j > 3) {
460                         froom(3, OSWORD, 3);            /* sunsword + 3 */
461                         froom(5, O2SWORD, rnd(4));      /* a two handed sword */
462                         froom(3, OBELT, 4);             /* belt of striking */
463                         froom(3, OENERGYRING, 3);       /* energy ring */
464                         froom(4, OPLATE, 5);            /* platemail + 5 */
465                 }
466         }
467 }
468
469 /*
470         subroutine to fill in a number of objects of the same kind
471  */
472 static void
473 fillmroom(int n, char what, int arg)
474 {
475         int i;
476         for (i = 0; i < n; i++)
477                 fillroom(what, arg);
478 }
479
480 static void
481 froom(int n, char itm, int arg)
482 {
483         if (rnd(151) < n)
484                 fillroom(itm, arg);
485 }
486
487 /*
488         subroutine to put an object into an empty room
489  *      uses a random walk
490  */
491 static void
492 fillroom(char what, int arg)
493 {
494         int x, y;
495
496 #ifdef EXTRA
497         c[FILLROOM]++;
498 #endif
499
500         x = rnd(MAXX - 2);
501         y = rnd(MAXY - 2);
502         while (item[x][y]) {
503 #ifdef EXTRA
504                 c[RANDOMWALK]++;/* count up these random walks */
505 #endif
506
507                 x += rnd(3) - 2;
508                 y += rnd(3) - 2;
509                 if (x > MAXX - 2)
510                         x = 1;
511                 if (x < 1)
512                         x = MAXX - 2;
513                 if (y > MAXY - 2)
514                         y = 1;
515                 if (y < 1)
516                         y = MAXY - 2;
517         }
518         item[x][y] = what;
519         iarg[x][y] = arg;
520 }
521
522 /*
523         subroutine to put monsters into an empty room without walls or other
524         monsters
525  */
526 int
527 fillmonst(char what)
528 {
529         int x, y, trys;
530         for (trys = 5; trys > 0; --trys) {      /* max # of creation attempts */
531                 x = rnd(MAXX - 2);
532                 y = rnd(MAXY - 2);
533                 if ((item[x][y] == 0) && (mitem[x][y] == 0) &&
534                     ((playerx != x) || (playery != y))) {
535                         mitem[x][y] = what;
536                         know[x][y] = 0;
537                         hitp[x][y] = monster[(int)what].hitpoints;
538                         return (0);
539                 }
540         }
541         return (-1);    /* creation failure */
542 }
543
544 /*
545         creates an entire set of monsters for a level
546         must be done when entering a new level
547         if sethp(1) then wipe out old monsters else leave them there
548  */
549 static void
550 sethp(int flg)
551 {
552         int i, j;
553         if (flg)
554                 for (i = 0; i < MAXY; i++)
555                         for (j = 0; j < MAXX; j++)
556                                 stealth[j][i] = 0;
557         if (level == 0) {
558                 c[TELEFLAG] = 0;
559                 return;
560         }
561         /* if teleported and found level 1 then know level we are on */
562         if (flg)
563                 j = rnd(12) + 2 + (level >> 1);
564         else
565                 j = (level >> 1) + 1;
566         for (i = 0; i < j; i++)
567                 fillmonst(makemonst(level));
568         positionplayer();
569 }
570
571 /*
572  *      Function to destroy all genocided monsters on the present level
573  */
574 static void
575 checkgen(void)
576 {
577         int x, y;
578         for (y = 0; y < MAXY; y++)
579                 for (x = 0; x < MAXX; x++)
580                         if (monster[(int)mitem[x][y]].genocided)
581                                 mitem[x][y] = 0;        /* no more monster */
582 }