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