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