Path: blob/main/assets/javascript/cookieclicker/DungeonGen.js
15352 views
if (1==1 || undefined==Math.seedrandom)1{2(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);3}45if (1==1 || undefined==choose) {function choose(arr) {if (arr.length==0) return 0; else return arr[Math.floor(Math.random()*arr.length)];}}678var DungeonGen=function()9{10var TILE_EMPTY=0;//solid11var TILE_LIMIT=-100;//can't build anything here; edges of map12var TILE_FLOOR_EDGE=100;13var TILE_FLOOR_CENTER=110;14var TILE_DOOR=200;15var TILE_PILLAR=300;//not just pillars, could be any type of repetitive decoration16var TILE_WATER=400;17var TILE_WALL=500;18var TILE_WALL_CORNER=510;19var TILE_ENTRANCE=250;20var TILE_EXIT=260;2122var colors=[];23colors[TILE_EMPTY]='000';24colors[TILE_LIMIT]='900';25colors[TILE_FLOOR_EDGE]='ffc';26colors[TILE_FLOOR_CENTER]='ff9';27colors[TILE_DOOR]='f9f';28colors[TILE_PILLAR]='990';29colors[TILE_WATER]='99f';30colors[TILE_WALL]='960';31colors[TILE_WALL_CORNER]='630';32colors[TILE_ENTRANCE]='f9f';33colors[TILE_EXIT]='f9f';3435var rand=function(a,b){return Math.floor(Math.random()*(b-a+1)+a);}//return random value between a and b3637var Patterns=[];38this.Pattern=function(name,func)39{40this.name=name;41this.func=func;42Patterns.push(this);43}44new this.Pattern('Pillars',function(x,y,room)45{46if ((x+room.x)%2==0 && (y+room.y)%2==0 && Math.random()<0.8) return TILE_PILLAR;47return 0;48});49new this.Pattern('Large pillars',function(x,y,room)50{51if ((x+room.x)%3<2 && (y+room.y)%3<2 && Math.random()<0.8) return TILE_PILLAR;52return 0;53});54new this.Pattern('Sparse pillars',function(x,y,room)55{56if ((x+room.x)%3==0 && (y+room.y)%3==0 && Math.random()<0.8) return TILE_PILLAR;57return 0;58});59new this.Pattern('Lines',function(x,y,room)60{61if (room.x%2==0) if ((x+room.x)%2==0 && Math.random()<0.98) return TILE_PILLAR;62if (room.x%2==1) if ((y+room.y)%2==0 && Math.random()<0.98) return TILE_PILLAR;63return 0;64});656667var getRandomPattern=function()68{return choose(Patterns);}6970var defaultGenerator=function(me)71{72me.roomSize=10;73me.corridorSize=5;74me.fillRatio=1/3;75me.corridorRatio=0.2;76me.pillarRatio=0.2;77me.waterRatio=0;78me.branching=4;79me.sizeVariance=0.2;8081me.fillRatio=0.1+Math.random()*0.4;82me.roomSize=Math.ceil(rand(5,15)*me.fillRatio*2);83me.corridorSize=Math.ceil(rand(1,7)*me.fillRatio*2);84me.corridorRatio=Math.random()*0.8+0.1;85me.pillarRatio=Math.random()*0.5+0.5;86me.waterRatio=Math.pow(Math.random(),2);87me.branching=Math.floor(Math.random()*6);88me.sizeVariance=Math.random();89}909192this.Map=function(w,h,seed,params)93{94//create a new map95//leave the seed out for a random seed96//params is an object that contains custom parameters as defined in defaultGenerator97//example : MyMap=new DungeonGen.Map(30,30,MySeed,{waterRatio:0.8}); (80 percent of the rooms will contain water)98if (undefined!=seed) this.seed=seed; else {Math.seedrandom();this.seed=Math.random();}99Math.seedrandom(this.seed);100this.seedState=Math.random;101this.w=w||20;102this.h=h||20;103104this.roomsAreHidden=0;105106this.rooms=[];107this.freeWalls=[];//all walls that would be a good spot for a door108this.freeTiles=[];//all passable floor tiles109this.doors=[];110this.tiles=this.w*this.h;111this.tilesDug=0;112this.digs=0;//amount of digging steps113this.stuck=0;//how many times we ran into a problem; stop digging if we get too many of these114115this.data=[];//fill the map with 0116for (var x=0;x<this.w;x++)117{118this.data[x]=[];119for (var y=0;y<this.h;y++)120{121this.data[x][y]=[TILE_EMPTY,-1,0];//data is stored as [tile system type,room id,tile displayed type] (-1 is no room)122if (x==0 || y==0 || x==this.w-1 || y==this.h-1) this.data[x][y]=[TILE_LIMIT,-1,0];123}124}125126defaultGenerator(this);127if (params)128{129for (var i in params)130{131this[i]=params[i];132}133}134Math.seedrandom();135136}137138this.Map.prototype.getType=function(x,y){return this.data[x][y][0];}139this.Map.prototype.getRoom=function(x,y){if (this.data[x][y][1]!=-1) return this.rooms[this.data[x][y][1]]; else return -1;}140this.Map.prototype.getTile=function(x,y){return this.rooms[this.data[x][y][2]];}141142this.Map.prototype.isWall=function(x,y)143{144var n=0;145for (var i in this.freeWalls){if (this.freeWalls[i][0]==x && this.freeWalls[i][1]==y) return n; else n++;}146return -1;147}148this.Map.prototype.isFloor=function(x,y)149{150var n=0;151for (var i in this.freeTiles){if (this.freeTiles[i][0]==x && this.freeTiles[i][1]==y) return n; else n++;}152return -1;153}154this.Map.prototype.removeFreeTile=function(x,y)155{156this.freeTiles.splice(this.isFloor(x,y),1);157}158159this.Map.prototype.fill=function(what)160{161var func=0;162if (typeof(what)=='function') func=1;163for (var x=0;x<this.w;x++){for (var y=0;y<this.h;y++){164if (func) this.data[x][y]=[what(this,x,y),-1,0]; else this.data[x][y]=[what,-1,0];165}}166this.rooms=[];167}168169this.Map.prototype.fillZone=function(X,Y,W,H,what)170{171//just plain fill a rectangle172for (var x=X;x<X+W;x++){for (var y=Y;y<Y+H;y++){173this.data[x][y][0]=what;174}}175}176177this.Map.prototype.getRoomTile=function(room,x,y)178{179var n=0;180for (var i in room.tiles) {if (room.tiles[i].x==x && room.tiles[i].y==y) return n; else n++;}181return -1;182}183184this.Map.prototype.getFloorTileInRoom=function(room)185{186var tiles=[];187for (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]);}188return choose(tiles);189}190191this.Map.prototype.canPlaceRoom=function(rx,ry,rw,rh)192{193if (rx<2 || ry<2 || rx+rw>=this.w-1 || ry+rh>=this.h-1) return false;194for (var x=rx;x<rx+rw;x++)195{196for (var y=ry;y<ry+rh;y++)197{198var tile=this.getType(x,y);199var room=this.getRoom(x,y);200if (tile==TILE_LIMIT) return false;201if (room!=-1) return false;202}203}204return true;205}206207this.Map.prototype.setRoomTile=function(room,x,y,tile)208{209//var mapTile=this.getType(x,y);210var oldTile=this.getRoomTile(room,x,y);211var oldTileType=oldTile!=-1?room.tiles[oldTile].type:-1;212if (oldTile!=-1 && (213//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER) ||// && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) ||214//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) ||215(tile==TILE_WALL || tile==TILE_WALL_CORNER) ||//don't place a wall over an existing room216(tile==TILE_FLOOR_EDGE && oldTileType==TILE_FLOOR_CENTER)//don't place an edge floor over a center floor217)) {return false;}218else219{220if (oldTile!=-1) room.tiles.splice(oldTile,1);221room.tiles.push({x:x,y:y,type:tile,score:0});222if ((tile==TILE_FLOOR_EDGE || tile==TILE_FLOOR_CENTER) && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) room.freeTiles++;223else if (tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER && (oldTileType==TILE_FLOOR_EDGE || oldTileType==TILE_FLOOR_CENTER)) room.freeTiles--;224return true;225}226}227228this.Map.prototype.expandRoom=function(room,rx,ry,rw,rh)229{230var x=0;var y=0;231//floor232for (var x=rx;x<rx+rw;x++){for (var y=ry;y<ry+rh;y++){233this.setRoomTile(room,x,y,TILE_FLOOR_EDGE);234}}235for (var x=rx+1;x<rx+rw-1;x++){for (var y=ry+1;y<ry+rh-1;y++){236this.setRoomTile(room,x,y,TILE_FLOOR_CENTER);237}}238//walls239y=ry-1;240for (var x=rx;x<rx+rw;x++){241this.setRoomTile(room,x,y,TILE_WALL);242}243y=ry+rh;244for (var x=rx;x<rx+rw;x++){245this.setRoomTile(room,x,y,TILE_WALL);246}247x=rx-1;248for (var y=ry;y<ry+rh;y++){249this.setRoomTile(room,x,y,TILE_WALL);250}251x=rx+rw;252for (var y=ry;y<ry+rh;y++){253this.setRoomTile(room,x,y,TILE_WALL);254}255//corners256x=rx-1;y=ry-1;257this.setRoomTile(room,x,y,TILE_WALL_CORNER);258x=rx+rw;y=ry-1;259this.setRoomTile(room,x,y,TILE_WALL_CORNER);260x=rx-1;y=ry+rh;261this.setRoomTile(room,x,y,TILE_WALL_CORNER);262x=rx+rw;y=ry+rh;263this.setRoomTile(room,x,y,TILE_WALL_CORNER);264265//decoration266var water=Math.random()<this.waterRatio?1:0;267var pattern=Math.random()<this.pillarRatio?getRandomPattern():0;268for (var x=rx;x<rx+rw;x++){for (var y=ry;y<ry+rh;y++){269if (room.tiles[this.getRoomTile(room,x,y)].type==TILE_FLOOR_CENTER)270{271var tile=0;272if (water!=0) tile=TILE_WATER;273if (pattern!=0)274{275tile=pattern.func(x,y,room)||tile;276}277if (tile!=0) this.setRoomTile(room,x,y,tile);278}279}}280}281282this.Map.prototype.newRoom=function(x,y,w,h,parent)283{284//create a new abstract room, ready to be carved285var room={};286room.id=this.rooms.length;287room.w=w;//||rand(2,this.roomSize);288room.h=h;//||rand(2,this.roomSize);289room.x=x||rand(1,this.w-room.w-1);290room.y=y||rand(1,this.h-room.h-1);291room.tiles=[];292room.freeTiles=0;293room.parent=parent?parent:-1;294room.children=[];295room.gen=0;296room.door=0;297room.corridor=Math.random()<this.corridorRatio?1:0;298room.hidden=this.roomsAreHidden;//if 1, don't draw299//if (room.parent!=-1) room.corridor=!room.parent.corridor;//alternate rooms and corridors300301return room;302}303this.Map.prototype.planRoom=function(room)304{305var branches=this.branching+1;306var forcedExpansions=[];307var w=room.w;308var h=room.h;309while (w>0 && h>0)310{311if (w>0) {forcedExpansions.push(1,3);w--;}312if (h>0) {forcedExpansions.push(2,4);h--;}313}314315for (var i=0;i<branches;i++)316{317var steps=0;318var expansions=[];319if (!room.corridor)320{321expansions=[1,2,3,4];322steps=this.roomSize;323}324else325{326expansions=choose([[1,3],[2,4]]);327steps=this.corridorSize;328}329steps=Math.max(room.w+room.h,Math.ceil(steps*(1-Math.random()*this.sizeVariance)));330if (room.tiles.length==0) {var rx=room.x;var ry=room.y;var rw=1;var rh=1;}331else {var randomTile=this.getFloorTileInRoom(room);var rx=randomTile.x;var ry=randomTile.y;var rw=1;var rh=1;}332for (var ii=0;ii<steps;ii++)333{334if (expansions.length==0) break;335var xd=0;var yd=0;var wd=0;var hd=0;336var side=choose(expansions);337if (forcedExpansions.length>0) side=forcedExpansions[0];338if (side==1) {xd=-1;wd=1;}339else if (side==2) {yd=-1;hd=1;}340else if (side==3) {wd=1;}341else if (side==4) {hd=1;}342if (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);343if (forcedExpansions.length>0) forcedExpansions.splice(0,1);344}345if (rw>1 || rh>1)346{347this.expandRoom(room,rx,ry,rw,rh);348}349}350}351352353this.Map.prototype.carve=function(room)354{355//carve a room into the map356for (var i in room.tiles)357{358var thisTile=room.tiles[i];359var x=thisTile.x;var y=thisTile.y;360var myType=this.data[x][y][0];361var type=thisTile.type;362363if ((type==TILE_WALL || type==TILE_WALL_CORNER) && this.isWall(x,y)!=-1) {this.freeWalls.splice(this.isWall(x,y),1);}364365if (this.data[x][y][1]!=-1 && (type==TILE_WALL || type==TILE_WALL_CORNER)) {}366else367{368if (this.data[x][y][1]==-1) this.tilesDug++;369this.data[x][y]=[thisTile.type,room.id,0];370if (x>1 && y>1 && x<this.w-2 && y<this.h-2 && type==TILE_WALL) this.freeWalls.push([x,y]);371if (type==TILE_FLOOR_EDGE || type==TILE_FLOOR_CENTER) this.freeTiles.push([x,y]);372}373var pos=[x,y];374}375this.rooms[room.id]=room;376}377378this.Map.prototype.newRandomRoom=function(params)379{380var success=1;381params=params||{};//params is an object such as {corridor:1}382var door=choose(this.freeWalls);//select a free wall to use as a door383if (!door) {success=0;}384else385{386//this.data[door[0]][door[1]][0]=TILE_LIMIT;//not door387var parentRoom=this.getRoom(door[0],door[1]);388var sides=[];//select a free side of that door389if (this.getType(door[0]-1,door[1])==TILE_EMPTY) sides.push([-1,0]);390if (this.getType(door[0]+1,door[1])==TILE_EMPTY) sides.push([1,0]);391if (this.getType(door[0],door[1]-1)==TILE_EMPTY) sides.push([0,-1]);392if (this.getType(door[0],door[1]+1)==TILE_EMPTY) sides.push([0,1]);393var side=choose(sides);394if (!side) {success=0;this.freeWalls.splice(this.isWall(door[0],door[1]),1);}395else396{397var room=this.newRoom(door[0]+side[0],door[1]+side[1],0,0,parentRoom);//try a new room from this spot398for (var i in params)399{400room[i]=params[i];401}402this.planRoom(room);403if (room.tiles.length>0 && room.freeTiles>0)//we got a decent room404{405this.carve(room);406this.data[door[0]][door[1]][0]=TILE_DOOR;//place door407room.door=[door[0],door[1]];408this.data[door[0]][door[1]][1]=room.id;//set ID409this.freeWalls.splice(this.isWall(door[0],door[1]),1);//the door isn't a wall anymore410this.doors.push([door[0],door[1],room]);411//remove free tiles on either side of the door412if (this.isFloor(door[0]+side[0],door[1]+side[1])!=-1) this.removeFreeTile(door[0]+side[0],door[1]+side[1]);413if (this.isFloor(door[0]-side[0],door[1]-side[1])!=-1) this.removeFreeTile(door[0]-side[0],door[1]-side[1]);414room.parent=parentRoom;415parentRoom.children.push(room);416room.gen=parentRoom.gen+1;417}418else//not a good spot; remove this tile from the list of walls419{420this.freeWalls.splice(this.isWall(door[0],door[1]),1);421success=0;422}423}424}425if (success) return room;426else return 0;427}428429this.Map.prototype.getRandomSpotInRoom=function(room)430{431var listOfTiles=[];432for (var i in room.tiles)433{434if ((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)435{436listOfTiles.push(room.tiles[i]);437}438}439if (listOfTiles.length==0) return -1;440return choose(listOfTiles);441}442this.Map.prototype.getBestSpotInRoom=function(room)443{444var highest=-1;445var listOfHighest=[];446for (var i in room.tiles)447{448if ((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)449{450if (room.tiles[i].score>highest)451{452listOfHighest=[];453highest=room.tiles[i].score;454listOfHighest.push(room.tiles[i]);455}456else if (room.tiles[i].score==highest)457{458listOfHighest.push(room.tiles[i]);459}460}461}462if (listOfHighest.length==0) return -1;463return choose(listOfHighest);464}465this.Map.prototype.getEarliestRoom=function()466{467return this.rooms[0];468}469this.Map.prototype.getDeepestRoom=function()470{471var deepest=0;472var deepestRoom=this.rooms[0];473for (var i in this.rooms)474{475if ((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];}476}477return deepestRoom;478}479480this.Map.prototype.dig=function()481{482//one step in which we try to carve new stuff483//returns 0 when we couldn't dig this step, 1 when we could, and 2 when the digging is complete484Math.random=this.seedState;485486var badDig=0;487488if (this.digs==0)//first dig : build a starting room in the middle of the map489{490var w=rand(3,7);491var h=rand(3,7);492var room=this.newRoom(Math.floor(this.w/2-w/2),Math.floor(this.h/2-h/2),w,h);493room.corridor=0;494this.planRoom(room);495this.carve(room);496}497else498{499if (this.newRandomRoom()==0) badDig++;500}501if (badDig>0) this.stuck++;502503this.digs++;504505var finished=0;506if (this.tilesDug>=this.tiles*this.fillRatio) finished=1;507if (this.stuck>100) finished=1;508509if (finished==1)//last touch : try to add a whole room at the end510{511for (var i=0;i<10;i++)512{513var newRoom=this.newRandomRoom({corridor:0,w:rand(3,7),h:rand(3,7)});514if (newRoom!=0 && newRoom.freeTiles>15) break;515}516}517518Math.seedrandom();519if (finished==1) return 1; else if (badDig>0) return -1; else return 0;520}521522this.Map.prototype.finish=function()523{524for (var i in this.rooms)525{526var pillars=Math.random()<this.pillarRatio;527for (var ii in this.rooms[i].tiles)528{529var x=this.rooms[i].tiles[ii].x;530var y=this.rooms[i].tiles[ii].y;531var me=this.data[x][y][0];532var x1=this.data[x-1][y][0];533var x2=this.data[x+1][y][0];534var y1=this.data[x][y-1][0];535var y2=this.data[x][y+1][0];536var xy1=this.data[x-1][y-1][0];537var xy2=this.data[x+1][y-1][0];538var xy3=this.data[x-1][y+1][0];539var xy4=this.data[x+1][y+1][0];540541var walls=0;542if ((x1==TILE_WALL||x1==TILE_WALL_CORNER)) walls++;543if ((y1==TILE_WALL||y1==TILE_WALL_CORNER)) walls++;544if ((x2==TILE_WALL||x2==TILE_WALL_CORNER)) walls++;545if ((y2==TILE_WALL||y2==TILE_WALL_CORNER)) walls++;546if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER)) walls++;547if ((xy2==TILE_WALL||xy2==TILE_WALL_CORNER)) walls++;548if ((xy3==TILE_WALL||xy3==TILE_WALL_CORNER)) walls++;549if ((xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) walls++;550551var floors=0;552if ((x1==TILE_FLOOR_CENTER||x1==TILE_FLOOR_EDGE)) floors++;553if ((y1==TILE_FLOOR_CENTER||y1==TILE_FLOOR_EDGE)) floors++;554if ((x2==TILE_FLOOR_CENTER||x2==TILE_FLOOR_EDGE)) floors++;555if ((y2==TILE_FLOOR_CENTER||y2==TILE_FLOOR_EDGE)) floors++;556if ((xy1==TILE_FLOOR_CENTER||xy1==TILE_FLOOR_EDGE)) floors++;557if ((xy2==TILE_FLOOR_CENTER||xy2==TILE_FLOOR_EDGE)) floors++;558if ((xy3==TILE_FLOOR_CENTER||xy3==TILE_FLOOR_EDGE)) floors++;559if ((xy4==TILE_FLOOR_CENTER||xy4==TILE_FLOOR_EDGE)) floors++;560561var complete=0;562if (walls+floors==8) complete=1;563564var angle=0;565if (complete)566{567var top=0;568var left=0;569var right=0;570var bottom=0;571if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER) && (y1==TILE_WALL||y1==TILE_WALL_CORNER) && (xy2==TILE_WALL||xy2==TILE_WALL_CORNER)) top=1;572else 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;573if ((xy2==TILE_WALL||xy2==TILE_WALL_CORNER) && (x2==TILE_WALL||x2==TILE_WALL_CORNER) && (xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) right=1;574else 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;575if ((xy1==TILE_WALL||xy1==TILE_WALL_CORNER) && (x1==TILE_WALL||x1==TILE_WALL_CORNER) && (xy3==TILE_WALL||xy3==TILE_WALL_CORNER)) left=1;576else 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;577if ((xy3==TILE_WALL||xy3==TILE_WALL_CORNER) && (y2==TILE_WALL||y2==TILE_WALL_CORNER) && (xy4==TILE_WALL||xy4==TILE_WALL_CORNER)) bottom=1;578else 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;579if ((top==1 && bottom==-1) || (top==-1 && bottom==1) || (left==1 && right==-1) || (left==-1 && right==1)) angle=1;580}581582if (pillars && Math.random()<0.8 && this.rooms[i].freeTiles>4)583{584if ((angle==1 || (complete && walls==7)) && me==TILE_FLOOR_EDGE && x1!=TILE_DOOR && x2!=TILE_DOOR && y1!=TILE_DOOR && y2!=TILE_DOOR)585{586this.data[x][y][0]=TILE_PILLAR;587me=TILE_PILLAR;588this.removeFreeTile(x,y);589this.rooms[i].freeTiles--;590}591}592593//calculate score (for placing items and exits)594if (top==1 || bottom==1 || left==1 || right==1)595{596this.rooms[i].tiles[ii].score+=2;597}598if (walls>5 || floors>5)599{600this.rooms[i].tiles[ii].score+=1;601}602if (walls==7 || floors==8)603{604this.rooms[i].tiles[ii].score+=5;605}606if ((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;607608}609}610611612613//carve entrance and exit614var entrance=this.getBestSpotInRoom(this.getEarliestRoom());615this.data[entrance.x][entrance.y][0]=TILE_ENTRANCE;616this.entrance=[entrance.x,entrance.y];617entrance.score=0;618this.removeFreeTile(entrance.x,entrance.y);619var exit=this.getBestSpotInRoom(this.getDeepestRoom());620this.data[exit.x][exit.y][0]=TILE_EXIT;621this.exit=[exit.x,exit.y];622this.removeFreeTile(exit.x,exit.y);623exit.score=0;624625/*626for (var i in this.doors)//remove door tiles (to add later; replace the tiles by entities that delete themselves when opened)627{628this.data[this.doors[i][0]][this.doors[i][1]][0]=TILE_FLOOR_EDGE;629}630*/631}632633this.Map.prototype.isObstacle=function(x,y)634{635var free=[TILE_FLOOR_EDGE,TILE_FLOOR_CENTER,TILE_DOOR,TILE_ENTRANCE,TILE_EXIT];636for (var i in free)637{638if (this.data[x][y][0]==free[i]) return 0;639}640return 1;641}642643var joinTile=function(map,x,y,joinWith)644{645//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.646//joinWith contains the tile types that count as joinable, in addition to this tile. (don't add the tested tile to joinWith!)647var p=1;648var me=map.data[x][y][0];649var x1=map.data[x-1][y][0];650var x2=map.data[x+1][y][0];651var y1=map.data[x][y-1][0];652var y2=map.data[x][y+1][0];653joinWith.push(me);654var joinsX=0;655for (var i in joinWith)656{657if (x1==joinWith[i]) joinsX++;658if (x2==joinWith[i]) joinsX++;659}660var joinsY=0;661for (var i in joinWith)662{663if (y1==joinWith[i]) joinsY++;664if (y2==joinWith[i]) joinsY++;665}666if (joinsX==2 && joinsY==2) p=1;667else if (joinsX==2) p=2;668else if (joinsY==2) p=3;669return p;670}671this.Map.prototype.getPic=function(x,y)672{673//return a position [x,y] in the tiles (as 0, 1, 2...) for the tile on the map at position x,y674if (Tiles[this.data[x][y][2]])675{676if (Tiles[this.data[x][y][2]].joinType=='join')677{678var thisPic=Tiles[this.data[x][y][2]].pic;679thisPic=[thisPic[0],thisPic[1]];//why is this even necessary?680var joinWith=[];681if (this.data[x][y][0]==TILE_WALL) joinWith.push(TILE_WALL_CORNER);682else if (this.data[x][y][0]==TILE_DOOR) joinWith.push(TILE_WALL,TILE_WALL_CORNER);683thisPic[0]+=joinTile(this,x,y,joinWith)-1;684return thisPic;685}686else if (Tiles[this.data[x][y][2]].joinType=='random3')687{688var thisPic=Tiles[this.data[x][y][2]].pic;689thisPic=[thisPic[0],thisPic[1]];690thisPic[0]+=Math.floor(Math.random()*3);691return thisPic;692}693return Tiles[this.data[x][y][2]].pic;694}695return [0,0];696}697698var Tiles=[];699var TilesByName=[];700this.Tile=function(name,pic,joinType)701{702this.name=name;703this.pic=pic;704this.joinType=joinType||'none';705this.id=Tiles.length;706Tiles[this.id]=this;707TilesByName[this.name]=this;708}709new this.Tile('void',[0,0]);710this.loadTiles=function(tiles)711{712for (var i in tiles)713{714var name=tiles[i][0];715var pic=tiles[i][1];716var joinType=tiles[i][2];717new this.Tile(name,pic,joinType);718}719}720721var computeTile=function(tile,tiles,value,name)722{723if (tile==value && tiles[name]) return TilesByName[tiles[name]];724return 0;725}726this.Map.prototype.assignTiles=function(room,tiles)727{728//set the displayed tiles for this room729for (var i in room.tiles)730{731var type=Tiles[0];732var me=room.tiles[i];733var tile=this.data[me.x][me.y][0];734type=computeTile(tile,tiles,TILE_WALL_CORNER,'wall corner')||type;735type=computeTile(tile,tiles,TILE_WALL,'wall')||type;736type=computeTile(tile,tiles,TILE_FLOOR_EDGE,'floor edges')||type;737type=computeTile(tile,tiles,TILE_FLOOR_CENTER,'floor')||type;738type=computeTile(tile,tiles,TILE_PILLAR,'pillar')||type;739type=computeTile(tile,tiles,TILE_DOOR,'door')||type;740type=computeTile(tile,tiles,TILE_WATER,'water')||type;741type=computeTile(tile,tiles,TILE_ENTRANCE,'entrance')||type;742type=computeTile(tile,tiles,TILE_EXIT,'exit')||type;743744this.data[me.x][me.y][2]=type.id;745}746}747748749this.Map.prototype.draw=function(size)750{751//return a string containing a rough visual representation of the map752var str='';753var size=size||10;754for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){755var text='';756if (this.isFloor(x,y)!=-1) text='o';757if (this.isWall(x,y)!=-1) text+='x';758var room=this.getRoom(x,y);759var opacity=Math.max(0.1,1-(this.getRoom(x,y).gen/10));760var title=room.freeTiles;//this.data[x][y][0].toString();761text='';762str+='<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>';763}764str+='<br>';765}766str='<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>';767return str;768}769770this.Map.prototype.drawDetailed=function()771{772//return a string containing a rough visual representation of the map (with graphics)773var str='';774var size=16;775for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){776var room=this.getRoom(x,y);777//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score);778var opacity=1;779var title='void';780if (room!=-1)781{782opacity=Math.max(0.1,1-room.gen/5);783if (this.data[x][y][0]==TILE_ENTRANCE || this.data[x][y][0]==TILE_EXIT) opacity=1;784title=(room.corridor?'corridor':'room')+' '+room.id+' | depth : '+room.gen+' | children : '+room.children.length;785}786var pic=this.getPic(x,y);787str+='<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>';788}789str+='<br>';790}791str='<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>';792return str;793}794795this.Map.prototype.getStr=function()796{797//return a string containing the map with tile graphics, ready to be pasted in a wrapper798var str='';799var size=16;800for (var y=0;y<this.h;y++){for (var x=0;x<this.w;x++){801var room=this.getRoom(x,y);802//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score);803var opacity=1;804var title='void';805var pic=this.getPic(x,y);806if (room!=-1)807{808/*809opacity=Math.max(0.1,1-room.gen/5);810if (room.hidden) opacity=0;811if (this.data[x][y][0]==TILE_ENTRANCE || this.data[x][y][0]==TILE_EXIT) opacity=1;812*/813if (room.hidden) pic=[0,0];814title=(room.corridor?'corridor':'room')+' '+room.id+' | depth : '+room.gen+' | children : '+room.children.length;815}816str+='<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>';817}818str+='<br>';819}820return str;821}822823}824825826