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