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