1 //
2 //   mapgen.c
3 //
4 //   Copyright 2007, 2008 Lancer-X/ASCEAI
5 //
6 //   This file is part of Meritous.
7 //
8 //   Meritous is free software: you can redistribute it and/or modify
9 //   it under the terms of the GNU General Public License as published by
10 //   the Free Software Foundation, either version 3 of the License, or
11 //   (at your option) any later version.
12 //
13 //   Meritous is distributed in the hope that it will be useful,
14 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //   GNU General Public License for more details.
17 //
18 //   You should have received a copy of the GNU General Public License
19 //   along with Meritous.  If not, see <http://www.gnu.org/licenses/>.
20 //
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <time.h>
27 #include <assert.h>
28 
29 #include <SDL.h>
30 #include "save.h"
31 #include "levelblit.h"
32 
33 void NewLevel();
34 
35 void SaveLevel();
36 
37 int Generate();
38 
39 int DoRepeat = 0;
40 
41 int place_of_power = 0;
42 
43 struct RoomConnection {
44 	int x, y;
45 	int x2, y2;
46 	int c;
47 	struct RoomConnection *n;
48 };
49 
50 typedef struct {
51 	int x, y;
52 	int w, h;
53 	int creator;
54 	int visited;
55 	int checkpoint;
56 	int s_dist;
57 	int connections;
58 	int room_type;
59 	int room_param;
60 	int enemies;
61 	struct RoomConnection *con;
62 } Room;
63 
64 typedef struct {
65 	int w, h;
66 	unsigned char *m;
67 	int *r;
68 	int totalRooms;
69 	//Room *rooms;
70 } GameLevel;
71 
72 GameLevel map;
73 Room rooms[3000];
74 int total_rooms = 0;
75 
76 int rdir = 0;
77 
78 int next_check = 30;
79 
80 int GetRoom(int x, int y);
81 
rndnum(int max)82 int rndnum(int max)
83 {
84 	return rand() % (max+1);
85 }
86 
87 int r_fails[4] = {0};
88 int r_successes[4] = {0};
89 
90 unsigned char floortiles[4] = {12, 18, 19, 20};
91 
WriteRoomData(Room * rm)92 void WriteRoomData(Room *rm)
93 {
94 	struct RoomConnection *rt;
95 	FWInt(rm->x);
96 	FWInt(rm->y);
97 	FWInt(rm->w);
98 	FWInt(rm->h);
99 	FWInt(rm->creator);
100 	FWInt(rm->visited);
101 	FWInt(rm->checkpoint);
102 	FWInt(rm->s_dist);
103 	FWInt(rm->connections);
104 	FWInt(rm->room_type);
105 	FWInt(rm->room_param);
106 	rt = rm->con;
107 	while (rt != NULL) {
108 		FWInt(rt->x);
109 		FWInt(rt->y);
110 		FWInt(rt->x2);
111 		FWInt(rt->y2);
112 		FWInt(rt->c);
113 		rt = rt->n;
114 	}
115 }
116 
ReadRoomData(Room * rm)117 void ReadRoomData(Room *rm)
118 {
119 	int i;
120 	struct RoomConnection *rt;
121 
122 	rm->x = FRInt();
123 	rm->y = FRInt();
124 	rm->w = FRInt();
125 	rm->h = FRInt();
126 	rm->creator = FRInt();
127 	rm->visited = FRInt();
128 	rm->checkpoint = FRInt();
129 	rm->s_dist = FRInt();
130 	rm->connections = FRInt();
131 	rm->room_type = FRInt();
132 	rm->room_param = FRInt();
133 
134 	rm->con = NULL;
135 
136 	rm->enemies = 0;
137 
138 	for (i = 0; i < rm->connections; i++) {
139 		rt = rm->con;
140 		rm->con = malloc(sizeof(struct RoomConnection));
141 		rm->con->x = FRInt();
142 		rm->con->y = FRInt();
143 		rm->con->x2 = FRInt();
144 		rm->con->y2 = FRInt();
145 		rm->con->c = FRInt();
146 		rm->con->n = rt;
147 	}
148 }
149 
WriteMapData()150 void WriteMapData()
151 {
152 	int i;
153 
154 	FWInt(map.w);
155 	FWInt(map.h);
156 	FWInt(map.totalRooms);
157 	FWInt(place_of_power);
158 	for (i = 0; i < map.w*map.h; i++) {
159 		FWChar(map.m[i]);
160 		FWInt(map.r[i]);
161 		if ((i % 7447) == 7446) {
162 			SavingScreen(0, (float)i / (float)(map.w*map.h));
163 		}
164 	}
165 	for (i = 0; i < map.totalRooms; i++) {
166 		WriteRoomData(&rooms[i]);
167 		if ((i % 85)==84) {
168 			SavingScreen(1, (float)i / (float)map.totalRooms);
169 		}
170 	}
171 }
172 
ReadMapData()173 void ReadMapData()
174 {
175 	int i;
176 
177 	map.w = FRInt();
178 	map.h = FRInt();
179 	map.totalRooms = total_rooms = FRInt();
180 	place_of_power = FRInt();
181 	for (i = 0; i < map.w*map.h; i++) {
182 		if ((i % 7447) == 7446) {
183 			LoadingScreen(0, (float)i / (float)(map.w*map.h));
184 		}
185 		map.m[i] = FRChar();
186 		map.r[i] = FRInt();
187 	}
188 	LoadingScreen(0, 1);
189 	for (i = 0; i < map.totalRooms; i++) {
190 		ReadRoomData(&rooms[i]);
191 		if ((i % 85)==84) {
192 			LoadingScreen(1, (float)i / (float)map.totalRooms);
193 		}
194 	}
195 	LoadingScreen(1, 1);
196 }
197 
rndval(int a,int b)198 int rndval(int a, int b)
199 {
200 	int temp;
201 
202 	if (a == b) {
203 		return a;
204 	}
205 
206 	if (b < a) {
207 		temp = a;
208 		a = b;
209 		b = temp;
210 	}
211 
212 	temp = rndnum(b - a);
213 
214 	return temp + a;
215 }
216 
RandomGenerateMap()217 void RandomGenerateMap()
218 {
219 	int trying = 1;
220 	if (game_load) {
221 		NewLevel();
222 		ReadMapData();
223 	} else {
224 		NewLevel();
225 		while (trying) {
226 
227 			trying = !Generate();
228 		}
229 	}
230 	//SaveLevel();
231 }
232 
NewLevel()233 void NewLevel()
234 {
235 	int x, y;
236 	unsigned char *map_p;
237 
238 	map.w = 512;
239 	map.h = 512;
240 
241 	map.m = malloc(map.w * map.h * sizeof(unsigned char));
242 	map.r = malloc(map.w * map.h * sizeof(int));
243 	map_p = map.m;
244 
245 	for (y = 0; y < map.h; y++) {
246 		for (x = 0; x < map.w; x++) {
247 			*(map_p++) = 17;
248 			map.r[y*map.w+x] = -1;
249 		}
250 	}
251 }
252 
DestroyDungeon()253 void DestroyDungeon()
254 {
255 	int i;
256 	struct RoomConnection *c, *d;
257 
258 	// Destroy map
259 	free(map.m);
260 	free(map.r);
261 
262 	// Destroy rooms
263 	for (i = 0; i < total_rooms; i++) {
264 		c = rooms[i].con;
265 		while (c != NULL) {
266 			d = c;
267 			c = c->n;
268 			free(d);
269 		}
270 	}
271 	total_rooms = 0;
272 }
273 
ResetLevel()274 void ResetLevel()
275 {
276 	int x, y;
277 	unsigned char *map_p;
278 
279 	map.w = 512;
280 	map.h = 512;
281 	map_p = map.m;
282 
283 	total_rooms = 0;
284 
285 	rdir = 0;
286 
287 	next_check = 30;
288 
289 	for (y = 0; y < map.h; y++) {
290 		for (x = 0; x < map.w; x++) {
291 			*(map_p++) = 17;
292 			map.r[y*map.w+x] = -1;
293 		}
294 	}
295 }
296 
SaveLevel()297 void SaveLevel()
298 {
299 	int x, y, i;
300 	SDL_Surface *map_surf;
301 	char cs[2] = ".";
302 	char rnum[5] = "0000";
303 	unsigned char ch;
304 	unsigned char *map_p;
305 	SDL_Color cpalette[4];
306 	Uint8 cl;
307 
308 	map_surf = SDL_CreateRGBSurface(0, 4096, 4096, 8, 0, 0, 0, 0);
309 
310 	map_p = map.m;
311 
312 	cpalette[0].r = cpalette[0].g = cpalette[0].b = 0;
313 	cpalette[1].r = cpalette[1].g = cpalette[1].b = 255;
314 	cpalette[2].r = 255; cpalette[2].g = 0; cpalette[2].b = 255;
315 	cpalette[3].r = 0; cpalette[3].g = 255; cpalette[3].b = 128;
316 
317 	SDL_SetPalette(map_surf, SDL_LOGPAL | SDL_PHYSPAL, cpalette, 0, 4);
318 
319 	for (y = 0; y < map.h; y++) {
320 		for (x = 0; x < map.w; x++) {
321 			ch = *(map_p++);
322 
323 			if (IsSolid(ch))
324 				*cs = 4;
325 			else
326 				*cs = 5;
327 
328 			if (ch == 17)
329 				*cs = 0;
330 
331 			cl = 1;
332 			if (rooms[GetRoom(x, y)].room_type == 2) cl = 2;
333 			if (rooms[GetRoom(x, y)].room_type == 3) cl = 3;
334 
335 			draw_text_ex(x*8, y*8, cs, cl, map_surf);
336 		}
337 	}
338 	for (i = 0; i < 3000; i++) {
339 		sprintf(rnum, "%d", i);
340 		draw_text_ex(rooms[i].x * 8, rooms[i].y * 8, rnum, 0, map_surf);
341 	}
342 
343 	SDL_SaveBMP(map_surf, "map.bmp");
344 }
345 
CreateRoomDimensions(int * w,int * h)346 void CreateRoomDimensions(int *w, int *h)
347 {
348 	*w = rndval(5, 12);
349 	*h = rndval(5, 12);
350 
351 	if (*w == 12) {
352 		*w = rndval(12, 15);
353 	}
354 	if (*h == 12) {
355 		*h = rndval(12, 15);
356 	}
357 }
358 
Put(int x,int y,unsigned char tile,int room)359 void Put(int x, int y, unsigned char tile, int room)
360 {
361 	map.m[map.w*y+x] = tile;
362 	map.r[map.w*y+x] = room;
363 }
364 
Get(int x,int y)365 unsigned char Get(int x, int y)
366 {
367 	if (x < 0) return 17;
368 	if (y < 0) return 17;
369 	if (x >= map.w) return 17;
370 	if (y >= map.h) return 17;
371 
372 	return map.m[map.w*y+x];
373 }
374 
GetRoom(int x,int y)375 int GetRoom(int x, int y)
376 {
377 	if (x < 0) return -1;
378 	if (y < 0) return -1;
379 	if (x >= map.w) return -1;
380 	if (y >= map.h) return -1;
381 
382 	return map.r[map.w*y+x];
383 }
384 
GetVisited(int x,int y)385 int GetVisited(int x, int y)
386 {
387 	if (x < 0) return 0;
388 	if (y < 0) return 0;
389 	if (x >= map.w) return 0;
390 	if (y >= map.h) return 0;
391 
392 	return rooms[GetRoom(x, y)].visited;
393 }
394 
Paint(int xp,int yp,int w,int h,char * fname)395 void Paint(int xp, int yp, int w, int h, char *fname)
396 {
397 	FILE *fp;
398 	int x, y;
399 	fp = fopen(fname, "rb");
400 
401 	for (y = 0; y < h; y++) {
402 		for (x = 0; x < w; x++) {
403 			Put(x+xp, y+yp, fgetc(fp), GetRoom(x+xp, y+yp));
404 		}
405 	}
406 	fclose(fp);
407 }
408 
DrawRoom(int place_x,int place_y,int room_w,int room_h,int room_id)409 void DrawRoom(int place_x, int place_y, int room_w, int room_h, int room_id)
410 {
411 	int x, y, i;
412 	int f_type;
413 
414 	f_type = rand()%4;
415 	// Corners
416 	Put(place_x, place_y, 11, room_id);
417 	Put(place_x + room_w - 1, place_y, 10, room_id);
418 	Put(place_x, place_y + room_h - 1, 9, room_id);
419 	Put(place_x + room_w - 1, place_y + room_h - 1, 8, room_id);
420 
421 	// Walls
422 
423 	for (i = 0; i < room_w - 2; i++) {
424 		Put(place_x + 1 + i, place_y + room_h - 1, 4, room_id);
425 		if (rand() % 16 == 0) Put(place_x + 1 + i, place_y + room_h - 1, 45 + (rand()%2)*4, room_id);
426 		Put(place_x + 1 + i, place_y, 5, room_id);
427 		if (rand() % 16 == 0) Put(place_x + 1 + i, place_y, 46 + (rand()%2)*4, room_id);
428 	}
429 	for (i = 0; i < room_h - 2; i++) {
430 		Put(place_x + room_w - 1, place_y + 1 + i, 6, room_id);
431 		if (rand() % 16 == 0) Put(place_x + room_w - 1, place_y + 1 + i, 47 + (rand()%2)*4, room_id);
432 		Put(place_x, place_y + 1 + i, 7, room_id);
433 		if (rand() % 16 == 0) Put(place_x, place_y + 1 + i, 48 + (rand()%2)*4, room_id);
434 	}
435 
436 	// Floor
437 
438 	for (y = 0; y < room_h - 2; y++) {
439 		for (x = 0; x < room_w - 2; x++) {
440 			Put(place_x + 1 + x, place_y + 1 + y, floortiles[f_type], room_id);
441 		}
442 	}
443 
444 	// Magic Tiles
445 
446 	if ((room_id % 30) == 29) {
447 		if (Get(place_x + 1 + rand()%(room_w-2), place_y + 1 + rand()%(room_h-2)) == floortiles[f_type]) {
448 			Put(place_x + 1 + rand()%(room_w-2), place_y + 1 + rand()%(room_h-2), 28+rand()%3, room_id);
449 		}
450 	}
451 
452 	// Save tiles
453 
454 	if ((room_id % 25) == 20) {
455 		x = place_x + 1 + rand()%(room_w-2);
456 		y = place_y + 1 + rand()%(room_h-2);
457 		if (Get(x, y) == floortiles[f_type]) {
458 			Put(x, y, 31, room_id);
459 		}
460 	}
461 
462 	// Summon tiles
463 	if ((room_id % 75) == 48) {
464 		x = place_x + 1 + rand()%(room_w-2);
465 		y = place_y + 1 + rand()%(room_h-2);
466 		if (Get(x, y) == floortiles[f_type]) {
467 			Put(x, y, 32, room_id);
468 		}
469 	}
470 
471 	// Compass tile
472 
473 	if ((room_id % 20) == 19) {
474 		x = place_x + 1 + rand()%(room_w-2);
475 		y = place_y + 1 + rand()%(room_h-2);
476 		if (Get(x, y) == floortiles[f_type]) {
477 			Put(x, y, 53, room_id);
478 		}
479 	}
480 
481 	// First room
482 	if (room_id == 0) {
483 		Paint(place_x+1, place_y+1, room_w-2, room_h-2, "/usr/local/share/meritous/d/centre.loc");
484 	}
485 	// Power object rooms
486 	if ((room_id % 1000) == 499) {
487 		Paint(place_x+1, place_y+1, room_w-2, room_h-2, "/usr/local/share/meritous/d/weapon.loc");
488 	}
489 	// Boss rooms
490 	if ((room_id % 1000) == 999) {
491 		Paint(place_x+1, place_y+1, room_w-2, room_h-2, "/usr/local/share/meritous/d/bossroom.loc");
492 	}
493 }
494 
NoRoomCollision(int place_x,int place_y,int room_w,int room_h)495 int NoRoomCollision(int place_x, int place_y, int room_w, int room_h)
496 {
497 	int x, y;
498 
499 	if (place_x < 0) return 0;
500 	if (place_y < 0) return 0;
501 	if ((place_x+room_w) > map.w) return 0;
502 	if ((place_y+room_h) > map.h) return 0;
503 
504 	for (y = 0; y < room_h; y++) {
505 		for (x = 0; x < room_w; x++) {
506 			if (Get(place_x + x, place_y + y) != 17) return 0;
507 		}
508 	}
509 
510 	return 1;
511 }
512 
MakeConnect(int x,int y,int type)513 void MakeConnect(int x, int y, int type)
514 {
515 	int nx, ny;
516 	int d1, d2;
517 	int room_1, room_2;
518 	struct RoomConnection *rconnect;
519 
520 	switch (type) {
521 		case 0:
522 			nx = x;
523 			ny = y - 1;
524 			d1 = 14;
525 			d2 = 13;
526 			break;
527 		case 1:
528 			nx = x;
529 			ny = y + 1;
530 			d1 = 13;
531 			d2 = 14;
532 			break;
533 		case 2:
534 			nx = x - 1;
535 			ny = y;
536 			d1 = 16;
537 			d2 = 15;
538 			break;
539 		case 3:
540 			nx = x + 1;
541 			ny = y;
542 			d1 = 15;
543 			d2 = 16;
544 			break;
545 		default:
546 			nx = 0;
547 			ny = 0;
548 			d1 = 0;
549 			d2 = 0;
550 			break;
551 	}
552 
553 	room_1 = GetRoom(x, y);
554 	room_2 = GetRoom(nx, ny);
555 	if ((room_1 % 1000) == 999) {
556 		d1 = d1 - 13 + 21;
557 		d2 = d2 - 13 + 38;
558 	} else {
559 		if ((room_2 % 1000) == 999) {
560 			d1 = d1 - 13 + 38;
561 			d2 = d2 - 13 + 21;
562 		}
563 	}
564 	Put(x, y, d1, GetRoom(x, y));
565 	Put(nx, ny, d2, GetRoom(nx, ny));
566 
567 	rooms[room_1].connections++;
568 	rconnect = rooms[room_1].con;
569 	rooms[room_1].con = malloc(sizeof(struct RoomConnection));
570 	rooms[room_1].con->n = rconnect;
571 	rooms[room_1].con->x = x;
572 	rooms[room_1].con->y = y;
573 	rooms[room_1].con->x2 = nx;
574 	rooms[room_1].con->y2 = ny;
575 	rooms[room_1].con->c = room_2;
576 
577 	rooms[room_2].connections++;
578 	rconnect = rooms[room_2].con;
579 	rooms[room_2].con = malloc(sizeof(struct RoomConnection));
580 	rooms[room_2].con->n = rconnect;
581 	rooms[room_2].con->x = nx;
582 	rooms[room_2].con->y = ny;
583 	rooms[room_2].con->x2 = x;
584 	rooms[room_2].con->y2 = y;
585 	rooms[room_2].con->c = room_1;
586 
587 }
588 
SuitableConnection(int t)589 int SuitableConnection(int t)
590 {
591 	switch (t) {
592 		case 4:
593 		case 5:
594 		case 6:
595 		case 7:
596 
597 		case 45:
598 		case 46:
599 		case 47:
600 		case 48:
601 
602 		case 49:
603 		case 50:
604 		case 51:
605 		case 52:
606 			return 1;
607 			break;
608 
609 		default:
610 			break;
611 	}
612 	return 0;
613 }
614 
NewRoom(int place_x,int place_y,int room_w,int room_h,int creator)615 void NewRoom(int place_x, int place_y, int room_w, int room_h, int creator)
616 {
617 	int connect_points = 0;
618 	int cplist_x[100], cplist_y[100], cplist_r[100], cplist_t[100];
619 
620 	int sr_cps = 0;
621 	int sr_cp[100];
622 
623 	int sr_nps = 0;
624 	int sr_np[100];
625 
626 	int i;
627 
628 	// Draw this room
629 	rooms[total_rooms].checkpoint = 0;
630 	DrawRoom(place_x, place_y, room_w, room_h, total_rooms);
631 
632 	rooms[total_rooms].x = place_x;
633 	rooms[total_rooms].y = place_y;
634 
635 	rooms[total_rooms].w = room_w;
636 	rooms[total_rooms].h = room_h;
637 
638 	rooms[total_rooms].room_type = 0;
639 	rooms[total_rooms].room_param = 0;
640 
641 	rooms[total_rooms].creator = creator;
642 
643 	rooms[total_rooms].connections = 0;
644 	rooms[total_rooms].con = NULL;
645 	rooms[total_rooms].enemies = 0;
646 
647 	rooms[total_rooms].visited = 0;
648 
649 	rooms[total_rooms].s_dist = -1;
650 
651 	if (total_rooms == 0) {
652 		rooms[total_rooms].checkpoint = 1;
653 	}
654 
655 
656 
657 	total_rooms++;
658 
659 	if (creator == -1) return;
660 
661 	// Find connection points
662 
663 	for (i = 0; i < room_w - 2; i++) {
664 		if (SuitableConnection(Get(place_x + 1 + i, place_y - 1))) {
665 			cplist_x[connect_points] = place_x + 1 + i;
666 			cplist_y[connect_points] = place_y;
667 			cplist_r[connect_points] = GetRoom(place_x + 1 + i, place_y - 1);
668 			cplist_t[connect_points] = 0;
669 			connect_points++;
670 		}
671 
672 		if (SuitableConnection(Get(place_x + 1 + i, place_y + room_h))) {
673 			cplist_x[connect_points] = place_x + 1 + i;
674 			cplist_y[connect_points] = place_y + room_h - 1;
675 			cplist_r[connect_points] = GetRoom(place_x + 1 + i, place_y + room_h);
676 			cplist_t[connect_points] = 1;
677 			connect_points++;
678 		}
679 	}
680 	for (i = 0; i < room_h - 2; i++) {
681 		if (SuitableConnection(Get(place_x - 1, place_y + 1 + i))) {
682 			cplist_x[connect_points] = place_x;
683 			cplist_y[connect_points] = place_y + 1 + i;
684 			cplist_r[connect_points] = GetRoom(place_x - 1, place_y + 1 + i);
685 			cplist_t[connect_points] = 2;
686 			connect_points++;
687 		}
688 
689 		if (SuitableConnection(Get(place_x + room_w, place_y + 1 + i))) {
690 			cplist_x[connect_points] = place_x + room_w - 1;
691 			cplist_y[connect_points] = place_y + 1 + i;
692 			cplist_r[connect_points] = GetRoom(place_x + room_w, place_y + 1 + i);
693 			cplist_t[connect_points] = 3;
694 			connect_points++;
695 		}
696 	}
697 
698 	for (i = 0; i < connect_points; i++) {
699 		if (cplist_r[i] == creator) {
700 			sr_cp[sr_cps++] = i;
701 		} else {
702 			sr_np[sr_nps++] = i;
703 		}
704 	}
705 
706 	//printf("cps: %d      room: %d\n", sr_cps, total_rooms);
707 
708 	assert(sr_cps > 0);
709 
710 	i = rndval(0, sr_cps-1);
711 	MakeConnect(cplist_x[sr_cp[i]], cplist_y[sr_cp[i]], cplist_t[sr_cp[i]]);
712 
713 	// one other connection (if we can)
714 	if (sr_nps > 0) {
715 		i = rndval(0, sr_nps-1);
716 		MakeConnect(cplist_x[sr_np[i]], cplist_y[sr_np[i]], cplist_t[sr_np[i]]);
717 	}
718 
719 }
720 
AddChild(int room_id)721 int AddChild(int room_id)
722 {
723 	Room r = rooms[room_id];
724 	int place_x = r.x;
725 	int place_y = r.y;
726 	int room_w = r.w;
727 	int room_h = r.h;
728 	int new_w, new_h, new_x, new_y;
729 	int room_pos;
730 
731 	int trying;
732 	int attempts;
733 
734 
735 
736 	trying = 1;
737 	attempts = 0;
738 	while (trying) {
739 		attempts++;
740 
741 		if (( (total_rooms+1) % 500)==0) {
742 			new_w = 20;
743 			new_h = 15;
744 		} else {
745 			CreateRoomDimensions(&new_w, &new_h);
746 		}
747 
748 		room_pos = (rdir++)%4;
749 
750 		if (room_pos < 2) {
751 			// vertical placement
752 			new_x = rndval(place_x - (new_w - 3), place_x + (room_w - 3));
753 			if (room_pos == 0) {
754 				new_y = place_y - new_h;
755 			} else {
756 				new_y = place_y + room_h;
757 			}
758 		} else {
759 			// horiz placement
760 			new_y = rndval(place_y - (new_h - 3), place_y + (room_h - 3));
761 			if (room_pos == 2) {
762 				new_x = place_x - new_w;
763 			} else {
764 				new_x = place_x + room_w;
765 			}
766 		}
767 
768 		if (NoRoomCollision(new_x, new_y, new_w, new_h)) {
769 			//printf("SUCCESS\n");
770 			r_successes[room_pos]++;
771 			NewRoom(new_x, new_y, new_w, new_h, room_id);
772 			return 1;
773 		} else {
774 			//printf("FAIL %d\n", attempts);
775 			r_fails[room_pos]++;
776 			if (attempts > 20) return 0;
777 		}
778 	}
779 	return 0;
780 }
781 
RecurseSetDist()782 void RecurseSetDist()
783 {
784 	struct RoomConnection *rc;
785 	int queue[10000];
786 	int q_top = 1;
787 	int q_bot = 0;
788 	int rooms_left = 3000;
789 	int c_room;
790 	queue[0] = 0;
791 
792 	if (rooms_left % 100 == 0) {
793 		LoadingScreen(1, 1.0 - ((float)rooms_left / 3000.0));
794 	}
795 
796 	rooms[0].s_dist = 0;
797 
798 	while ((rooms_left > 0)) {
799 		c_room = queue[q_bot];
800 		q_bot++;
801 		rooms_left--;
802 
803 		rc = rooms[c_room].con;
804 
805 		while (rc != NULL) {
806 			//assert(qp < 3000);
807 			if (rooms[rc->c].s_dist == -1) {
808 				queue[q_top] = rc->c;
809 				q_top++;
810 				rooms[rc->c].s_dist = rooms[c_room].s_dist+1;
811 			}
812 			rc = rc->n;
813 		}
814 	}
815 }
816 
RoomSize(int c_room)817 int RoomSize(int c_room)
818 {
819 	return sqrt(rooms[c_room].w*rooms[c_room].w + rooms[c_room].h*rooms[c_room].h);
820 }
821 
MakeSpecialRooms()822 void MakeSpecialRooms()
823 {
824 	int i, j;
825 	int c_tier;
826 	int c_room;
827 	int biggest_room_sz = 0;
828 	int biggest_room_n = -1;
829 	int rtyp[8] = {0};
830 	int ctyp;
831 	int x, y;
832 
833 	// Special rooms are:
834 	// - Boss rooms @ 500, 1000, 1500, 2000, 2500, 3000
835 	// - Artifact rooms (biggest non-boss room of a given tier)
836 	//		Tiers: 5-9  10-14  15-19  20-24  25-29  30-34  35-39  40-44
837 
838 	// boss rooms
839 	for (i = 0; i < 3; i++) {
840 		c_room = i*1000+999;
841 		rooms[c_room].room_type = 2;
842 		rooms[c_room].room_param = i;
843 	}
844 	// power object rooms
845 	for (i = 0; i < 3; i++) {
846 		c_room = i*1000+499;
847 		rooms[c_room].room_type = 5;
848 		rooms[c_room].room_param = i;
849 	}
850 
851 	// artifact rooms
852 	for (c_tier = 0; c_tier < 8; c_tier++) {
853 		biggest_room_sz = 0;
854 		for (c_room = 0; c_room < 3000; c_room++) {
855 			if (rooms[c_room].room_type == 0) {
856 				if (rooms[c_room].s_dist >= (c_tier*5+5)) {
857 					if (rooms[c_room].s_dist <= (c_tier*5+9)) {
858 						if (RoomSize(c_room) > biggest_room_sz) {
859 							biggest_room_sz = RoomSize(c_room);
860 							biggest_room_n = c_room;
861 						}
862 					}
863 				}
864 			}
865 		}
866 		rooms[biggest_room_n].room_type = 3;
867 
868 		// pick a #
869 		for (;;) {
870 			ctyp = rand()%8;
871 			if (rtyp[ctyp] == 0) {
872 				rtyp[ctyp] = 1;
873 				break;
874 			}
875 		}
876 
877 		rooms[biggest_room_n].room_param = ctyp;
878 
879 		//printf("Artifact room for tier %d is room %d (size %d), with artifact %d\n", c_tier, biggest_room_n, biggest_room_sz, ctyp);
880 	}
881 
882 	// place of power
883 	// The room with the highest s_dist that is not of any other type
884 
885 	for (i = 0; i < 3000; i++) {
886 		if (rooms[i].s_dist > rooms[place_of_power].s_dist) {
887 			if (rooms[i].room_type == 0) {
888 				place_of_power = i;
889 			}
890 		}
891 	}
892 
893 	rooms[place_of_power].room_type = 6;
894 
895 	// Now place some checkpoints in the remaining rooms
896 	// Normally, we would have a checkpoint for every 30
897 	// rooms, BUT since we aren't using that method any
898 	// more, we will simply use an equivalent--namely, to
899 	// divide the map into an 8x8 grid and place one
900 	// checkpoint per square
901 
902 	for (y = 0; y < 8; y++) {
903 		for (x = 0; x < 8; x++) {
904 			j = -1;
905 			for (i = 0; i < 20; i++) {
906 				j = GetRoom(rand() % 64 + x * 64, rand() % 64 + y * 64);
907 
908                 if (j >= 0) {
909                     if (rooms[j].room_type == 0) {
910                         Put(rooms[j].x + rooms[j].w / 2, rooms[j].y + rooms[j].h / 2, 25, j);
911                         rooms[j].checkpoint = 1;
912                         break;
913                     }
914                 }
915 			}
916 		}
917 	}
918 
919 	next_check--;
920 }
921 
Generate()922 int Generate()
923 {
924 	int attempts = 0;
925 	int i;
926 	int correct_dist = 0;
927 	int maxdist = 0;
928 	rdir = rand()%4;
929 	NewRoom(map.w / 2 - 20 / 2, map.h / 2 - 15 / 2, 20, 15, -1);
930 
931 	for (attempts = 0; attempts < 100000; attempts++) {
932         assert(map.w == 512);
933 		AddChild(rndval(rndval(0, total_rooms-1), total_rooms-1));
934 		if (total_rooms % 100 == 99) {
935 			LoadingScreen(0, (float)total_rooms / 3000.0);
936 		}
937 		if (total_rooms == 3000) break;
938 	}
939 
940 	if ((total_rooms < 3000)||(DoRepeat == 1)) {
941 		DoRepeat = 0;
942 		ResetLevel();
943 		return 0;
944 	}
945 
946 	RecurseSetDist();
947 
948 	for (i = 0; i < 3000; i++) {
949 		if (rooms[i].s_dist > maxdist) {
950 			maxdist = rooms[i].s_dist;
951 		}
952 
953 		if (rooms[i].s_dist >= 50) {
954 			correct_dist = 1;
955 		}
956 	}
957 
958 	if (correct_dist == 0) {
959 		//printf("Dist fail (only %d)\n", maxdist);
960 		DoRepeat = 0;
961 		ResetLevel();
962 		return 0;
963 	}
964 
965 	//printf("Rooms: %d\n", total_rooms);
966 
967 	MakeSpecialRooms();
968 
969 	map.totalRooms = total_rooms;
970 	return 1;
971 }
972 
973