1 /* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
2 /* gen2.c */
3 /* level generator functions */
4 
5 #include "glob.h"
6 
7 
8 
9 /* For each level, there should be one stairway going up and one down.
10 fromlevel determines whether the player is placed on the up or the down
11 staircase. The aux value is currently unused elsewhere, but is set
12 to the destination level. */
13 
make_stairs(fromlevel)14 void make_stairs(fromlevel)
15 int fromlevel;
16 {
17   int i,j;
18   /* no stairway out of astral */
19   if (Current_Environment != E_ASTRAL) {
20     findspace(&i,&j,-1);
21     Level->site[i][j].locchar = STAIRS_UP;
22     Level->site[i][j].aux = Level->depth-1;
23     lset(i,j,STOPS);
24     if (fromlevel >= 0 && fromlevel < Level->depth) {
25       Player.x = i;
26       Player.y = j;
27     }
28   }
29   if (Level->depth < MaxDungeonLevels) {
30     findspace(&i,&j,-1);
31     Level->site[i][j].locchar = STAIRS_DOWN;
32     Level->site[i][j].aux = Level->depth+1;
33     lset(i,j,STOPS);
34     if (fromlevel > Level->depth) {
35       Player.x = i;
36       Player.y = j;
37     }
38   }
39 }
40 
41 
42 
43 
44 
45 /* tactical map generating functions */
46 
47 
make_country_screen(terrain)48 void make_country_screen(terrain)
49 Symbol terrain;
50 {
51   int i,j;
52   TempLevel = Level;
53   if (ok_to_free(TempLevel)) {
54 #ifndef SAVE_LEVELS
55     free_level(TempLevel);
56 #endif
57     TempLevel = NULL;
58   }
59 #ifndef SAVE_LEVELS
60   Level = ((plv) checkmalloc(sizeof(levtype)));
61 #else
62   msdos_changelevel(TempLevel,0,-1);
63   Level = &TheLevel;
64 #endif
65   clear_level(Level);
66   Level->environment = E_TACTICAL_MAP;
67   Level->generated = TRUE;
68   switch(terrain) {
69   case FOREST: make_forest(); break;
70   case JUNGLE: make_jungle(); break;
71   case SWAMP: make_swamp(); break;
72   case RIVER: make_river(); break;
73   case MOUNTAINS: case PASS: make_mountains(); break;
74   case ROAD: make_road(); break;
75   default: make_plains(); break;
76   }
77   if (nighttime()) {
78     print3("Night's gloom shrouds your sight.");
79     for(i=0;i<WIDTH;i++)
80       for(j=0;j<LENGTH;j++) {
81 	Level->site[i][j].showchar = SPACE;
82 	Level->site[i][j].lstatus = 0;
83       }
84   }
85 }
86 
make_general_map(terrain)87 void make_general_map(terrain)
88 char *terrain;
89 {
90   int i, j;
91   int size = strlen(terrain);
92   char curr;
93 
94   for (i=0;i<WIDTH;i++)
95     for (j=0;j<LENGTH;j++) {
96       if ((i == 0 && j == 0) || !random_range(5))
97 	curr = terrain[random_range(size)];
98       else if (j == 0 || (random_range(2) && i > 0))
99 	curr = Level->site[i - 1][j].locchar&0xff;
100       else
101 	curr = Level->site[i][j - 1].locchar&0xff;
102       switch (curr) {
103 	case (FLOOR&0xff):
104 	  Level->site[i][j].locchar = Level->site[i][j].showchar = FLOOR;
105 	  Level->site[i][j].p_locf = L_NO_OP;
106 	  break;
107 	case (HEDGE&0xff):
108 	  Level->site[i][j].locchar = Level->site[i][j].showchar = HEDGE;
109 	  Level->site[i][j].p_locf = L_HEDGE;
110 	  break;
111 	case (WATER&0xff):
112 	  Level->site[i][j].locchar = Level->site[i][j].showchar = WATER;
113 	  Level->site[i][j].p_locf = L_WATER;
114 	  break;
115 	case (RUBBLE&0xff):
116 	  Level->site[i][j].locchar = Level->site[i][j].showchar = RUBBLE;
117 	  Level->site[i][j].p_locf = L_RUBBLE;
118 	  break;
119       }
120       Level->site[i][j].lstatus = SEEN+LIT;
121       Level->site[i][j].roomnumber = RS_COUNTRYSIDE;
122       if ((i == 0) || (j == 0) || (i == WIDTH-1) || (j == LENGTH-1))
123 	Level->site[i][j].p_locf = L_TACTICAL_EXIT;
124     }
125 }
126 
make_plains()127 void make_plains()
128 {
129   make_general_map(".");
130 }
131 
make_road()132 void make_road()
133 {
134   int x, y;
135   make_general_map("\"\"~4....");
136   for (x = WIDTH/2 - 3; x <= WIDTH/2 + 3; x++)
137     for (y = 0; y < LENGTH; y++) {
138       Level->site[x][y].locchar = Level->site[x][y].showchar = FLOOR;
139       if (y != 0 && y != LENGTH - 1)
140 	Level->site[x][y].p_locf = L_NO_OP;
141     }
142 }
143 
144 
145 
make_forest()146 void make_forest()
147 {
148   make_general_map("\".");
149   straggle_corridor(0,random_range(LENGTH),WIDTH,random_range(LENGTH),
150     WATER,RS_COUNTRYSIDE);
151 }
152 
153 
make_jungle()154 void make_jungle()
155 {
156   make_general_map("\"\".");
157 }
158 
159 
make_river()160 void make_river()
161 {
162   int i,y,y1;
163   make_general_map("\".......");
164   y = random_range(LENGTH);
165   y1 = random_range(LENGTH);
166   straggle_corridor(0,y,WIDTH,y1,WATER,RS_COUNTRYSIDE);
167   for(i=0;i<7;i++) {
168     if (y > LENGTH/2) y--;
169     else y++;
170     if (y1 > LENGTH/2) y1--;
171     else y1++;
172     straggle_corridor(0,y,WIDTH,y1,WATER,RS_COUNTRYSIDE);
173   }
174 }
175 
176 
make_mountains()177 void make_mountains()
178 {
179   int i,x,y,x1,y1;
180   make_general_map("4...");
181   x = 0;
182   y = random_range(LENGTH);
183   x1 = WIDTH;
184   y1 = random_range(LENGTH);
185   straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE);
186   for(i=0;i<7;i++) {
187     x = random_range(WIDTH);
188     x1 = random_range(WIDTH);
189     y = 0;
190     y1 = LENGTH;
191     straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE);
192   }
193 }
194 
195 
196 
make_swamp()197 void make_swamp()
198 {
199   make_general_map("~~\".");
200 }
201 
202 
203 
204 
205 
206 
207 /* builds a room. Then, for each successive room, sends off at least one
208 corridor which is guaranteed to connect up to another room, thus guaranteeing
209 fully connected level. */
210 
room_level()211 void room_level()
212 {
213   int i,fx,fy,tx,ty,t,l,e;
214   char rsi;
215 
216   Level->numrooms = random_range(8)+9;
217 
218   do {
219     t = random_range(LENGTH-10)+1;
220     l = random_range(WIDTH-10)+1;
221     e = 4+random_range(5);
222   } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) ||
223 	   (Level->site[l+e][t].roomnumber != RS_WALLSPACE) ||
224 	   (Level->site[l][t+e].roomnumber != RS_WALLSPACE) ||
225 	   (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE));
226   if (Current_Dungeon == E_SEWERS) {
227     if (random_range(2)) rsi = ROOMBASE+25;
228     else rsi = ROOMBASE+random_range(NUMROOMNAMES);
229   }
230   else rsi = ROOMBASE+random_range(NUMROOMNAMES);
231   build_room(l,t,e,rsi,1);
232 
233 
234   for (i=2;i<=Level->numrooms;i++) {
235     do {
236       t = random_range(LENGTH-10)+1;
237       l = random_range(WIDTH-10)+1;
238       e = 4+random_range(5);
239     } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) ||
240 	     (Level->site[l+e][t].roomnumber != RS_WALLSPACE) ||
241 	     (Level->site[l][t+e].roomnumber != RS_WALLSPACE) ||
242 	     (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE));
243     if (Current_Dungeon == E_SEWERS) {
244       if (random_range(2)) rsi = ROOMBASE+25;
245       else rsi = ROOMBASE+random_range(NUMROOMNAMES);
246     }
247     else rsi = ROOMBASE+random_range(NUMROOMNAMES);
248     build_room(l,t,e,rsi,i);
249 
250 
251     /* corridor which is guaranteed to connect */
252     findspace(&tx,&ty,i);
253 
254     /* figure out where to start corridor from */
255     if ((ty <= t) && (tx <= l+e)) {
256       fx = l+1+random_range(e-1);
257       fy = t;
258     }
259     else if ((tx >= l+e) && (ty <= t+e)) {
260       fx = l+e;
261       fy = t+1+random_range(e-1);
262     }
263     else if ((ty >= t+e) && (tx >= l)) {
264       fx = l+1+random_range(e-1);
265       fy = t+e;
266     }
267     else {
268       fx = l;
269       fy = t+1+random_range(e-1);
270     }
271 
272     room_corridor(fx,fy,tx,ty,i);
273 
274 
275     /* corridor which may not go anywhere */
276     if (random_range(2)) {
277       findspace(&tx,&ty,i);
278       if ((ty <= t) && (tx <= l+e)) {
279 	fx = l+1+random_range(e-1);
280 	fy = t;
281       }
282       else if ((tx >= l+e) && (ty <= t+e)) {
283 	fx = l+e;
284 	fy = t+1+random_range(e-1);
285       }
286       else if ((ty >= t+e) && (tx >= l)) {
287 	fx = l+1+random_range(e-1);
288 	fy = t+e;
289       }
290       else {
291 	fx = l;
292 	fy = t+1+random_range(e-1);
293       }
294       room_corridor(fx,fy,tx,ty,i);
295     }
296   }
297 
298   if (Current_Dungeon == E_SEWERS) {
299     if (Level->depth == SEWERLEVELS) {
300       findspace(&tx,&ty,-1);
301       Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
302       Level->mlist->next = NULL;
303       Level->mlist->m =
304 	Level->site[tx][ty].creature =
305 	  ((pmt) make_creature(GREAT_WYRM)); /* The Great Wyrm */
306       Level->mlist->m->x = tx;
307       Level->mlist->m->y = ty;
308     }
309   }
310   else if (Current_Environment == E_CASTLE) {
311     if (Level->depth == CASTLELEVELS) {
312       findspace(&tx,&ty,-1);
313       Level->site[tx][ty].locchar = STAIRS_DOWN;
314       Level->site[tx][ty].p_locf = L_ENTER_COURT;
315     }
316   }
317   else if (Current_Environment == E_VOLCANO) {
318     if (Level->depth == VOLCANOLEVELS && !gamestatusp(COMPLETED_VOLCANO)) {
319       findspace(&tx,&ty,-1);
320       Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
321       Level->mlist->next = NULL;
322       Level->mlist->m =
323 	Level->site[tx][ty].creature =
324 	  ((pmt) make_creature(DEMON_EMP)); /* The demon emp */
325       Level->mlist->m->x = tx;
326       Level->mlist->m->y = ty;
327     }
328   }
329 }
330 
331 
332 
333 /* goes from f to t unless it hits a site which is not a wall and doesn't
334    have buildaux field == baux */
room_corridor(fx,fy,tx,ty,baux)335 void room_corridor(fx,fy,tx,ty,baux)
336 int fx,fy,tx,ty,baux;
337 {
338   int dx,dy,continuing = TRUE;
339 
340   dx = sign(tx-fx);
341   dy = sign(ty-fy);
342 
343   makedoor(fx,fy);
344 
345   fx+=dx;
346   fy+=dy;
347 
348   while(continuing) {
349     Level->site[fx][fy].locchar = FLOOR;
350     Level->site[fx][fy].roomnumber = RS_CORRIDOR;
351     Level->site[fx][fy].buildaux = baux;
352     dx = sign(tx-fx);
353     dy = sign(ty-fy);
354     if ((dx != 0) && (dy != 0)) {
355       if (random_range(2)) dx = 0;
356       else if (random_range(2)) dy = 0;
357     }
358     fx+=dx;
359     fy+=dy;
360     continuing = (((fx != tx) || (fy != ty)) &&
361 		  ((Level->site[fx][fy].buildaux == 0) ||
362 		   (Level->site[fx][fy].buildaux == baux)));
363   }
364   makedoor(fx,fy);
365 }
366 
367 
368 
369 
370 
maze_level()371 void maze_level()
372 {
373   int i,j,tx,ty,mid;
374   char rsi;
375   if (Current_Environment == E_ASTRAL)
376     switch(Level->depth){
377     case 1: rsi = RS_EARTHPLANE; break;
378     case 2: rsi = RS_AIRPLANE; break;
379     case 3: rsi = RS_WATERPLANE; break;
380     case 4: rsi = RS_FIREPLANE; break;
381     case 5: rsi = RS_HIGHASTRAL; break;
382     }
383   else rsi = RS_VOLCANO;
384   maze_corridor(random_range(WIDTH-1)+1,
385 		random_range(LENGTH-1)+1,
386 		random_range(WIDTH-1)+1,
387 		random_range(LENGTH-1)+1,
388 		rsi,0);
389   if (Current_Dungeon == E_ASTRAL) {
390     for(i=0;i<WIDTH;i++)
391       for(j=0;j<LENGTH;j++)
392 	if (Level->site[i][j].locchar == WALL)
393 	  switch(Level->depth){
394 	  case 1: Level->site[i][j].aux = 500; break;
395 	  case 2:
396 	    Level->site[i][j].locchar = WHIRLWIND;
397 	    Level->site[i][j].p_locf = L_WHIRLWIND;
398 	    break;
399 	  case 3:
400 	    Level->site[i][j].locchar = WATER;
401 	    Level->site[i][j].p_locf = L_WATER;
402 	    break;
403 	  case 4:
404 	    Level->site[i][j].locchar = FIRE;
405 	    Level->site[i][j].p_locf = L_FIRE;
406 	    break;
407 	  case 5:
408 	    Level->site[i][j].locchar = ABYSS;
409 	    Level->site[i][j].p_locf = L_ABYSS;
410 	    break;
411 	  }
412     switch(Level->depth) {
413     case 1: mid = LORD_EARTH; break; /* Elemental Lord of Earth */
414     case 2: mid = LORD_AIR; break; /* Elemental Lord of Air */
415     case 3: mid = LORD_WATER; break; /* Elemental Lord of Water */
416     case 4: mid = LORD_FIRE; break; /* Elemental Lord of Fire */
417     case 5: mid = ELEM_MASTER; break; /* Elemental Master */
418     }
419     if (Level->depth == 5) {
420       findspace(&tx,&ty,-1);
421       Level->site[tx][ty].p_locf = L_ENTER_CIRCLE;
422       Level->site[tx][ty].locchar = STAIRS_DOWN;
423     }
424     if (! gamestatusp(COMPLETED_ASTRAL)) {
425       findspace(&tx,&ty,-1);
426       Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
427       Level->mlist->next = NULL;
428       Level->mlist->m =
429 	Level->site[tx][ty].creature =
430 	  ((pmt) make_creature(mid));
431       Level->mlist->m->x = tx;
432       Level->mlist->m->y = ty;
433     }
434   }
435   else if (Current_Environment == E_VOLCANO) {
436     if (Level->depth == VOLCANOLEVELS && !gamestatusp(COMPLETED_VOLCANO)) {
437       findspace(&tx,&ty,-1);
438       Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
439       Level->mlist->next = NULL;
440       Level->mlist->m =
441 	Level->site[tx][ty].creature =
442 	  ((pmt) make_creature(DEMON_EMP)); /* The demon emp */
443       Level->mlist->m->x = tx;
444       Level->mlist->m->y = ty;
445     }
446   }
447 }
448 
449 
450 /* keep drawing corridors recursively for 2^5 endpoints */
maze_corridor(fx,fy,tx,ty,rsi,num)451 void maze_corridor(fx,fy,tx,ty,rsi,num)
452 int fx,fy,tx,ty;
453 char rsi,num;
454 {
455   if (num < 6) {
456     straggle_corridor(fx,fy,tx,ty,FLOOR,rsi);
457     maze_corridor(tx,ty,
458 		  random_range(WIDTH-1)+1,
459 		  random_range(LENGTH-1)+1,
460 		  rsi,num+1);
461 
462   }
463 }
464 
465 
466 
467 
468 
469