1 /***************************************************************************
2 mondrian.cpp - Dungeon generator
3 -------------------
4 begin : Thu May 15 2003
5 copyright : (C) 2006 by Raphael Bosshard
6 email : raphael.bosshard@gmail.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "common/constants.h"
19 #include "mondrian.h"
20 #include "render/renderlib.h"
21 #include "rpg/rpglib.h"
22 #include "scourge.h"
23 #include "shapepalette.h"
24 #include "board.h"
25 #include "gui/progress.h"
26 #include "item.h"
27 #include "creature.h"
28 #include "debug.h"
29
30 using namespace std;
31
32 #define FORCE_WATER 0
33
34 // 1 out of SECRET_DOOR_CHANCE doors are secret doors
35 #ifdef DEBUG_SECRET_DOORS
36 #define SECRET_DOOR_CHANCE 2
37 #else
38 #define SECRET_DOOR_CHANCE 10
39 #endif
40
41 int totalWidth, totalHeight;
42
43 /*
44 width - max 31
45 height - max 31
46
47 curvyness - in %, the lower the more twisty maze
48 sparseness - (1-5) the higher the more sparse (more empty space)
49 loopyness - in %, the higher the more loops in the maze
50
51 roomcount
52 room max width
53 room max height
54
55 object count
56 */
57 #define MAX_DUNGEON_LEVEL 7
58
59 const int MondrianGenerator::levels[][9] = {
60 //height width roomMaxW roomMaxH roomMinW roomMinH objects
61 { 10, 10, 4, 4, 2, 2, 5 },
62 { 15, 15, 6, 4, 2, 2, 10 },
63 { 15, 15, 5, 5, 3, 3, 15 },
64 { 20, 20, 6, 5, 3, 2, 20 },
65 { 25, 25, 6, 5, 3, 4, 25 },
66 { 30, 25, 6, 6, 4, 4, 30 },
67 { 31, 31, 7, 7, 5, 5, 35 }
68 };
69
MondrianGenerator(Scourge * scourge,int level,int depth,int maxDepth,bool stairsDown,bool stairsUp,Mission * mission)70 MondrianGenerator::MondrianGenerator( Scourge *scourge, int level, int depth, int maxDepth,
71 bool stairsDown, bool stairsUp, Mission *mission ) :
72 TerrainGenerator( scourge, level, depth, maxDepth, stairsDown, stairsUp, mission, 18 ) {
73
74
75 initByLevel();
76
77 nodes = new Uint16*[ width ];
78 for ( int i = 0; i < width; i++ ) {
79 nodes[i] = new Uint16[ height ];
80 }
81
82 for ( int x = 0; x < width; x++ ) {
83 for ( int y = 0; y < height; y++ ) {
84 nodes[x][y] = UNVISITED;
85 }
86 }
87
88
89 doorCount = 0;
90 }
91
~MondrianGenerator()92 MondrianGenerator::~MondrianGenerator() {
93 for ( int i = 0; i < width; i++ ) {
94 delete [] nodes[i];
95 }
96 delete [] nodes;
97
98 }
99
initByLevel()100 void MondrianGenerator::initByLevel() {
101 int dungeonLevel = level / 8;
102 if ( dungeonLevel < 0 ) dungeonLevel = 0;
103
104 if ( dungeonLevel >= MAX_DUNGEON_LEVEL ) {
105 cerr << "*** Warning: attempted to create dungeon level " << dungeonLevel <<
106 ". Max is " << MAX_DUNGEON_LEVEL << endl;
107 dungeonLevel = MAX_DUNGEON_LEVEL - 1;
108 }
109
110 // cerr << "*** Creating dungeon level: " << dungeonLevel << " depth=" << depth << endl;
111
112 this->width = levels[dungeonLevel][dgWIDTH];
113 this->height = levels[dungeonLevel][dgHEIGHT];
114 this->roomMaxWidth = levels[dungeonLevel][dgROOMMAXWIDTH];
115 this->roomMaxHeight = levels[dungeonLevel][dgROOMMAXHEIGHT];
116 this->roomMinWidth = levels[dungeonLevel][dgROOMMINWIDTH];
117 this->roomMinHeight = levels[dungeonLevel][dgROOMMINHEIGHT];
118 this->objectCount = levels[dungeonLevel][dgOBJECTCOUNT];
119
120 this->monsters = true;
121 this->roomCount = 0;
122 }
123
124 /* Nice unicode maze printer. Doesn't work with all fonts, through */
125
126 #ifdef _MSC_VER // -=K=-: and i dont want the warnings
127 # pragma warning(push)
128 # pragma warning(disable : 4566) // "character cannot be represented in current code page"
129 #endif
130
printMazeUC()131 void MondrianGenerator::printMazeUC() {
132 printf( "---------------------------------------\n" );
133 for ( int y = 0; y < height; y++ ) {
134 for ( int x = 0; x < width; x++ ) {
135 Uint16 node = nodes[x][y];
136
137 if ( node & ROOM && node & N_PASS && node & W_PASS && node & S_PASS && node & E_PASS ) {
138 printf( "\u253c" );
139 } else if ( node & ROOM && node & N_PASS && node & W_PASS && node & S_PASS ) {
140 printf( "\u2524" );
141 } else if ( node & ROOM && node & N_PASS && node & S_PASS && node & E_PASS ) {
142 printf( "\u251c" );
143 } else if ( node & ROOM && node & S_PASS && node & E_PASS && node & W_PASS ) {
144 printf( "\u252c" );
145 } else if ( node & ROOM && node & N_PASS && node & E_PASS && node & W_PASS ) {
146 printf( "\u2534" );
147 } else if ( node & ROOM && node & S_PASS && node & N_PASS ) {
148 printf( "\u2503" );
149 } else if ( node & ROOM && node & S_PASS && node & E_PASS ) {
150 printf( "\u250c" );
151 } else if ( node & ROOM && node & S_PASS && node & W_PASS ) {
152 printf( "\u2510" );
153 } else if ( node & ROOM && node & N_PASS && node & E_PASS ) {
154 printf( "\u2514" );
155 } else if ( node & ROOM && node & N_PASS && node & W_PASS ) {
156 printf( "\u2518" );
157 } else if ( node & ROOM && node & E_PASS && node & W_PASS ) {
158 printf( "\u2501" );
159 } else if ( node & ROOM && node & E_PASS ) {
160 printf( "\u257a" );
161 } else if ( node & ROOM && node & W_PASS ) {
162 printf( "\u2578" );
163 } else if ( node & ROOM && node & S_PASS ) {
164 printf( "\u257b" );
165 } else if ( node & ROOM && node & N_PASS ) {
166 printf( "\u2579" );
167 } else if ( node & ROOM ) {
168 printf( "*" );
169 } else if ( node & ROOM2 ) {
170 printf( "#" );
171 } else {
172 printf( " " );
173 }
174 }
175 printf( "\n" );
176 }
177 printf( "---------------------------------------\n" );
178 }
179
180 #ifdef _MSC_VER
181 # pragma warning(pop) // back
182 #endif
183
184
printMaze()185 void MondrianGenerator::printMaze() {
186 printf( "---------------------------------------\n" );
187 int c = 0;
188 for ( int y = 0; y < height; y++ ) {
189 for ( int i = 0; i < 3; i++ ) {
190 for ( int x = 0; x < width; x++ ) {
191
192 switch ( i ) {
193 case 0: // top row
194 if ( ( nodes[x][y] & N_PASS ) ) {
195 printf( " | " );
196 } else {
197 printf( " " );
198 }
199 break;
200 case 1:
201 if ( ( nodes[x][y] & W_PASS ) ) {
202 printf( "-" );
203 } else {
204 printf( " " );
205 }
206 if ( nodes[x][y] == UNVISITED )
207 printf( " " );
208 else if ( nodes[x][y] & ROOM )
209 printf( "*" );
210 else
211 printf( "O" );
212 if ( ( nodes[x][y] & E_PASS ) ) {
213 printf( "-" );
214 } else {
215 printf( " " );
216 }
217 break;
218 case 2: // bottom row
219 if ( ( nodes[x][y] & S_PASS ) ) {
220 printf( " | " );
221 } else {
222 printf( " " );
223 }
224 break;
225 }
226 c++;
227 }
228 printf( "\n" );
229 }
230 c++;
231 }
232 printf( "---------------------------------------\n" );
233 }
234
235
236
subdivideMaze(Sint16 x_start,Sint16 y_start,Sint16 width,Sint16 height,bool init)237 int MondrianGenerator::subdivideMaze( Sint16 x_start, Sint16 y_start, Sint16 width, Sint16 height, bool init ) {
238
239 //If this is the first iteration, randomize init.
240 // Later it's used to decide wether to divide the room horzontal or vertical
241 if ( init )
242 // init = (rand()%2 == 0);
243 init = ( Util::dice( 2 ) ) != 0;
244
245 // fprintf( stderr, "Iteration: %d %d : %d %d\n", x_start, y_start, width, height);
246
247 int horizontal = 0;
248 int div = 0;
249
250 bool passageHasDoor;
251
252 Room roomA, roomB;
253 int passage_x;
254 int passage_y;
255 Uint16 passage = ROOM;
256
257
258
259 /* Try some sane defaults */
260 int roomMinWidth = 2;// this->roomMinWidth;
261 int roomMinHeight = 2; //this->roomMinHeight;
262 float roomMulFac = 2.15f;
263
264 // NOTE:
265 // Horizontal subdivision: divide width
266 // Vertical subdivision: divide height
267 //
268 // This is noted here because the original got confused himself. This is no
269 // uncommon state for him, though.
270 //
271
272
273 bool hSubdivisionOK = ( static_cast<float>( width ) > static_cast<float>( roomMinWidth * roomMulFac ) );
274 bool vSubdivisionOK = ( static_cast<float>( height ) > static_cast<float>( roomMinHeight * roomMulFac ) );
275
276 // What would fit now? Two horizontal or two vertial rooms?
277 if ( hSubdivisionOK && vSubdivisionOK ) {
278 // Everything fits
279 horizontal = init;
280
281 } else if ( hSubdivisionOK ) {
282 //only horizonal rooms fit
283 horizontal = 1;
284
285 } else if ( vSubdivisionOK ) {
286 //only vertical rooms fit
287 horizontal = 0;
288 } else {
289
290 // there is no space for more rooms. Boil out and let the caller
291 // place one big room instead of two little ones.
292 return 0;
293 }
294
295
296 // Is it a door or a passage?
297
298
299 // FIXME!
300 // The "make-sure-that-there-is-no-clutter-in-front-of-the-door"-algorithm notices _DOORs only, thus
301 // simple pathways are always cluttered. Improve Map::isDoor and enable the rand() again.
302
303 //if(0 == rand()%2)
304 passageHasDoor = true;
305
306 // Now that we know that there's space left for another two rooms, lets make them.
307
308 // make two rooms alongside
309 if ( horizontal ) {
310 while ( ( div < roomMinWidth ) || ( width - div < roomMinWidth ) ) {
311 div = Util::dice( width );
312 }
313
314 // printf("horizontal, div %d, w2 %d, h %d\n", div, width - div, height );
315 roomA.x = offset + x_start * unitSide;
316 roomA.y = offset + y_start * unitSide;
317 roomA.w = div * unitSide;
318 roomA.h = height * unitSide;
319 roomA.valueBonus = depth / 2;
320
321 roomB.x = offset + ( x_start + div ) * unitSide;
322 roomB.y = offset + y_start * unitSide;
323 roomB.w = ( width - div ) * unitSide;
324 roomB.h = height * unitSide;
325 roomB.valueBonus = depth / 2;
326
327 passage_x = x_start + div - 1;
328 passage_y = y_start + ( height / 2 );
329
330 passage = E_PASS;
331 if ( passageHasDoor )
332 passage |= E_DOOR;
333
334 } else {
335 // make two rooms, on on top of the other
336 while ( ( div < roomMinHeight ) || ( height - div < roomMinHeight ) ) {
337 div = Util::dice( height );
338 }
339
340 // printf("vertical, div %d, w2 %d, h %d\n", div, width - div, height );
341 roomA.x = offset + x_start * unitSide;
342 roomA.y = offset + y_start * unitSide;
343 roomA.w = width * unitSide;
344 roomA.h = div * unitSide;
345 roomA.valueBonus = depth / 2;
346
347 roomB.x = offset + x_start * unitSide;
348 roomB.y = offset + ( y_start + div ) * unitSide;
349 roomB.w = width * unitSide;
350 roomB.h = ( height - div ) * unitSide;
351 roomB.valueBonus = depth / 2;
352
353 passage_x = x_start + ( width / 2 );
354 passage_y = y_start + ( div - 1 );
355
356 passage = S_PASS;
357 if ( passageHasDoor )
358 passage |= S_DOOR;
359 }
360
361 int r = roomCount; //this->roomCount;
362 if ( !subdivideMaze( ( roomA.x - offset ) / unitSide, ( roomA.y - offset ) / unitSide, roomA.w / unitSide, roomA.h / unitSide, false ) ) {
363 // if we cannot divide the space once more, make a room
364 room[r].x = roomA.x;
365 room[r].y = roomA.y;
366 room[r].w = roomA.w;
367 room[r].h = roomA.h;
368 room[r].valueBonus = roomA.valueBonus;
369
370 // alternate floor tile style
371 if ( roomCount % 2 == 0 ) {
372 for ( int x = 0; x < room[r].w; x++ ) {
373 for ( int y = 0; y < room[r].h; y++ ) {
374 //nodes[x + ( room[r].x - offset ) / unitSide][y + ( room[r].y - offset ) / unitSide] -= ROOM;
375 }
376 }
377 }
378
379 // printf("N: %d x/y %d/%d w/h %d/%d\n", r, roomA.x, roomA.y, roomA.w, roomA.h);
380
381 roomCount++;//this->roomCount++;
382 }
383 assert( roomCount < 200 );
384
385
386
387 r = roomCount;//this->roomCount;
388 if ( !subdivideMaze( ( roomB.x - offset ) / unitSide, ( roomB.y - offset ) / unitSide, roomB.w / unitSide, roomB.h / unitSide, false ) ) {
389 //if we cannot divice the space once more, make a room
390 room[r].x = roomB.x;
391 room[r].y = roomB.y;
392 room[r].w = roomB.w;
393 room[r].h = roomB.h;
394 room[r].valueBonus = roomB.valueBonus;
395
396 // alternate floor tile style
397 if ( roomCount % 2 == 0 ) {
398 for ( int x = 0; x < room[r].w; x++ ) {
399 for ( int y = 0; y < room[r].h; y++ ) {
400 //nodes[x + ( room[r].x - offset ) / unitSide][y + ( room[r].y - offset ) / unitSide] -= ROOM;
401 }
402 }
403 }
404
405 // printf("N: %d x/y %d/%d w/h %d/%d\n", r, roomB.x, roomB.y, roomB.w, roomB.h);
406
407 roomCount ++;//this->roomCount++;
408 }
409 assert( roomCount < 200 );
410
411
412 if ( horizontal ) {
413 for ( int y = 0; y < height; y++ ) {
414 assert( ( x_start + ( div - 1 ) ) >= 0 &&
415 ( x_start + ( div - 1 ) ) < totalWidth &&
416 ( y_start + y ) >= 0 &&
417 ( y_start + y ) < totalHeight );
418 nodes[( x_start + ( div - 1 ) )][ ( y_start + y ) ] -= E_PASS;
419 }
420 } else {
421 for ( int x = 0; x < width; x++ ) {
422 assert( x_start + x >= 0 &&
423 x_start + x < totalWidth &&
424 y_start + ( div - 1 ) >= 0 &&
425 y_start + ( div - 1 ) < totalHeight );
426 nodes[ ( x_start + x )][ ( y_start + ( div - 1 ) ) ] -= S_PASS;
427 }
428 }
429
430 //connect the rooms
431 assert( passage_x >= 0 && passage_x < totalWidth && passage_y >= 0 && passage_y < totalHeight );
432 nodes[ passage_x ][passage_y ] |= passage;
433
434 // the space has been subdivided successfully
435 return 1;
436 }
437
initRoom(Room room)438 void MondrianGenerator::initRoom( Room room ) {
439 for ( int x = 0; x < room.w; x++ ) {
440 for ( int y = 0; y < room.h; y++ ) {
441 int pass = 0;
442 if ( x > 0 )
443 pass |= W_PASS;
444 if ( x < room.w - 1 )
445 pass |= E_PASS;
446 if ( y > 0 )
447 pass |= N_PASS;
448 if ( y < room.h - 1 )
449 pass |= S_PASS;
450
451 assert( x + room.x >= 0 &&
452 x + room.x < totalWidth &&
453 y + room.y >= 0 &&
454 y + room.y < totalHeight );
455 nodes[x + room.x][y + room.y] = ROOM | pass;
456 }
457 }
458
459 }
460
461
generate(Map * map,ShapePalette * shapePal)462 void MondrianGenerator::generate( Map *map, ShapePalette *shapePal ) {
463 // cerr << "MONDRIAN" << endl;
464
465 updateStatus( _( "Assembling Dungeon Level" ) );
466
467 //Sint16 mapx, mapy;
468 for ( Sint16 x = 0; x < width; x++ ) {
469 for ( Sint16 y = 0; y < height; y++ ) {
470 int pass = 0;
471 if ( x > 0 )
472 pass |= W_PASS;
473 if ( x < width - 1 )
474 pass |= E_PASS;
475 if ( y > 0 )
476 pass |= N_PASS;
477 if ( y < height - 1 )
478 pass |= S_PASS;
479
480 nodes[x][y] = ROOM | pass;
481 }
482 }
483
484
485 this->roomCount = 0;
486
487 totalWidth = width;
488 totalHeight = height;
489 subdivideMaze( 0, 0, width, height, true );
490
491 /*
492 int i = 0;
493 room[i].x = offset + 0 * unitSide;
494 room[i].y = offset + 0 * unitSide;
495 room[i].w = width * unitSide;
496 room[i].h = height * unitSide;
497 room[i].valueBonus = depth / 2;
498 roomCount = 1;
499 */
500
501 //printMaze();
502 //for( int i = 0; i < roomCount; i++ ) {
503 //cerr << "Room: " << i << " " << room[i].x << "," << room[i].y << " dim=" << room[i].w << "," << room[i].h << endl;
504 //}
505 }
506
507
drawNodes(Map * map,ShapePalette * shapePal)508 bool MondrianGenerator::drawNodes( Map *map, ShapePalette *shapePal ) {
509 // flooded map?
510 map->setHasWater( FORCE_WATER ||
511 0 == Util::dice( 5 ) );
512
513 updateStatus( _( "Loading theme" ) );
514 if ( map->getPreferences()->isDebugTheme() ) shapePal->loadDebugTheme();
515 else shapePal->loadRandomTheme();
516
517 updateStatus( _( "Drawing walls" ) );
518 drawBasics( map, shapePal );
519
520 updateStatus( _( "Fixing rooms" ) );
521 removeColumns( map, shapePal );
522 addRugs( map, shapePal );
523
524 return true;
525 }
526
527
528
drawBasics(Map * map,ShapePalette * shapePal)529 void MondrianGenerator::drawBasics( Map *map, ShapePalette *shapePal ) {
530 // add shapes to map
531 Sint16 mapx, mapy;
532 for ( Sint16 x = 0; x < width; x++ ) {
533 for ( Sint16 y = 0; y < height; y++ ) {
534
535 mapx = x * unitSide + offset;
536 mapy = y * unitSide + offset;
537 if ( nodes[x][y] != UNVISITED ) {
538
539 if ( nodes[x][y] >= ROOM ) {
540 map->setFloorPosition( mapx, mapy + unitSide,
541 shapePal->findShapeByName( "ROOM_FLOOR_TILE" ) );
542 } else {
543 map->setFloorPosition( mapx, mapy + unitSide,
544 shapePal->findShapeByName( "FLOOR_TILE" ) );
545 }
546
547 // init the free space
548 int secretDoor = 0;
549 if ( nodes[x][y] & E_DOOR ) {
550 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
551 nodes[x][y] -= E_DOOR;
552 secretDoor = E_DOOR;
553 nodes[x][y] -= E_PASS;
554 } else {
555 drawDoor( map, shapePal, mapx, mapy, E_DOOR );
556 }
557 } else if ( nodes[x][y] & W_DOOR ) {
558 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
559 nodes[x][y] -= W_DOOR;
560 secretDoor = W_DOOR;
561 nodes[x][y] -= W_PASS;
562 } else {
563 drawDoor( map, shapePal, mapx, mapy, W_DOOR );
564 }
565 } else if ( nodes[x][y] & N_DOOR ) {
566 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
567 nodes[x][y] -= N_DOOR;
568 secretDoor = N_DOOR;
569 nodes[x][y] -= N_PASS;
570 } else {
571 drawDoor( map, shapePal, mapx, mapy, N_DOOR );
572 }
573 } else if ( nodes[x][y] & S_DOOR ) {
574 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
575 nodes[x][y] -= S_DOOR;
576 secretDoor = S_DOOR;
577 nodes[x][y] -= S_PASS;
578 } else {
579 drawDoor( map, shapePal, mapx, mapy, S_DOOR );
580 }
581 }
582
583 // random doors
584 if ( !secretDoor ) {
585 if ( ( nodes[x][y] & W_PASS ) &&
586 !( nodes[x][y] & N_PASS ) &&
587 !( nodes[x][y] & S_PASS ) ) {
588 if ( Util::dice( 100 ) <= randomDoors ) {
589 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
590 nodes[x][y] -= W_DOOR;
591 secretDoor = W_DOOR;
592 nodes[x][y] -= W_PASS;
593 } else {
594 drawDoor( map, shapePal, mapx, mapy, W_DOOR );
595 }
596 }
597 }
598 if ( ( nodes[x][y] & E_PASS ) &&
599 !( nodes[x][y] & N_PASS ) &&
600 !( nodes[x][y] & S_PASS ) ) {
601 if ( Util::dice( 100 ) <= randomDoors ) {
602 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
603 nodes[x][y] -= E_DOOR;
604 secretDoor = E_DOOR;
605 nodes[x][y] -= E_PASS;
606 } else {
607 drawDoor( map, shapePal, mapx, mapy, E_DOOR );
608 }
609 }
610 }
611 if ( ( nodes[x][y] & S_PASS ) &&
612 !( nodes[x][y] & W_PASS ) &&
613 !( nodes[x][y] & E_PASS ) ) {
614 if ( Util::dice( 100 ) <= randomDoors ) {
615 if ( 0 == Util::dice( static_cast<int>( SECRET_DOOR_CHANCE ) ) ) {
616 nodes[x][y] -= S_DOOR;
617 secretDoor = S_DOOR;
618 nodes[x][y] -= S_PASS;
619 } else {
620 drawDoor( map, shapePal, mapx, mapy, S_DOOR );
621 }
622 }
623 }
624 if ( ( nodes[x][y] & N_PASS ) &&
625 !( nodes[x][y] & W_PASS ) &&
626 !( nodes[x][y] & E_PASS ) ) {
627 if ( Util::dice( 100 ) <= randomDoors ) {
628 if ( 0 == Util::dice( SECRET_DOOR_CHANCE ) ) {
629 nodes[x][y] -= N_DOOR;
630 secretDoor = N_DOOR;
631 nodes[x][y] -= N_PASS;
632 } else {
633 drawDoor( map, shapePal, mapx, mapy, N_DOOR );
634 }
635 }
636 }
637 }
638
639 int wallX, wallY;
640 Shape *wall = NULL;
641 if ( !( nodes[x][y] & W_PASS ) ) {
642 if ( nodes[x][y] & N_PASS && nodes[x][y] & S_PASS ) {
643 wallX = mapx;
644 wallY = mapy + unitSide;
645 wall = shapePal->findShapeByName( "EW_WALL_TWO_EXTRAS" );
646 } else if ( nodes[x][y] & N_PASS ) {
647 wallX = mapx;
648 wallY = mapy + unitSide - unitOffset;
649 wall = shapePal->findShapeByName( "EW_WALL_EXTRA" );
650 } else if ( nodes[x][y] & S_PASS ) {
651 wallX = mapx;
652 wallY = mapy + unitSide;
653 wall = shapePal->findShapeByName( "EW_WALL_EXTRA" );
654 } else {
655 wallX = mapx;
656 wallY = mapy + unitSide - unitOffset;
657 wall = shapePal->findShapeByName( "EW_WALL" );
658 }
659 if ( wall ) {
660 map->setPosition( wallX, wallY, 0, wall );
661 if ( secretDoor == W_DOOR ) {
662 map->addSecretDoor( wallX, wallY );
663 } else {
664 if ( Util::dice( 100 ) <= torches ) {
665 map->setPosition( mapx + unitOffset, mapy + unitSide - 4,
666 6, shapePal->findShapeByName( "LAMP_WEST" ) );
667 map->setPosition( mapx + unitOffset, mapy + unitSide - 4,
668 4, shapePal->findShapeByName( "LAMP_BASE" ) );
669 }
670 }
671 }
672 }
673 if ( !( nodes[x][y] & E_PASS ) ) {
674 if ( nodes[x][y] & N_PASS && nodes[x][y] & S_PASS ) {
675 wallX = mapx + unitSide - unitOffset;
676 wallY = mapy + unitSide;
677 wall = shapePal->findShapeByName( "EW_WALL_TWO_EXTRAS" );
678 } else if ( nodes[x][y] & N_PASS ) {
679 wallX = mapx + unitSide - unitOffset;
680 wallY = mapy + unitSide - unitOffset;
681 wall = shapePal->findShapeByName( "EW_WALL_EXTRA" );
682 } else if ( nodes[x][y] & S_PASS ) {
683 wallX = mapx + unitSide - unitOffset;
684 wallY = mapy + unitSide;
685 wall = shapePal->findShapeByName( "EW_WALL_EXTRA" );
686 } else {
687 wallX = mapx + unitSide - unitOffset;
688 wallY = mapy + unitSide - unitOffset;
689 wall = shapePal->findShapeByName( "EW_WALL" );
690 }
691 if ( wall ) {
692 map->setPosition( wallX, wallY, 0, wall );
693 if ( secretDoor == E_DOOR ) {
694 map->addSecretDoor( wallX, wallY );
695 } else {
696 if ( Util::dice( 100 ) <= torches ) {
697 map->setPosition( mapx + unitSide - ( unitOffset + 1 ), mapy + unitSide - 4,
698 6, shapePal->findShapeByName( "LAMP_EAST" ) );
699 map->setPosition( mapx + unitSide - ( unitOffset + 1 ), mapy + unitSide - 4,
700 4, shapePal->findShapeByName( "LAMP_BASE" ) );
701 }
702 }
703 }
704 }
705 if ( !( nodes[x][y] & N_PASS ) ) {
706 if ( nodes[x][y] & W_PASS && nodes[x][y] & E_PASS ) {
707 wallX = mapx;
708 wallY = mapy + unitOffset;
709 wall = shapePal->findShapeByName( "NS_WALL_TWO_EXTRAS" );
710 } else if ( nodes[x][y] & W_PASS ) {
711 wallX = mapx;
712 wallY = mapy + unitOffset;
713 wall = shapePal->findShapeByName( "NS_WALL_EXTRA" );
714 } else if ( nodes[x][y] & E_PASS ) {
715 wallX = mapx + unitOffset;
716 wallY = mapy + unitOffset;
717 wall = shapePal->findShapeByName( "NS_WALL_EXTRA" );
718 } else {
719 wallX = mapx + unitOffset;
720 wallY = mapy + unitOffset;
721 wall = shapePal->findShapeByName( "NS_WALL" );
722 }
723 if ( wall ) {
724 map->setPosition( wallX, wallY, 0, wall );
725 if ( secretDoor == N_DOOR ) {
726 map->addSecretDoor( wallX, wallY );
727 } else {
728 if ( Util::dice( 100 ) <= torches ) {
729 map->setPosition( mapx + 4, mapy + unitOffset + 1, 6,
730 shapePal->findShapeByName( "LAMP_NORTH" ) );
731 map->setPosition( mapx + 4, mapy + unitOffset + 1, 4,
732 shapePal->findShapeByName( "LAMP_BASE" ) );
733 }
734 }
735 }
736 }
737 if ( !( nodes[x][y] & S_PASS ) ) {
738 if ( nodes[x][y] & W_PASS && nodes[x][y] & E_PASS ) {
739 wallX = mapx;
740 wallY = mapy + unitSide;
741 wall = shapePal->findShapeByName( "NS_WALL_TWO_EXTRAS" );
742 } else if ( nodes[x][y] & W_PASS ) {
743 wallX = mapx;
744 wallY = mapy + unitSide;
745 wall = shapePal->findShapeByName( "NS_WALL_EXTRA" );
746 } else if ( nodes[x][y] & E_PASS ) {
747 wallX = mapx + unitOffset;
748 wallY = mapy + unitSide;
749 wall = shapePal->findShapeByName( "NS_WALL_EXTRA" );
750 } else {
751 wallX = mapx + unitOffset;
752 wallY = mapy + unitSide;
753 wall = shapePal->findShapeByName( "NS_WALL" );
754 }
755 if ( wall ) {
756 map->setPosition( wallX, wallY, 0, wall );
757 if ( secretDoor == S_DOOR ) {
758 map->addSecretDoor( wallX, wallY );
759 }
760 }
761 }
762
763
764 if ( nodes[x][y] & N_PASS && nodes[x][y] & W_PASS ) {
765 map->setPosition( mapx, mapy + unitOffset, 0,
766 shapePal->findShapeByName( "CORNER" ) );
767 }
768 if ( nodes[x][y] & N_PASS && nodes[x][y] & E_PASS ) {
769 map->setPosition( mapx + unitSide - unitOffset, mapy + unitOffset, 0,
770 shapePal->findShapeByName( "CORNER" ) );
771 }
772 if ( nodes[x][y] & S_PASS && nodes[x][y] & W_PASS ) {
773 map->setPosition( mapx, mapy + unitSide, 0,
774 shapePal->findShapeByName( "CORNER" ) );
775 }
776 if ( nodes[x][y] & S_PASS && nodes[x][y] & E_PASS ) {
777 map->setPosition( mapx + unitSide - unitOffset, mapy + unitSide, 0,
778 shapePal->findShapeByName( "CORNER" ) );
779 }
780 if ( !( nodes[x][y] & N_PASS ) && !( nodes[x][y] & W_PASS ) ) {
781 map->setPosition( mapx, mapy + unitOffset, 0,
782 shapePal->findShapeByName( "CORNER" ) );
783 }
784 if ( !( nodes[x][y] & N_PASS ) && !( nodes[x][y] & E_PASS ) ) {
785 map->setPosition( mapx + unitSide - unitOffset, mapy + unitOffset, 0,
786 shapePal->findShapeByName( "CORNER" ) );
787 }
788 if ( !( nodes[x][y] & S_PASS ) && !( nodes[x][y] & W_PASS ) ) {
789 map->setPosition( mapx, mapy + unitSide, 0,
790 shapePal->findShapeByName( "CORNER" ) );
791 }
792 if ( !( nodes[x][y] & S_PASS ) && !( nodes[x][y] & E_PASS ) ) {
793 map->setPosition( mapx + unitSide - unitOffset, mapy + unitSide, 0,
794 shapePal->findShapeByName( "CORNER" ) );
795 }
796 }
797 }
798 }
799 }
800
801
removeColumns(Map * map,ShapePalette * shapePal)802 void MondrianGenerator::removeColumns( Map *map, ShapePalette *shapePal ) {
803 // Remove 'columns' from rooms
804 for ( int roomIndex = 0; roomIndex < roomCount; roomIndex++ ) {
805 int startx = ( room[roomIndex].x ) + unitOffset;
806 int endx = ( room[roomIndex].x + room[roomIndex].w ) - ( unitOffset * 2 );
807 int starty = ( room[roomIndex].y ) + ( unitOffset * 2 );
808 int endy = ( room[roomIndex].y + room[roomIndex].h ) - unitOffset;
809 for ( int x = startx; x < endx; x++ ) {
810 for ( int y = starty; y < endy; y++ ) {
811 map->removePosition( x, y, 0 );
812 }
813 }
814 }
815 }
816
817
drawEastDoor(Map * map,ShapePalette * shapePal,Sint16 mapx,Sint16 mapy,bool secret)818 void MondrianGenerator::drawEastDoor( Map *map, ShapePalette *shapePal, Sint16 mapx, Sint16 mapy, bool secret ) {
819 if ( !map->coversDoor( shapePal->findShapeByName( "EW_DOOR" ),
820 mapx + unitSide - unitOffset + 1, mapy + unitSide - unitOffset - 2 ) ) {
821 if ( secret ) {
822 } else {
823 map->setPosition( mapx + unitSide - unitOffset, mapy + unitSide - unitOffset,
824 wallHeight - 2, shapePal->findShapeByName( "EW_DOOR_TOP" ) );
825 map->setPosition( mapx + unitSide - unitOffset, mapy + unitOffset + 2,
826 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
827 map->setPosition( mapx + unitSide - unitOffset, mapy + unitOffset * 2 + 2,
828 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
829 map->setPosition( mapx + unitSide - unitOffset + 1, mapy + unitSide - unitOffset - 2,
830 0, shapePal->findShapeByName( "EW_DOOR" ) );
831 if ( doorCount < MAX_DOOR_COUNT ) {
832 door[doorCount][0] = mapx + unitSide - unitOffset + 1;
833 door[doorCount][1] = mapy + unitSide - unitOffset - 2;
834 doorCount++;
835 }
836 map->setPosition( mapx + unitSide - unitOffset, mapy + unitSide - unitOffset,
837 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
838 }
839 }
840 }
841
drawWestDoor(Map * map,ShapePalette * shapePal,Sint16 mapx,Sint16 mapy,bool secret)842 void MondrianGenerator::drawWestDoor( Map *map, ShapePalette *shapePal, Sint16 mapx, Sint16 mapy, bool secret ) {
843 if ( !map->coversDoor( shapePal->findShapeByName( "EW_DOOR" ),
844 mapx + 1, mapy + unitSide - unitOffset - 2 ) ) {
845 map->setPosition( mapx, mapy + unitSide - unitOffset,
846 wallHeight - 2, shapePal->findShapeByName( "EW_DOOR_TOP" ) );
847 map->setPosition( mapx, mapy + unitOffset + 2,
848 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
849 map->setPosition( mapx, mapy + unitOffset * 2 + 2,
850 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
851 map->setPosition( mapx + 1, mapy + unitSide - unitOffset - 2,
852 0, shapePal->findShapeByName( "EW_DOOR" ) );
853 if ( doorCount < MAX_DOOR_COUNT ) {
854 door[doorCount][0] = mapx + 1;
855 door[doorCount][1] = mapy + unitSide - unitOffset - 2;
856 doorCount++;
857 }
858 map->setPosition( mapx, mapy + unitSide - unitOffset,
859 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
860 }
861 }
862
drawSouthDoor(Map * map,ShapePalette * shapePal,Sint16 mapx,Sint16 mapy,bool secret)863 void MondrianGenerator::drawSouthDoor( Map *map, ShapePalette *shapePal, Sint16 mapx, Sint16 mapy, bool secret ) {
864 if ( !map->coversDoor( shapePal->findShapeByName( "NS_DOOR" ),
865 mapx + unitOffset * 2, mapy + unitSide - 1 ) ) {
866 map->setPosition( mapx + unitOffset, mapy + unitSide,
867 wallHeight - 2, shapePal->findShapeByName( "NS_DOOR_TOP" ) );
868 map->setPosition( mapx + unitOffset, mapy + unitSide,
869 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
870 map->setPosition( mapx + unitOffset * 2, mapy + unitSide - 1,
871 0, shapePal->findShapeByName( "NS_DOOR" ) );
872 if ( doorCount < MAX_DOOR_COUNT ) {
873 door[doorCount][0] = mapx + unitOffset * 2;
874 door[doorCount][1] = mapy + unitSide - 1;
875 doorCount++;
876 }
877 map->setPosition( mapx + unitSide - unitOffset * 2, mapy + unitSide,
878 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
879 map->setPosition( mapx + unitSide - unitOffset * 3, mapy + unitSide,
880 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
881 }
882 }
883
drawNorthDoor(Map * map,ShapePalette * shapePal,Sint16 mapx,Sint16 mapy,bool secret)884 void MondrianGenerator::drawNorthDoor( Map *map, ShapePalette *shapePal, Sint16 mapx, Sint16 mapy, bool secret ) {
885 if ( !map->coversDoor( shapePal->findShapeByName( "NS_DOOR" ),
886 mapx + unitOffset * 2, mapy + unitOffset - 1 ) ) {
887 map->setPosition( mapx + unitOffset, mapy + unitOffset,
888 wallHeight - 2, shapePal->findShapeByName( "NS_DOOR_TOP" ) );
889 map->setPosition( mapx + unitOffset, mapy + unitOffset,
890 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
891 map->setPosition( mapx + unitOffset * 2, mapy + unitOffset - 1,
892 0, shapePal->findShapeByName( "NS_DOOR" ) );
893 if ( doorCount < MAX_DOOR_COUNT ) {
894 door[doorCount][0] = mapx + unitOffset * 2;
895 door[doorCount][1] = mapy + unitOffset - 1;
896 doorCount++;
897 }
898 map->setPosition( mapx + unitSide - unitOffset * 2, mapy + unitOffset,
899 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
900 map->setPosition( mapx + unitSide - unitOffset * 3, mapy + unitOffset,
901 0, shapePal->findShapeByName( "DOOR_SIDE" ) );
902 }
903 }
904
drawDoor(Map * map,ShapePalette * shapePal,Sint16 mapx,Sint16 mapy,int doorType,bool secret)905 void MondrianGenerator::drawDoor( Map *map, ShapePalette *shapePal,
906 Sint16 mapx, Sint16 mapy, int doorType, bool secret ) {
907 switch ( doorType ) {
908 case E_DOOR: drawEastDoor( map, shapePal, mapx, mapy, secret ); break;
909 case W_DOOR: drawWestDoor( map, shapePal, mapx, mapy, secret ); break;
910 case N_DOOR: drawNorthDoor( map, shapePal, mapx, mapy, secret ); break;
911 case S_DOOR: drawSouthDoor( map, shapePal, mapx, mapy, secret ); break;
912 default: cerr << "*** Error: Unknown door type: " << doorType << endl;
913 }
914 }
915
addFurniture(Map * map,ShapePalette * shapePal)916 void MondrianGenerator::addFurniture( Map *map, ShapePalette *shapePal ) {
917
918 // add tables, chairs, etc.
919 addItemsInEveryRoom( RpgItem::getItemByName( "Table" ), 1 );
920 addItemsInEveryRoom( RpgItem::getItemByName( "Chair" ), 2 );
921
922 // add some magic pools
923 DisplayInfo di;
924 for ( int i = 0; i < roomCount; i++ ) {
925 MagicSchool *ms = MagicSchool::getRandomSchool();
926 di.red = ms->getDeityRed();
927 di.green = ms->getDeityGreen();
928 di.blue = ms->getDeityBlue();
929 Location *pos = addShapeInRoom( scourge->getShapePalette()->findShapeByName( "POOL" ), i, &di );
930 if ( pos ) {
931 // store pos->deity in scourge
932 scourge->addDeityLocation( pos, ms );
933 }
934 //}
935 }
936 }
937
addContainers(Map * map,ShapePalette * shapePal)938 void MondrianGenerator::addContainers( Map *map, ShapePalette *shapePal ) {
939 addContainersInRooms( map, shapePal );
940 }
941
getMapRenderHelper()942 MapRenderHelper *MondrianGenerator::getMapRenderHelper() {
943 return MapRenderHelper::helpers[ MapRenderHelper::ROOM_HELPER ];
944 }
945
946