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