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