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 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 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 } 472