|
var M = {}; |
|
M.parent = Game.Objects['Temple']; |
|
M.parent.minigame = M; |
|
M.launch = function () { |
|
var M = this; |
|
M.name = M.parent.minigameName; |
|
M.init = function (div) { |
|
//populate div with html and initialize values |
|
|
|
M.ourDiv = div; |
|
|
|
// == NEW DUNGEON STUFF |
|
|
|
M.dungeonTiles = [ |
|
['wall', [1, 0], 'join'], |
|
['wall corner', [1, 0]], |
|
['floor', [1, 1], 'random3'], |
|
['tiled floor', [1, 2], 'join'], |
|
['round pillar', [1, 4]], |
|
['square pillar', [2, 4]], |
|
['potted plant', [3, 4]], |
|
['bookshelf', [4, 5], 'join'], |
|
['door', [1, 3], 'join'], |
|
['alt wall', [4, 0], 'join'], |
|
['alt wall corner', [4, 0]], |
|
['alt floor', [4, 1], 'random3'], |
|
['alt tiled floor', [4, 2], 'join'], |
|
['alt round pillar', [4, 4]], |
|
['alt square pillar', [5, 4]], |
|
['alt potted plant', [6, 4]], |
|
['alt bookshelf', [4, 6], 'join'], |
|
['alt door', [4, 3], 'join'], |
|
['water', [1, 5]], |
|
['green water', [2, 5]], |
|
['dark water', [3, 5]], |
|
['wooden wall', [1, 7], 'join'], |
|
['wooden floor', [1, 6], 'random3'], |
|
['conveyor belt', [4, 7], 'join'], |
|
['entrance', [0, 1]], |
|
['alt entrance', [0, 3]], |
|
['exit', [0, 2]], |
|
['alt exit', [0, 4]] |
|
]; |
|
|
|
M.heroes = [ |
|
{ |
|
name: 'Chip', |
|
pic: 'girlscoutChip', |
|
portrait: 'portraitChip', |
|
icon: [1, 0], |
|
stats: { |
|
hp: 30, |
|
hpm: 30, |
|
might: 5, |
|
guard: 5, |
|
speed: 5, |
|
dodge: 5, |
|
luck: 5 |
|
}, |
|
dialogue: { |
|
'intro': 'I\'m Chip! I just really like exploring stuff. Let\'s go have an adventure!', |
|
'greeting': 'Hello there!|I\'m ready!|Where are we going today?|Adventure!', |
|
'win': 'Take that!|Hah!|That\'s right.', |
|
'entrance': 'Chipping in!|Welp, here goes nothing!|I wonder what I\'ll find!|Hey, this place is new!|This place seems familiar.|Let\'s make it happen.', |
|
'completion': 'I\'m one smart cookie.|Oh yeah!|Let\'s explore some more!|That was easy!|That sure was fun!|I\'m not lost, am I?|More exploring? Sure, why not!', |
|
'defeat': 'B-better luck next time.|That really hurt!|I yield! I yield!|That went badly.|No half-baked excuses next time.|I think I scraped my knee!|Owie.|Woopsie!', |
|
'win against Sentient Furnace': 'The irony, it burns! (...it\'s funny because it was burning. And made of iron. ...Moving on.)', |
|
'win against Ascended Baking Pod': 'Where is your pod now?|That was disturbing.', |
|
}, |
|
}, |
|
{ |
|
name: 'Crumb', |
|
pic: 'girlscoutCrumb', |
|
portrait: 'portraitCrumb', |
|
icon: [2, 0], |
|
stats: { |
|
hp: 25, |
|
hpm: 25, |
|
might: 5, |
|
guard: 7, |
|
speed: 4, |
|
dodge: 4, |
|
luck: 5 |
|
}, |
|
dialogue: { |
|
'intro': 'I\'m Crumb. I look like this because of a baking accident when I was little. Big deal. At least now I don\'t get hurt as easily as others, I guess.', |
|
'greeting': 'Hi there.|Ready for adventure, I guess.|Reporting for duty.', |
|
'win': 'Oh sorry, did that hurt?|Should have moved out of the way.|Oops. My bad.', |
|
'entrance': 'Let\'s do this, I guess.|Well, let\'s go...|I gotta go in there?|Are we really doing this?|I hope I won\'t get lost like last time.|Let\'s get this over with.', |
|
'completion': 'I... I did it...|I\'m glad that\'s over.|What, there\'s more?|In I go, I guess.|It doesn\'t end, does it?|But it\'s dark in there.', |
|
'defeat': 'I, uh, ouch.|Why does that always happen to me?|I\'m just no good, am I?|Oh no.|I\'m... I\'m not crying.|Well that wasn\'t fun at all.|I\'m sorry I failed you.|Please... make them go away...', |
|
'meet Ascended Baking Pod': 'That thing shouldn\'t even be alive.|Is that where they all came from?', |
|
'win against Ascended Baking Pod': 'Hm. Fascinating.' |
|
} |
|
}, |
|
{ |
|
name: 'Doe', |
|
pic: 'girlscoutDoe', |
|
portrait: 'portraitDoe', |
|
icon: [3, 0], |
|
stats: { |
|
hp: 25, |
|
hpm: 25, |
|
might: 4, |
|
guard: 4, |
|
speed: 7, |
|
dodge: 5, |
|
luck: 5 |
|
}, |
|
dialogue: { |
|
'intro': 'H-hey. Name\'s Doe. I\'m pretty fast. I uh, I promise I\'ll do my best.', |
|
'greeting': 'H-hey.|Oh, uh, h-hi there.|C-can I join?', |
|
'win': 'Th-that looks like it hurt... awesome...|D-did I do that?|N-neat... there\'s pieces everywhere.', |
|
'entrance': 'Alright, let\'s do this!|I-if I really have to.|I-in there? By myself?|...won\'t you come with me this time?|H-here I go!', |
|
'completion': 'Oh... oh my.|That\'s... I uh, I\'m glad.|Y-yeah that was real easy. Piece of pie!|T-too easy, right?|S-so many cookies...|Ooh? F-fascinating.', |
|
'defeat': 'I-if you can\'t beat them... join them.|I-it\'s because I stutter, isn\'t it?|W-well that\'s just no good at all.|I, uh, I meant for that to happen.|H-how embarrassing.', |
|
'meet Ascended Baking Pod': 'W-whoah... it\'s... magnificent...', |
|
'win against Ascended Baking Pod': 'I\'m sorry, buddy.|I... I think I hurt it...|Oh no... I-I think I broke it...' |
|
} |
|
}, |
|
{ |
|
name: 'Lucky', |
|
pic: 'girlscoutLucky', |
|
portrait: 'portraitLucky', |
|
icon: [4, 0], |
|
stats: { |
|
hp: 25, |
|
hpm: 25, |
|
might: 5, |
|
guard: 4, |
|
speed: 4, |
|
dodge: 5, |
|
luck: 7 |
|
}, |
|
dialogue: { |
|
'intro': 'Oh joy! My name\'s Lucky. Guess what I\'m good at?', |
|
'greeting': 'I\'m feeling lucky!|It\'s a bright day today!|Let\'s do great things together.', |
|
'win': 'Ooh lucky shot!|Pow! One more.|Damn straight!', |
|
'entrance': 'Glad to be of service!|Oooh this one\'ll be interesting.|This will be a good one, I can feel it!|Here I come!', |
|
'completion': 'Over already?|Let\'s explore some more!|That was lucky!|That was no luck, I\'m just that good.|Alright, let\'s move on!|I\'m just getting warmed up!', |
|
'defeat': 'I can\'t believe it!|...This is a joke, right?|Hey! No fair!|B-but...|I\'m gonna need a bandaid. And some hot chocolate.|I\'ll, uh, try again later.|Bad luck! Bad luck!', |
|
'win against Ascended Baking Pod': 'Golly, that was peculiar.' |
|
} |
|
} |
|
]; |
|
|
|
//external |
|
Game.GetWord = function (type) { |
|
if (type == 'secret') return choose(['hidden', 'secret', 'mysterious', 'forgotten', 'forbidden', 'lost', 'sunk', 'buried', 'concealed', 'shrouded', 'invisible', 'elder']); |
|
if (type == 'ruined') return choose(['ancient', 'old', 'ruined', 'ravaged', 'destroyed', 'collapsed', 'demolished', 'burnt', 'torn-down', 'shattered', 'dilapidated', 'abandoned', 'crumbling', 'derelict', 'decaying']); |
|
if (type == 'magical') return choose(['arcane', 'magical', 'mystical', 'sacred', 'honed', 'banished', 'unholy', 'holy', 'demonic', 'enchanted', 'necromantic', 'bewitched', 'haunted', 'occult', 'astral']); |
|
return ''; |
|
} |
|
|
|
Game.DungeonTypes = []; |
|
Game.DungeonType = function (name) { |
|
this.name = name; |
|
this.nameGenerator = function () { |
|
return 'Mysterious dungeon'; |
|
}; |
|
this.roomTypes = []; |
|
Game.DungeonTypes[this.name] = this; |
|
return this; |
|
}; |
|
|
|
/*===================================================================================== |
|
CREATE DUNGEON TYPES |
|
=======================================================================================*/ |
|
new Game.DungeonType('Factory').nameGenerator = function () { |
|
var str = ''; |
|
str += Game.GetWord(choose(['secret', 'ruined', 'magical'])) + ' ' + choose(['factory', 'factories', 'bakery', 'bakeries', 'confectionery', 'laboratory', 'research center', 'chocolate forge', 'chocolate foundry', 'manufactory', 'warehouse', 'machinery', 'works', 'bakeworks', 'workshop', 'assembly line']); |
|
return str; |
|
}; |
|
|
|
new Game.DungeonType('Mine').nameGenerator = function () { |
|
var str = ''; |
|
str += Game.GetWord(choose(['secret', 'ruined', 'magical'])) + ' ' + choose(['chocolate', 'chocolate', 'chocolate', 'white chocolate', 'sugar', 'cacao']) + ' ' + choose(['mine', 'mines', 'pit', 'pits', 'quarry', 'excavation', 'tunnel', 'shaft', 'lode', 'trench', 'mountain', 'vein', 'cliff', 'peak', 'dome', 'crater', 'abyss', 'chasm', 'hole', 'burrow']); |
|
return str; |
|
}; |
|
|
|
new Game.DungeonType('Portal').nameGenerator = function () { |
|
var str = ''; |
|
str += Game.GetWord(choose(['secret', 'ruined', 'magical'])) + ' ' + choose(['portal', 'gate', 'dimension', 'warpgate', 'door']); |
|
return str; |
|
}; |
|
|
|
new Game.DungeonType('Secret zebra level').nameGenerator = function () { |
|
var str = ''; |
|
str += Game.GetWord(choose(['secret'])) + ' ' + choose(['zebra level']); |
|
return str; |
|
}; |
|
|
|
|
|
Game.DungeonGen = function () { |
|
var TILE_EMPTY = 0;//solid |
|
var TILE_LIMIT = -100;//can't build anything here; edges of map |
|
var TILE_FLOOR_EDGE = 100; |
|
var TILE_FLOOR_CENTER = 110; |
|
var TILE_DOOR = 200; |
|
var TILE_PILLAR = 300;//not just pillars, could be any type of repetitive decoration |
|
var TILE_WATER = 400; |
|
var TILE_WALL = 500; |
|
var TILE_WALL_CORNER = 510; |
|
var TILE_ENTRANCE = 250; |
|
var TILE_EXIT = 260; |
|
|
|
var colors = []; |
|
colors[TILE_EMPTY] = '000'; |
|
colors[TILE_LIMIT] = '900'; |
|
colors[TILE_FLOOR_EDGE] = 'ffc'; |
|
colors[TILE_FLOOR_CENTER] = 'ff9'; |
|
colors[TILE_DOOR] = 'f9f'; |
|
colors[TILE_PILLAR] = '990'; |
|
colors[TILE_WATER] = '99f'; |
|
colors[TILE_WALL] = '960'; |
|
colors[TILE_WALL_CORNER] = '630'; |
|
colors[TILE_ENTRANCE] = 'f9f'; |
|
colors[TILE_EXIT] = 'f9f'; |
|
|
|
var rand = function (a, b) { |
|
return Math.floor(Math.random() * (b - a + 1) + a); |
|
}//return random value between a and b |
|
|
|
var Patterns = []; |
|
this.Pattern = function (name, func) { |
|
this.name = name; |
|
this.func = func; |
|
Patterns.push(this); |
|
} |
|
new this.Pattern('Pillars', function (x, y, room) { |
|
if ((x + room.x) % 2 == 0 && (y + room.y) % 2 == 0 && Math.random() < 0.8) return TILE_PILLAR; |
|
return 0; |
|
}); |
|
new this.Pattern('Large pillars', function (x, y, room) { |
|
if ((x + room.x) % 3 < 2 && (y + room.y) % 3 < 2 && Math.random() < 0.8) return TILE_PILLAR; |
|
return 0; |
|
}); |
|
new this.Pattern('Sparse pillars', function (x, y, room) { |
|
if ((x + room.x) % 3 == 0 && (y + room.y) % 3 == 0 && Math.random() < 0.8) return TILE_PILLAR; |
|
return 0; |
|
}); |
|
new this.Pattern('Lines', function (x, y, room) { |
|
if (room.x % 2 == 0) if ((x + room.x) % 2 == 0 && Math.random() < 0.98) return TILE_PILLAR; |
|
if (room.x % 2 == 1) if ((y + room.y) % 2 == 0 && Math.random() < 0.98) return TILE_PILLAR; |
|
return 0; |
|
}); |
|
|
|
|
|
var getRandomPattern = function () { |
|
return choose(Patterns); |
|
} |
|
|
|
var defaultGenerator = function (me) { |
|
me.roomSize = 10; |
|
me.corridorSize = 5; |
|
me.fillRatio = 1 / 3; |
|
me.corridorRatio = 0.2; |
|
me.pillarRatio = 0.2; |
|
me.waterRatio = 0; |
|
me.branching = 4; |
|
me.sizeVariance = 0.2; |
|
|
|
me.fillRatio = 0.1 + Math.random() * 0.4; |
|
me.roomSize = Math.ceil(rand(5, 15) * me.fillRatio * 2); |
|
me.corridorSize = Math.ceil(rand(1, 7) * me.fillRatio * 2); |
|
me.corridorRatio = Math.random() * 0.8 + 0.1; |
|
me.pillarRatio = Math.random() * 0.5 + 0.5; |
|
me.waterRatio = Math.pow(Math.random(), 2); |
|
me.branching = Math.floor(Math.random() * 6); |
|
me.sizeVariance = Math.random(); |
|
} |
|
|
|
|
|
this.Map = function (w, h, seed, params) { |
|
//create a new map |
|
//leave the seed out for a random seed |
|
//params is an object that contains custom parameters as defined in defaultGenerator |
|
//example : MyMap=new DungeonGen.Map(30,30,MySeed,{waterRatio:0.8}); (80 percent of the rooms will contain water) |
|
if (undefined != seed) this.seed = seed; else { |
|
Math.seedrandom(); |
|
this.seed = Math.random(); |
|
} |
|
Math.seedrandom(this.seed); |
|
this.seedState = Math.random; |
|
this.w = w || 20; |
|
this.h = h || 20; |
|
|
|
this.roomsAreHidden = 0; |
|
|
|
this.rooms = []; |
|
this.freeWalls = [];//all walls that would be a good spot for a door |
|
this.freeTiles = [];//all passable floor tiles |
|
this.doors = []; |
|
this.tiles = this.w * this.h; |
|
this.tilesDug = 0; |
|
this.digs = 0;//amount of digging steps |
|
this.stuck = 0;//how many times we ran into a problem; stop digging if we get too many of these |
|
|
|
this.data = [];//fill the map with 0 |
|
for (var x = 0; x < this.w; x++) { |
|
this.data[x] = []; |
|
for (var y = 0; y < this.h; y++) { |
|
this.data[x][y] = [TILE_EMPTY, -1, 0];//data is stored as [tile system type,room id,tile displayed type] (-1 is no room) |
|
if (x == 0 || y == 0 || x == this.w - 1 || y == this.h - 1) this.data[x][y] = [TILE_LIMIT, -1, 0]; |
|
} |
|
} |
|
|
|
defaultGenerator(this); |
|
if (params) { |
|
for (var i in params) { |
|
this[i] = params[i]; |
|
} |
|
} |
|
Math.seedrandom(); |
|
|
|
} |
|
|
|
this.Map.prototype.getType = function (x, y) { |
|
return this.data[x][y][0]; |
|
} |
|
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; |
|
} |
|
this.Map.prototype.getTile = function (x, y) { |
|
return this.rooms[this.data[x][y][2]]; |
|
} |
|
|
|
this.Map.prototype.isWall = function (x, y) { |
|
var n = 0; |
|
for (var i in this.freeWalls) { |
|
if (this.freeWalls[i][0] == x && this.freeWalls[i][1] == y) return n; else n++; |
|
} |
|
return -1; |
|
} |
|
this.Map.prototype.isFloor = function (x, y) { |
|
var n = 0; |
|
for (var i in this.freeTiles) { |
|
if (this.freeTiles[i][0] == x && this.freeTiles[i][1] == y) return n; else n++; |
|
} |
|
return -1; |
|
} |
|
this.Map.prototype.removeFreeTile = function (x, y) { |
|
this.freeTiles.splice(this.isFloor(x, y), 1); |
|
} |
|
|
|
this.Map.prototype.fill = function (what) { |
|
//fill with something (either a set value, or a function that takes the map, a position X and a position Y as arguments) |
|
//NOTE : this also resets the rooms! |
|
//example : MyMap.fill(function(m,x,y){return Math.floor((Math.random());}); |
|
//...will fill the map with 0s and 1s |
|
var func = 0; |
|
if (typeof(what) == 'function') func = 1; |
|
for (var x = 0; x < this.w; x++) { |
|
for (var y = 0; y < this.h; y++) { |
|
if (func) this.data[x][y] = [what(this, x, y), -1, 0]; else this.data[x][y] = [what, -1, 0]; |
|
} |
|
} |
|
this.rooms = []; |
|
} |
|
|
|
this.Map.prototype.fillZone = function (X, Y, W, H, what) { |
|
//just plain fill a rectangle |
|
for (var x = X; x < X + W; x++) { |
|
for (var y = Y; y < Y + H; y++) { |
|
this.data[x][y][0] = what; |
|
} |
|
} |
|
} |
|
|
|
this.Map.prototype.getRoomTile = function (room, x, y) { |
|
var n = 0; |
|
for (var i in room.tiles) { |
|
if (room.tiles[i].x == x && room.tiles[i].y == y) return n; else n++; |
|
} |
|
return -1; |
|
} |
|
|
|
this.Map.prototype.getFloorTileInRoom = function (room) { |
|
var tiles = []; |
|
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]); |
|
} |
|
return choose(tiles); |
|
} |
|
|
|
this.Map.prototype.canPlaceRoom = function (rx, ry, rw, rh) { |
|
if (rx < 2 || ry < 2 || rx + rw >= this.w - 1 || ry + rh >= this.h - 1) return false; |
|
for (var x = rx; x < rx + rw; x++) { |
|
for (var y = ry; y < ry + rh; y++) { |
|
var tile = this.getType(x, y); |
|
var room = this.getRoom(x, y); |
|
if (tile == TILE_LIMIT) return false; |
|
if (room != -1) return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
this.Map.prototype.setRoomTile = function (room, x, y, tile) { |
|
//var mapTile=this.getType(x,y); |
|
var oldTile = this.getRoomTile(room, x, y); |
|
var oldTileType = oldTile != -1 ? room.tiles[oldTile].type : -1; |
|
if (oldTile != -1 && ( |
|
//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER) ||// && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) || |
|
//(tile!=TILE_FLOOR_EDGE && tile!=TILE_FLOOR_CENTER && (oldTileType!=TILE_FLOOR_EDGE && oldTileType!=TILE_FLOOR_CENTER)) || |
|
(tile == TILE_WALL || tile == TILE_WALL_CORNER) ||//don't place a wall over an existing room |
|
(tile == TILE_FLOOR_EDGE && oldTileType == TILE_FLOOR_CENTER)//don't place an edge floor over a center floor |
|
)) { |
|
return false; |
|
} |
|
else { |
|
if (oldTile != -1) room.tiles.splice(oldTile, 1); |
|
room.tiles.push({x: x, y: y, type: tile, score: 0}); |
|
if ((tile == TILE_FLOOR_EDGE || tile == TILE_FLOOR_CENTER) && (oldTileType != TILE_FLOOR_EDGE && oldTileType != TILE_FLOOR_CENTER)) room.freeTiles++; |
|
else if (tile != TILE_FLOOR_EDGE && tile != TILE_FLOOR_CENTER && (oldTileType == TILE_FLOOR_EDGE || oldTileType == TILE_FLOOR_CENTER)) room.freeTiles--; |
|
return true; |
|
} |
|
} |
|
|
|
this.Map.prototype.expandRoom = function (room, rx, ry, rw, rh) { |
|
var x = 0; |
|
var y = 0; |
|
//floor |
|
for (var x = rx; x < rx + rw; x++) { |
|
for (var y = ry; y < ry + rh; y++) { |
|
this.setRoomTile(room, x, y, TILE_FLOOR_EDGE); |
|
} |
|
} |
|
for (var x = rx + 1; x < rx + rw - 1; x++) { |
|
for (var y = ry + 1; y < ry + rh - 1; y++) { |
|
this.setRoomTile(room, x, y, TILE_FLOOR_CENTER); |
|
} |
|
} |
|
//walls |
|
y = ry - 1; |
|
for (var x = rx; x < rx + rw; x++) { |
|
this.setRoomTile(room, x, y, TILE_WALL); |
|
} |
|
y = ry + rh; |
|
for (var x = rx; x < rx + rw; x++) { |
|
this.setRoomTile(room, x, y, TILE_WALL); |
|
} |
|
x = rx - 1; |
|
for (var y = ry; y < ry + rh; y++) { |
|
this.setRoomTile(room, x, y, TILE_WALL); |
|
} |
|
x = rx + rw; |
|
for (var y = ry; y < ry + rh; y++) { |
|
this.setRoomTile(room, x, y, TILE_WALL); |
|
} |
|
//corners |
|
x = rx - 1; |
|
y = ry - 1; |
|
this.setRoomTile(room, x, y, TILE_WALL_CORNER); |
|
x = rx + rw; |
|
y = ry - 1; |
|
this.setRoomTile(room, x, y, TILE_WALL_CORNER); |
|
x = rx - 1; |
|
y = ry + rh; |
|
this.setRoomTile(room, x, y, TILE_WALL_CORNER); |
|
x = rx + rw; |
|
y = ry + rh; |
|
this.setRoomTile(room, x, y, TILE_WALL_CORNER); |
|
|
|
//decoration |
|
var water = Math.random() < this.waterRatio ? 1 : 0; |
|
var pattern = Math.random() < this.pillarRatio ? getRandomPattern() : 0; |
|
for (var x = rx; x < rx + rw; x++) { |
|
for (var y = ry; y < ry + rh; y++) { |
|
if (room.tiles[this.getRoomTile(room, x, y)].type == TILE_FLOOR_CENTER) { |
|
var tile = 0; |
|
if (water != 0) tile = TILE_WATER; |
|
if (pattern != 0) { |
|
tile = pattern.func(x, y, room) || tile; |
|
} |
|
if (tile != 0) this.setRoomTile(room, x, y, tile); |
|
} |
|
} |
|
} |
|
} |
|
|
|
this.Map.prototype.newRoom = function (x, y, w, h, parent) { |
|
//create a new abstract room, ready to be carved |
|
var room = {}; |
|
room.id = this.rooms.length; |
|
room.w = w;//||rand(2,this.roomSize); |
|
room.h = h;//||rand(2,this.roomSize); |
|
room.x = x || rand(1, this.w - room.w - 1); |
|
room.y = y || rand(1, this.h - room.h - 1); |
|
room.tiles = []; |
|
room.freeTiles = 0; |
|
room.parent = parent ? parent : -1; |
|
room.children = []; |
|
room.gen = 0; |
|
room.door = 0; |
|
room.corridor = Math.random() < this.corridorRatio ? 1 : 0; |
|
room.hidden = this.roomsAreHidden;//if 1, don't draw |
|
//if (room.parent!=-1) room.corridor=!room.parent.corridor;//alternate rooms and corridors |
|
|
|
return room; |
|
} |
|
this.Map.prototype.planRoom = function (room) { |
|
var branches = this.branching + 1; |
|
var forcedExpansions = []; |
|
var w = room.w; |
|
var h = room.h; |
|
while (w > 0 && h > 0) { |
|
if (w > 0) { |
|
forcedExpansions.push(1, 3); |
|
w--; |
|
} |
|
if (h > 0) { |
|
forcedExpansions.push(2, 4); |
|
h--; |
|
} |
|
} |
|
|
|
for (var i = 0; i < branches; i++) { |
|
var steps = 0; |
|
var expansions = []; |
|
if (!room.corridor) { |
|
expansions = [1, 2, 3, 4]; |
|
steps = this.roomSize; |
|
} |
|
else { |
|
expansions = choose([[1, 3], [2, 4]]); |
|
steps = this.corridorSize; |
|
} |
|
steps = Math.max(room.w + room.h, Math.ceil(steps * (1 - Math.random() * this.sizeVariance))); |
|
if (room.tiles.length == 0) { |
|
var rx = room.x; |
|
var ry = room.y; |
|
var rw = 1; |
|
var rh = 1; |
|
} |
|
else { |
|
var randomTile = this.getFloorTileInRoom(room); |
|
var rx = randomTile.x; |
|
var ry = randomTile.y; |
|
var rw = 1; |
|
var rh = 1; |
|
} |
|
for (var ii = 0; ii < steps; ii++) { |
|
if (expansions.length == 0) break; |
|
var xd = 0; |
|
var yd = 0; |
|
var wd = 0; |
|
var hd = 0; |
|
var side = choose(expansions); |
|
if (forcedExpansions.length > 0) side = forcedExpansions[0]; |
|
if (side == 1) { |
|
xd = -1; |
|
wd = 1; |
|
} |
|
else if (side == 2) { |
|
yd = -1; |
|
hd = 1; |
|
} |
|
else if (side == 3) { |
|
wd = 1; |
|
} |
|
else if (side == 4) { |
|
hd = 1; |
|
} |
|
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); |
|
if (forcedExpansions.length > 0) forcedExpansions.splice(0, 1); |
|
} |
|
if (rw > 1 || rh > 1) { |
|
this.expandRoom(room, rx, ry, rw, rh); |
|
} |
|
} |
|
} |
|
|
|
|
|
this.Map.prototype.carve = function (room) { |
|
//carve a room into the map |
|
for (var i in room.tiles) { |
|
var thisTile = room.tiles[i]; |
|
var x = thisTile.x; |
|
var y = thisTile.y; |
|
var myType = this.data[x][y][0]; |
|
var type = thisTile.type; |
|
|
|
if ((type == TILE_WALL || type == TILE_WALL_CORNER) && this.isWall(x, y) != -1) { |
|
this.freeWalls.splice(this.isWall(x, y), 1); |
|
} |
|
|
|
if (this.data[x][y][1] != -1 && (type == TILE_WALL || type == TILE_WALL_CORNER)) { |
|
} |
|
else { |
|
if (this.data[x][y][1] == -1) this.tilesDug++; |
|
this.data[x][y] = [thisTile.type, room.id, 0]; |
|
if (x > 1 && y > 1 && x < this.w - 2 && y < this.h - 2 && type == TILE_WALL) this.freeWalls.push([x, y]); |
|
if (type == TILE_FLOOR_EDGE || type == TILE_FLOOR_CENTER) this.freeTiles.push([x, y]); |
|
} |
|
var pos = [x, y]; |
|
} |
|
this.rooms[room.id] = room; |
|
} |
|
|
|
this.Map.prototype.newRandomRoom = function (params) { |
|
var success = 1; |
|
params = params || {};//params is an object such as {corridor:1} |
|
var door = choose(this.freeWalls);//select a free wall to use as a door |
|
if (!door) { |
|
success = 0; |
|
} |
|
else { |
|
//this.data[door[0]][door[1]][0]=TILE_LIMIT;//not door |
|
var parentRoom = this.getRoom(door[0], door[1]); |
|
var sides = [];//select a free side of that door |
|
if (this.getType(door[0] - 1, door[1]) == TILE_EMPTY) sides.push([-1, 0]); |
|
if (this.getType(door[0] + 1, door[1]) == TILE_EMPTY) sides.push([1, 0]); |
|
if (this.getType(door[0], door[1] - 1) == TILE_EMPTY) sides.push([0, -1]); |
|
if (this.getType(door[0], door[1] + 1) == TILE_EMPTY) sides.push([0, 1]); |
|
var side = choose(sides); |
|
if (!side) { |
|
success = 0; |
|
this.freeWalls.splice(this.isWall(door[0], door[1]), 1); |
|
} |
|
else { |
|
var room = this.newRoom(door[0] + side[0], door[1] + side[1], 0, 0, parentRoom);//try a new room from this spot |
|
for (var i in params) { |
|
room[i] = params[i]; |
|
} |
|
this.planRoom(room); |
|
if (room.tiles.length > 0 && room.freeTiles > 0)//we got a decent room |
|
{ |
|
this.carve(room); |
|
this.data[door[0]][door[1]][0] = TILE_DOOR;//place door |
|
room.door = [door[0], door[1]]; |
|
this.data[door[0]][door[1]][1] = room.id;//set ID |
|
this.freeWalls.splice(this.isWall(door[0], door[1]), 1);//the door isn't a wall anymore |
|
this.doors.push([door[0], door[1], room]); |
|
//remove free tiles on either side of the door |
|
if (this.isFloor(door[0] + side[0], door[1] + side[1]) != -1) this.removeFreeTile(door[0] + side[0], door[1] + side[1]); |
|
if (this.isFloor(door[0] - side[0], door[1] - side[1]) != -1) this.removeFreeTile(door[0] - side[0], door[1] - side[1]); |
|
room.parent = parentRoom; |
|
parentRoom.children.push(room); |
|
room.gen = parentRoom.gen + 1; |
|
} |
|
else//not a good spot; remove this tile from the list of walls |
|
{ |
|
this.freeWalls.splice(this.isWall(door[0], door[1]), 1); |
|
success = 0; |
|
} |
|
} |
|
} |
|
if (success) return room; |
|
else return 0; |
|
} |
|
|
|
this.Map.prototype.getRandomSpotInRoom = function (room) { |
|
var listOfTiles = []; |
|
for (var i in room.tiles) { |
|
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) { |
|
listOfTiles.push(room.tiles[i]); |
|
} |
|
} |
|
if (listOfTiles.length == 0) return -1; |
|
return choose(listOfTiles); |
|
} |
|
this.Map.prototype.getBestSpotInRoom = function (room) { |
|
var highest = -1; |
|
var listOfHighest = []; |
|
for (var i in room.tiles) { |
|
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) { |
|
if (room.tiles[i].score > highest) { |
|
listOfHighest = []; |
|
highest = room.tiles[i].score; |
|
listOfHighest.push(room.tiles[i]); |
|
} |
|
else if (room.tiles[i].score == highest) { |
|
listOfHighest.push(room.tiles[i]); |
|
} |
|
} |
|
} |
|
if (listOfHighest.length == 0) return -1; |
|
return choose(listOfHighest); |
|
} |
|
this.Map.prototype.getEarliestRoom = function () { |
|
return this.rooms[0]; |
|
} |
|
this.Map.prototype.getDeepestRoom = function () { |
|
var deepest = 0; |
|
var deepestRoom = this.rooms[0]; |
|
for (var i in this.rooms) { |
|
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]; |
|
} |
|
} |
|
return deepestRoom; |
|
} |
|
|
|
this.Map.prototype.dig = function () { |
|
//one step in which we try to carve new stuff |
|
//returns 0 when we couldn't dig this step, 1 when we could, and 2 when the digging is complete |
|
Math.random = this.seedState; |
|
|
|
var badDig = 0; |
|
|
|
if (this.digs == 0)//first dig : build a starting room in the middle of the map |
|
{ |
|
var w = rand(3, 7); |
|
var h = rand(3, 7); |
|
var room = this.newRoom(Math.floor(this.w / 2 - w / 2), Math.floor(this.h / 2 - h / 2), w, h); |
|
room.corridor = 0; |
|
this.planRoom(room); |
|
this.carve(room); |
|
} |
|
else { |
|
if (this.newRandomRoom() == 0) badDig++; |
|
} |
|
if (badDig > 0) this.stuck++; |
|
|
|
this.digs++; |
|
|
|
var finished = 0; |
|
if (this.tilesDug >= this.tiles * this.fillRatio) finished = 1; |
|
if (this.stuck > 100) finished = 1; |
|
|
|
if (finished == 1)//last touch : try to add a whole room at the end |
|
{ |
|
for (var i = 0; i < 10; i++) { |
|
var newRoom = this.newRandomRoom({corridor: 0, w: rand(3, 7), h: rand(3, 7)}); |
|
if (newRoom != 0 && newRoom.freeTiles > 15) break; |
|
} |
|
} |
|
|
|
Math.seedrandom(); |
|
if (finished == 1) return 1; else if (badDig > 0) return -1; else return 0; |
|
} |
|
|
|
this.Map.prototype.finish = function () { |
|
//touch up the map : add pillars in corners etc |
|
/* |
|
//set paths |
|
for (var i in this.rooms) |
|
{ |
|
var me=this.rooms[i]; |
|
if (me.door!=0) |
|
{ |
|
var doors=[]; |
|
doors.push(me.door); |
|
for (var ii in me.children) |
|
{ |
|
if (me.children[ii].door!=0) doors.push(me.children[ii].door); |
|
} |
|
for (var ii in doors) |
|
{ |
|
this.data[doors[ii][0]][doors[ii][1]][0]=TILE_LIMIT; |
|
//ideally we should run agents that step from each door to the next |
|
} |
|
} |
|
} |
|
*/ |
|
for (var i in this.rooms) { |
|
var pillars = Math.random() < this.pillarRatio; |
|
for (var ii in this.rooms[i].tiles) { |
|
var x = this.rooms[i].tiles[ii].x; |
|
var y = this.rooms[i].tiles[ii].y; |
|
var me = this.data[x][y][0]; |
|
var x1 = this.data[x - 1][y][0]; |
|
var x2 = this.data[x + 1][y][0]; |
|
var y1 = this.data[x][y - 1][0]; |
|
var y2 = this.data[x][y + 1][0]; |
|
var xy1 = this.data[x - 1][y - 1][0]; |
|
var xy2 = this.data[x + 1][y - 1][0]; |
|
var xy3 = this.data[x - 1][y + 1][0]; |
|
var xy4 = this.data[x + 1][y + 1][0]; |
|
|
|
var walls = 0; |
|
if ((x1 == TILE_WALL || x1 == TILE_WALL_CORNER)) walls++; |
|
if ((y1 == TILE_WALL || y1 == TILE_WALL_CORNER)) walls++; |
|
if ((x2 == TILE_WALL || x2 == TILE_WALL_CORNER)) walls++; |
|
if ((y2 == TILE_WALL || y2 == TILE_WALL_CORNER)) walls++; |
|
if ((xy1 == TILE_WALL || xy1 == TILE_WALL_CORNER)) walls++; |
|
if ((xy2 == TILE_WALL || xy2 == TILE_WALL_CORNER)) walls++; |
|
if ((xy3 == TILE_WALL || xy3 == TILE_WALL_CORNER)) walls++; |
|
if ((xy4 == TILE_WALL || xy4 == TILE_WALL_CORNER)) walls++; |
|
|
|
var floors = 0; |
|
if ((x1 == TILE_FLOOR_CENTER || x1 == TILE_FLOOR_EDGE)) floors++; |
|
if ((y1 == TILE_FLOOR_CENTER || y1 == TILE_FLOOR_EDGE)) floors++; |
|
if ((x2 == TILE_FLOOR_CENTER || x2 == TILE_FLOOR_EDGE)) floors++; |
|
if ((y2 == TILE_FLOOR_CENTER || y2 == TILE_FLOOR_EDGE)) floors++; |
|
if ((xy1 == TILE_FLOOR_CENTER || xy1 == TILE_FLOOR_EDGE)) floors++; |
|
if ((xy2 == TILE_FLOOR_CENTER || xy2 == TILE_FLOOR_EDGE)) floors++; |
|
if ((xy3 == TILE_FLOOR_CENTER || xy3 == TILE_FLOOR_EDGE)) floors++; |
|
if ((xy4 == TILE_FLOOR_CENTER || xy4 == TILE_FLOOR_EDGE)) floors++; |
|
|
|
var complete = 0; |
|
if (walls + floors == 8) complete = 1; |
|
|
|
var angle = 0; |
|
if (complete) { |
|
var top = 0; |
|
var left = 0; |
|
var right = 0; |
|
var bottom = 0; |
|
if ((xy1 == TILE_WALL || xy1 == TILE_WALL_CORNER) && (y1 == TILE_WALL || y1 == TILE_WALL_CORNER) && (xy2 == TILE_WALL || xy2 == TILE_WALL_CORNER)) top = 1; |
|
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; |
|
if ((xy2 == TILE_WALL || xy2 == TILE_WALL_CORNER) && (x2 == TILE_WALL || x2 == TILE_WALL_CORNER) && (xy4 == TILE_WALL || xy4 == TILE_WALL_CORNER)) right = 1; |
|
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; |
|
if ((xy1 == TILE_WALL || xy1 == TILE_WALL_CORNER) && (x1 == TILE_WALL || x1 == TILE_WALL_CORNER) && (xy3 == TILE_WALL || xy3 == TILE_WALL_CORNER)) left = 1; |
|
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; |
|
if ((xy3 == TILE_WALL || xy3 == TILE_WALL_CORNER) && (y2 == TILE_WALL || y2 == TILE_WALL_CORNER) && (xy4 == TILE_WALL || xy4 == TILE_WALL_CORNER)) bottom = 1; |
|
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; |
|
if ((top == 1 && bottom == -1) || (top == -1 && bottom == 1) || (left == 1 && right == -1) || (left == -1 && right == 1)) angle = 1; |
|
} |
|
|
|
if (pillars && Math.random() < 0.8 && this.rooms[i].freeTiles > 4) { |
|
if ((angle == 1 || (complete && walls == 7)) && me == TILE_FLOOR_EDGE && x1 != TILE_DOOR && x2 != TILE_DOOR && y1 != TILE_DOOR && y2 != TILE_DOOR) { |
|
this.data[x][y][0] = TILE_PILLAR; |
|
me = TILE_PILLAR; |
|
this.removeFreeTile(x, y); |
|
this.rooms[i].freeTiles--; |
|
} |
|
} |
|
|
|
//calculate score (for placing items and exits) |
|
if (top == 1 || bottom == 1 || left == 1 || right == 1) { |
|
this.rooms[i].tiles[ii].score += 2; |
|
} |
|
if (walls > 5 || floors > 5) { |
|
this.rooms[i].tiles[ii].score += 1; |
|
} |
|
if (walls == 7 || floors == 8) { |
|
this.rooms[i].tiles[ii].score += 5; |
|
} |
|
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; |
|
|
|
} |
|
} |
|
|
|
|
|
//carve entrance and exit |
|
var entrance = this.getBestSpotInRoom(this.getEarliestRoom()); |
|
this.data[entrance.x][entrance.y][0] = TILE_ENTRANCE; |
|
this.entrance = [entrance.x, entrance.y]; |
|
entrance.score = 0; |
|
this.removeFreeTile(entrance.x, entrance.y); |
|
var exit = this.getBestSpotInRoom(this.getDeepestRoom()); |
|
this.data[exit.x][exit.y][0] = TILE_EXIT; |
|
this.exit = [exit.x, exit.y]; |
|
this.removeFreeTile(exit.x, exit.y); |
|
exit.score = 0; |
|
|
|
/* |
|
for (var i in this.doors)//remove door tiles (to add later; replace the tiles by entities that delete themselves when opened) |
|
{ |
|
this.data[this.doors[i][0]][this.doors[i][1]][0]=TILE_FLOOR_EDGE; |
|
} |
|
*/ |
|
} |
|
|
|
this.Map.prototype.isObstacle = function (x, y) { |
|
var free = [TILE_FLOOR_EDGE, TILE_FLOOR_CENTER, TILE_DOOR, TILE_ENTRANCE, TILE_EXIT]; |
|
for (var i in free) { |
|
if (this.data[x][y][0] == free[i]) return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
var joinTile = function (map, x, y, joinWith) { |
|
//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. |
|
//joinWith contains the tile types that count as joinable, in addition to this tile. (don't add the tested tile to joinWith!) |
|
var p = 1; |
|
var me = map.data[x][y][0]; |
|
var x1 = map.data[x - 1][y][0]; |
|
var x2 = map.data[x + 1][y][0]; |
|
var y1 = map.data[x][y - 1][0]; |
|
var y2 = map.data[x][y + 1][0]; |
|
joinWith.push(me); |
|
var joinsX = 0; |
|
for (var i in joinWith) { |
|
if (x1 == joinWith[i]) joinsX++; |
|
if (x2 == joinWith[i]) joinsX++; |
|
} |
|
var joinsY = 0; |
|
for (var i in joinWith) { |
|
if (y1 == joinWith[i]) joinsY++; |
|
if (y2 == joinWith[i]) joinsY++; |
|
} |
|
if (joinsX == 2 && joinsY == 2) p = 1; |
|
else if (joinsX == 2) p = 2; |
|
else if (joinsY == 2) p = 3; |
|
return p; |
|
} |
|
this.Map.prototype.getPic = function (x, y) { |
|
//return a position [x,y] in the tiles (as 0, 1, 2...) for the tile on the map at position x,y |
|
if (Tiles[this.data[x][y][2]]) { |
|
if (Tiles[this.data[x][y][2]].joinType == 'join') { |
|
var thisPic = Tiles[this.data[x][y][2]].pic; |
|
thisPic = [thisPic[0], thisPic[1]];//why is this even necessary? |
|
var joinWith = []; |
|
if (this.data[x][y][0] == TILE_WALL) joinWith.push(TILE_WALL_CORNER); |
|
else if (this.data[x][y][0] == TILE_DOOR) joinWith.push(TILE_WALL, TILE_WALL_CORNER); |
|
thisPic[0] += joinTile(this, x, y, joinWith) - 1; |
|
return thisPic; |
|
} |
|
else if (Tiles[this.data[x][y][2]].joinType == 'random3') { |
|
var thisPic = Tiles[this.data[x][y][2]].pic; |
|
thisPic = [thisPic[0], thisPic[1]]; |
|
thisPic[0] += Math.floor(Math.random() * 3); |
|
return thisPic; |
|
} |
|
return Tiles[this.data[x][y][2]].pic; |
|
} |
|
return [0, 0]; |
|
} |
|
|
|
var Tiles = []; |
|
var TilesByName = []; |
|
this.Tile = function (name, pic, joinType) { |
|
this.name = name; |
|
this.pic = pic; |
|
this.joinType = joinType || 'none'; |
|
this.id = Tiles.length; |
|
Tiles[this.id] = this; |
|
TilesByName[this.name] = this; |
|
} |
|
new this.Tile('void', [0, 0]); |
|
this.loadTiles = function (tiles) { |
|
for (var i in tiles) { |
|
var name = tiles[i][0]; |
|
var pic = tiles[i][1]; |
|
var joinType = tiles[i][2]; |
|
new this.Tile(name, pic, joinType); |
|
} |
|
} |
|
|
|
var computeTile = function (tile, tiles, value, name) { |
|
if (tile == value && tiles[name]) return TilesByName[tiles[name]]; |
|
return 0; |
|
} |
|
this.Map.prototype.assignTiles = function (room, tiles) { |
|
//set the displayed tiles for this room |
|
for (var i in room.tiles) { |
|
var type = Tiles[0]; |
|
var me = room.tiles[i]; |
|
var tile = this.data[me.x][me.y][0]; |
|
type = computeTile(tile, tiles, TILE_WALL_CORNER, 'wall corner') || type; |
|
type = computeTile(tile, tiles, TILE_WALL, 'wall') || type; |
|
type = computeTile(tile, tiles, TILE_FLOOR_EDGE, 'floor edges') || type; |
|
type = computeTile(tile, tiles, TILE_FLOOR_CENTER, 'floor') || type; |
|
type = computeTile(tile, tiles, TILE_PILLAR, 'pillar') || type; |
|
type = computeTile(tile, tiles, TILE_DOOR, 'door') || type; |
|
type = computeTile(tile, tiles, TILE_WATER, 'water') || type; |
|
type = computeTile(tile, tiles, TILE_ENTRANCE, 'entrance') || type; |
|
type = computeTile(tile, tiles, TILE_EXIT, 'exit') || type; |
|
|
|
this.data[me.x][me.y][2] = type.id; |
|
} |
|
} |
|
|
|
|
|
this.Map.prototype.draw = function (size) { |
|
//return a string containing a rough visual representation of the map |
|
var str = ''; |
|
var size = size || 10; |
|
for (var y = 0; y < this.h; y++) { |
|
for (var x = 0; x < this.w; x++) { |
|
var text = ''; |
|
if (this.isFloor(x, y) != -1) text = 'o'; |
|
if (this.isWall(x, y) != -1) text += 'x'; |
|
var room = this.getRoom(x, y); |
|
var opacity = Math.max(0.1, 1 - (this.getRoom(x, y).gen / 10)); |
|
var title = room.freeTiles;//this.data[x][y][0].toString(); |
|
text = ''; |
|
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>'; |
|
} |
|
str += '<br>'; |
|
} |
|
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>'; |
|
return str; |
|
} |
|
|
|
this.Map.prototype.drawDetailed = function () { |
|
//return a string containing a rough visual representation of the map (with graphics) |
|
var str = ''; |
|
var size = 16; |
|
for (var y = 0; y < this.h; y++) { |
|
for (var x = 0; x < this.w; x++) { |
|
var room = this.getRoom(x, y); |
|
//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score); |
|
var opacity = 1; |
|
var title = 'void'; |
|
if (room != -1) { |
|
opacity = Math.max(0.1, 1 - room.gen / 5); |
|
if (this.data[x][y][0] == TILE_ENTRANCE || this.data[x][y][0] == TILE_EXIT) opacity = 1; |
|
title = (room.corridor ? 'corridor' : 'room') + ' ' + room.id + ' | depth : ' + room.gen + ' | children : ' + room.children.length; |
|
} |
|
var pic = this.getPic(x, y); |
|
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>'; |
|
} |
|
str += '<br>'; |
|
} |
|
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>'; |
|
return str; |
|
} |
|
|
|
this.Map.prototype.getStr = function () { |
|
//return a string containing the map with tile graphics, ready to be pasted in a wrapper |
|
var str = ''; |
|
var size = 16; |
|
for (var y = 0; y < this.h; y++) { |
|
for (var x = 0; x < this.w; x++) { |
|
var room = this.getRoom(x, y); |
|
//var opacity=Math.max(0.1,room.tiles[this.getRoomTile(room,x,y)].score); |
|
var opacity = 1; |
|
var title = 'void'; |
|
var pic = this.getPic(x, y); |
|
if (room != -1) { |
|
/* |
|
opacity=Math.max(0.1,1-room.gen/5); |
|
if (room.hidden) opacity=0; |
|
if (this.data[x][y][0]==TILE_ENTRANCE || this.data[x][y][0]==TILE_EXIT) opacity=1; |
|
*/ |
|
if (room.hidden) pic = [0, 0]; |
|
title = (room.corridor ? 'corridor' : 'room') + ' ' + room.id + ' | depth : ' + room.gen + ' | children : ' + room.children.length; |
|
} |
|
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>'; |
|
} |
|
str += '<br>'; |
|
} |
|
return str; |
|
} |
|
|
|
} |
|
|
|
/*===================================================================================== |
|
CREATE MONSTER TYPES |
|
=======================================================================================*/ |
|
|
|
/* |
|
An explanation of stats : |
|
-hp : health points |
|
-speed : determines who attacks first in a fight; bypasses dodging; determines how fast heroes auto-run dungeons |
|
-might : determines how much damage is done to opponents |
|
-guard : lowers incoming damage |
|
-dodge : chance of avoiding incoming attacks completely (affected by the opponent's speed) |
|
-luck : heroes only, determines drops and rare encounters |
|
-rarity : monsters only, determines how often a monster is added to the spawn table |
|
-level : monsters only, determines which average room depth the monster is more likely to spawn in (also determines the loot amount) |
|
*/ |
|
Game.monsterIconY = 10;//offset for dungeonItems.png monsters |
|
Game.Monsters = []; |
|
Game.Monster = function (name, pic, icon, level, stats, loot) { |
|
this.name = name; |
|
this.pic = pic; |
|
this.icon = icon; |
|
this.level = level; |
|
this.stats = {}; |
|
for (var i in stats) { |
|
this.stats[i] = stats[i]; |
|
} |
|
this.stats.hpm = this.stats.hp; |
|
this.stats.rarity = stats.rarity || 1; |
|
this.loot = loot || {}; |
|
this.boss = 0; |
|
this.quotes = {}; |
|
Game.Monsters[this.name] = this; |
|
} |
|
var basicLoot = {cookies: {min: 1, max: 5, prob: 0.5}}; |
|
var goodLoot = {cookies: {min: 3, max: 8, prob: 1}, gear: {prob: 0.05}}; |
|
var bossLoot = {gear: {prob: 1}}; |
|
var chestLoot = {cookies: {min: 2, max: 20, prob: 1}, gear: {prob: 0.1}}; |
|
var bossLoot = {cookies: {min: 10, max: 50, prob: 1}, gear: {prob: 0.2}}; |
|
|
|
//general monsters |
|
new Game.Monster('Doughling', 'doughling', [0, 0], 1, { |
|
hp: 5, |
|
might: 2, |
|
guard: 2, |
|
speed: 6, |
|
dodge: 6, |
|
rarity: 0.7 |
|
}, basicLoot); |
|
new Game.Monster('Elder doughling', 'elderDoughling', [1, 0], 7, { |
|
hp: 20, |
|
might: 7, |
|
guard: 7, |
|
speed: 4, |
|
dodge: 4, |
|
rarity: 0.7 |
|
}, goodLoot); |
|
new Game.Monster('Angry sentient cookie', 'angrySentientCookie', [5, 0], 5, { |
|
hp: 16, |
|
might: 8, |
|
guard: 4, |
|
speed: 5, |
|
dodge: 5, |
|
rarity: 1 |
|
}, basicLoot); |
|
new Game.Monster('Baby sentient cookie', 'babySentientCookie', [4, 0], 1, { |
|
hp: 3, |
|
might: 1, |
|
guard: 1, |
|
speed: 7, |
|
dodge: 7, |
|
rarity: 1 |
|
}, basicLoot); |
|
new Game.Monster('Burnt sentient cookie', 'burntSentientCookie', [6, 0], 5, { |
|
hp: 16, |
|
might: 12, |
|
guard: 2, |
|
speed: 3, |
|
dodge: 2, |
|
rarity: 0.2 |
|
}, basicLoot); |
|
new Game.Monster('Raw sentient cookie', 'rawSentientCookie', [5, 0], 5, { |
|
hp: 16, |
|
might: 6, |
|
guard: 4, |
|
speed: 7, |
|
dodge: 7, |
|
rarity: 0.2 |
|
}, basicLoot); |
|
new Game.Monster('Sugar bunny', 'sugarBunny', [8, 0], 5, { |
|
hp: 10, |
|
might: 3, |
|
guard: 8, |
|
speed: 12, |
|
dodge: 9, |
|
rarity: 0.001 |
|
}, {cookies: {min: 1000, max: 10000}}); |
|
Game.Monsters['Sugar bunny'].onKill = function () { |
|
Game.Win('Follow the white rabbit'); |
|
}; |
|
Game.Monsters['Sugar bunny'].AI = 'flee'; |
|
|
|
//factory monsters |
|
new Game.Monster('Crazed kneader', 'crazedKneader', [0, 2], 6, { |
|
hp: 18, |
|
might: 6, |
|
guard: 8, |
|
speed: 3, |
|
dodge: 2, |
|
rarity: 0.5 |
|
}, goodLoot); |
|
new Game.Monster('Crazed chip-spurter', 'crazedDoughSpurter', [0, 2], 6, { |
|
hp: 15, |
|
might: 6, |
|
guard: 8, |
|
speed: 5, |
|
dodge: 3, |
|
rarity: 0.5 |
|
}, goodLoot); |
|
new Game.Monster('Alarm bot', 'alarmTurret', [3, 2], 2, { |
|
hp: 6, |
|
might: 3, |
|
guard: 5, |
|
speed: 8, |
|
dodge: 8, |
|
rarity: 0.5 |
|
}, basicLoot); |
|
new Game.Monster('Chirpy', 'chirpy', [4, 2], 3, { |
|
hp: 7, |
|
might: 4, |
|
guard: 6, |
|
speed: 9, |
|
dodge: 9, |
|
rarity: 0.01 |
|
}, {cookies: {min: 500, max: 5000}}); |
|
Game.Monsters['Chirpy'].onKill = function () { |
|
Game.Win('Chirped out'); |
|
}; |
|
Game.Monsters['Chirpy'].quotes = {fight: 'oh, hello <3'}; |
|
new Game.Monster('Disgruntled worker', 'disgruntledWorker', [1, 2], 4, { |
|
hp: 14, |
|
might: 5, |
|
guard: 5, |
|
speed: 6, |
|
dodge: 4, |
|
rarity: 0.6 |
|
}, basicLoot); |
|
new Game.Monster('Disgruntled overseer', 'disgruntledOverseer', [1, 2], 7, { |
|
hp: 22, |
|
might: 7, |
|
guard: 5, |
|
speed: 6, |
|
dodge: 4, |
|
rarity: 0.5 |
|
}, basicLoot); |
|
new Game.Monster('Disgruntled cleaning lady', 'disgruntledCleaningLady', [2, 2], 4, { |
|
hp: 13, |
|
might: 4, |
|
guard: 5, |
|
speed: 7, |
|
dodge: 6, |
|
rarity: 0.3 |
|
}, basicLoot); |
|
|
|
new Game.Monster('Sentient Furnace', 'sentientFurnace', [0, 3], 0, { |
|
hp: 60, |
|
might: 14, |
|
guard: 12, |
|
speed: 4, |
|
dodge: 0, |
|
rarity: 1 |
|
}, bossLoot);//boss |
|
Game.Monsters['Sentient Furnace'].onKill = function () { |
|
Game.Win('Getting even with the oven'); |
|
}; |
|
Game.Monsters['Sentient Furnace'].AI = 'static'; |
|
Game.Monsters['Sentient Furnace'].boss = 1; |
|
Game.Monsters['Sentient Furnace'].quotes = {fight: 'YOU ARE NOT READY!', defeat: 'OH... BURN.'}; |
|
new Game.Monster('Ascended Baking Pod', 'ascendedBakingPod', [1, 3], 0, { |
|
hp: 60, |
|
might: 12, |
|
guard: 14, |
|
speed: 4, |
|
dodge: 0, |
|
rarity: 0.7 |
|
}, bossLoot);//boss |
|
Game.Monsters['Ascended Baking Pod'].onKill = function () { |
|
Game.Win('Now this is pod-smashing'); |
|
}; |
|
Game.Monsters['Ascended Baking Pod'].AI = 'static'; |
|
Game.Monsters['Ascended Baking Pod'].boss = 1; |
|
Game.Monsters['Ascended Baking Pod'].quotes = {fight: 'rrrrrrrise.', defeat: 'blrglblg.'}; |
|
|
|
|
|
Game.BossMonsters = []; |
|
for (var i in Game.Monsters) { |
|
if (Game.Monsters[i].boss) Game.BossMonsters.push(Game.Monsters[i]); |
|
} |
|
|
|
/*===================================================================================== |
|
ENTITY MECHANICS |
|
=======================================================================================*/ |
|
|
|
Game.Entity = function (type, subtype, dungeon, pic, stats)//objects you could find on the map : doors, mobs, interactables, items, player, exits... |
|
{ |
|
this.type = type; |
|
this.subtype = subtype || ''; |
|
this.dungeon = dungeon; |
|
this.pic = pic || [0, 0]; |
|
this.stats = {}; |
|
for (var i in stats) { |
|
this.stats[i] = stats[i]; |
|
} |
|
|
|
this.x = -1; |
|
this.y = -1; |
|
this.obstacle = 0; |
|
this.zIndex = 1; |
|
if (this.type == 'monster') { |
|
this.obstacle = 1; |
|
this.pic = [Game.Monsters[this.subtype].icon[0], Game.Monsters[this.subtype].icon[1]]; |
|
this.pic[1] += Game.monsterIconY; |
|
this.targets = []; |
|
this.stuck = 0; |
|
this.zIndex = 10; |
|
this.fighting = 0; |
|
this.AI = Game.Monsters[this.subtype].AI || 'normal'; |
|
this.onKill = Game.Monsters[this.subtype].onKill || function () { |
|
}; |
|
for (var i in Game.Monsters[this.subtype].stats) { |
|
this.stats[i] = Game.Monsters[this.subtype].stats[i]; |
|
} |
|
} |
|
else if (this.type == 'hero') { |
|
this.obstacle = 1; |
|
this.pic = [Game.Heroes[this.subtype].icon[0], Game.Heroes[this.subtype].icon[1]]; |
|
this.targets = []; |
|
this.stuck = 0; |
|
this.zIndex = 100; |
|
this.fighting = 0; |
|
for (var i in Game.Heroes[this.subtype].stats) { |
|
this.stats[i] = Game.Heroes[this.subtype].stats[i]; |
|
} |
|
|
|
//increase stats by amount of matching building (change that later to use gear instead) |
|
var mult = Math.max(0, (Game.Objects[this.dungeon.type].amount / 20 - 1)); |
|
this.stats.hpm += Math.ceil(mult * 2); |
|
this.stats.hp = this.stats.hpm; |
|
this.stats.might += mult; |
|
this.stats.guard += mult; |
|
this.stats.speed += mult; |
|
this.stats.dodge += mult; |
|
} |
|
else if (this.type == 'item') { |
|
this.zIndex = 5; |
|
this.value = 0; |
|
} |
|
else if (this.type == 'destructible')//crates, doors |
|
{ |
|
this.obstacle = 1; |
|
this.life = 3; |
|
this.zIndex = 15; |
|
if (this.subtype == 'door') this.pic = [0, 7]; |
|
else this.pic = [Math.floor(Math.random() * 4 + 2), 7]; |
|
|
|
this.onKill = function () { |
|
if (this.subtype == 'random') { |
|
var value = Math.round(Math.pow(Math.random(), 6) * (10 + this.dungeon.level)); |
|
if (value > 0) { |
|
var entity = this.dungeon.AddEntity('item', 'cookies', this.x, this.y); |
|
entity.value = value; |
|
} |
|
} |
|
} |
|
} |
|
else if (this.type == 'special') { |
|
this.zIndex = 5; |
|
this.value = ''; |
|
this.obstacle = 1; |
|
} |
|
|
|
this.Say = function (what) { |
|
if (this.type == 'monster') { |
|
if (Game.Monsters[this.subtype].quotes[what]) this.dungeon.Log(this.subtype + ' : "<span style="color:#f96;">' + choose(Game.Monsters[this.subtype].quotes[what].split('|')) + '</span>"'); |
|
} |
|
} |
|
this.Draw = function ()//return the string to draw this |
|
{ |
|
var name = '?'; |
|
if (this.subtype == 'random') name = 'clutter'; else name = this.subtype; |
|
if (this.type == 'item' && this.subtype == 'cookies' && this.value > 0) { |
|
if (this.value < 2) this.pic = [0, 5]; |
|
else if (this.value < 3) this.pic = [1, 5]; |
|
else if (this.value < 4) this.pic = [2, 5]; |
|
else if (this.value < 6) this.pic = [3, 5]; |
|
else if (this.value < 10) this.pic = [4, 5]; |
|
else if (this.value < 20) this.pic = [5, 5]; |
|
else if (this.value < 30) this.pic = [7, 5]; |
|
else if (this.value < 70) this.pic = [6, 5]; |
|
else if (this.value < 200) this.pic = [8, 5]; |
|
else this.pic = [6, 6];// if (this.value<1000) this.pic=[1,5]; |
|
} |
|
else if (this.type == 'special' && this.subtype == 'upgrade') { |
|
if (this.value != '') this.pic = [7, 6]; else this.pic = [8, 6]; |
|
} |
|
return '<div class="thing" title="' + name + '" style="z-index:' + (200 + this.zIndex) + ';left:' + (this.x * 16) + 'px;top:' + (this.y * 16) + 'px;background-position:' + (-this.pic[0] * 16) + 'px ' + (-this.pic[1] * 16) + 'px;"></div>'; |
|
} |
|
this.Wander = function ()//AI to move around aimlessly |
|
{ |
|
this.targets = []; |
|
this.targets.push([-1, 0], [1, 0], [0, -1], [0, 1]); |
|
this.Move(); |
|
} |
|
this.GoTo = function (x, y)//AI to move to a specific point |
|
{ |
|
this.targets = []; |
|
if (this.x < x) this.targets.push([1, 0]); |
|
if (this.x > x) this.targets.push([-1, 0]); |
|
if (this.y < y) this.targets.push([0, 1]); |
|
if (this.y > y) this.targets.push([0, -1]); |
|
if (!this.Move())//really stuck? try to maneuver laterally! |
|
{ |
|
this.targets = []; |
|
if (this.x == x) this.targets.push([1, 0], [-1, 0]);//somehow this feels inverted... but it doesn't work the other way |
|
if (this.y == y) this.targets.push([0, 1], [0, -1]);//hypothesis : *MAGIC* |
|
this.Move(); |
|
} |
|
} |
|
this.Flee = function (x, y)//AI to run away from a specific point |
|
{ |
|
this.targets = []; |
|
if (this.x > x) this.targets.push([1, 0]); |
|
if (this.x < x) this.targets.push([-1, 0]); |
|
if (this.y > y) this.targets.push([0, 1]); |
|
if (this.y < y) this.targets.push([0, -1]); |
|
if (!this.Move())//really stuck? try to maneuver laterally! |
|
{ |
|
this.targets = []; |
|
if (this.x == x) this.targets.push([1, 0], [-1, 0]);//somehow this feels inverted... but it doesn't work the other way |
|
if (this.y == y) this.targets.push([0, 1], [0, -1]);//hypothesis : *MAGIC* |
|
this.Move(); |
|
} |
|
} |
|
this.Move = function ()//AI to move to the target |
|
{ |
|
if (this.targets.length > 0) { |
|
var goodTargets = []; |
|
if (this.type == 'hero') goodTargets = this.targets; |
|
else { |
|
for (var i in this.targets) { |
|
var thisTarget = this.targets[i]; |
|
if (this.dungeon.CheckObstacle(this.x + thisTarget[0], this.y + thisTarget[1]) != -1) goodTargets.push([thisTarget[0], thisTarget[1]]); |
|
} |
|
} |
|
if (goodTargets.length > 0) { |
|
var target = choose(goodTargets); |
|
var obstacle = this.dungeon.CheckObstacle(this.x + target[0], this.y + target[1]); |
|
if (obstacle == this) obstacle = 0; |
|
if (obstacle == 0 && this.AI != 'static') { |
|
this.x += target[0]; |
|
this.y += target[1]; |
|
} |
|
else this.stuck += 2; |
|
if (obstacle != 0 && obstacle != -1) { |
|
obstacle.HitBy(this); |
|
} |
|
if (obstacle == -1) return 0; |
|
} |
|
else { |
|
this.stuck += 2; |
|
return 0; |
|
} |
|
if (this.AI == 'static') this.stuck = 0; |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
this.HitBy = function (by)//attacked by another entity |
|
{ |
|
if (this.type == 'destructible' && by.type == 'hero')//break destructibles |
|
{ |
|
by.stuck = 0; |
|
this.life--; |
|
if (this.life <= 0) { |
|
if (this.onKill) this.onKill(); |
|
this.Destroy(); |
|
} |
|
else this.pic = [this.pic[0], this.pic[1] + 1]; |
|
} |
|
else if (this.type == 'special' && this.subtype == 'upgrade')//upgrade relic |
|
{ |
|
this.obstacle = 0; |
|
if (Game.Upgrades[this.value]) Game.Upgrades[this.value].earn(); |
|
this.value = ''; |
|
} |
|
else if ((this.type == 'monster' && by.type == 'hero') || (this.type == 'hero' && by.type == 'monster') && this.stats.hp > 0)//it's a fight! |
|
{ |
|
by.stuck = 0; |
|
|
|
var monster = (this.type == 'hero' ? by : this); |
|
var hero = (this.type == 'hero' ? this : by); |
|
this.dungeon.currentOpponent = monster; |
|
|
|
if (monster.fighting == 0)//first meeting |
|
{ |
|
Game.Heroes[hero.subtype].Say('meet ' + Game.Monsters[monster.subtype].name); |
|
this.Say('fight'); |
|
} |
|
if (this.fighting == 0) { |
|
this.fighting = 1; |
|
by.fighting = 1; |
|
} |
|
|
|
var attackStr = ''; |
|
var attackerName = ''; |
|
var defenderName = ''; |
|
if (by.type == 'hero') attackerName = Game.Heroes[by.subtype].name; |
|
else if (by.type == 'monster') attackerName = Game.Monsters[by.subtype].name; |
|
if (this.type == 'hero') defenderName = Game.Heroes[this.subtype].name; |
|
else if (this.type == 'monster') defenderName = Game.Monsters[this.subtype].name; |
|
|
|
//battle formulas (have fun with these) |
|
attackStr += attackerName + ' swings at ' + defenderName + '!'; |
|
var damage = Math.round(Math.max(1, Math.min(by.stats.might, Math.pow(((by.stats.might + 2.5) / Math.max(1, this.stats.guard)), 2))) * (0.8 + Math.random() * 0.4 + Math.pow(Math.random() * 0.8, 6))); |
|
var dodge = Math.random() > (by.stats.speed / Math.max(1, this.stats.dodge + 2.5)); |
|
if (dodge) { |
|
attackStr += ' ' + defenderName + ' dodged the attack.'; |
|
} |
|
else { |
|
if (by.stats.luck && by.type == 'hero' && Math.random() < by.stats.luck * 0.01) { |
|
damage *= 2; |
|
attackStr += ' <b>It\'s a critical!</b>'; |
|
}//very rare critical based on luck |
|
attackStr += ' <b>' + damage + '</b> damage!'; |
|
|
|
this.stats.hp -= damage; |
|
this.stats.hp = Math.max(this.stats.hp, 0); |
|
if (this.stats.luck && this.type == 'hero') { |
|
if (this.stats.hp == 0 && Math.random() < this.stats.luck * 0.01) { |
|
this.stats.hp = 1; |
|
attackStr += ' ' + defenderName + ' was saved from certain death!'; |
|
}//very rare life-saving based on luck |
|
} |
|
} |
|
|
|
if (this.type == 'hero') attackStr = '<span style="color:#f99;">' + attackStr + '</span>'; |
|
if (attackStr != '') this.dungeon.Log(attackStr); |
|
|
|
if (this.stats.hp <= 0)//die |
|
{ |
|
this.dungeon.Log(attackerName + ' crushed ' + defenderName + '!'); |
|
if (this.type == 'hero') { |
|
Game.Heroes[this.subtype].Say('defeat'); |
|
this.dungeon.Log('<span style="color:#f66;">' + Game.Heroes[this.subtype].name + ' has been defeated.</span>'); |
|
this.dungeon.FailLevel(); |
|
} |
|
if (this.type == 'monster' && by.type == 'hero') { |
|
l('monsterSlot' + this.dungeon.id).style.visibility = 'hidden'; |
|
this.dungeon.monstersKilledThisRun += 1; |
|
if (Math.random() < 0.05) Game.Heroes[by.subtype].Say('win'); |
|
Game.Heroes[by.subtype].Say('win against ' + Game.Monsters[this.subtype].name); |
|
this.Say('defeat'); |
|
if (Game.Monsters[this.subtype].loot) { |
|
var loot = Game.Monsters[this.subtype].loot; |
|
if (loot.gear && (!loot.gear.prob || Math.random() < loot.gear.prob)) { |
|
}//drop gear |
|
if (loot.cookies && (!loot.cookies.prob || Math.random() < loot.cookies.prob)) { |
|
var entity = this.dungeon.AddEntity('item', 'cookies', this.x, this.y);//drop cookies |
|
entity.value = Math.round(loot.cookies.min + Math.random() * (loot.cookies.max - loot.cookies.min)); |
|
} |
|
} |
|
if (this.onKill) this.onKill(); |
|
this.Destroy(); |
|
} |
|
} |
|
} |
|
} |
|
this.Turn = function ()//do this every turn (walk around, heal up...) |
|
{ |
|
if (this.type == 'monster') { |
|
var howManyTurns = this.GetInitiative(); |
|
for (var i = 0; i < howManyTurns; i++) { |
|
if (1 == 1)//this.AI!='static') |
|
{ |
|
if (this.AI == 'flee') this.Flee(this.dungeon.heroEntity.x, this.dungeon.heroEntity.y);//flee from the player |
|
else { |
|
this.GoTo(this.dungeon.heroEntity.x, this.dungeon.heroEntity.y);//track the player |
|
if (this.stuck || this.targets.length == []) this.Wander();//can't reach the player? walk around randomly |
|
} |
|
} |
|
} |
|
} |
|
if (this.type == 'monster' || this.type == 'hero') { |
|
if (this.stuck > 0) this.stuck--; |
|
this.stuck = Math.min(10, this.stuck); |
|
this.targets = []; |
|
} |
|
if ((this.type == 'hero' || this.type == 'monster') && this.fighting == 0 && this.stats.hp < this.stats.hpm) this.stats.hp++;//heal up |
|
if (this.type == 'hero')//collect items and cookies |
|
{ |
|
var entities = this.dungeon.GetEntities(this.x, this.y); |
|
for (var i in entities) { |
|
if (entities[i].type == 'item' && entities[i].subtype == 'cookies') { |
|
var entity = entities[i]; |
|
var value = Math.ceil(entity.value * Game.Objects[this.dungeon.type].amount * 50 * (1 + Math.random() * ((this.stats.luck) / 20)));//temporary; scale with matching building CpS later |
|
if (value > 0) { |
|
this.dungeon.Log('<span style="color:#9f9;">Found <b>' + Beautify(value) + '</b> cookie' + (value == 1 ? '' : 's') + '!</span>'); |
|
this.dungeon.cookiesMadeThisRun += value; |
|
Game.Earn(value); |
|
} |
|
entity.Destroy(); |
|
} |
|
} |
|
} |
|
if (this.type == 'hero') this.fighting = 0; |
|
} |
|
this.Destroy = function () { |
|
this.dungeon.entities.splice(this.dungeon.entities.indexOf(this), 1); |
|
} |
|
this.GetInitiative = function () { |
|
return randomFloor((this.stats.speed / 5) * (1 / Math.max(1, (this.dungeon.heroEntity.stats.speed / 5)))); |
|
} |
|
} |
|
|
|
/*===================================================================================== |
|
DUNGEON MECHANICS |
|
=======================================================================================*/ |
|
|
|
Game.Dungeons = []; |
|
Game.Dungeon = function (type, id) { |
|
this.type = type; |
|
this.id = id; |
|
Game.Dungeons[this.id] = this; |
|
this.log = []; |
|
this.logNew = 0; |
|
this.name = Game.DungeonTypes[this.type].nameGenerator(); |
|
this.hero = null; |
|
this.currentOpponent = 0; |
|
this.level = 0; |
|
this.auto = 1; |
|
this.portalPic = ''; |
|
|
|
this.cookiesMadeThisRun = 0; |
|
this.monstersKilledThisRun = 0; |
|
|
|
this.Log = function (what, nested) { |
|
if (typeof what === 'string') { |
|
this.log.unshift(what); |
|
this.logNew++; |
|
} |
|
else { |
|
for (var i in what) { |
|
this.Log(what[i], 1); |
|
} |
|
} |
|
//if (!nested) this.UpdateLog(); |
|
} |
|
|
|
this.UpdateLog = function () { |
|
this.log = this.log.slice(0, 30); |
|
var str = ''; |
|
for (var i in this.log) { |
|
if (i < this.logNew) str += '<div class="new">' + this.log[i] + '</div>'; |
|
else str += '<div>' + this.log[i] + '</div>'; |
|
} |
|
this.logNew = 0; |
|
l('dungeonLog' + this.id).innerHTML = str; |
|
} |
|
|
|
this.entities = []; |
|
this.GetEntities = function (x, y)//returns the first entity found on tile x,y |
|
{ |
|
var entities = []; |
|
for (var i in this.entities) { |
|
if (this.entities[i].x == x && this.entities[i].y == y) entities.push(this.entities[i]); |
|
} |
|
return entities; |
|
} |
|
this.AddEntity = function (type, subtype, x, y) { |
|
//this.RemoveEntities(x,y); |
|
var entity = new Game.Entity(type, subtype, this); |
|
entity.x = x; |
|
entity.y = y; |
|
entity.dungeon = this; |
|
this.entities.push(entity); |
|
return entity; |
|
} |
|
this.RemoveEntities = function (x, y) { |
|
var entities = this.GetEntities(x, y); |
|
for (var i in entities) { |
|
entities[i].Destroy(); |
|
} |
|
} |
|
this.DrawEntities = function () { |
|
var str = ''; |
|
for (var i in this.entities) { |
|
str += this.entities[i].Draw(); |
|
} |
|
return str; |
|
} |
|
|
|
this.CheckObstacle = function (x, y)//returns 0 for no obstacle; -1 for a wall; an entity if there's at least one entity on this tile |
|
{ |
|
if (x < 0 || x >= this.map.w || y < 0 || y >= this.map.h) return -1; |
|
var entities = this.GetEntities(x, y); |
|
for (var i in entities) { |
|
if (entities[i].obstacle) return entities[i]; |
|
} |
|
return this.map.isObstacle(x, y) ? -1 : 0; |
|
} |
|
|
|
|
|
this.map = {}; |
|
this.Generate = function () { |
|
if (this.level == 0) this.name = Game.DungeonTypes[this.type].nameGenerator(); |
|
this.entities = []; |
|
var Gerald = new M.dungeonGen.Map(40, 40, Math.random(), { |
|
roomSize: 10, |
|
corridorSize: 5, |
|
fillRatio: 1 / 2, |
|
corridorRatio: 0.3, |
|
pillarRatio: Math.random() * 0.8 + 0.2, |
|
waterRatio: Math.random(), |
|
branching: Math.ceil(Math.random() * 6), |
|
sizeVariance: 0.4 |
|
}); |
|
r = 0; |
|
while (r != 1) { |
|
r = Gerald.dig(); |
|
} |
|
//all done! decorate and render. |
|
Gerald.finish(); |
|
//spawn treasure |
|
/* |
|
for (var i in M.rooms) |
|
{ |
|
if (M.rooms[i].freeTiles>1) |
|
{ |
|
for (var ii=0;ii<Math.ceil(Math.sqrt(M.rooms[i].freeTiles*(M.rooms[i].gen*0.25+0.1))/2);ii++) |
|
{ |
|
if (Math.random()<0.95 && M.rooms[i].freeTiles>1) |
|
{ |
|
var spot=M.getBestSpotInRoom(M.rooms[i]); |
|
M.data[spot.x][spot.y][0]=0; |
|
spot.score=0; |
|
M.rooms[i].freeTiles--; |
|
} |
|
} |
|
} |
|
}*/ |
|
|
|
for (var i in Gerald.doors)//place door entities on door positions |
|
{ |
|
//M.data[M.doors[i][0]][M.doors[i][1]][0]=TILE_FLOOR_EDGE; |
|
this.AddEntity('destructible', 'door', Gerald.doors[i][0], Gerald.doors[i][1]); |
|
} |
|
//set tile graphics |
|
for (var i in Gerald.rooms) { |
|
var altStr = choose(['alt ', '', '']); |
|
var tiles = { |
|
'void': altStr + 'void', |
|
'wall': altStr + 'wall', |
|
'wall corner': altStr + 'wall corner', |
|
'floor': altStr + 'tiled floor', |
|
'floor edges': altStr + 'floor',//choose([altStr+'floor',altStr+'floor edges']), |
|
'door': altStr + 'door', |
|
'water': choose(['water', 'green water', 'dark water']), |
|
'pillar': choose([altStr + 'wall', altStr + 'round pillar', altStr + 'square pillar', altStr + 'potted plant', 'conveyor belt']), |
|
'entrance': altStr + 'entrance', |
|
'exit': altStr + 'exit', |
|
}; |
|
if (Math.random() < 0.1) { |
|
tiles['wall corner'] = 'wooden wall'; |
|
tiles['wall'] = 'wooden wall'; |
|
tiles['floor edges'] = 'wooden floor'; |
|
tiles['pillar'] = 'wooden wall'; |
|
} |
|
if (Math.random() < 0.1) { |
|
tiles['wall corner'] = altStr + 'bookshelf'; |
|
tiles['wall'] = altStr + 'bookshelf'; |
|
tiles['pillar'] = altStr + 'bookshelf'; |
|
} |
|
Gerald.assignTiles(Gerald.rooms[i], tiles); |
|
} |
|
this.map = Gerald; |
|
this.map.str = this.map.getStr(); |
|
|
|
//place a boss |
|
var tile = this.map.exit; |
|
var monsters = []; |
|
for (var ii in Game.BossMonsters) { |
|
var me = Game.BossMonsters[ii]; |
|
if (me.level <= (depth + this.level) && Math.random() < (me.stats.rarity || 1)) monsters.push(me.name); |
|
} |
|
if (monsters.length == 0) monsters = [choose(Game.BossMonsters).name]; |
|
if (monsters.length > 0) { |
|
this.AddEntity('monster', choose(monsters), tile[0], tile[1]); |
|
this.map.removeFreeTile(tile[0], tile[1]); |
|
} |
|
|
|
//place relics |
|
/* |
|
var tile=this.map.getBestSpotInRoom(this.map.getRoom(this.map.exit[0],this.map.exit[1])); |
|
var entity=this.AddEntity('special','upgrade',tile.x,tile.y); |
|
entity.value='Dungeon cookie upgrade'; |
|
this.map.removeFreeTile(tile.x,tile.y); |
|
for (var i=0;i<Math.floor(Math.pow(Math.random(),2)*3);i++) |
|
{ |
|
var room=choose(this.map.rooms); |
|
if (room.freeTiles.length>10) |
|
{ |
|
var tile=this.map.getBestSpotInRoom(room); |
|
var entity=this.AddEntity('special','upgrade',tile.x,tile.y); |
|
entity.value='Dungeon cookie upgrade'; |
|
this.map.removeFreeTile(tile.x,tile.y); |
|
} |
|
}*/ |
|
|
|
//sprinkle monsters and treasure |
|
for (var i = 0; i < Math.ceil(this.map.freeTiles.length * 0.7); i++)//let's fill this up with A LOT of stuff |
|
{ |
|
var tile = choose(this.map.freeTiles); |
|
if (tile != -1) { |
|
var room = this.map.getRoom(tile[0], tile[1]); |
|
var depth = room.gen + 1; |
|
if (Math.random() < 0.2)//2 in 10 spawns are monsters |
|
{ |
|
var monsters = []; |
|
for (var ii in Game.Monsters) { |
|
var me = Game.Monsters[ii]; |
|
if (me.level != 0 && me.level <= (depth + this.level) && Math.random() < (me.stats.rarity || 1)) monsters.push(me.name);//spawn type depending on monster level and rarity |
|
} |
|
if (monsters.length > 0) { |
|
this.AddEntity('monster', choose(monsters), tile[0], tile[1]); |
|
this.map.removeFreeTile(tile[0], tile[1]); |
|
} |
|
} |
|
else//the rest of the spawns are destructibles or loot |
|
{ |
|
if (Math.random() < 0.6) { |
|
var value = Math.round(Math.pow(Math.random(), 6) * (10 + this.level)); |
|
if (value > 0) { |
|
var entity = this.AddEntity('item', 'cookies', tile[0], tile[1]);//random cookies |
|
entity.value = value; |
|
} |
|
} |
|
else this.AddEntity('destructible', 'random', tile[0], tile[1]);//random crates etc |
|
this.map.removeFreeTile(tile[0], tile[1]); |
|
} |
|
} |
|
} |
|
} |
|
|
|
this.onTile = -1; |
|
|
|
this.Draw = function () { |
|
var str = ''; |
|
var x = -this.hero.x; |
|
var y = -this.hero.y; |
|
str += '<div id="map' + this.id + '" class="map" style="width:' + (9 * 16) + 'px;height:' + (9 * 16) + 'px;"><div class="mapContainer" id="mapcontainer' + this.id + '" style="position:absolute;left:' + (x * 16) + 'px;top:' + (y * 16) + 'px;"><div id="mapitems' + this.id + '"></div>' + this.map.str + '</div></div>'; |
|
str += '<div style="position:absolute;left:' + (9 * 16 + 16) + 'px;">' + |
|
'<a class="control west" onclick="Game.HeroesById[' + this.hero.id + '].Move(-1,0);"></a><br>' + |
|
'<a class="control east" onclick="Game.HeroesById[' + this.hero.id + '].Move(1,0);"></a><br>' + |
|
'<a class="control north" onclick="Game.HeroesById[' + this.hero.id + '].Move(0,-1);"></a><br>' + |
|
'<a class="control south" onclick="Game.HeroesById[' + this.hero.id + '].Move(0,1);"></a><br>' + |
|
'<a class="control middle" onclick="Game.HeroesById[' + this.hero.id + '].Move(0,0);"></a><br>' + |
|
'</div>'; |
|
str += '<div style="position:absolute;left:' + (9 * 16 + 16 + 48 * 3) + 'px;bottom:16px;height:100%;">' + |
|
'<div class="dungeonName"><a onclick="Game.ObjectsById[' + this.id + '].setSpecial(0);">Exit</a> - <span class="title" style="font-size:12px;">' + this.name + '</span> lvl.' + (this.level + 1) + '</div>' + |
|
'<div id="heroSlot' + this.id + '" class="mobSlot"><div id="picHero' + this.id + '" class="mobPic"></div><div id="nameHero' + this.id + '" class="title mobName"></div><div class="hpmBar"><div id="hpHero' + this.id + '" class="hpBar"></div></div></div>' + |
|
'<div id="monsterSlot' + this.id + '" class="mobSlot" style="left:128px;"><div id="picMonster' + this.id + '" class="mobPic"></div><div id="nameMonster' + this.id + '" class="title mobName"></div><div class="hpmBar"><div id="hpMonster' + this.id + '" class="hpBar"></div></div></div>' + |
|
'</div>' + |
|
'<div id="dungeonLog' + this.id + '" class="dungeonLog"></div>'; |
|
l('rowSpecial' + this.id).innerHTML = '<div style="width:100%;height:100%;z-index:10000;position:absolute;left:0px;top:0px;">' + str + '</div>'; |
|
|
|
l('picHero' + this.id).style.backgroundImage = 'url(img/' + this.hero.portrait + '.png)'; |
|
l('nameHero' + this.id).innerHTML = this.hero.name; |
|
} |
|
this.Refresh = function () { |
|
if (!l('mapcontainer' + this.id)) this.Draw(); |
|
var x = 4 - this.hero.x; |
|
var y = 4 - this.hero.y; |
|
l('mapcontainer' + this.id).style.left = (x * 16) + 'px'; |
|
l('mapcontainer' + this.id).style.top = (y * 16) + 'px'; |
|
l('mapitems' + this.id).innerHTML = this.DrawEntities(); |
|
} |
|
this.RedrawMap = function () { |
|
this.map.str = this.map.getStr(); |
|
this.Draw(); |
|
} |
|
this.Turn = function () { |
|
for (var i in this.entities) { |
|
if (this.entities[i] && this.entities[i].type) this.entities[i].Turn(); |
|
} |
|
if (this.currentOpponent) { |
|
l('monsterSlot' + this.id).style.visibility = 'visible'; |
|
l('hpMonster' + this.id).style.width = Math.round((this.currentOpponent.stats.hp / this.currentOpponent.stats.hpm) * 100) + '%'; |
|
l('picMonster' + this.id).style.backgroundImage = 'url(img/' + Game.Monsters[this.currentOpponent.subtype].pic + '.png)'; |
|
l('nameMonster' + this.id).innerHTML = Game.Monsters[this.currentOpponent.subtype].name; |
|
l('picHero' + this.id).style.backgroundImage = 'url(img/' + this.hero.pic + '.png)'; |
|
} |
|
else { |
|
l('monsterSlot' + this.id).style.visibility = 'hidden'; |
|
l('hpMonster' + this.id).style.width = '100%'; |
|
l('picHero' + this.id).style.backgroundImage = 'url(img/' + this.hero.portrait + '.png)'; |
|
} |
|
this.currentOpponent = 0; |
|
l('hpHero' + this.id).style.width = Math.round((this.heroEntity.stats.hp / this.heroEntity.stats.hpm) * 100) + '%'; |
|
|
|
this.Refresh(); |
|
this.UpdateLog(); |
|
|
|
if (this.hero.x == this.map.exit[0] && this.hero.y == this.map.exit[1]) { |
|
this.CompleteLevel(); |
|
} |
|
} |
|
|
|
this.DrawButton = function () { |
|
var str = ''; |
|
//str+='<div style="text-align:center;margin:48px auto;color:#999;"><a onclick="Game.ObjectsById['+this.id+'].setSpecial(1);">Enter</a></div>'; |
|
str += '<div style="width:144px;height:144px;position:absolute;left:0px;bottom:0px;"><a class="specialButtonPic" style="background-image:url(img/' + this.portalPic + '.png);" onclick="Game.ObjectsById[' + this.id + '].setSpecial(1);"><div class="specialButtonText">Enter dungeons</div></a></div>'; |
|
return str; |
|
} |
|
|
|
this.CompleteLevel = function () { |
|
this.hero.Say('completion'); |
|
this.level++; |
|
this.Generate(); |
|
Game.HeroesById[0].EnterDungeon(this, this.map.entrance[0], this.map.entrance[1]); |
|
this.Draw(); |
|
} |
|
this.FailLevel = function () { |
|
this.Log('Cookies made this run : ' + Beautify(this.cookiesMadeThisRun) + ' | Monsters defeated this run : ' + Beautify(this.monstersKilledThisRun)); |
|
this.cookiesMadeThisRun = 0; |
|
this.monstersKilledThisRun = 0; |
|
this.level = 0; |
|
this.Generate(); |
|
Game.HeroesById[0].EnterDungeon(this, this.map.entrance[0], this.map.entrance[1]); |
|
this.Draw(); |
|
} |
|
} |
|
|
|
Game.DungeonLocationChain = function (map, x, y)//return an array of the rooms between the root room and this tile's room, inclusive |
|
{//we shouldn't need all this if we used A*... |
|
var room = map.getRoom(x, y); |
|
var chain = []; |
|
if (room != -1) { |
|
while (room.parent) { |
|
chain.push(room); |
|
room = room.parent; |
|
} |
|
} |
|
chain.reverse(); |
|
return chain; |
|
} |
|
Game.DungeonLinkLocationChains = function (start, end)//return the room in which the first location chain should go to to get closer to the second location chain |
|
{ |
|
/* |
|
4 cases |
|
-we're already in the same room |
|
-the target is in a different branch |
|
-the target is above in the same branch |
|
-the target is below in the same branch |
|
*/ |
|
start.reverse(); |
|
end.reverse(); |
|
if (start[0].id == end[0].id) return start[start.length - 1];//same room |
|
for (var i in end) { |
|
if (start[0] == end[i].parent) return end[i];//inferior branch, go to the inferior room |
|
} |
|
if (start.length > 1) return start[1];//different or superior branch, go to the superior room |
|
return start[0];//eeeh, let's just stay in the same room |
|
} |
|
|
|
/*===================================================================================== |
|
CREATE DUNGEONS |
|
=======================================================================================*/ |
|
Game.Objects['Factory'].special = function () { |
|
M.dungeon = new Game.Dungeon('Factory', M.parent.id); |
|
M.dungeon.Generate(); |
|
M.specialDrawFunction = function () { |
|
this.dungeon.Refresh(); |
|
}; |
|
M.drawSpecialButton = function () { |
|
return this.dungeon.DrawButton(); |
|
}; |
|
M.dungeon.timer = 0; |
|
M.dungeon.timerWarmup = 5; |
|
M.dungeon.portalPic = 'dungeonFactory'; |
|
|
|
M.EachFrame = function () { |
|
if (M.dungeon.auto) { |
|
if (M.dungeon.timer > 0) M.dungeon.timer--; |
|
if (M.dungeon.timer == 0) { |
|
M.dungeon.timer = Game.fps * (Math.max(0.1, 2 - (M.dungeon.hero.stats.speed * 0.2)) + Math.max(M.dungeon.timerWarmup, 0)); |
|
if (M.dungeon.timerWarmup > 0) M.dungeon.timerWarmup--; |
|
|
|
var dungeon = M.dungeon; |
|
var hero = dungeon.heroEntity; |
|
|
|
var targetRoom = Game.DungeonLinkLocationChains(Game.DungeonLocationChain(dungeon.map, hero.x, hero.y), Game.DungeonLocationChain(dungeon.map, dungeon.map.exit[0], dungeon.map.exit[1])); |
|
var targetTile = (targetRoom.gen == 0 || targetRoom.id == dungeon.map.getRoom(hero.x, hero.y).id) ? [dungeon.map.exit[0], dungeon.map.exit[1]] : targetRoom.door; |
|
hero.GoTo(targetTile[0], targetTile[1]); |
|
if (hero.stuck) hero.Wander(); |
|
dungeon.hero.x = hero.x; |
|
dungeon.hero.y = hero.y; |
|
dungeon.Turn(); |
|
} |
|
} |
|
} |
|
|
|
if (document.addEventListener)//clean this up later |
|
{ |
|
l('rowSpecial' + M.dungeon.id).removeEventListener('keydown', arguments.callee, false); |
|
l('rowSpecial' + M.dungeon.id).addEventListener('keydown', function (event) { |
|
var dungeon = Game.Objects['Factory'].dungeon; |
|
var control = 0; |
|
if (event.keyCode == 37) { |
|
dungeon.hero.Move(-1, 0); |
|
control = 1; |
|
} |
|
else if (event.keyCode == 38) { |
|
dungeon.hero.Move(0, -1); |
|
control = 1; |
|
} |
|
else if (event.keyCode == 39) { |
|
dungeon.hero.Move(1, 0); |
|
control = 1; |
|
} |
|
else if (event.keyCode == 40) { |
|
dungeon.hero.Move(0, 1); |
|
control = 1; |
|
} |
|
else if (event.keyCode == 32) { |
|
dungeon.hero.Move(0, 0); |
|
control = 1; |
|
}//space |
|
else if (event.keyCode == 65)//A (auto) |
|
{ |
|
if (dungeon.auto) { |
|
dungeon.auto = 0; |
|
dungeon.timerWarmup = -1; |
|
} |
|
else { |
|
dungeon.auto = 1; |
|
dungeon.timer = 0; |
|
dungeon.timerWarmup = 0; |
|
} |
|
event.preventDefault(); |
|
} |
|
|
|
if (control) { |
|
event.preventDefault(); |
|
dungeon.timer = Game.fps * 10; |
|
dungeon.timerWarmup = 5; |
|
} |
|
} |
|
); |
|
} |
|
|
|
var hero = choose(Game.HeroesById); |
|
hero.EnterDungeon(this.dungeon, this.dungeon.map.entrance[0], this.dungeon.map.entrance[1]); |
|
} |
|
|
|
/*===================================================================================== |
|
HEROES |
|
=======================================================================================*/ |
|
Game.Heroes = []; |
|
Game.HeroesById = []; |
|
Game.Hero = function (name, pic, portrait, icon) { |
|
this.name = name; |
|
this.pic = pic; |
|
this.portrait = portrait; |
|
this.icon = icon; |
|
this.stats = { |
|
hp: 25, |
|
hpm: 25, |
|
might: 5, |
|
guard: 5, |
|
speed: 5, |
|
dodge: 5, |
|
luck: 5 |
|
}; |
|
this.dialogue = { |
|
'greeting': 'Oh hey.|Sup.', |
|
'entrance': 'Here we go.|So exciting.', |
|
'completion': 'That was easy.|All done here.', |
|
'defeat': 'Welp.|Better luck next time.' |
|
}; |
|
this.gear = { |
|
'armor': -1, |
|
'weapon': -1 |
|
}; |
|
this.inDungeon = -1; |
|
this.completedDungeons = 0; |
|
|
|
this.x = 0; |
|
this.y = 0; |
|
|
|
this.EnterDungeon = function (dungeon, x, y) { |
|
this.inDungeon = dungeon.id; |
|
dungeon.hero = this; |
|
this.x = x; |
|
this.y = y; |
|
dungeon.heroEntity = dungeon.AddEntity('hero', dungeon.hero.name, x, y); |
|
var room = dungeon.map.getRoom(this.x, this.y); |
|
if (room != -1 && room.hidden) { |
|
room.hidden = 0; |
|
dungeon.RedrawMap(); |
|
} |
|
Game.Dungeons[this.inDungeon].Refresh(); |
|
dungeon.Log('--------------------'); |
|
if (dungeon.level == 0) this.Say('greeting'); |
|
this.Say('entrance'); |
|
l('monsterSlot' + dungeon.id).style.visibility = 'hidden'; |
|
} |
|
this.Move = function (x, y) { |
|
var dungeon = Game.Dungeons[this.inDungeon]; |
|
dungeon.heroEntity.targets = [[x, y]]; |
|
if (dungeon.heroEntity.Move()) { |
|
this.x = dungeon.heroEntity.x; |
|
this.y = dungeon.heroEntity.y; |
|
dungeon.Turn(); |
|
} |
|
} |
|
|
|
this.Say = function (what) { |
|
if (this.dialogue[what]) Game.Dungeons[this.inDungeon].Log(this.name + ' : "<span style="color:#99f;">' + choose(this.dialogue[what].split('|')) + '</span>"'); |
|
} |
|
|
|
this.save = function () { |
|
var str = ''; |
|
str += |
|
this.inDungeon + ',' + |
|
this.completedDungeons + ',' + |
|
this.gear.armor + ',' + |
|
this.gear.weapon |
|
; |
|
return str; |
|
} |
|
this.load = function (data) { |
|
var str = data.split(','); |
|
this.inDungeon = parseInt(str[0]); |
|
this.completedDungeons = parseInt(str[1]); |
|
this.gear.armor = parseInt(str[2]); |
|
this.gear.weapon = parseInt(str[3]); |
|
} |
|
this.id = Game.HeroesById.length; |
|
Game.HeroesById.push(this); |
|
Game.Heroes[this.name] = this; |
|
} |
|
|
|
/*===================================================================================== |
|
CREATE HEROES |
|
=======================================================================================*/ |
|
var hero = new Game.Hero('Chip', 'girlscoutChip', 'portraitChip', [1, 0]); |
|
hero.dialogue = { |
|
'intro': 'I\'m Chip! I just really like exploring stuff. Let\'s go have an adventure!', |
|
'greeting': 'Hello there!|I\'m ready!|Where are we going today?|Adventure!', |
|
'win': 'Take that!|Hah!|That\'s right.', |
|
'entrance': 'Chipping in!|Welp, here goes nothing!|I wonder what I\'ll find!|Hey, this place is new!|This place seems familiar.|Let\'s make it happen.', |
|
'completion': 'I\'m one smart cookie.|Oh yeah!|Let\'s explore some more!|That was easy!|That sure was fun!|I\'m not lost, am I?|More exploring? Sure, why not!', |
|
'defeat': 'B-better luck next time.|That really hurt!|I yield! I yield!|That went badly.|No half-baked excuses next time.|I think I scraped my knee!|Owie.|Woopsie!', |
|
'win against Sentient Furnace': 'The irony, it burns! (...it\'s funny because it was burning. And made of iron. ...Moving on.)', |
|
'win against Ascended Baking Pod': 'Where is your pod now?|That was disturbing.' |
|
}; |
|
hero.stats = { |
|
hp: 30, |
|
hpm: 30, |
|
might: 5, |
|
guard: 5, |
|
speed: 5, |
|
dodge: 5, |
|
luck: 5 |
|
}; |
|
var hero = new Game.Hero('Crumb', 'girlscoutCrumb', 'portraitCrumb', [2, 0]); |
|
hero.dialogue = { |
|
'intro': 'I\'m Crumb. I look like this because of a baking accident when I was little. Big deal. At least now I don\'t get hurt as easily as others, I guess.', |
|
'greeting': 'Hi there.|Ready for adventure, I guess.|Reporting for duty.', |
|
'win': 'Oh sorry, did that hurt?|Should have moved out of the way.|Oops. My bad.', |
|
'entrance': 'Let\'s do this, I guess.|Well, let\'s go...|I gotta go in there?|Are we really doing this?|I hope I won\'t get lost like last time.|Let\'s get this over with.', |
|
'completion': 'I... I did it...|I\'m glad that\'s over.|What, there\'s more?|In I go, I guess.|It doesn\'t end, does it?|But it\'s dark in there.', |
|
'defeat': 'I, uh, ouch.|Why does that always happen to me?|I\'m just no good, am I?|Oh no.|I\'m... I\'m not crying.|Well that wasn\'t fun at all.|I\'m sorry I failed you.|Please... make them go away...', |
|
'meet Ascended Baking Pod': 'That thing shouldn\'t even be alive.|Is that where they all came from?', |
|
'win against Ascended Baking Pod': 'Hm. Fascinating.' |
|
}; |
|
hero.stats = { |
|
hp: 25, |
|
hpm: 25, |
|
might: 5, |
|
guard: 7, |
|
speed: 4, |
|
dodge: 4, |
|
luck: 5 |
|
}; |
|
var hero = new Game.Hero('Doe', 'girlscoutDoe', 'portraitDoe', [3, 0]); |
|
hero.dialogue = { |
|
'intro': 'H-hey. Name\'s Doe. I\'m pretty fast. I uh, I promise I\'ll do my best.', |
|
'greeting': 'H-hey.|Oh, uh, h-hi there.|C-can I join?', |
|
'win': 'Th-that looks like it hurt... awesome...|D-did I do that?|N-neat... there\'s pieces everywhere.', |
|
'entrance': 'Alright, let\'s do this!|I-if I really have to.|I-in there? By myself?|...won\'t you come with me this time?|H-here I go!', |
|
'completion': 'Oh... oh my.|That\'s... I uh, I\'m glad.|Y-yeah that was real easy. Piece of pie!|T-too easy, right?|S-so many cookies...|Ooh? F-fascinating.', |
|
'defeat': 'I-if you can\'t beat them... join them.|I-it\'s because I stutter, isn\'t it?|W-well that\'s just no good at all.|I, uh, I meant for that to happen.|H-how embarrassing.', |
|
'meet Ascended Baking Pod': 'W-whoah... it\'s... magnificent...', |
|
'win against Ascended Baking Pod': 'I\'m sorry, buddy.|I... I think I hurt it...|Oh no... I-I think I broke it...' |
|
}; |
|
hero.stats = { |
|
hp: 25, |
|
hpm: 25, |
|
might: 4, |
|
guard: 4, |
|
speed: 7, |
|
dodge: 5, |
|
luck: 5 |
|
}; |
|
var hero = new Game.Hero('Lucky', 'girlscoutLucky', 'portraitLucky', [4, 0]); |
|
hero.dialogue = { |
|
'intro': 'Oh joy! My name\'s Lucky. Guess what I\'m good at?', |
|
'greeting': 'I\'m feeling lucky!|It\'s a bright day today!|Let\'s do great things together.', |
|
'win': 'Ooh lucky shot!|Pow! One more.|Damn straight!', |
|
'entrance': 'Glad to be of service!|Oooh this one\'ll be interesting.|This will be a good one, I can feel it!|Here I come!', |
|
'completion': 'Over already?|Let\'s explore some more!|That was lucky!|That was no luck, I\'m just that good.|Alright, let\'s move on!|I\'m just getting warmed up!', |
|
'defeat': 'I can\'t believe it!|...This is a joke, right?|Hey! No fair!|B-but...|I\'m gonna need a bandaid. And some hot chocolate.|I\'ll, uh, try again later.|Bad luck! Bad luck!', |
|
'win against Ascended Baking Pod': 'Golly, that was peculiar.' |
|
}; |
|
hero.stats = { |
|
hp: 25, |
|
hpm: 25, |
|
might: 5, |
|
guard: 4, |
|
speed: 4, |
|
dodge: 5, |
|
luck: 7 |
|
}; |
|
|
|
|
|
var str = ''; |
|
// str += ''; |
|
// stringbuild our markup here |
|
div.innerHTML = str; |
|
|
|
M.dungeonGen = new Game.DungeonGen(); |
|
M.dungeonGen.loadTiles(M.dungeonTiles); |
|
|
|
Game.Objects['Factory'].special(); |
|
} |
|
M.save = function () { |
|
//output cannot use ",", ";" or "|" |
|
var str = ''; |
|
/* |
|
for (var i in M.slot) { |
|
str += parseFloat(M.slot[i]) + '/'; |
|
} |
|
str = str.slice(0, -1); |
|
str += ' ' + parseFloat(M.swaps) + ' ' + parseFloat(M.swapT);*/ |
|
return str; |
|
} |
|
M.load = function (str) { |
|
//interpret str; called after .init |
|
//note : not actually called in the Game's load; see "minigameSave" in main.js |
|
if (!str) return false; |
|
/*var i = 0; |
|
var spl = str.split(' '); |
|
var bit = spl[i++].split('/') || []; |
|
for (var ii in M.slot) { |
|
if (parseFloat(bit[ii]) != -1) { |
|
var god = M.godsById[parseFloat(bit[ii])]; |
|
M.slotGod(god, ii); |
|
l('templeSlot' + god.slot).appendChild(l('templeGod' + god.id)); |
|
} |
|
} |
|
M.swaps = parseFloat(spl[i++] || 3); |
|
M.swapT = parseFloat(spl[i++] || Date.now());*/ |
|
} |
|
M.reset = function () { |
|
// ??? |
|
} |
|
M.logic = function () { |
|
//run each frame |
|
M.dungeon.EachFrame(); |
|
} |
|
M.draw = function () { |
|
M.ourDiv.innerHTML = M.dungeon.Draw(); |
|
} |
|
M.init(l('rowSpecial' + M.parent.id)); |
|
} |
|
var M = 0; |