4
// Copyright 2007, 2008 Lancer-X/ASCEAI
6
// This file is part of Meritous.
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.
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.
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/>.
31
#include "levelblit.h"
41
int place_of_power = 0;
43
struct RoomConnection {
47
struct RoomConnection *n;
61
struct RoomConnection *con;
80
int GetRoom(int x, int y);
84
return rand() % (max+1);
88
int r_successes[4] = {0};
90
unsigned char floortiles[4] = {12, 18, 19, 20};
92
void WriteRoomData(Room *rm)
94
struct RoomConnection *rt;
101
FWInt(rm->checkpoint);
103
FWInt(rm->connections);
104
FWInt(rm->room_type);
105
FWInt(rm->room_param);
117
void ReadRoomData(Room *rm)
120
struct RoomConnection *rt;
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();
138
for (i = 0; i < rm->connections; i++) {
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();
156
FWInt(map.totalRooms);
157
FWInt(place_of_power);
158
for (i = 0; i < map.w*map.h; i++) {
161
if ((i % 7447) == 7446) {
162
SavingScreen(0, (float)i / (float)(map.w*map.h));
165
for (i = 0; i < map.totalRooms; i++) {
166
WriteRoomData(&rooms[i]);
168
SavingScreen(1, (float)i / (float)map.totalRooms);
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));
189
for (i = 0; i < map.totalRooms; i++) {
190
ReadRoomData(&rooms[i]);
192
LoadingScreen(1, (float)i / (float)map.totalRooms);
198
int rndval(int a, int b)
212
temp = rndnum(b - a);
217
void RandomGenerateMap()
227
trying = !Generate();
236
unsigned char *map_p;
241
map.m = malloc(map.w * map.h * sizeof(unsigned char));
242
map.r = malloc(map.w * map.h * sizeof(int));
245
for (y = 0; y < map.h; y++) {
246
for (x = 0; x < map.w; x++) {
248
map.r[y*map.w+x] = -1;
253
void DestroyDungeon()
256
struct RoomConnection *c, *d;
263
for (i = 0; i < total_rooms; i++) {
277
unsigned char *map_p;
289
for (y = 0; y < map.h; y++) {
290
for (x = 0; x < map.w; x++) {
292
map.r[y*map.w+x] = -1;
300
SDL_Surface *map_surf;
302
char rnum[5] = "0000";
304
unsigned char *map_p;
305
SDL_Color cpalette[4];
308
map_surf = SDL_CreateRGBSurface(0, 4096, 4096, 8, 0, 0, 0, 0);
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;
317
SDL_SetPalette(map_surf, SDL_LOGPAL | SDL_PHYSPAL, cpalette, 0, 4);
319
for (y = 0; y < map.h; y++) {
320
for (x = 0; x < map.w; x++) {
332
if (rooms[GetRoom(x, y)].room_type == 2) cl = 2;
333
if (rooms[GetRoom(x, y)].room_type == 3) cl = 3;
335
draw_text_ex(x*8, y*8, cs, cl, map_surf);
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);
343
SDL_SaveBMP(map_surf, "map.bmp");
346
void CreateRoomDimensions(int *w, int *h)
359
void Put(int x, int y, unsigned char tile, int room)
361
map.m[map.w*y+x] = tile;
362
map.r[map.w*y+x] = room;
365
unsigned char Get(int x, int y)
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;
372
return map.m[map.w*y+x];
375
int GetRoom(int x, int y)
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;
382
return map.r[map.w*y+x];
385
int GetVisited(int x, int y)
389
if (x >= map.w) return 0;
390
if (y >= map.h) return 0;
392
return rooms[GetRoom(x, y)].visited;
395
void Paint(int xp, int yp, int w, int h, char *fname)
399
fp = fopen(fname, "rb");
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));
409
void DrawRoom(int place_x, int place_y, int room_w, int room_h, int room_id)
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);
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);
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);
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);
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);
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);
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);
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);
483
Paint(place_x+1, place_y+1, room_w-2, room_h-2, "dat/d/centre.loc");
485
// Power object rooms
486
if ((room_id % 1000) == 499) {
487
Paint(place_x+1, place_y+1, room_w-2, room_h-2, "dat/d/weapon.loc");
490
if ((room_id % 1000) == 999) {
491
Paint(place_x+1, place_y+1, room_w-2, room_h-2, "dat/d/bossroom.loc");
495
int NoRoomCollision(int place_x, int place_y, int room_w, int room_h)
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;
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;
513
void MakeConnect(int x, int y, int type)
518
struct RoomConnection *rconnect;
553
room_1 = GetRoom(x, y);
554
room_2 = GetRoom(nx, ny);
555
if ((room_1 % 1000) == 999) {
559
if ((room_2 % 1000) == 999) {
564
Put(x, y, d1, GetRoom(x, y));
565
Put(nx, ny, d2, GetRoom(nx, ny));
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;
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;
589
int SuitableConnection(int t)
615
void NewRoom(int place_x, int place_y, int room_w, int room_h, int creator)
617
int connect_points = 0;
618
int cplist_x[100], cplist_y[100], cplist_r[100], cplist_t[100];
629
rooms[total_rooms].checkpoint = 0;
630
DrawRoom(place_x, place_y, room_w, room_h, total_rooms);
632
rooms[total_rooms].x = place_x;
633
rooms[total_rooms].y = place_y;
635
rooms[total_rooms].w = room_w;
636
rooms[total_rooms].h = room_h;
638
rooms[total_rooms].room_type = 0;
639
rooms[total_rooms].room_param = 0;
641
rooms[total_rooms].creator = creator;
643
rooms[total_rooms].connections = 0;
644
rooms[total_rooms].con = NULL;
645
rooms[total_rooms].enemies = 0;
647
rooms[total_rooms].visited = 0;
649
rooms[total_rooms].s_dist = -1;
651
if (total_rooms == 0) {
652
rooms[total_rooms].checkpoint = 1;
659
if (creator == -1) return;
661
// Find connection points
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;
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;
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;
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;
698
for (i = 0; i < connect_points; i++) {
699
if (cplist_r[i] == creator) {
706
//printf("cps: %d room: %d\n", sr_cps, total_rooms);
710
i = rndval(0, sr_cps-1);
711
MakeConnect(cplist_x[sr_cp[i]], cplist_y[sr_cp[i]], cplist_t[sr_cp[i]]);
713
// one other connection (if we can)
715
i = rndval(0, sr_nps-1);
716
MakeConnect(cplist_x[sr_np[i]], cplist_y[sr_np[i]], cplist_t[sr_np[i]]);
721
int AddChild(int room_id)
723
Room r = rooms[room_id];
728
int new_w, new_h, new_x, new_y;
741
if (( (total_rooms+1) % 500)==0) {
745
CreateRoomDimensions(&new_w, &new_h);
748
room_pos = (rdir++)%4;
751
// vertical placement
752
new_x = rndval(place_x - (new_w - 3), place_x + (room_w - 3));
754
new_y = place_y - new_h;
756
new_y = place_y + room_h;
760
new_y = rndval(place_y - (new_h - 3), place_y + (room_h - 3));
762
new_x = place_x - new_w;
764
new_x = place_x + room_w;
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);
774
//printf("FAIL %d\n", attempts);
776
if (attempts > 20) return 0;
782
void RecurseSetDist()
784
struct RoomConnection *rc;
788
int rooms_left = 3000;
792
if (rooms_left % 100 == 0) {
793
LoadingScreen(1, 1.0 - ((float)rooms_left / 3000.0));
798
while ((rooms_left > 0)) {
799
c_room = queue[q_bot];
803
rc = rooms[c_room].con;
807
if (rooms[rc->c].s_dist == -1) {
808
queue[q_top] = rc->c;
810
rooms[rc->c].s_dist = rooms[c_room].s_dist+1;
817
int RoomSize(int c_room)
819
return sqrt(rooms[c_room].w*rooms[c_room].w + rooms[c_room].h*rooms[c_room].h);
822
void MakeSpecialRooms()
827
int biggest_room_sz = 0;
828
int biggest_room_n = -1;
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
839
for (i = 0; i < 3; i++) {
841
rooms[c_room].room_type = 2;
842
rooms[c_room].room_param = i;
844
// power object rooms
845
for (i = 0; i < 3; i++) {
847
rooms[c_room].room_type = 5;
848
rooms[c_room].room_param = i;
852
for (c_tier = 0; c_tier < 8; c_tier++) {
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;
866
rooms[biggest_room_n].room_type = 3;
871
if (rtyp[ctyp] == 0) {
877
rooms[biggest_room_n].room_param = ctyp;
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);
883
// The room with the highest s_dist that is not of any other type
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) {
893
rooms[place_of_power].room_type = 6;
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
902
for (y = 0; y < 8; y++) {
903
for (x = 0; x < 8; x++) {
905
for (i = 0; i < 20; i++) {
906
j = GetRoom(rand() % 64 + x * 64, rand() % 64 + y * 64);
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;
926
int correct_dist = 0;
929
NewRoom(map.w / 2 - 20 / 2, map.h / 2 - 15 / 2, 20, 15, -1);
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);
937
if (total_rooms == 3000) break;
940
if ((total_rooms < 3000)||(DoRepeat == 1)) {
948
for (i = 0; i < 3000; i++) {
949
if (rooms[i].s_dist > maxdist) {
950
maxdist = rooms[i].s_dist;
953
if (rooms[i].s_dist >= 50) {
958
if (correct_dist == 0) {
959
//printf("Dist fail (only %d)\n", maxdist);
965
//printf("Rooms: %d\n", total_rooms);
969
map.totalRooms = total_rooms;