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