Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
TheGameCenter
GitHub Repository: TheGameCenter/TheGameCenter.github.io
Path: blob/main/assets/javascript/cookieclicker/DungeonGen.js
15352 views
1
if (1==1 || undefined==Math.seedrandom)
2
{
3
(function(a,b,c,d,e,f){function k(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=j&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=j&f+1],c=c*d+h[j&(h[f]=h[g=j&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function l(a,b){var e,c=[],d=(typeof a)[0];if(b&&"o"==d)for(e in a)try{c.push(l(a[e],b-1))}catch(f){}return c.length?c:"s"==d?a:a+"\0"}function m(a,b){for(var d,c=a+"",e=0;c.length>e;)b[j&e]=j&(d^=19*b[j&e])+c.charCodeAt(e++);return o(b)}function n(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),o(c)}catch(e){return[+new Date,a,a.navigator.plugins,a.screen,o(b)]}}function o(a){return String.fromCharCode.apply(0,a)}var g=c.pow(d,e),h=c.pow(2,f),i=2*h,j=d-1;c.seedrandom=function(a,f){var j=[],p=m(l(f?[a,o(b)]:0 in arguments?a:n(),3),j),q=new k(j);return m(o(q.S),b),c.random=function(){for(var a=q.g(e),b=g,c=0;h>a;)a=(a+c)*d,b*=d,c=q.g(1);for(;a>=i;)a/=2,b/=2,c>>>=1;return(a+c)/b},p},m(c.random(),b)})(this,[],Math,256,6,52);
4
}
5
6
if (1==1 || undefined==choose) {function choose(arr) {if (arr.length==0) return 0; else return arr[Math.floor(Math.random()*arr.length)];}}
7
8
9
var DungeonGen=function()
10
{
11
var TILE_EMPTY=0;//solid
12
var TILE_LIMIT=-100;//can't build anything here; edges of map
13
var TILE_FLOOR_EDGE=100;
14
var TILE_FLOOR_CENTER=110;
15
var TILE_DOOR=200;
16
var TILE_PILLAR=300;//not just pillars, could be any type of repetitive decoration
17
var TILE_WATER=400;
18
var TILE_WALL=500;
19
var TILE_WALL_CORNER=510;
20
var TILE_ENTRANCE=250;
21
var TILE_EXIT=260;
22
23
var colors=[];
24
colors[TILE_EMPTY]='000';
25
colors[TILE_LIMIT]='900';
26
colors[TILE_FLOOR_EDGE]='ffc';
27
colors[TILE_FLOOR_CENTER]='ff9';
28
colors[TILE_DOOR]='f9f';
29
colors[TILE_PILLAR]='990';
30
colors[TILE_WATER]='99f';
31
colors[TILE_WALL]='960';
32
colors[TILE_WALL_CORNER]='630';
33
colors[TILE_ENTRANCE]='f9f';
34
colors[TILE_EXIT]='f9f';
35
36
var rand=function(a,b){return Math.floor(Math.random()*(b-a+1)+a);}//return random value between a and b
37
38
var Patterns=[];
39
this.Pattern=function(name,func)
40
{
41
this.name=name;
42
this.func=func;
43
Patterns.push(this);
44
}
45
new this.Pattern('Pillars',function(x,y,room)
46
{
47
if ((x+room.x)%2==0 && (y+room.y)%2==0 && Math.random()<0.8) return TILE_PILLAR;
48
return 0;
49
});
50
new this.Pattern('Large pillars',function(x,y,room)
51
{
52
if ((x+room.x)%3<2 && (y+room.y)%3<2 && Math.random()<0.8) return TILE_PILLAR;
53
return 0;
54
});
55
new this.Pattern('Sparse pillars',function(x,y,room)
56
{
57
if ((x+room.x)%3==0 && (y+room.y)%3==0 && Math.random()<0.8) return TILE_PILLAR;
58
return 0;
59
});
60
new this.Pattern('Lines',function(x,y,room)
61
{
62
if (room.x%2==0) if ((x+room.x)%2==0 && Math.random()<0.98) return TILE_PILLAR;
63
if (room.x%2==1) if ((y+room.y)%2==0 && Math.random()<0.98) return TILE_PILLAR;
64
return 0;
65
});
66
67
68
var getRandomPattern=function()
69
{return choose(Patterns);}
70
71
var defaultGenerator=function(me)
72
{
73
me.roomSize=10;
74
me.corridorSize=5;
75
me.fillRatio=1/3;
76
me.corridorRatio=0.2;
77
me.pillarRatio=0.2;
78
me.waterRatio=0;
79
me.branching=4;
80
me.sizeVariance=0.2;
81
82
me.fillRatio=0.1+Math.random()*0.4;
83
me.roomSize=Math.ceil(rand(5,15)*me.fillRatio*2);
84
me.corridorSize=Math.ceil(rand(1,7)*me.fillRatio*2);
85
me.corridorRatio=Math.random()*0.8+0.1;
86
me.pillarRatio=Math.random()*0.5+0.5;
87
me.waterRatio=Math.pow(Math.random(),2);
88
me.branching=Math.floor(Math.random()*6);
89
me.sizeVariance=Math.random();
90
}
91
92
93
this.Map=function(w,h,seed,params)
94
{
95
//create a new map
96
//leave the seed out for a random seed
97
//params is an object that contains custom parameters as defined in defaultGenerator
98
//example : MyMap=new DungeonGen.Map(30,30,MySeed,{waterRatio:0.8}); (80 percent of the rooms will contain water)
99
if (undefined!=seed) this.seed=seed; else {Math.seedrandom();this.seed=Math.random();}
100
Math.seedrandom(this.seed);
101
this.seedState=Math.random;
102
this.w=w||20;
103
this.h=h||20;
104
105
this.roomsAreHidden=0;
106
107
this.rooms=[];
108
this.freeWalls=[];//all walls that would be a good spot for a door
109
this.freeTiles=[];//all passable floor tiles
110
this.doors=[];
111
this.tiles=this.w*this.h;
112
this.tilesDug=0;
113
this.digs=0;//amount of digging steps
114
this.stuck=0;//how many times we ran into a problem; stop digging if we get too many of these
115
116
this.data=[];//fill the map with 0
117
for (var x=0;x<this.w;x++)
118
{
119
this.data[x]=[];
120
for (var y=0;y<this.h;y++)
121
{
122
this.data[x][y]=[TILE_EMPTY,-1,0];//data is stored as [tile system type,room id,tile displayed type] (-1 is no room)
123
if (x==0 || y==0 || x==this.w-1 || y==this.h-1) this.data[x][y]=[TILE_LIMIT,-1,0];
124
}
125
}
126
127
defaultGenerator(this);
128
if (params)
129
{
130
for (var i in params)
131
{
132
this[i]=params[i];
133
}
134
}
135
Math.seedrandom();
136
137
}
138
139
this.Map.prototype.getType=function(x,y){return this.data[x][y][0];}
140
this.Map.prototype.getRoom=function(x,y){if (this.data[x][y][1]!=-1) return this.rooms[this.data[x][y][1]]; else return -1;}
141
this.Map.prototype.getTile=function(x,y){return this.rooms[this.data[x][y][2]];}
142
143
this.Map.prototype.isWall=function(x,y)
144
{
145
var n=0;
146
for (var i in this.freeWalls){if (this.freeWalls[i][0]==x && this.freeWalls[i][1]==y) return n; else n++;}
147
return -1;
148
}
149
this.Map.prototype.isFloor=function(x,y)
150
{
151
var n=0;
152
for (var i in this.freeTiles){if (this.freeTiles[i][0]==x && this.freeTiles[i][1]==y) return n; else n++;}
153
return -1;
154
}
155
this.Map.prototype.removeFreeTile=function(x,y)
156
{
157
this.freeTiles.splice(this.isFloor(x,y),1);
158
}
159
160
this.Map.prototype.fill=function(what)
161
{
162
var func=0;
163
if (typeof(what)=='function') func=1;
164
for (var x=0;x<this.w;x++){for (var y=0;y<this.h;y++){
165
if (func) this.data[x][y]=[what(this,x,y),-1,0]; else this.data[x][y]=[what,-1,0];
166
}}
167
this.rooms=[];
168
}
169
170
this.Map.prototype.fillZone=function(X,Y,W,H,what)
171
{
172
//just plain fill a rectangle
173
for (var x=X;x<X+W;x++){for (var y=Y;y<Y+H;y++){
174
this.data[x][y][0]=what;
175
}}
176
}
177
178
this.Map.prototype.getRoomTile=function(room,x,y)
179
{
180
var n=0;
181
for (var i in room.tiles) {if (room.tiles[i].x==x && room.tiles[i].y==y) return n; else n++;}
182
return -1;
183
}
184
185
this.Map.prototype.getFloorTileInRoom=function(room)
186
{
187
var tiles=[];
188
for (var i in room.tiles) {if (room.tiles[i].type==TILE_FLOOR_EDGE || room.tiles[i].type==TILE_FLOOR_CENTER) tiles.push(room.tiles[i]);}
189
return choose(tiles);
190
}
191
192
this.Map.prototype.canPlaceRoom=function(rx,ry,rw,rh)
193
{
194
if (rx<2 || ry<2 || rx+rw>=this.w-1 || ry+rh>=this.h-1) return false;
195
for (var x=rx;x<rx+rw;x++)
196
{
197
for (var y=ry;y<ry+rh;y++)
198
{
199
var tile=this.getType(x,y);
200
var room=this.getRoom(x,y);
201
if (tile==TILE_LIMIT) return false;
202
if (room!=-1) return false;
203
}
204
}
205
return true;
206
}
207
208
this.Map.prototype.setRoomTile=function(room,x,y,tile)
209
{
210
//var mapTile=this.getType(x,y);
211
var oldTile=this.getRoomTile(room,x,y);
212
var oldTileType=oldTile!=-1?room.tiles[oldTile].type:-1;
213
if (oldTile!=-1 && (
214
//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER) ||// && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) ||
215
//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) ||
216
(tile==TILE_WALL || tile==TILE_WALL_CORNER) ||//don't place a wall over an existing room
217
(tile==TILE_FLOOR_EDGE && oldTileType==TILE_FLOOR_CENTER)//don't place an edge floor over a center floor
218
)) {return false;}
219
else
220
{
221
if (oldTile!=-1) room.tiles.splice(oldTile,1);
222
room.tiles.push({x:x,y:y,type:tile,score:0});
223
if ((tile==TILE_FLOOR_EDGE || tile==TILE_FLOOR_CENTER) && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) room.freeTiles++;
224
else if (tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER && (oldTileType==TILE_FLOOR_EDGE || oldTileType==TILE_FLOOR_CENTER)) room.freeTiles--;
225
return true;
226
}
227
}
228
229
this.Map.prototype.expandRoom=function(room,rx,ry,rw,rh)
230
{
231
var x=0;var y=0;
232
//floor
233
for (var x=rx;x<rx+rw;x++){for (var y=ry;y<ry+rh;y++){
234
this.setRoomTile(room,x,y,TILE_FLOOR_EDGE);
235
}}
236
for (var x=rx+1;x<rx+rw-1;x++){for (var y=ry+1;y<ry+rh-1;y++){
237
this.setRoomTile(room,x,y,TILE_FLOOR_CENTER);
238
}}
239
//walls
240
y=ry-1;
241
for (var x=rx;x<rx+rw;x++){
242
this.setRoomTile(room,x,y,TILE_WALL);
243
}
244
y=ry+rh;
245
for (var x=rx;x<rx+rw;x++){
246
this.setRoomTile(room,x,y,TILE_WALL);
247
}
248
x=rx-1;
249
for (var y=ry;y<ry+rh;y++){
250
this.setRoomTile(room,x,y,TILE_WALL);
251
}
252
x=rx+rw;
253
for (var y=ry;y<ry+rh;y++){
254
this.setRoomTile(room,x,y,TILE_WALL);
255
}
256
//corners
257
x=rx-1;y=ry-1;
258
this.setRoomTile(room,x,y,TILE_WALL_CORNER);
259
x=rx+rw;y=ry-1;
260
this.setRoomTile(room,x,y,TILE_WALL_CORNER);
261
x=rx-1;y=ry+rh;
262
this.setRoomTile(room,x,y,TILE_WALL_CORNER);
263
x=rx+rw;y=ry+rh;
264
this.setRoomTile(room,x,y,TILE_WALL_CORNER);
265
266
//decoration
267
var water=Math.random()<this.waterRatio?1:0;
268
var pattern=Math.random()<this.pillarRatio?getRandomPattern():0;
269
for (var x=rx;x<rx+rw;x++){for (var y=ry;y<ry+rh;y++){
270
if (room.tiles[this.getRoomTile(room,x,y)].type==TILE_FLOOR_CENTER)
271
{
272
var tile=0;
273
if (water!=0) tile=TILE_WATER;
274
if (pattern!=0)
275
{
276
tile=pattern.func(x,y,room)||tile;
277
}
278
if (tile!=0) this.setRoomTile(room,x,y,tile);
279
}
280
}}
281
}
282
283
this.Map.prototype.newRoom=function(x,y,w,h,parent)
284
{
285
//create a new abstract room, ready to be carved
286
var room={};
287
room.id=this.rooms.length;
288
room.w=w;//||rand(2,this.roomSize);
289
room.h=h;//||rand(2,this.roomSize);
290
room.x=x||rand(1,this.w-room.w-1);
291
room.y=y||rand(1,this.h-room.h-1);
292
room.tiles=[];
293
room.freeTiles=0;
294
room.parent=parent?parent:-1;
295
room.children=[];
296
room.gen=0;
297
room.door=0;
298
room.corridor=Math.random()<this.corridorRatio?1:0;
299
room.hidden=this.roomsAreHidden;//if 1, don't draw
300
//if (room.parent!=-1) room.corridor=!room.parent.corridor;//alternate rooms and corridors
301
302
return room;
303
}
304
this.Map.prototype.planRoom=function(room)
305
{
306
var branches=this.branching+1;
307
var forcedExpansions=[];
308
var w=room.w;
309
var h=room.h;
310
while (w>0 && h>0)
311
{
312
if (w>0) {forcedExpansions.push(1,3);w--;}
313
if (h>0) {forcedExpansions.push(2,4);h--;}
314
}
315
316
for (var i=0;i<branches;i++)
317
{
318
var steps=0;
319
var expansions=[];
320
if (!room.corridor)
321
{
322
expansions=[1,2,3,4];
323
steps=this.roomSize;
324
}
325
else
326
{
327
expansions=choose([[1,3],[2,4]]);
328
steps=this.corridorSize;
329
}
330
steps=Math.max(room.w+room.h,Math.ceil(steps*(1-Math.random()*this.sizeVariance)));
331
if (room.tiles.length==0) {var rx=room.x;var ry=room.y;var rw=1;var rh=1;}
332
else {var randomTile=this.getFloorTileInRoom(room);var rx=randomTile.x;var ry=randomTile.y;var rw=1;var rh=1;}
333
for (var ii=0;ii<steps;ii++)
334
{
335
if (expansions.length==0) break;
336
var xd=0;var yd=0;var wd=0;var hd=0;
337
var side=choose(expansions);
338
if (forcedExpansions.length>0) side=forcedExpansions[0];
339
if (side==1) {xd=-1;wd=1;}
340
else if (side==2) {yd=-1;hd=1;}
341
else if (side==3) {wd=1;}
342
else if (side==4) {hd=1;}
343
if (this.canPlaceRoom(rx+xd,ry+yd,rw+wd,rh+hd)) {rx+=xd;ry+=yd;rw+=wd;rh+=hd;} else expansions.splice(expansions.indexOf(side),1);
344
if (forcedExpansions.length>0) forcedExpansions.splice(0,1);
345
}
346
if (rw>1 || rh>1)
347
{
348
this.expandRoom(room,rx,ry,rw,rh);
349
}
350
}
351
}
352
353
354
this.Map.prototype.carve=function(room)
355
{
356
//carve a room into the map
357
for (var i in room.tiles)
358
{
359
var thisTile=room.tiles[i];
360
var x=thisTile.x;var y=thisTile.y;
361
var myType=this.data[x][y][0];
362
var type=thisTile.type;
363
364
if ((type==TILE_WALL || type==TILE_WALL_CORNER) && this.isWall(x,y)!=-1) {this.freeWalls.splice(this.isWall(x,y),1);}
365
366
if (this.data[x][y][1]!=-1 && (type==TILE_WALL || type==TILE_WALL_CORNER)) {}
367
else
368
{
369
if (this.data[x][y][1]==-1) this.tilesDug++;
370
this.data[x][y]=[thisTile.type,room.id,0];
371
if (x>1 && y>1 && x<this.w-2 && y<this.h-2 && type==TILE_WALL) this.freeWalls.push([x,y]);
372
if (type==TILE_FLOOR_EDGE || type==TILE_FLOOR_CENTER) this.freeTiles.push([x,y]);
373
}
374
var pos=[x,y];
375
}
376
this.rooms[room.id]=room;
377
}
378
379
this.Map.prototype.newRandomRoom=function(params)
380
{
381
var success=1;
382
params=params||{};//params is an object such as {corridor:1}
383
var door=choose(this.freeWalls);//select a free wall to use as a door
384
if (!door) {success=0;}
385
else
386
{
387
//this.data[door[0]][door[1]][0]=TILE_LIMIT;//not door
388
var parentRoom=this.getRoom(door[0],door[1]);
389
var sides=[];//select a free side of that door
390
if (this.getType(door[0]-1,door[1])==TILE_EMPTY) sides.push([-1,0]);
391
if (this.getType(door[0]+1,door[1])==TILE_EMPTY) sides.push([1,0]);
392
if (this.getType(door[0],door[1]-1)==TILE_EMPTY) sides.push([0,-1]);
393
if (this.getType(door[0],door[1]+1)==TILE_EMPTY) sides.push([0,1]);
394
var side=choose(sides);
395
if (!side) {success=0;this.freeWalls.splice(this.isWall(door[0],door[1]),1);}
396
else
397
{
398
var room=this.newRoom(door[0]+side[0],door[1]+side[1],0,0,parentRoom);//try a new room from this spot
399
for (var i in params)
400
{
401
room[i]=params[i];
402
}
403
this.planRoom(room);
404
if (room.tiles.length>0 && room.freeTiles>0)//we got a decent room
405
{
406
this.carve(room);
407
this.data[door[0]][door[1]][0]=TILE_DOOR;//place door
408
room.door=[door[0],door[1]];
409
this.data[door[0]][door[1]][1]=room.id;//set ID
410
this.freeWalls.splice(this.isWall(door[0],door[1]),1);//the door isn't a wall anymore
411
this.doors.push([door[0],door[1],room]);
412
//remove free tiles on either side of the door
413
if (this.isFloor(door[0]+side[0],door[1]+side[1])!=-1) this.removeFreeTile(door[0]+side[0],door[1]+side[1]);
414
if (this.isFloor(door[0]-side[0],door[1]-side[1])!=-1) this.removeFreeTile(door[0]-side[0],door[1]-side[1]);
415
room.parent=parentRoom;
416
parentRoom.children.push(room);
417
room.gen=parentRoom.gen+1;
418
}
419
else//not a good spot; remove this tile from the list of walls
420
{
421
this.freeWalls.splice(this.isWall(door[0],door[1]),1);
422
success=0;
423
}
424
}
425
}
426
if (success) return room;
427
else return 0;
428
}
429
430
this.Map.prototype.getRandomSpotInRoom=function(room)
431
{
432
var listOfTiles=[];
433
for (var i in room.tiles)
434
{
435
if ((room.tiles[i].type==TILE_FLOOR_EDGE || room.tiles[i].type==TILE_FLOOR_CENTER) && this.isFloor(room.tiles[i].x,room.tiles[i].y)!=-1)
436
{
437
listOfTiles.push(room.tiles[i]);
438
}
439
}
440
if (listOfTiles.length==0) return -1;
441
return choose(listOfTiles);
442
}
443
this.Map.prototype.getBestSpotInRoom=function(room)
444
{
445
var highest=-1;
446
var listOfHighest=[];
447
for (var i in room.tiles)
448
{
449
if ((room.tiles[i].type==TILE_FLOOR_EDGE || room.tiles[i].type==TILE_FLOOR_CENTER) && this.isFloor(room.tiles[i].x,room.tiles[i].y)!=-1)
450
{
451
if (room.tiles[i].score>highest)
452
{
453
listOfHighest=[];
454
highest=room.tiles[i].score;
455
listOfHighest.push(room.tiles[i]);
456
}
457
else if (room.tiles[i].score==highest)
458
{
459
listOfHighest.push(room.tiles[i]);
460
}
461
}
462
}
463
if (listOfHighest.length==0) return -1;
464
return choose(listOfHighest);
465
}
466
this.Map.prototype.getEarliestRoom=function()
467
{
468
return this.rooms[0];
469
}
470
this.Map.prototype.getDeepestRoom=function()
471
{
472
var deepest=0;
473
var deepestRoom=this.rooms[0];
474
for (var i in this.rooms)
475
{
476
if ((this.rooms[i].gen+Math.sqrt(this.rooms[i].freeTiles)*0.05)>=deepest && this.rooms[i].corridor==0 && this.rooms[i].freeTiles>4) {deepest=(this.rooms[i].gen+Math.sqrt(this.rooms[i].freeTiles)*0.05);deepestRoom=this.rooms[i];}
477
}
478
return deepestRoom;
479
}
480
481
this.Map.prototype.dig=function()
482
{
483
//one step in which we try to carve new stuff
484
//returns 0 when we couldn't dig this step, 1 when we could, and 2 when the digging is complete
485
Math.random=this.seedState;
486
487
var badDig=0;
488
489
if (this.digs==0)//first dig : build a starting room in the middle of the map
490
{
491
var w=rand(3,7);
492
var h=rand(3,7);
493
var room=this.newRoom(Math.floor(this.w/2-w/2),Math.floor(this.h/2-h/2),w,h);
494
room.corridor=0;
495
this.planRoom(room);
496
this.carve(room);
497
}
498
else
499
{
500
if (this.newRandomRoom()==0) badDig++;
501
}
502
if (badDig>0) this.stuck++;
503
504
this.digs++;
505
506
var finished=0;
507
if (this.tilesDug>=this.tiles*this.fillRatio) finished=1;
508
if (this.stuck>100) finished=1;
509
510
if (finished==1)//last touch : try to add a whole room at the end
511
{
512
for (var i=0;i<10;i++)
513
{
514
var newRoom=this.newRandomRoom({corridor:0,w:rand(3,7),h:rand(3,7)});
515
if (newRoom!=0 && newRoom.freeTiles>15) break;
516
}
517
}
518
519
Math.seedrandom();
520
if (finished==1) return 1; else if (badDig>0) return -1; else return 0;
521
}
522
523
this.Map.prototype.finish=function()
524
{
525
for (var i in this.rooms)
526
{
527
var pillars=Math.random()<this.pillarRatio;
528
for (var ii in this.rooms[i].tiles)
529
{
530
var x=this.rooms[i].tiles[ii].x;
531
var y=this.rooms[i].tiles[ii].y;
532
var me=this.data[x][y][0];
533
var x1=this.data[x-1][y][0];
534
var x2=this.data[x+1][y][0];
535
var y1=this.data[x][y-1][0];
536
var y2=this.data[x][y+1][0];
537
var xy1=this.data[x-1][y-1][0];
538
var xy2=this.data[x+1][y-1][0];
539
var xy3=this.data[x-1][y+1][0];
540
var xy4=this.data[x+1][y+1][0];
541
542
var walls=0;
543
if ((x1==TILE_WALL||x1==TILE_WALL_CORNER)) walls++;
544
if ((y1==TILE_WALL||y1==TILE_WALL_CORNER)) walls++;
545
if ((x2==TILE_WALL||x2==TILE_WALL_CORNER)) walls++;
546
if ((y2==TILE_WALL||y2==TILE_WALL_CORNER)) walls++;
547
if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER)) walls++;
548
if ((xy2==TILE_WALL||xy2==TILE_WALL_CORNER)) walls++;
549
if ((xy3==TILE_WALL||xy3==TILE_WALL_CORNER)) walls++;
550
if ((xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) walls++;
551
552
var floors=0;
553
if ((x1==TILE_FLOOR_CENTER||x1==TILE_FLOOR_EDGE)) floors++;
554
if ((y1==TILE_FLOOR_CENTER||y1==TILE_FLOOR_EDGE)) floors++;
555
if ((x2==TILE_FLOOR_CENTER||x2==TILE_FLOOR_EDGE)) floors++;
556
if ((y2==TILE_FLOOR_CENTER||y2==TILE_FLOOR_EDGE)) floors++;
557
if ((xy1==TILE_FLOOR_CENTER||xy1==TILE_FLOOR_EDGE)) floors++;
558
if ((xy2==TILE_FLOOR_CENTER||xy2==TILE_FLOOR_EDGE)) floors++;
559
if ((xy3==TILE_FLOOR_CENTER||xy3==TILE_FLOOR_EDGE)) floors++;
560
if ((xy4==TILE_FLOOR_CENTER||xy4==TILE_FLOOR_EDGE)) floors++;
561
562
var complete=0;
563
if (walls+floors==8) complete=1;
564
565
var angle=0;
566
if (complete)
567
{
568
var top=0;
569
var left=0;
570
var right=0;
571
var bottom=0;
572
if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER) && (y1==TILE_WALL||y1==TILE_WALL_CORNER) && (xy2==TILE_WALL||xy2==TILE_WALL_CORNER)) top=1;
573
else if ((xy1==TILE_FLOOR_CENTER||xy1==TILE_FLOOR_EDGE) && (y1==TILE_FLOOR_CENTER||y1==TILE_FLOOR_EDGE) && (xy2==TILE_FLOOR_CENTER||xy2==TILE_FLOOR_EDGE)) top=-1;
574
if ((xy2==TILE_WALL||xy2==TILE_WALL_CORNER) && (x2==TILE_WALL||x2==TILE_WALL_CORNER) && (xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) right=1;
575
else if ((xy2==TILE_FLOOR_CENTER||xy2==TILE_FLOOR_EDGE) && (x2==TILE_FLOOR_CENTER||x2==TILE_FLOOR_EDGE) && (xy4==TILE_FLOOR_CENTER||xy4==TILE_FLOOR_EDGE)) right=-1;
576
if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER) && (x1==TILE_WALL||x1==TILE_WALL_CORNER) && (xy3==TILE_WALL||xy3==TILE_WALL_CORNER)) left=1;
577
else if ((xy1==TILE_FLOOR_CENTER||xy1==TILE_FLOOR_EDGE) && (x1==TILE_FLOOR_CENTER||x1==TILE_FLOOR_EDGE) && (xy3==TILE_FLOOR_CENTER||xy3==TILE_FLOOR_EDGE)) left=-1;
578
if ((xy3==TILE_WALL||xy3==TILE_WALL_CORNER) && (y2==TILE_WALL||y2==TILE_WALL_CORNER) && (xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) bottom=1;
579
else if ((xy3==TILE_FLOOR_CENTER||xy3==TILE_FLOOR_EDGE) && (y2==TILE_FLOOR_CENTER||y2==TILE_FLOOR_EDGE) && (xy4==TILE_FLOOR_CENTER||xy4==TILE_FLOOR_EDGE)) bottom=-1;
580
if ((top==1 && bottom==-1) || (top==-1 && bottom==1) || (left==1 && right==-1) || (left==-1 && right==1)) angle=1;
581
}
582
583
if (pillars && Math.random()<0.8 && this.rooms[i].freeTiles>4)
584
{
585
if ((angle==1 || (complete && walls==7)) && me==TILE_FLOOR_EDGE && x1!=TILE_DOOR && x2!=TILE_DOOR && y1!=TILE_DOOR && y2!=TILE_DOOR)
586
{
587
this.data[x][y][0]=TILE_PILLAR;
588
me=TILE_PILLAR;
589
this.removeFreeTile(x,y);
590
this.rooms[i].freeTiles--;
591
}
592
}
593
594
//calculate score (for placing items and exits)
595
if (top==1 || bottom==1 || left==1 || right==1)
596
{
597
this.rooms[i].tiles[ii].score+=2;
598
}
599
if (walls>5 || floors>5)
600
{
601
this.rooms[i].tiles[ii].score+=1;
602
}
603
if (walls==7 || floors==8)
604
{
605
this.rooms[i].tiles[ii].score+=5;
606
}
607
if ((me!=TILE_FLOOR_CENTER && me!=TILE_FLOOR_EDGE) || x1==TILE_DOOR || x2==TILE_DOOR || y1==TILE_DOOR || y2==TILE_DOOR) this.rooms[i].tiles[ii].score=-1;
608
609
}
610
}
611
612
613
614
//carve entrance and exit
615
var entrance=this.getBestSpotInRoom(this.getEarliestRoom());
616
this.data[entrance.x][entrance.y][0]=TILE_ENTRANCE;
617
this.entrance=[entrance.x,entrance.y];
618
entrance.score=0;
619
this.removeFreeTile(entrance.x,entrance.y);
620
var exit=this.getBestSpotInRoom(this.getDeepestRoom());
621
this.data[exit.x][exit.y][0]=TILE_EXIT;
622
this.exit=[exit.x,exit.y];
623
this.removeFreeTile(exit.x,exit.y);
624
exit.score=0;
625
626
/*
627
for (var i in this.doors)//remove door tiles (to add later; replace the tiles by entities that delete themselves when opened)
628
{
629
this.data[this.doors[i][0]][this.doors[i][1]][0]=TILE_FLOOR_EDGE;
630
}
631
*/
632
}
633
634
this.Map.prototype.isObstacle=function(x,y)
635
{
636
var free=[TILE_FLOOR_EDGE,TILE_FLOOR_CENTER,TILE_DOOR,TILE_ENTRANCE,TILE_EXIT];
637
for (var i in free)
638
{
639
if (this.data[x][y][0]==free[i]) return 0;
640
}
641
return 1;
642
}
643
644
var joinTile=function(map,x,y,joinWith)
645
{
646
//for the tile at x,y, return 2 if it joins with its horizontal neighbors, 3 if it joins with its vertical neighbors, 1 if it joins with either both or neither.
647
//joinWith contains the tile types that count as joinable, in addition to this tile. (don't add the tested tile to joinWith!)
648
var p=1;
649
var me=map.data[x][y][0];
650
var x1=map.data[x-1][y][0];
651
var x2=map.data[x+1][y][0];
652
var y1=map.data[x][y-1][0];
653
var y2=map.data[x][y+1][0];
654
joinWith.push(me);
655
var joinsX=0;
656
for (var i in joinWith)
657
{
658
if (x1==joinWith[i]) joinsX++;
659
if (x2==joinWith[i]) joinsX++;
660
}
661
var joinsY=0;
662
for (var i in joinWith)
663
{
664
if (y1==joinWith[i]) joinsY++;
665
if (y2==joinWith[i]) joinsY++;
666
}
667
if (joinsX==2 && joinsY==2) p=1;
668
else if (joinsX==2) p=2;
669
else if (joinsY==2) p=3;
670
return p;
671
}
672
this.Map.prototype.getPic=function(x,y)
673
{
674
//return a position [x,y] in the tiles (as 0, 1, 2...) for the tile on the map at position x,y
675
if (Tiles[this.data[x][y][2]])
676
{
677
if (Tiles[this.data[x][y][2]].joinType=='join')
678
{
679
var thisPic=Tiles[this.data[x][y][2]].pic;
680
thisPic=[thisPic[0],thisPic[1]];//why is this even necessary?
681
var joinWith=[];
682
if (this.data[x][y][0]==TILE_WALL) joinWith.push(TILE_WALL_CORNER);
683
else if (this.data[x][y][0]==TILE_DOOR) joinWith.push(TILE_WALL,TILE_WALL_CORNER);
684
thisPic[0]+=joinTile(this,x,y,joinWith)-1;
685
return thisPic;
686
}
687
else if (Tiles[this.data[x][y][2]].joinType=='random3')
688
{
689
var thisPic=Tiles[this.data[x][y][2]].pic;
690
thisPic=[thisPic[0],thisPic[1]];
691
thisPic[0]+=Math.floor(Math.random()*3);
692
return thisPic;
693
}
694
return Tiles[this.data[x][y][2]].pic;
695
}
696
return [0,0];
697
}
698
699
var Tiles=[];
700
var TilesByName=[];
701
this.Tile=function(name,pic,joinType)
702
{
703
this.name=name;
704
this.pic=pic;
705
this.joinType=joinType||'none';
706
this.id=Tiles.length;
707
Tiles[this.id]=this;
708
TilesByName[this.name]=this;
709
}
710
new this.Tile('void',[0,0]);
711
this.loadTiles=function(tiles)
712
{
713
for (var i in tiles)
714
{
715
var name=tiles[i][0];
716
var pic=tiles[i][1];
717
var joinType=tiles[i][2];
718
new this.Tile(name,pic,joinType);
719
}
720
}
721
722
var computeTile=function(tile,tiles,value,name)
723
{
724
if (tile==value && tiles[name]) return TilesByName[tiles[name]];
725
return 0;
726
}
727
this.Map.prototype.assignTiles=function(room,tiles)
728
{
729
//set the displayed tiles for this room
730
for (var i in room.tiles)
731
{
732
var type=Tiles[0];
733
var me=room.tiles[i];
734
var tile=this.data[me.x][me.y][0];
735
type=computeTile(tile,tiles,TILE_WALL_CORNER,'wall corner')||type;
736
type=computeTile(tile,tiles,TILE_WALL,'wall')||type;
737
type=computeTile(tile,tiles,TILE_FLOOR_EDGE,'floor edges')||type;
738
type=computeTile(tile,tiles,TILE_FLOOR_CENTER,'floor')||type;
739
type=computeTile(tile,tiles,TILE_PILLAR,'pillar')||type;
740
type=computeTile(tile,tiles,TILE_DOOR,'door')||type;
741
type=computeTile(tile,tiles,TILE_WATER,'water')||type;
742
type=computeTile(tile,tiles,TILE_ENTRANCE,'entrance')||type;
743
type=computeTile(tile,tiles,TILE_EXIT,'exit')||type;
744
745
this.data[me.x][me.y][2]=type.id;
746
}
747
}
748
749
750
this.Map.prototype.draw=function(size)
751
{
752
//return a string containing a rough visual representation of the map
753
var str='';
754
var size=size||10;
755
for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){
756
var text='';
757
if (this.isFloor(x,y)!=-1) text='o';
758
if (this.isWall(x,y)!=-1) text+='x';
759
var room=this.getRoom(x,y);
760
var opacity=Math.max(0.1,1-(this.getRoom(x,y).gen/10));
761
var title=room.freeTiles;//this.data[x][y][0].toString();
762
text='';
763
str+='<div style="opacity:'+opacity+';width:'+size+'px;height:'+size+'px;position:absolute;left:'+(x*size)+'px;top:'+(y*size)+'px;display:block;padding:0px;margin:0px;background:#'+colors[this.data[x][y][0]]+';color:#999;" title="'+title+'">'+text+'</div>';
764
}
765
str+='<br>';
766
}
767
str='<div style="position:relative;width:'+(this.w*size)+'px;height:'+(this.h*size)+'px;background:#000;font-family:Courier;font-size:'+size+'px;float:left;margin:10px;">'+str+'</div>';
768
return str;
769
}
770
771
this.Map.prototype.drawDetailed=function()
772
{
773
//return a string containing a rough visual representation of the map (with graphics)
774
var str='';
775
var size=16;
776
for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){
777
var room=this.getRoom(x,y);
778
//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score);
779
var opacity=1;
780
var title='void';
781
if (room!=-1)
782
{
783
opacity=Math.max(0.1,1-room.gen/5);
784
if (this.data[x][y][0]==TILE_ENTRANCE || this.data[x][y][0]==TILE_EXIT) opacity=1;
785
title=(room.corridor?'corridor':'room')+' '+room.id+' | depth : '+room.gen+' | children : '+room.children.length;
786
}
787
var pic=this.getPic(x,y);
788
str+='<div style="opacity:'+opacity+';width:'+size+'px;height:'+size+'px;position:absolute;left:'+(x*size)+'px;top:'+(y*size)+'px;display:block;padding:0px;margin:0px;background:#'+colors[this.data[x][y][0]]+' url(img/dungeonTiles.png) '+(-pic[0]*16)+'px '+(-pic[1]*16)+'px;color:#999;" title="'+title+'"></div>';
789
}
790
str+='<br>';
791
}
792
str='<div style="box-shadow:0px 0px 12px 6px #00061b;position:relative;width:'+(this.w*size)+'px;height:'+(this.h*size)+'px;background:#00061b;font-family:Courier;font-size:'+size+'px;float:left;margin:10px;">'+str+'</div>';
793
return str;
794
}
795
796
this.Map.prototype.getStr=function()
797
{
798
//return a string containing the map with tile graphics, ready to be pasted in a wrapper
799
var str='';
800
var size=16;
801
for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){
802
var room=this.getRoom(x,y);
803
//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score);
804
var opacity=1;
805
var title='void';
806
var pic=this.getPic(x,y);
807
if (room!=-1)
808
{
809
/*
810
opacity=Math.max(0.1,1-room.gen/5);
811
if (room.hidden) opacity=0;
812
if (this.data[x][y][0]==TILE_ENTRANCE || this.data[x][y][0]==TILE_EXIT) opacity=1;
813
*/
814
if (room.hidden) pic=[0,0];
815
title=(room.corridor?'corridor':'room')+' '+room.id+' | depth : '+room.gen+' | children : '+room.children.length;
816
}
817
str+='<div style="opacity:'+opacity+';width:'+size+'px;height:'+size+'px;position:absolute;left:'+(x*size)+'px;top:'+(y*size)+'px;display:block;padding:0px;margin:0px;background:#'+colors[this.data[x][y][0]]+' url(img/dungeonTiles.png) '+(-pic[0]*16)+'px '+(-pic[1]*16)+'px;color:#999;" title="'+title+'"></div>';
818
}
819
str+='<br>';
820
}
821
return str;
822
}
823
824
}
825
826