// javascript for make no wonder // initialize jQuery $(document).ready(function(){ /* setup */ // initialize variables var admin = { 'mini': true, // default true (shows minimap) 'fog': true, // default true (fog hides unexplored areas) 'warp': false, // default false (shows cursor info, click miniMap to warp) 'fly': false, // default false (unrestricted movement) 'free': false, // default false (no cost to build) 'heli': false // default false (helicopter at start) }; var start = { 'tile': {'x': false, 'y': false}, // set tile coordinates, or false for random 'i': { 'canoe': 0, 'map': 0, 'backpack': 0, 'pickaxe': 0, 'axe': 0, 'shovel': 0, 'boots': 0, 'radio': 0, 'binoculars': 0, 'wire': 0, 'rabbit': 0, 'fur': 0, 'bone': 0, 'ice': 0, 'shell': 0, 'slate': 0, 'quartz': 0, 'stone': 2, 'wood': 2, 'boughs': 2, 'birchbark': 0, 'charcoal': 0, 'berries': 0 } }; function Game() { this.mapSize = 2048; this.mapFraction = 16; this.tileSize = 16; this.loopRate = 40; // 50 = 20fps, 40 = 25fps; 30 = 30fps; 25 = 40fps; use 50 or 40 this.softMap = true; // default true this.miniMapTrees = false; // default false this.mapCanvasW = 624; // should match 'normal' size option this.mapCanvasH = 624; this.mapCanvasTileW = this.mapCanvasW / this.tileSize; this.mapCanvasTileH = this.mapCanvasH / this.tileSize; this.mapCanvasHalfTiles = this.mapCanvasTileW/2; // if view area is odd number of tiles wide and high (game.mapCanvasTileW%2 is 0 if even number of tiles, 1 if odd number of tiles) if (this.mapCanvasTileW%2) { this.mapCanvasHalfTiles = this.mapCanvasHalfTiles - 0.5; } this.mapTileMultiplier = this.tileSize / this.mapFraction; // 1, 2, 4, 8 this.mapTileSquare = this.mapTileMultiplier*this.mapTileMultiplier; // 1, 4, 16, 64 this.mapTileCount = this.mapSize/this.mapFraction; // 128 (0-127), 256 (0-255), etc. this.mapTileMax = this.mapTileCount-1; // 127, 255, etc. this.miniMapVisW = Math.round(this.mapCanvasTileW / this.mapTileMultiplier); this.miniMapVisH = Math.round(this.mapCanvasTileH / this.mapTileMultiplier); this.canvasMiniMapPx = 128; this.canvasMiniMapW = this.mapTileCount; // was 128 this.canvasMiniMapH = this.mapTileCount; // was 128 // small map: 128 x 128 if (this.mapFraction === 16) { this.roughness = 14; // roughness of map; higher generates more mountains & islands this.campVisionMiniAdjust = 1; // small adjustment to size of fog cleared around camps on miniMap, on small maps this.markerSize = 2; // size in pixels of you and markers on miniMap // normal map: 256 x 256 } else if (this.mapFraction === 8) { this.roughness = 23; this.campVisionMiniAdjust = 0; this.markerSize = 2; // large map: 512 x 512 } else if (this.mapFraction === 4) { this.roughness = 48; this.campVisionMiniAdjust = 0; this.markerSize = 2; // extra large map: 1024 x 1024 } else if (this.mapFraction === 2) { this.roughness = 65; this.campVisionMiniAdjust = 0; this.markerSize = 2; // huge map: 2048 x 2048 } else if (this.mapFraction === 1) { this.roughness = 88; this.campVisionMiniAdjust = 0; this.markerSize = 2; } }; var game = new Game(); var platformOffset = game.tileSize*1.5; var zip1OffsetX = game.tileSize*1.5; var zip1OffsetY = -game.tileSize/2; var zip2OffsetX = -2; var zip2OffsetY = game.tileSize-1; var zip3OffsetX = game.tileSize*3; var zip3OffsetY = game.tileSize-1; // define queries for later use, and declare global variables var $system = $('#system'); var $mapTerrain = $('#mapTerrain'); var $mapSprites = $('#mapSprites'); var $mapCover = $('#mapCover'); var $mapFog = $('#mapFog'); var $miniMap = $('#miniMap'); var $miniMapCanvas = $('#miniMapCanvas'); var $miniMapSprites = $('#miniMapSprites'); var $miniMapFog = $('#miniMapFog'); var $miniMapCursor = $('#miniMapCursor'); var $cursor = $('#cursor'); var $fader = $('#fader'); var $dimmer = $('#dimmer'); var $cancel = $('#cancel'); var $radio = $('#radio'); var $energyBar = $('#energyBar'); var $cursorInfo = $('#cursorInfo'); var $actions = $('#actions'); // make sure to also add new actions to mnw.php var $actionsGuide = $('#actionsGuide'); var $actionsItems = $('#actions li'); var $aHand = $('#aHand'); var $aBridge = $('#aBridge'); var $aFlag = $('#aFlag'); var $aSign = $('#aSign'); var $aSnare = $('#aSnare'); var $aCamp = $('#aCamp'); var $aRaft = $('#aRaft'); var $aCanoe = $('#aCanoe'); var $aLetter = $('#aLetter'); var $aPlatform = $('#aPlatform'); var $aZip = $('#aZip'); var $aRoof = $('#aRoof'); var $aQuarry = $('#aQuarry'); var $aPickaxe = $('#aPickaxe'); var $aAxe = $('#aAxe'); var $aShovel = $('#aShovel'); var $aFur = $('#aFur'); var $aBoots = $('#aBoots'); var $aRadio = $('#aRadio'); var $aLand = $('#aLand'); var $inventory = $('#inventory'); var $inventoryGuide = $('#inventoryGuide'); var $inventoryDiscard = $('#inventoryDiscard'); var $cacheInventoryBox = $('#cacheInventoryBox'); var $cacheInventoryLabel = $('#cacheInventoryLabel'); var $cacheInventoryDesc = $('#cacheInventoryDesc'); var $cacheInventory = $('#cacheInventory'); var $cacheInventoryGuide = $('#cacheInventoryGuide'); var $letterSelectionBox = $('#letterSelectionBox'); var $signInputBox = $('#signInputBox'); var canvasSprites = document.getElementById('mapSprites'); // used when copying to contextFader var canvasMiniMap = document.getElementById('miniMapCanvas'); var contextFader = document.getElementById('fader').getContext("2d"); var contextTerrain = document.getElementById('mapTerrain').getContext("2d"); var contextSprites = document.getElementById('mapSprites').getContext("2d"); var contextCover = document.getElementById('mapCover').getContext("2d"); var contextFog = document.getElementById('mapFog').getContext("2d"); var contextMiniMap = document.getElementById('miniMapCanvas').getContext("2d"); var contextMiniMapSprites = document.getElementById('miniMapSprites').getContext("2d"); var contextMiniMapFog = document.getElementById('miniMapFog').getContext("2d"); var contextMiniMapCursor = document.getElementById('miniMapCursor').getContext("2d"); // used for prerendering images var sprites1x1Image, sprites1x1, sprites1x2Image, sprites1x2, sprites2x2Image, sprites2x2, sprites3x2Image, sprites3x2, sprites3x3Image, sprites3x3, sprites9x3Image, sprites9x3, sprites9x6Image, sprites9x6, sprites15x10Image, sprites15x10; var miniMapPixel = contextMiniMap.createImageData(1,1), miniMapPixelData = miniMapPixel.data; // counters, switches, timers, arrays of tiles and objects var frameCount = 0, stepCount = 0, raftCounter = 0, canoeCounter = 0; var clearStatusTimer; var redrawTerrain = true, redrawFog = true, redrawMiniMapCursor = true; var radioFeed, radioRescue = false; var startTilesArray = []; var crashSiteTilesArray = []; var fieldStationTilesArray = []; var helicopterTilesArray = []; var startTreesArray = []; var startStonesArray = []; var newStonesArray = []; var newBerriesArray = []; var newShellsArray = []; var lettersArray = []; // objects instead of arrays, since we need to remove specific keys var objects = {}; var caches = {}; var rafts = {}; var canoes = {}; var helicopters = {}; var platforms = {}; var snares = {}; var holes = {}; var trees = {}; var fires = {}; // special walkable tiles var specialWalkable = [ 2.4, // cave 3.1, 3.2, 3.3, 3.4, // icebergs 4.20, 4.21, 4.22, 4.23, // crash site 6.004, // field station 6.104, 6.108, 6.109, 6.110, 6.111, 6.204, 6.208, 6.207, 6.209, 6.210, 6.211, 6.213, 6.303, 6.304, 6.306, 6.307, 6.308, 6.309, 6.310, 6.311, 6.312, 6.313, 6.314, 6.403, 6.404, 6.405, 6.406, 6.407, 6.408, 6.409, 6.410, 6.411, 6.412, 6.413, 6.414, 6.504, 6.506, 6.507, 6.508, 6.509, 6.510, 6.511, 6.512, 6.513, 6.514, 6.604, 6.606, 6.607, 6.608, 6.609, 6.610, 6.611, 6.612, 6.613, 6.614, 6.704, 6.706, 6.707, 6.708, 6.709, 6.710, 6.711, 6.712, 6.713, 6.714, 6.804, 6.810, 6.904, 6.905, 6.906, 6.907, 6.908, 6.909, 6.910, 6.911, 6.912, 6.913, 6.914, 6.915 ]; // player properties and states function Player() { this.tile = {'x': false, 'y': false}; this.walk = {'min': 0.55, 'max': 0.98}; // uses > min, <= max this.reach = 4.25; this.carry = {'now': 20, 'normal': 20, 'fromBackpack': 10}; // if onPlatform or onHelicopter vision changes, make sure radius doesn't extend outside small view size, else miniMapFog doesn't clear properly this.vision = {'normal': 100, 'fromBinoculars': 35, 'fromHighTerrain': 35, 'onBoat': -28, 'onPlatform': 160, 'onHelicopter': 160}; this.energy = {'now': 900, 'max': 900, 'fromBerries': 40, 'fromRabbit': 100}; this.status = { 'cold': false, 'active': 0, 'sleep': 1, 'buildingZip': false, 'buildingLetter': false, 'buildingSign': false, 'calledHelicopter': false, 'paused1': false, 'paused2': false }; this.on = {'water': false, 'cache': false, 'raft': false, 'canoe': false, 'platform': false, 'zip': false, 'helicopter': false} this.offset = game.tileSize/2; this.animating = {'sleep': 0, 'stand': 0}; this.updateCarry = function() { this.carry.now = this.carry.normal + (this.inventory.backpack.count*this.carry.fromBackpack); }; this.updateEnergy = function(energyChange) { energyChange = energyChange || 0; // sets default if parameter is undefined this.energy.now += energyChange; if (energyChange < 0 && this.status.cold) { this.energy.now += energyChange; } // if losing energy and cold, lose twice as much if (energyChange > 0 && !$energyBar.hasClass('increasing')) { $energyBar.addClass('increasing'); } // if gaining energy, animate energy bar if (this.energy.now > this.energy.max) { this.energy.now = this.energy.max; } else if (this.energy.now <= 0) { this.energy.now = 0; } var energyFraction = this.energy.now / this.energy.max; var newEnergyWidth = Math.round(energyBarWidth * energyFraction); // if energy level has changed, update css if (newEnergyWidth + 'px' !== $('#energyNow').width()) { if (energyFraction < 0.10) { $('#energyNow').css({'background-color': '#a34848', 'width': newEnergyWidth}); } else if (energyFraction < 0.25) { $('#energyNow').css({'background-color': '#d8625f', 'width': newEnergyWidth}); } else if (energyFraction < 0.50) { $('#energyNow').css({'background-color': '#db9460', 'width': newEnergyWidth}); } else if (energyFraction < 0.75) { $('#energyNow').css({'background-color': '#dbb760', 'width': newEnergyWidth}); } else { $('#energyNow').css({'background-color': '#dbda60', 'width': newEnergyWidth}); } } if (this.status.cold) { $('#energyBox').addClass('cold'); } else { $('#energyBox').removeClass('cold'); } }; this.getTerrain = function() { return mapArray[this.tile.x][this.tile.y]; }; this.getVisionRadius = function() { var vr = this.vision.normal; if (this.inventory.binoculars.count > 0) { vr += this.vision.fromBinoculars; } if (this.getTerrain() > 0.98 && this.getTerrain() <= 1) { vr += this.vision.fromHighTerrain; } if (this.on.raft || this.on.canoe) { vr += this.vision.onBoat; } if (this.on.platform) { vr = this.vision.normal+this.vision.onPlatform; } // binoculars or high terrain do not affect vision when on platform if (this.on.helicopter) { vr = this.vision.normal+this.vision.onHelicopter; } // binoculars or high terrain do not affect vision when on helicopter return vr; }; this.updateSleep = function() { // if not already asleep, in water, building zip or letter, on zip or on helicopter, chance to fall asleep if (this.status.sleep <= 0 && this.on.water === false && this.status.buildingZip === false && this.status.buildingLetter === false && this.status.buildingSign === false && this.on.zip === false && this.on.helicopter === false) { var sleepChance = randomBetween(0, 50); if (sleepChance === 1) { this.status.sleep++; // don't animate sleep when already animating if (this.status.sleep >= 1 && this.animating.sleep === 0) { this.animating.sleep = 3; } } } }; // two functions to pause control, so that two events can pause control without cancelling each other this.pause1 = function(interval) { if (you.status.paused1 === false) { you.status.paused1 = true; var pause1Timer = requestTimeout(function() { you.status.paused1 = false; }, interval); } }; this.pause2 = function(interval) { if (you.status.paused2 === false) { you.status.paused2 = true; var pause2Timer = requestTimeout(function() { you.status.paused2 = false; }, interval); } }; } var you = new Player(); // camps, caves, and other caches function Cache(type, description, carry, energy) { this.type = type; this.description = description; this.carry = carry; } function Camp(inventory) { this.inventory = inventory; this.vision = 275; // if this changes, make sure fog drawing buffer is the right size this.energy = {'now': 100, 'max': 100}; this.offset = game.tileSize; this.updateEnergy = function(energyChange) { energyChange = energyChange || 0; // sets default if parameter is undefined this.energy.now += energyChange; if (this.energy.now > this.energy.max) { this.energy.now = this.energy.max; } else if (this.energy.now <= 0) { this.energy.now = 0; } }; } Camp.prototype = new Cache('camp', 'Click items you are carrying to store them here. Camps also restore energy.', 25); function Cave(inventory) { this.inventory = inventory; } Cave.prototype = new Cache('cave', 'A small cave. You can stash items here.', 10); function Crash(inventory) { this.inventory = inventory; } Crash.prototype = new Cache('crash site', 'The cockpit is smashed and smells of smoke.', 15); function Cupboard(inventory) { this.inventory = inventory; } Cupboard.prototype = new Cache('crash site', 'The wooden cupboard is damp and moldy.', 10); function Quarry(inventory) { this.inventory = inventory; } Quarry.prototype = new Cache('quarry', 'Beneath the thin soil are many stones.', 20); // cursor function Cursor() { this.tile = {'x': false, 'y': false}; this.near = false; this.mode = 'hand'; this.offset; this.hide = function() { this.near = false; $cursor.hide(); $('body').css('cursor', 'crosshair'); }; } var cursor = new Cursor(); var mapOffsetX, mapOffsetY, drawOffsetX, drawOffsetY; var flagVision = 40; var platformVision = 400; var platformEnergy = 250; var energyBarWidth = 126; var inventoryItemHeight = 22; var stationX, stationY, stationW, stationH; var raftMoveMin = 0, raftMoveMax = 0.6; var canoeMoveMin = 0, canoeMoveMax = 0.6; var raftSplashLeft = 0, raftSplashRight = 0, raftSplashUp = 0, raftSplashDown = 0; var fogColor = '#36516f'; var miniMapFogColor = '#324b67'; var startTreeMin = 0.65, startTreeMax = 0.9; var newTreeMin = 0.61, newTreeMax = 0.95; var berriesMin = 0.69, berriesMax = 0.71; var shellMin = 0.45, shellMax = 0.55; // shallows var boneMin = 0.86, boneMax = 0.95; var startStoneMin = 0.56, startStoneMax = 0.98; var newStoneMin = 0.56, newStoneMax = 0.65; var stepStoneMin = 0.05, stepStoneMax = 0.55; // uses > min, <= max var stepStoneSink = 7000; var shovelTerrainMin = 0.55, shovelTerrainMax = 0.85; var pickaxeTerrainMin = 0.99, pickaxeTerrainMax = 1; // terrain values use > min, <= max var buildable = { 'bridge': {'cost': {'wood': 2}, 'terrain': {'min': 0, 'max': 0.55}, 'energy': 1, 'action': $aBridge}, 'flag': {'cost': {'birchbark': 1, 'berries': 1}, 'energy': 1, 'action': $aFlag}, 'sign': {'cost': {'birchbark': 1, 'charcoal': 1}, 'energy': 1, 'action': $aSign}, 'snare': {'cost': {'wire': 1, 'boughs': 1}, 'terrain': {'min': 0.55, 'max': 0.98}, 'energy': 1, 'action': $aSnare}, 'camp': {'cost': {'stone': 2, 'wood': 2, 'boughs': 2}, 'terrain': {'min': 0.55, 'max': 0.85}, 'energy': 1, 'action': $aCamp}, 'raft': {'cost': {'wood': 8}, 'terrain': {'min': 0.55, 'max': 0.6}, 'energy': 1, 'action': $aRaft}, 'canoe': {'cost': {'wood': 2, 'birchbark': 6}, 'terrain': {'min': 0.55, 'max': 0.6}, 'energy': 1, 'action': $aCanoe}, 'letter': {'cost': {'charcoal': 6}, 'terrain': {'min': 0.55, 'max': 0.98}, 'energy': 1, 'action': $aLetter}, 'platform': {'cost': {'wood': 6, 'boughs': 2}, 'terrain': {'min': 0.55, 'max': 0.98}, 'energy': 1, 'action': $aPlatform}, 'zip': {'cost': {'wire': 1, 'wood': 1}, 'energy': 1, 'action': $aZip}, 'roof': {'cost': {'slate': 6, 'wood': 2}, 'energy': 1, 'action': $aRoof}, 'quarry': {'cost': {'shovel': 1, 'wood': 4}, 'energy': 1, 'action': $aQuarry}, 'pickaxe': {'cost': {'bone': 1, 'wood': 1}, 'restriction': 'pickaxe', 'energy': 1, 'action': $aPickaxe}, 'axe': {'cost': {'slate': 1, 'wood': 1}, 'restriction': 'axe', 'energy': 1, 'action': $aAxe}, 'shovel': {'cost': {'shell': 1, 'wood': 1}, 'restriction': 'shovel', 'energy': 1, 'action': $aShovel}, 'fur': {'cost': {'rabbit': 1}, 'energy': 1, 'action': $aFur}, 'boots': {'cost': {'fur': 2, 'birchbark': 2}, 'restriction': 'boots', 'energy': 1, 'action': $aBoots}, 'radio': {'cost': {'wire': 1, 'shell': 1, 'quartz': 1}, 'restriction': 'radio', 'energy': 1, 'action': $aRadio} }; var wireAtFieldStation = randomOneOf([0, 1]); // used to randomize position of wire function Item(count, size, description, found) { this.count = count; this.size = size; // number of blocks taken up in inventory grid this.description = description; this.found = found; } function Inventory(canoe, map, backpack, pickaxe, axe, shovel, boots, radio, binoculars, wire, rabbit, fur, bone, ice, shell, slate, quartz, stone, wood, boughs, birchbark, charcoal, berries) { this.canoe = new Item(canoe, 3, 'It\'s a birchbark canoe. Place it on a sand tile to use it. You can click canoes to pick them up again.', ''); this.map = new Item(map, 1, 'It\'s a map of the area.', 'You found a map!'); this.backpack = new Item(backpack, 1, 'A backpack lets you carry more items.', 'You found a backpack!'); this.pickaxe = new Item(pickaxe, 1, 'An pickaxe lets you smash rocks.', 'You found a pickaxe!'); this.axe = new Item(axe, 1, 'An axe lets you cut down large trees.', 'You found an axe!'); this.shovel = new Item(shovel, 1, 'A shovel lets you dig holes.', 'You found a shovel!'); this.boots = new Item(boots, 1, 'Boots let you walk on higher terrain.', ''); this.radio = new Item(radio, 1, 'A makeshift crystal radio.', ''); this.binoculars = new Item(binoculars, 1, 'Binoculars increase view distance.', 'You found a pair of binoculars!'); this.wire = new Item(wire, 1, 'Wire is used to build snares and ziplines.', ''); this.rabbit = new Item(rabbit, 1, 'Rabbits are a source of energy and fur.', ''); this.fur = new Item(fur, 1, 'Fur can be used to make boots.', ''); this.bone = new Item(bone, 1, 'Bone is used to craft pickaxes.', ''); this.ice = new Item(ice, 1, 'Ice is used to erase charcoal marks.', ''); this.shell = new Item(shell, 1, 'Shells are used to craft shovels.', ''); this.slate = new Item(slate, 1, 'Slate is used to craft axes and build platform roofs.', ''); this.quartz = new Item(quartz, 1, 'Quartz can be used to craft a crystal radio.', ''); this.stone = new Item(stone, 1, 'Stone is used to place stepping stones, or build camps.', ''); this.wood = new Item(wood, 1, 'Wood is used to build camps, rafts, and other things.', ''); this.boughs = new Item(boughs, 1, 'Boughs are used to build snares, camps and platforms.', ''); this.birchbark = new Item(birchbark, 1, 'Birchbark is used to make canoes, flags and other things.', ''); this.charcoal = new Item(charcoal, 1, 'Charcoal is used to make marks.', ''); this.berries = new Item(berries, 1, 'Berries are a source of energy and are used to make flags.', ''); this.count = function() { var thisInventory = this; var inventoryCount = 0; for (var key in thisInventory) { if (key !== 'count') { // 'i' is used for cacheInventory items that never run out var addCount = thisInventory[key].count; if (addCount === 'i') { addCount = 1; } inventoryCount += addCount*thisInventory[key].size; } } return inventoryCount; }; } you.inventory = new Inventory( start.i.canoe, start.i.map, start.i.backpack, start.i.pickaxe, start.i.axe, start.i.shovel, start.i.boots, start.i.radio, start.i.binoculars, start.i.wire, start.i.rabbit, start.i.fur, start.i.bone, start.i.ice, start.i.shell, start.i.slate, start.i.quartz, start.i.stone, start.i.wood, start.i.boughs, start.i.birchbark, start.i.charcoal, start.i.berries ); you.updateCarry(); you.updateEnergy(); // build map and set css properties var drawLoop, mapArray, airArray; var mapData = multiDimensionalArray(game.mapSize+1, game.mapSize+1); var airData = multiDimensionalArray(game.mapSize+1, game.mapSize+1); $system.css({'width': game.mapCanvasW, 'height': game.mapCanvasH}); $dimmer.css({'width': game.mapCanvasW, 'height': game.mapCanvasH}); // important to set attributes for canvas elements, not css values $mapTerrain.attr({'width': game.mapCanvasW, 'height': game.mapCanvasH}); $mapSprites.attr({'width': game.mapCanvasW, 'height': game.mapCanvasH}); $mapCover.attr({'width': game.mapCanvasW, 'height': game.mapCanvasH}); $mapFog.attr({'width': game.mapCanvasW, 'height': game.mapCanvasH}); $fader.attr({'width': game.tileSize, 'height': game.tileSize}).css({'left': game.mapCanvasHalfTiles*game.tileSize, 'top': game.mapCanvasHalfTiles*game.tileSize}); $miniMap.css({'width': game.canvasMiniMapPx, 'height': game.canvasMiniMapPx}); $miniMapCanvas.attr({'width': game.canvasMiniMapPx, 'height': game.canvasMiniMapPx}); $miniMapSprites.attr({'width': game.canvasMiniMapPx, 'height': game.canvasMiniMapPx}); $miniMapFog.attr({'width': game.canvasMiniMapPx, 'height': game.canvasMiniMapPx}); $miniMapCursor.attr({'width': game.canvasMiniMapPx, 'height': game.canvasMiniMapPx}); // special admin conditions if (admin.warp) { $('#infoBox').show(); } if (!admin.mini) { $miniMap.css({'display': 'none'}); } if (!admin.fog) { $mapFog.css({'display': 'none'}); $miniMapFog.css({'display': 'none'}); } /* utility functions */ // timer for testing // see: http://addyosmani.com/blog/8-jquery-performance-tips/ function clockTime() { var time = new Date(); return time.getTime(); } var s = clockTime(); // insert somewhere to check script timing //console.log('Script executed in ' + (clockTime()-s) +'ms.'); // drop-down menus. $('#menuSwitchSize') .on('mouseenter', function(e) { $(this).children('ul').css("z-index", "50000").show(); }) .on('mouseleave', function(e) { $(this).children('ul').css("z-index", "50").hide(); }); // given a string, display status function status(string) { clearTimeout(clearStatusTimer); //$('#status').hide().text(string).fadeIn(400); $('#status').hide().text(string).show(0); } // clear status after given milliseconds (or default) function clearStatus(milliseconds) { milliseconds = milliseconds || 2500; // sets default if parameter is undefined clearStatusTimer = requestTimeout(function(){ $('#status').empty(); return false; }, milliseconds); } // given a minimum and maximum value, return a random integer function randomBetween(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // given an array of possible values, return a random value. function randomOneOf(possibilities) { return possibilities[Math.floor(possibilities.length*Math.random())] || false; } // given an object, return a random property // source: http://stackoverflow.com/questions/2532218/pick-random-property-from-a-javascript-object function randomProperty(obj) { var result, count = 0; for (var prop in obj) { if (Math.random() < 1/++count) { result = prop; } } return result; } // given two point objects {'x', 'y'}, return the distance between function getDistance(point1, point2) { var xd = point1.x - point2.x; var yd = point1.y - point2.y; var xy = Math.pow(xd, 2) + Math.pow(yd, 2); var distance = Math.round(Math.sqrt(xy)*100)/100; return distance; } /* map generation */ // see: http://www.somethinghitme.com/2009/12/06/terrain-generation-with-canvas-and-javascript/ // create a multi-dimensional array (don't need to fill array, just create it) function multiDimensionalArray(nRows, nCols) { var a = [nRows]; for (var i=0; i 1) { mapArray[x][y] = 1; } airArray[x][y] = Math.round(airData[x*game.mapFraction][y*game.mapFraction]*100)/100; } } // filter terrain to create islands instead of land ending at edges of map var trimTerrain1 = 0.8, trimTerrain2 = 0.3, trimTerrain3 = 0.2, trimTerrain4 = 0.1; for (var x=0; x 5 && y > 5 && x+15 < game.mapTileMax-5 && y+10 < game.mapTileMax-5 // and terrain is appropriate && mapArray[x][y] < you.walk.max && mapArray[x][y] > you.walk.min && mapArray[x+7][y] < you.walk.max && mapArray[x+7][y] > you.walk.min && mapArray[x+14][y] < you.walk.max && mapArray[x+14][y] > you.walk.min && mapArray[x+7][y+9] < you.walk.max && mapArray[x+7][y+9] > you.walk.min && mapArray[x+14][y+9] < you.walk.max && mapArray[x+14][y+9] > you.walk.min ) { fieldStationTilesArray.push({'x': x, 'y': y}); } // store possible helicopter tiles if ( // if within map limits x > 5 && y > 5 && x+9 < game.mapTileMax-5 && y+3 < game.mapTileMax-5 // and terrain is appropriate && mapArray[x+1][y+2] < you.walk.max && mapArray[x+1][y+2] > you.walk.min && mapArray[x+2][y+2] < you.walk.max && mapArray[x+2][y+2] > you.walk.min && mapArray[x+3][y+2] < you.walk.max && mapArray[x+3][y+2] > you.walk.min && mapArray[x+4][y+2] < you.walk.max && mapArray[x+4][y+2] > you.walk.min ) { helicopterTilesArray.push({'x': x, 'y': y}); } } } } // generate crash site if (crashSiteTilesArray.length) { var cS = randomOneOf(crashSiteTilesArray); mapArray[cS.x][cS.y] = 4.10; mapArray[cS.x+1][cS.y] = 4.11; mapArray[cS.x+2][cS.y] = 4.12; mapArray[cS.x+3][cS.y] = 4.13; mapArray[cS.x][cS.y+1] = 4.20; mapArray[cS.x+1][cS.y+1] = 4.21; mapArray[cS.x+2][cS.y+1] = 4.22; mapArray[cS.x+3][cS.y+1] = 4.23; var cacheId = 'X'+(cS.x+2)+'Y'+cS.y; objects[cacheId] = {'type': 'crash', 'x': (cS.x+2), 'y': cS.y}; if (wireAtFieldStation) { var crashInventory = new Inventory(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // backpack } else { var crashInventory = new Inventory(0, 0, 1, 0, 0, 0, 0, 0, 0, 'i', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // backpack, infinite wire } caches[cacheId] = new Crash(crashInventory); miniMapMarker(cS.x, cS.y, 'yellow'); } // generate field station if (fieldStationTilesArray.length) { var fS = randomOneOf(fieldStationTilesArray); // row 1 mapArray[fS.x][fS.y] = 6.001; mapArray[fS.x+1][fS.y] = 6.002; mapArray[fS.x+2][fS.y] = 6.003; mapArray[fS.x+3][fS.y] = 6.004; mapArray[fS.x+4][fS.y] = 6.005; mapArray[fS.x+5][fS.y] = 6.006; mapArray[fS.x+6][fS.y] = 6.007; mapArray[fS.x+7][fS.y] = 6.008; mapArray[fS.x+8][fS.y] = 6.009; mapArray[fS.x+9][fS.y] = 6.010; mapArray[fS.x+10][fS.y] = 6.011; mapArray[fS.x+11][fS.y] = 6.012; mapArray[fS.x+12][fS.y] = 6.013; mapArray[fS.x+13][fS.y] = 6.014; mapArray[fS.x+14][fS.y] = 6.015; // row 2 mapArray[fS.x][fS.y+1] = 6.101; mapArray[fS.x+1][fS.y+1] = 6.102; mapArray[fS.x+2][fS.y+1] = 6.103; mapArray[fS.x+3][fS.y+1] = 6.104; mapArray[fS.x+4][fS.y+1] = 6.105; mapArray[fS.x+5][fS.y+1] = 6.106; mapArray[fS.x+6][fS.y+1] = 6.107; mapArray[fS.x+7][fS.y+1] = 6.108; mapArray[fS.x+8][fS.y+1] = 6.109; mapArray[fS.x+9][fS.y+1] = 6.110; mapArray[fS.x+10][fS.y+1] = 6.111; mapArray[fS.x+11][fS.y+1] = 6.112; mapArray[fS.x+12][fS.y+1] = 6.113; mapArray[fS.x+13][fS.y+1] = 6.114; mapArray[fS.x+14][fS.y+1] = 6.115; // row 3 mapArray[fS.x][fS.y+2] = 6.201; mapArray[fS.x+1][fS.y+2] = 6.202; mapArray[fS.x+2][fS.y+2] = 6.203; mapArray[fS.x+3][fS.y+2] = 6.204; mapArray[fS.x+4][fS.y+2] = 6.205; mapArray[fS.x+5][fS.y+2] = 6.206; mapArray[fS.x+6][fS.y+2] = 6.207; mapArray[fS.x+7][fS.y+2] = 6.208; mapArray[fS.x+8][fS.y+2] = 6.209; mapArray[fS.x+9][fS.y+2] = 6.210; mapArray[fS.x+10][fS.y+2] = 6.211; mapArray[fS.x+11][fS.y+2] = 6.212; mapArray[fS.x+12][fS.y+2] = 6.213; mapArray[fS.x+13][fS.y+2] = 6.214; mapArray[fS.x+14][fS.y+2] = 6.215; // row 4 mapArray[fS.x+2][fS.y+3] = 6.303; mapArray[fS.x+3][fS.y+3] = 6.304; mapArray[fS.x+4][fS.y+3] = 6.305; mapArray[fS.x+5][fS.y+3] = 6.306; mapArray[fS.x+6][fS.y+3] = 6.307; mapArray[fS.x+7][fS.y+3] = 6.308; mapArray[fS.x+8][fS.y+3] = 6.309; mapArray[fS.x+9][fS.y+3] = 6.310; mapArray[fS.x+10][fS.y+3] = 6.311; mapArray[fS.x+11][fS.y+3] = 6.312; mapArray[fS.x+12][fS.y+3] = 6.313; mapArray[fS.x+13][fS.y+3] = 6.314; mapArray[fS.x+14][fS.y+3] = 6.315; // row 5 mapArray[fS.x+2][fS.y+4] = 6.403; mapArray[fS.x+3][fS.y+4] = 6.404; mapArray[fS.x+4][fS.y+4] = 6.405; mapArray[fS.x+5][fS.y+4] = 6.406; mapArray[fS.x+6][fS.y+4] = 6.407; mapArray[fS.x+7][fS.y+4] = 6.408; mapArray[fS.x+8][fS.y+4] = 6.409; mapArray[fS.x+9][fS.y+4] = 6.410; mapArray[fS.x+10][fS.y+4] = 6.411; mapArray[fS.x+11][fS.y+4] = 6.412; mapArray[fS.x+12][fS.y+4] = 6.413; mapArray[fS.x+13][fS.y+4] = 6.414; mapArray[fS.x+14][fS.y+4] = 6.415; // row 6 mapArray[fS.x+3][fS.y+5] = 6.504; mapArray[fS.x+4][fS.y+5] = 6.505; mapArray[fS.x+5][fS.y+5] = 6.506; mapArray[fS.x+6][fS.y+5] = 6.507; mapArray[fS.x+7][fS.y+5] = 6.508; mapArray[fS.x+8][fS.y+5] = 6.509; mapArray[fS.x+9][fS.y+5] = 6.510; mapArray[fS.x+10][fS.y+5] = 6.511; mapArray[fS.x+11][fS.y+5] = 6.512; mapArray[fS.x+12][fS.y+5] = 6.513; mapArray[fS.x+13][fS.y+5] = 6.514; mapArray[fS.x+14][fS.y+5] = 6.515; // row 7 mapArray[fS.x+3][fS.y+6] = 6.604; mapArray[fS.x+4][fS.y+6] = 6.605; mapArray[fS.x+5][fS.y+6] = 6.606; mapArray[fS.x+6][fS.y+6] = 6.607; mapArray[fS.x+7][fS.y+6] = 6.608; mapArray[fS.x+8][fS.y+6] = 6.609; mapArray[fS.x+9][fS.y+6] = 6.610; mapArray[fS.x+10][fS.y+6] = 6.611; mapArray[fS.x+11][fS.y+6] = 6.612; mapArray[fS.x+12][fS.y+6] = 6.613; mapArray[fS.x+13][fS.y+6] = 6.614; mapArray[fS.x+14][fS.y+6] = 6.615; // row 8 mapArray[fS.x+3][fS.y+7] = 6.704; mapArray[fS.x+4][fS.y+7] = 6.705; mapArray[fS.x+5][fS.y+7] = 6.706; mapArray[fS.x+6][fS.y+7] = 6.707; mapArray[fS.x+7][fS.y+7] = 6.708; mapArray[fS.x+8][fS.y+7] = 6.709; mapArray[fS.x+9][fS.y+7] = 6.710; mapArray[fS.x+10][fS.y+7] = 6.711; mapArray[fS.x+11][fS.y+7] = 6.712; mapArray[fS.x+12][fS.y+7] = 6.713; mapArray[fS.x+13][fS.y+7] = 6.714; mapArray[fS.x+14][fS.y+7] = 6.715; // row 9 mapArray[fS.x+3][fS.y+8] = 6.804; mapArray[fS.x+4][fS.y+8] = 6.805; mapArray[fS.x+5][fS.y+8] = 6.806; mapArray[fS.x+6][fS.y+8] = 6.807; mapArray[fS.x+7][fS.y+8] = 6.808; mapArray[fS.x+8][fS.y+8] = 6.809; mapArray[fS.x+9][fS.y+8] = 6.810; mapArray[fS.x+10][fS.y+8] = 6.811; mapArray[fS.x+11][fS.y+8] = 6.812; mapArray[fS.x+12][fS.y+8] = 6.813; mapArray[fS.x+13][fS.y+8] = 6.814; mapArray[fS.x+14][fS.y+8] = 6.815; // row 10 mapArray[fS.x+3][fS.y+9] = 6.904; mapArray[fS.x+4][fS.y+9] = 6.905; mapArray[fS.x+5][fS.y+9] = 6.906; mapArray[fS.x+6][fS.y+9] = 6.907; mapArray[fS.x+7][fS.y+9] = 6.908; mapArray[fS.x+8][fS.y+9] = 6.909; mapArray[fS.x+9][fS.y+9] = 6.910; mapArray[fS.x+10][fS.y+9] = 6.911; mapArray[fS.x+11][fS.y+9] = 6.912; mapArray[fS.x+12][fS.y+9] = 6.913; mapArray[fS.x+13][fS.y+9] = 6.914; mapArray[fS.x+14][fS.y+9] = 6.915; // row 11 (front of building) mapArray[fS.x+4][fS.y+10] = 0.77; mapArray[fS.x+5][fS.y+10] = 0.77; mapArray[fS.x+6][fS.y+10] = 0.77; mapArray[fS.x+7][fS.y+10] = 0.77; mapArray[fS.x+8][fS.y+10] = 0.77; mapArray[fS.x+9][fS.y+10] = 0.77; mapArray[fS.x+10][fS.y+10] = 0.77; mapArray[fS.x+11][fS.y+10] = 0.77; mapArray[fS.x+12][fS.y+10] = 0.77; mapArray[fS.x+13][fS.y+10] = 0.77; mapArray[fS.x+14][fS.y+10] = 0.77; // add map objects['X'+(fS.x+12)+'Y'+(fS.y+2)] = {'type': 'map', 'x': (fS.x+12), 'y': (fS.y+2), 'collectable': true, 'collectItem': 'map'}; // add cupboard var cacheId = 'X'+(fS.x+6)+'Y'+(fS.y+2); objects[cacheId] = {'type': 'field station', 'x': (fS.x+6), 'y': (fS.y+2)}; if (wireAtFieldStation) { var stationInventory = new Inventory(0, 0, 0, 0, 0, 0, 0, 0, 0, 'i', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // infinite wire } else { var stationInventory = new Inventory(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // nothing } caches[cacheId] = new Cupboard(stationInventory); stationX = (fS.x+4); stationY = fS.y; stationW = 11; stationH = 9; miniMapMarker(fS.x+7, fS.y+5, '#DD22C3'); } // filter terrain to add advanced terrain features (not near edges of map) for (var x=2, xLimit=game.mapTileCount-2; x 0.5) { var caveChance = randomBetween(0, 5); if (caveChance === 1) { mapArray[x-1][y] = 2.1; // left mapArray[x][y] = 2.2; // entrance mapArray[x+1][y] = 2.3; // right mapArray[x][y+1] = 2.4; // front of entrance var cacheId = 'X'+x+'Y'+y; objects[cacheId] = {'type': 'cave', 'x': x, 'y': y}; var caveSlate = randomOneOf([0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]); var caveQuartz = randomOneOf([0, 0, 0, 0, 0, 0, 0, 1, 1, 1]); var caveStone = randomOneOf([0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3]); var caveWood = randomOneOf([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]); caches[cacheId] = new Cave(new Inventory(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, caveSlate, caveQuartz, caveStone, caveWood, 0, 0, 0, 0)); //miniMapMarker(x, y, 'black'); } } } } // store possible tree and stone tiles (can't combine with above loop because that loop alters terrain) for (var x=1, xLimit=game.mapTileCount-1; x startTreeMin && mapArray[x][y] < startTreeMax && typeof(objects['X'+x+'Y'+y]) === "undefined") { // typeof returns a string, so "undefined" is in quotes startTreesArray.push({'x': x, 'y': y}); } // store start stone tiles if (mapArray[x][y] > startStoneMin && mapArray[x][y] < startStoneMax && typeof(objects['X'+x+'Y'+y]) === "undefined") { startStonesArray.push({'x': x, 'y': y}); } } } } // generate start trees, start stones, and berries on random tiles that are suitable (can't combine with above loop because that loop generates arrays) for (var x=1, xLimit=game.mapTileCount-1; x 0.8 && mapArray[x][y] > 0.66 && mapArray[x][y] < 0.98) { var birchChance = randomBetween(0, 10); if (birchChance === 1) { objects[tileId] = {'type': 'tree', 'class': 'birch', 'chopped': 0, 'flagged': false, 'x': x, 'y': y, 'flammable': true}; } else { objects[tileId] = {'type': 'tree', 'class': 'fir', 'chopped': 0, 'flagged': false, 'x': x, 'y': y, 'flammable': true}; } //trees['X' + x + 'Y' + y] = {'type': 'tree', 'class': 'fir', 'x': x, 'y': y, 'flammable': true}; // slows game loading } // generate berries if (mapArray[x][y] > berriesMin && mapArray[x][y] <= berriesMax) { var berriesChance = randomBetween(0, 10); if (berriesChance === 1) { objects[tileId] = {'type': 'berries', 'x': x, 'y': y, 'flammable': true, 'collectable': true, 'collectItem': 'berries'}; } } // generate bones /* if (mapArray[x][y] > boneMin && mapArray[x][y] <= boneMax) { var boneChance = randomBetween(0, 150); if (boneChance === 1) { objects[tileId] = {'type': 'bone', 'x': x, 'y': y, 'collectable': true, 'collectItem': 'bone'}; } } */ // generate shells if ((x < 8 || x > game.mapTileCount-8 || y < 8 || y > game.mapTileCount-8) && mapArray[x][y] > shellMin && mapArray[x][y] <= shellMax) { var shellChance = randomBetween(0, 40); if (shellChance === 1) { objects[tileId] = {'type': 'shell', 'x': x, 'y': y, 'collectable': true, 'collectItem': 'shell'}; } } // start stones var startStoneChance = randomBetween(0, 500); // was 800 if (startStoneChance === 1) { var startStoneTile = randomOneOf(startStonesArray); var objectId = 'X'+startStoneTile.x+'Y'+startStoneTile.y; if (typeof(objects[objectId]) === "undefined") { objects[objectId] = {'type': 'stone', 'class': 'stone1', 'x': startStoneTile.x, 'y': startStoneTile.y, 'collectable': true, 'collectItem': 'stone'}; } } } } // iterate over trees to grow clusters of trees for (var n=0; n<3; n++) { for (var tree in trees) { var newTreeTile = getRandomAdjacentTerrainTile(trees[tree].x, trees[tree].y, newTreeMin, newTreeMax); if (newTreeTile) { var objectId = 'X'+newTreeTile.x+'Y'+newTreeTile.y; objects[objectId] = {'type': 'tree', 'class': trees[tree].class, 'x': newTreeTile.x, 'y': newTreeTile.y, 'flammable': true, 'collectable': true, 'collectItem': 'wood'}; trees[objectId] = objects[objectId]; } } } // remove random trees to create gaps for (var d=0, dLimit = 30*game.mapTileMultiplier; d you.walk.min && mapArray[x][y] <= you.walk.max && typeof(objects['X'+x+'Y'+y]) === "undefined" // check row above && mapArray[x-1][y-1] > you.walk.min && mapArray[x-1][y-1] <= you.walk.max && typeof(objects['X'+(x-1)+'Y'+(y-1)]) === "undefined" && mapArray[x][y-1] > you.walk.min && mapArray[x][y-1] <= you.walk.max && typeof(objects['X'+x+'Y'+(y-1)]) === "undefined" && mapArray[x+1][y-1] > you.walk.min && mapArray[x+1][y-1] <= you.walk.max && typeof(objects['X'+(x+1)+'Y'+(y-1)]) === "undefined" // check either side && mapArray[x-1][y] > you.walk.min && mapArray[x-1][y] <= you.walk.max && typeof(objects['X'+(x-1)+'Y'+y]) === "undefined" && mapArray[x+1][y] > you.walk.min && mapArray[x+1][y] <= you.walk.max && typeof(objects['X'+(x+1)+'Y'+y]) === "undefined" // check row below && mapArray[x-1][y+1] > you.walk.min && mapArray[x-1][y+1] <= you.walk.max && typeof(objects['X'+(x-1)+'Y'+(y+1)]) === "undefined" && mapArray[x][y+1] > you.walk.min && mapArray[x][y+1] <= you.walk.max && typeof(objects['X'+x+'Y'+(y+1)]) === "undefined" && mapArray[x+1][y+1] > you.walk.min && mapArray[x+1][y+1] <= you.walk.max && typeof(objects['X'+(x+1)+'Y'+(y+1)]) === "undefined" ) { startTilesArray.push({'x': x, 'y': y}); } } // store newStones tiles if (mapArray[x][y] > newStoneMin && mapArray[x][y] < newStoneMax) { newStonesArray.push({'x': x, 'y': y}); } // store newBerries tiles if (mapArray[x][y] > berriesMin && mapArray[x][y] < berriesMax) { newBerriesArray.push({'x': x, 'y': y}); } // store newShells tiles if ((x < 8 || x > game.mapTileCount-8 || y < 8 || y > game.mapTileCount-8) && mapArray[x][y] > shellMin && mapArray[x][y] <= shellMax) { newShellsArray.push({'x': x, 'y': y}); } } } } // generate binoculars on a random tile (use berries tiles) var startBinocularsTile = randomOneOf(newBerriesArray); if (startBinocularsTile) { // overwrite existing objects objects['X'+startBinocularsTile.x+'Y'+startBinocularsTile.y] = {'type': 'binoculars', 'x': startBinocularsTile.x, 'y': startBinocularsTile.y, 'collectable': true, 'collectItem': 'binoculars'}; //miniMapMarker(startBinocularsTile.x, startBinocularsTile.y, '#4afff9'); } // set large unused variables to null to reclaim memory // note: use delete for properties, set to null for variables // see: http://stackoverflow.com/questions/5181954/memory-leak-in-javascript-chrome // also: http://stackoverflow.com/questions/742623/deleting-objects-in-javascript // also: http://stackoverflow.com/questions/4523172/freeing-javascript-object mapData = null; airData = null; startTreesArray = null; startStonesArray = null; } // update map with generated objects (called with each step) function updateMap() { // trees spread to nearby tiles that are suitable for trees; seedlings grow into trees var treeSpreadChance = randomBetween(0, 10); if (treeSpreadChance === 1) { var treeToSeed = randomProperty(trees); if (treeToSeed) { // if seedling, grow into tree if (typeof(objects[treeToSeed]) !== "undefined") { if (objects[treeToSeed].class === 'mapleSeedling') { objects[treeToSeed].class = 'maple'; trees[treeToSeed].class = 'maple'; } if (objects[treeToSeed].class === 'pineSeedling') { objects[treeToSeed].class = 'pine'; trees[treeToSeed].class = 'pine'; } if (objects[treeToSeed].class === 'alderSeedling') { objects[treeToSeed].class = 'alder'; trees[treeToSeed].class = 'alder'; } // if newTreeTile is suitable, add new tree var newTreeTile = getRandomAdjacentTerrainTile(trees[treeToSeed].x, trees[treeToSeed].y, newTreeMin, newTreeMax); if (newTreeTile) { var objectId = 'X'+newTreeTile.x+'Y'+newTreeTile.y; if (trees[treeToSeed].class === 'maple' || trees[treeToSeed].class === 'mapleSeedling') { objects[objectId] = {'type': 'tree', 'class': 'mapleSeedling', 'x': newTreeTile.x, 'y': newTreeTile.y, 'flammable': true, 'collectable': true, 'collectItem': 'wood'}; trees[objectId] = objects[objectId]; } else if (trees[treeToSeed].class === 'pine' || trees[treeToSeed].class === 'pineSeedling') { objects[objectId] = {'type': 'tree', 'class': 'pineSeedling', 'x': newTreeTile.x, 'y': newTreeTile.y, 'flammable': true, 'collectable': true, 'collectItem': 'wood'}; trees[objectId] = objects[objectId]; } else if (trees[treeToSeed].class === 'alder' || trees[treeToSeed].class === 'alderSeedling') { objects[objectId] = {'type': 'tree', 'class': 'alderSeedling', 'x': newTreeTile.x, 'y': newTreeTile.y, 'flammable': true, 'collectable': true, 'collectItem': 'wood'}; trees[objectId] = objects[objectId]; } //miniMapMarker(newTreeTile.x, newTreeTile.y, 'green'); } } } } // stones appear on random tiles that are suitable for stones var newStoneChance = randomBetween(0, 40); if (newStoneChance === 1) { var newStoneTile = randomOneOf(newStonesArray); if (newStoneTile) { var objectId = 'X'+newStoneTile.x+'Y'+newStoneTile.y; if (typeof(objects[objectId]) === "undefined") { objects[objectId] = {'type': 'stone', 'class': 'stone2', 'x': newStoneTile.x, 'y': newStoneTile.y, 'collectable': true, 'collectItem': 'stone'}; } } } // berries appear on random tiles that are suitable for berries var newBerriesChance = randomBetween(0, 40); if (newBerriesChance === 1) { var newBerriesTile = randomOneOf(newBerriesArray); if (newBerriesTile) { var objectId = 'X'+newBerriesTile.x+'Y'+newBerriesTile.y; if (typeof(objects[objectId]) === "undefined") { objects[objectId] = {'type': 'berries', 'x': newBerriesTile.x, 'y': newBerriesTile.y, 'flammable': true, 'collectable': true, 'collectItem': 'berries'}; } } } // shells appear on random tiles that are suitable for shells var newShellChance = randomBetween(0, 100); if (newShellChance === 1) { var newShellTile = randomOneOf(newShellsArray); if (newShellTile) { var objectId = 'X'+newShellTile.x+'Y'+newShellTile.y; if (typeof(objects[objectId]) === "undefined") { objects[objectId] = {'type': 'shell', 'x': newShellTile.x, 'y': newShellTile.y, 'collectable': true, 'collectItem': 'shell'}; } } } // chance for snares to catch rabbits, if they are a certain distance from player var snareTriggerChance = randomBetween(0, 40); if (snareTriggerChance === 1) { var snareId = randomProperty(snares); if (snareId) { if (typeof(objects[snareId]) !== "undefined") { // if snare is a certain distance from player var snareDistance = getDistance(snares[snareId], you.tile); if (snareDistance > 25) { delete objects[snareId]; objects[snareId] = {'type': 'rabbit', 'x': snares[snareId].x, 'y': snares[snareId].y, 'collectable': true, 'collectItem': 'rabbit'}; delete snares[snareId]; } } } } } // end updateMap // random function to offset map center function displace(num) { var max = num / (game.mapSize + game.mapSize) * game.roughness; return (Math.random() - 0.5) * max; } // normalize a value to make sure it is within bounds function normalize(value) { if (value > 1) { value = 1; } else if (value < 0) { value = 0; } return value; } // round to the nearest pixel function round(n) { if (n-(parseInt(n)) >= 0.5) { return parseInt(n)+1; } else { return parseInt(n); } } // terrain generation function midpointDisplacement(dataObject, dimension) { var newDimension = dimension / 2, top, topRight, topLeft, bottom, bottomLeft, bottomRight, right, left, center, i, j; if (newDimension > game.mapFraction) { for (var i=newDimension; i<=game.mapSize; i+=newDimension) { for (var j=newDimension; j<=game.mapSize; j+=newDimension) { x = i - (newDimension / 2); y = j - (newDimension / 2); topLeft = dataObject[i - newDimension][j - newDimension]; topRight = dataObject[i][j - newDimension]; bottomLeft = dataObject[i - newDimension][j]; bottomRight = dataObject[i][j]; // center dataObject[x][y] = (topLeft + topRight + bottomLeft + bottomRight) / 4 + displace(dimension); dataObject[x][y] = normalize(dataObject[x][y]); center = dataObject[x][y]; // top if (j - (newDimension * 2) + (newDimension / 2) > 0) { dataObject[x][j - newDimension] = (topLeft + topRight + center + dataObject[x][j - dimension + (newDimension / 2)]) / 4 + displace(dimension); } else { dataObject[x][j - newDimension] = (topLeft + topRight + center) / 3+ displace(dimension); } dataObject[x][j - newDimension] = normalize(dataObject[x][j - newDimension]); // bottom if (j + (newDimension / 2) < game.mapSize) { dataObject[x][j] = (bottomLeft + bottomRight + center + dataObject[x][j + (newDimension / 2)]) / 4+ displace(dimension); } else { dataObject[x][j] = (bottomLeft + bottomRight + center) / 3+ displace(dimension); } dataObject[x][j] = normalize(dataObject[x][j]); // right if (i + (newDimension / 2) < game.mapSize) { dataObject[i][y] = (topRight + bottomRight + center + dataObject[i + (newDimension / 2)][y]) / 4+ displace(dimension); } else { dataObject[i][y] = (topRight + bottomRight + center) / 3+ displace(dimension); } dataObject[i][y] = normalize(dataObject[i][y]); // left if (i - (newDimension * 2) + (newDimension / 2) > 0) { dataObject[i - newDimension][y] = (topLeft + bottomLeft + center + dataObject[i - dimension + (newDimension / 2)][y]) / 4 + displace(dimension); } else { dataObject[i - newDimension][y] = (topLeft + bottomLeft + center) / 3+ displace(dimension); } dataObject[i - newDimension][y] = normalize(dataObject[i - newDimension][y]); } } midpointDisplacement(dataObject, newDimension); } } // draw an ellipse // source: http://www.williammalone.com/briefs/how-to-draw-ellipse-html5-canvas/ function drawEllipse(context, centerX, centerY, width, height, fillStyle) { context.beginPath(); context.moveTo(centerX, centerY - height/2); // A1 context.bezierCurveTo( centerX + width/2, centerY - height/2, // C1 centerX + width/2, centerY + height/2, // C2 centerX, centerY + height/2); // A2 context.bezierCurveTo( centerX - width/2, centerY + height/2, // C3 centerX - width/2, centerY - height/2, // C4 centerX, centerY - height/2); // A1 context.fillStyle = fillStyle; context.fill(); context.closePath(); } // draw map canvas // mapData contains values from [0][0] to [game.mapSize][game.mapSize] ([2048][2048]) at steps of [game.tileSize][game.tileSize], representing raw terrain data // mapArray contains values from [0][0] to [(game.mapSize/game.tileSize)-1][(game.mapSize/game.tileSize)-1] ([127][127]), representing tile data. function drawMap() { var drawTime = clockTime(); var frameMod2 = frameCount%2; // repeats 0,1 var frameMod3 = frameCount%3; // repeats 0-2 var frameMod9 = frameCount%9; // repeats 0-8 var frameMod15 = frameCount%15; // repeats 0-14 var frameMod30 = frameCount%30; // repeats 0-29 // for testing stone and tree generation (lots of steps) //stepCount++; updateMap(); you.status.active--; // remove 'increasing' class from $energyBar every 3 frames (so that it blinks out quickly) if (frameMod3 === 1 && $energyBar.hasClass('increasing')) { $energyBar.removeClass(); } // if at cache or on platform and not on zip or helicopter, check if energy is supplied if ((you.on.cache || you.on.platform) && you.on.zip === false && you.on.helicopter === false) { // if at camp if (you.on.cache) { if (caches[you.on.cache].energy) { you.status.cold = false; you.updateEnergy(); if (caches[you.on.cache].energy.now > 0 && you.energy.now < you.energy.max) { if (frameMod3 === 1) { caches[you.on.cache].updateEnergy(-1); you.updateEnergy(1); } } } // else if on platform with roof } else if (you.on.platform) { if (platforms[you.on.platform].roof === true) { you.status.cold = false; you.updateEnergy(); if (platforms[you.on.platform].platformEnergy > 0 && you.energy.now < you.energy.max) { if (frameMod3 === 1) { platforms[you.on.platform].platformEnergy -= 2; you.updateEnergy(2); } } } } } // if player has no energy and stops moving, chance to fall asleep if (you.energy.now <= 0 && you.status.active < 0 && you.status.sleep <= 0) { you.updateSleep(); } if (redrawTerrain) { drawTerrain(); redrawTerrain = false; } // sprites layer // sprite sheet uses drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); // clear sprites canvas contextSprites.clearRect(0, 0, game.mapCanvasW, game.mapCanvasH); for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisTile = mapArray[x+mapOffsetX][y+mapOffsetY]; // waves 1 if (thisTile <= 0.01) { if (frameMod30 <= 2) { contextSprites.drawImage(sprites1x1['waves1Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 5) { contextSprites.drawImage(sprites1x1['waves2Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 8) { contextSprites.drawImage(sprites1x1['waves3Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 11) { contextSprites.drawImage(sprites1x1['waves4Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 14) { contextSprites.drawImage(sprites1x1['waves5Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 17) { contextSprites.drawImage(sprites1x1['waves6Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 20) { contextSprites.drawImage(sprites1x1['waves7Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 23) { contextSprites.drawImage(sprites1x1['waves8Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 26) { contextSprites.drawImage(sprites1x1['waves9Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 29) { contextSprites.drawImage(sprites1x1['waves10Canvas'], x*game.tileSize, y*game.tileSize); } // waves 2 } else if (thisTile > 0.01 && thisTile <= 0.03) { if (frameMod30 <= 2) { contextSprites.drawImage(sprites1x1['waves6Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 5) { contextSprites.drawImage(sprites1x1['waves7Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 8) { contextSprites.drawImage(sprites1x1['waves8Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 11) { contextSprites.drawImage(sprites1x1['waves9Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 14) { contextSprites.drawImage(sprites1x1['waves10Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 17) { contextSprites.drawImage(sprites1x1['waves1Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 20) { contextSprites.drawImage(sprites1x1['waves2Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 23) { contextSprites.drawImage(sprites1x1['waves3Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 26) { contextSprites.drawImage(sprites1x1['waves4Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod30 <= 29) { contextSprites.drawImage(sprites1x1['waves5Canvas'], x*game.tileSize, y*game.tileSize); } // waves 3 } else if (thisTile > 0.03 && thisTile <= 0.05) { if (frameMod30 <= 2) { contextSprites.drawImage(sprites1x1['waves3Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves8Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 5) { contextSprites.drawImage(sprites1x1['waves4Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves9Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 8) { contextSprites.drawImage(sprites1x1['waves5Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves10Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 11) { contextSprites.drawImage(sprites1x1['waves6Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves1Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 14) { contextSprites.drawImage(sprites1x1['waves7Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves2Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 17) { contextSprites.drawImage(sprites1x1['waves8Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves3Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 20) { contextSprites.drawImage(sprites1x1['waves9Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves4Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 23) { contextSprites.drawImage(sprites1x1['waves10Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves5Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 26) { contextSprites.drawImage(sprites1x1['waves1Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves6Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } else if (frameMod30 <= 29) { contextSprites.drawImage(sprites1x1['waves2Canvas'], x*game.tileSize, (y*game.tileSize)-4); contextSprites.drawImage(sprites1x1['waves7Canvas'], (x*game.tileSize)-1, (y*game.tileSize)+4); } } // was drawing mountains, etc. here } } } // end y loop } // end x loop // clear cover canvas contextCover.clearRect(0, 0, game.mapCanvasW, game.mapCanvasH); // this loop was originally for all larger terrain, now just for cover layer // tiles larger than 1x1; buffer 15 tiles because of field station for (var x=-15, xLimit=game.mapCanvasTileW+15; x<=xLimit; x++) { for (var y=-15, yLimit=game.mapCanvasTileH+15; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisTile = mapArray[x+mapOffsetX][y+mapOffsetY]; // crash if (thisTile === 4.10) { contextCover.drawImage(sprites9x6['crashCoverCanvas'], (x-3)*game.tileSize, (y-3)*game.tileSize); //contextTerrain.drawImage(sprites9x6['crashCanvas'], (x-3)*game.tileSize, y*game.tileSize); // mountain range 2 } else if (thisTile === 5.1) { contextCover.drawImage(sprites3x3['range2CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); //contextTerrain.drawImage(sprites3x3['range2Canvas'], x*game.tileSize, y*game.tileSize); // field station } else if (thisTile === 6.001) { // if player is inside station and not on zip, do not draw roof if (you.tile.x >= stationX && you.tile.x < (stationX*1+stationW) && you.tile.y >= stationY && you.tile.y < (stationY*1+stationH) && you.on.zip === false && you.on.helicopter === false) { //contextTerrain.drawImage(sprites15x10['fieldStationCanvas'], x*game.tileSize, y*game.tileSize); } else { contextCover.drawImage(sprites15x10['fieldStationCoverCanvas'], x*game.tileSize, y*game.tileSize); //contextTerrain.drawImage(sprites15x10['fieldStationCanvas'], x*game.tileSize, y*game.tileSize); } } } } } // end y loop } // end x loop for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisObject = objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; var thisHole = holes['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; // holes are separate loop if (typeof(thisHole) !== "undefined") { if (thisHole.class === 1) { contextSprites.drawImage(sprites1x1['hole1Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisHole.class === 2) { contextSprites.drawImage(sprites1x1['hole2Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisHole.class === 3) { contextSprites.drawImage(sprites1x1['hole3Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisHole.class === 4) { contextSprites.drawImage(sprites1x1['hole4Canvas'], x*game.tileSize, y*game.tileSize); } } if (typeof(thisObject) !== "undefined") { // small trees (maple, pine, alder) if (thisObject.type === 'tree') { if (thisObject.class === 'mapleSeedling') { contextSprites.drawImage(sprites1x1['mapleSeedlingCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'pineSeedling') { contextSprites.drawImage(sprites1x1['pineSeedlingCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'alderSeedling') { contextSprites.drawImage(sprites1x1['alderSeedlingCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'maple') { contextSprites.drawImage(sprites1x1['mapleTreeCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'pine') { contextSprites.drawImage(sprites1x1['pineTreeCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'alder') { contextSprites.drawImage(sprites1x1['alderTreeCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'stump') { contextSprites.drawImage(sprites1x1['stumpCanvas'], x*game.tileSize, y*game.tileSize); } // found stones } else if (thisObject.type === 'stone') { if (thisObject.class === 'stone1') { contextSprites.drawImage(sprites1x1['stone1Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.class === 'stone2') { contextSprites.drawImage(sprites1x1['stone2Canvas'], x*game.tileSize, y*game.tileSize); } // berries } else if (thisObject.type === 'berries') { contextSprites.drawImage(sprites1x1['berriesCanvas'], x*game.tileSize, y*game.tileSize); // bones } else if (thisObject.type === 'bone') { contextSprites.drawImage(sprites1x1['boneCanvas'], x*game.tileSize, y*game.tileSize); // ice } else if (thisObject.type === 'ice') { contextSprites.drawImage(sprites1x1['iceCanvas'], x*game.tileSize, y*game.tileSize); // shells } else if (thisObject.type === 'shell') { contextSprites.drawImage(sprites1x1['shellCanvas'], x*game.tileSize, y*game.tileSize); // quartz } else if (thisObject.type === 'quartz') { contextSprites.drawImage(sprites1x1['quartzCanvas'], x*game.tileSize, y*game.tileSize); // stepstones } else if (thisObject.type === 'stepstone') { if (thisObject.timer > 0) { thisObject.timer = thisObject.timer*1 - game.loopRate; var sinkPercent = thisObject.timer / stepStoneSink * 100; if (sinkPercent >= 90) { contextSprites.drawImage(sprites1x1['stepStone1Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 80) { contextSprites.drawImage(sprites1x1['stepStone2Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 70) { contextSprites.drawImage(sprites1x1['stepStone3Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 60) { contextSprites.drawImage(sprites1x1['stepStone4Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 50) { contextSprites.drawImage(sprites1x1['stepStone5Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 40) { contextSprites.drawImage(sprites1x1['stepStone6Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 30) { contextSprites.drawImage(sprites1x1['stepStone7Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 20) { contextSprites.drawImage(sprites1x1['stepStone8Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 10) { contextSprites.drawImage(sprites1x1['stepStone9Canvas'], x*game.tileSize, y*game.tileSize); } else if (sinkPercent >= 0) { contextSprites.drawImage(sprites1x1['stepStone10Canvas'], x*game.tileSize, y*game.tileSize); } } else { // stepstone sinks; if you is on this tile, falls in water delete objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; if (x+mapOffsetX === you.tile.x && y+mapOffsetY === you.tile.y) { you.on.water = true; you.status.cold = true; you.updateEnergy(); } } // bridges } else if (thisObject.type === 'bridge') { contextSprites.drawImage(sprites1x1['bridgeCanvas'], x*game.tileSize, y*game.tileSize); // snares } else if (thisObject.type === 'snare') { contextSprites.drawImage(sprites1x1['snareCanvas'], x*game.tileSize, y*game.tileSize); // rabbits } else if (thisObject.type === 'rabbit') { contextSprites.drawImage(sprites1x1['snareRabbitCanvas'], x*game.tileSize, y*game.tileSize); // map } else if (thisObject.type === 'map') { contextSprites.drawImage(sprites1x1['mapCanvas'], x*game.tileSize, y*game.tileSize); // binoculars } else if (thisObject.type === 'binoculars') { contextSprites.drawImage(sprites1x1['binocularsCanvas'], x*game.tileSize, y*game.tileSize); // backpack } else if (thisObject.type === 'backpack') { contextSprites.drawImage(sprites1x1['backpackCanvas'], x*game.tileSize, y*game.tileSize); // radio } else if (thisObject.type === 'radio') { contextSprites.drawImage(sprites1x1['radioCanvas'], x*game.tileSize, y*game.tileSize); } } } } } // end y loop } // end x loop // tiles larger than 1x1; buffer 9 tiles (was 4 before helicopter) for (var x=-9, xLimit=game.mapCanvasTileW+9; x<=xLimit; x++) { for (var y=-9, yLimit=game.mapCanvasTileH+9; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisObject = objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; if (typeof(thisObject) !== "undefined") { // large trees (fir) if (thisObject.type === 'tree') { if (thisObject.class === 'fir') { if (thisObject.chopped === 0) { contextCover.drawImage(sprites1x2['firCoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 1) { contextCover.drawImage(sprites1x2['firChopped1CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firChopped1Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 2) { contextCover.drawImage(sprites1x2['firChopped2CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firChopped2Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 3) { contextCover.drawImage(sprites1x2['firChopped3CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firChopped3Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 4) { contextCover.drawImage(sprites1x2['firChopped4CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firChopped4Canvas'], x*game.tileSize, y*game.tileSize); } else { contextCover.drawImage(sprites1x2['firChopped5CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['firChopped5Canvas'], x*game.tileSize, y*game.tileSize); } } else if (thisObject.class === 'birch') { if (thisObject.chopped === 0) { contextCover.drawImage(sprites1x2['birchCoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 1) { contextCover.drawImage(sprites1x2['birchChopped1CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchChopped1Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 2) { contextCover.drawImage(sprites1x2['birchChopped2CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchChopped2Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 3) { contextCover.drawImage(sprites1x2['birchChopped3CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchChopped3Canvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.chopped === 4) { contextCover.drawImage(sprites1x2['birchChopped4CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchChopped4Canvas'], x*game.tileSize, y*game.tileSize); } else { contextCover.drawImage(sprites1x2['birchChopped5CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextSprites.drawImage(sprites1x2['birchChopped5Canvas'], x*game.tileSize, y*game.tileSize); } } if (thisObject.flagged === true) { contextSprites.drawImage(sprites1x2['treeFlagCanvas'], x*game.tileSize, y*game.tileSize); } else if (typeof(thisObject.flagged) === "string") { contextSprites.drawImage(sprites1x2['treeSignCanvas'], x*game.tileSize, y*game.tileSize); } // camps } else if (thisObject.type === 'camp') { var thisCampId = 'X'+thisObject.x+'Y'+thisObject.y; // if player is in camp (and not on zip or on helicopter) if (thisCampId === you.on.cache && you.on.zip === false && you.on.helicopter === false) { if (frameMod9 >= 6) { if (thisObject.part === 1) { contextSprites.drawImage(sprites2x2['camp2Canvas'], x*game.tileSize, y*game.tileSize); } } else if (frameMod9 >= 3 && frameMod9 < 6) { if (thisObject.part === 1) { contextSprites.drawImage(sprites2x2['camp3Canvas'], x*game.tileSize, y*game.tileSize); } } else { if (thisObject.part === 1) { contextSprites.drawImage(sprites2x2['camp4Canvas'], x*game.tileSize, y*game.tileSize); } } // else player is either not in camp or on zip } else { if (thisObject.part === 1) { contextSprites.drawImage(sprites2x2['camp1Canvas'], x*game.tileSize, y*game.tileSize); // nearby empty camps slowly regain energy if (frameMod15 === 1 && caches[thisCampId].energy.now < caches[thisCampId].energy.max) { caches[thisCampId].updateEnergy(1); } } } // rafts } else if (thisObject.type === 'raft') { var objectId = 'X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY); // note that for rafts this is not the same as objects[objectId].id if (thisObject.part === 1) { // if player is on raft if (objects[objectId].id === you.on.raft && raftSplashLeft > 0) { contextSprites.drawImage(sprites2x2['raftSplashLeftCanvas'], x*game.tileSize, y*game.tileSize); raftSplashLeft--; raftSplashRight = 0; raftSplashUp = 0; raftSplashDown = 0; } else if (objects[objectId].id === you.on.raft && raftSplashRight > 0) { contextSprites.drawImage(sprites2x2['raftSplashRightCanvas'], x*game.tileSize, y*game.tileSize); raftSplashRight--; raftSplashLeft = 0; raftSplashUp = 0; raftSplashDown = 0; } else if (objects[objectId].id === you.on.raft && raftSplashUp > 0) { contextSprites.drawImage(sprites2x2['raftSplashUpCanvas'], x*game.tileSize, y*game.tileSize); raftSplashUp--; raftSplashLeft = 0; raftSplashRight = 0; raftSplashDown = 0; } else if (objects[objectId].id === you.on.raft && raftSplashDown > 0) { contextSprites.drawImage(sprites2x2['raftSplashDownCanvas'], x*game.tileSize, y*game.tileSize); raftSplashDown--; raftSplashLeft = 0; raftSplashRight = 0; raftSplashUp = 0; } else { contextSprites.drawImage(sprites2x2['raftCanvas'], x*game.tileSize, y*game.tileSize); raftSplashLeft = 0; raftSplashRight = 0; raftSplashUp = 0; raftSplashDown = 0; } } // canoes } else if (thisObject.type === 'canoe') { if (thisObject.direction === 'horz') { contextSprites.drawImage(sprites3x3['canoeHorzCanvas'], (x-1)*game.tileSize, (y-1)*game.tileSize); } else { contextSprites.drawImage(sprites3x3['canoeVertCanvas'], (x-1)*game.tileSize, (y-1)*game.tileSize); } // helicopters } else if (thisObject.type === 'helicopter') { if (!you.on.helicopter) { if (helicopters[1].direction === 'left') { contextCover.drawImage(sprites9x3['helicopterLeftLandedCoverCanvas'], (x-2)*game.tileSize, (y-2)*game.tileSize); contextSprites.drawImage(sprites9x3['helicopterLeftShadowCanvas'], (x-2)*game.tileSize, y*game.tileSize); contextSprites.drawImage(sprites9x3['helicopterLeftLandedCanvas'], (x-2)*game.tileSize, y*game.tileSize); } else { contextCover.drawImage(sprites9x3['helicopterRightLandedCoverCanvas'], (x-6)*game.tileSize, (y-2)*game.tileSize); contextSprites.drawImage(sprites9x3['helicopterRightShadowCanvas'], (x-6)*game.tileSize, y*game.tileSize); contextSprites.drawImage(sprites9x3['helicopterRightLandedCanvas'], (x-6)*game.tileSize, y*game.tileSize); } } // quarries } else if (thisObject.type === 'quarry') { if (thisObject.part === 1) { contextSprites.drawImage(sprites3x3['quarryCanvas'], x*game.tileSize, y*game.tileSize); } // letters } else if (thisObject.type === 'letter') { if (thisObject.part === 1) { if (thisObject.char === 'other') { contextSprites.drawImage(sprites3x3['letterOtherCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'a') { contextSprites.drawImage(sprites3x3['letterACanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'b') { contextSprites.drawImage(sprites3x3['letterBCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'c') { contextSprites.drawImage(sprites3x3['letterCCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'd') { contextSprites.drawImage(sprites3x3['letterDCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'e') { contextSprites.drawImage(sprites3x3['letterECanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'f') { contextSprites.drawImage(sprites3x3['letterFCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'g') { contextSprites.drawImage(sprites3x3['letterGCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'h') { contextSprites.drawImage(sprites3x3['letterHCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'i') { contextSprites.drawImage(sprites3x3['letterICanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'j') { contextSprites.drawImage(sprites3x3['letterJCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'k') { contextSprites.drawImage(sprites3x3['letterKCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'l') { contextSprites.drawImage(sprites3x3['letterLCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'm') { contextSprites.drawImage(sprites3x3['letterMCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'n') { contextSprites.drawImage(sprites3x3['letterNCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'o') { contextSprites.drawImage(sprites3x3['letterOCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'p') { contextSprites.drawImage(sprites3x3['letterPCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'q') { contextSprites.drawImage(sprites3x3['letterQCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'r') { contextSprites.drawImage(sprites3x3['letterRCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 's') { contextSprites.drawImage(sprites3x3['letterSCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 't') { contextSprites.drawImage(sprites3x3['letterTCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'u') { contextSprites.drawImage(sprites3x3['letterUCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'v') { contextSprites.drawImage(sprites3x3['letterVCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'w') { contextSprites.drawImage(sprites3x3['letterWCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'x') { contextSprites.drawImage(sprites3x3['letterXCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'y') { contextSprites.drawImage(sprites3x3['letterYCanvas'], x*game.tileSize, y*game.tileSize); } else if (thisObject.char === 'z') { contextSprites.drawImage(sprites3x3['letterZCanvas'], x*game.tileSize, y*game.tileSize); } } // platforms } else if (thisObject.type === 'platform') { var thisPlatformId = 'X'+thisObject.x+'Y'+thisObject.y; var thisPlatform = platforms[thisPlatformId]; if (thisObject.part === 1) { contextSprites.drawImage(sprites3x3['platformCanvas'], x*game.tileSize, y*game.tileSize); } if (thisObject.part === 2 && thisPlatform.node1 !== false) { contextCover.drawImage(sprites3x3['zip1Canvas'], (x-1)*game.tileSize, (y-1)*game.tileSize); } if (thisObject.part === 4 && thisPlatform.node2 !== false) { contextCover.drawImage(sprites3x3['zip2Canvas'], ((x-1)*game.tileSize)-1, ((y-1)*game.tileSize)-1); } if (thisObject.part === 6 && thisPlatform.node3 !== false) { contextCover.drawImage(sprites3x3['zip3Canvas'], (x-1)*game.tileSize, ((y-1)*game.tileSize)-1); } if (thisObject.part === 9 && thisPlatform.roof === true) { // using part 9 so roof is drawn in front of zip nodes if (thisPlatformId !== you.on.platform) { contextCover.drawImage(sprites3x3['slateRoofCanvas'], (x-2)*game.tileSize, ((y-2)*game.tileSize)-6); } else { contextCover.drawImage(sprites3x3['roofPillarsCanvas'], (x-2)*game.tileSize, (y-2)*game.tileSize); } } // nearby empty platforms with roofs slowly regain energy if (frameMod15 === 1 && thisObject.part === 5) { if (thisPlatformId !== you.on.platform && you.on.zip === false && thisPlatform.roof === true && thisPlatform.platformEnergy < platformEnergy) { thisPlatform.platformEnergy++; } } } } } } } // end y loop } // end x loop // draw fire; fire spreads to nearby flammable objects; buffer 5 tiles for (var x=-5, xLimit=game.mapCanvasTileW+5; x<=xLimit; x++) { for (var y=-5, yLimit=game.mapCanvasTileH+5; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisFire = fires['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; var thisObject = objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; if (typeof(thisFire) !== "undefined" && typeof(thisObject) !== "undefined") { if (thisFire === 3) { // 3 and 2 are the same animation, just out of sync to provide variation if (frameMod15 >= 13) { contextSprites.drawImage(sprites1x1['fire4Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke2Canvas'], (x*game.tileSize)+7, (y*game.tileSize)-12); } else if (frameMod15 >= 10 && frameMod15 < 13) { contextSprites.drawImage(sprites1x1['fire4Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke2Canvas'], (x*game.tileSize)+5, (y*game.tileSize)-9); } else if (frameMod15 >= 7 && frameMod15 < 10) { contextSprites.drawImage(sprites1x1['fire3Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke1Canvas'], (x*game.tileSize)+2, (y*game.tileSize)-6); } else if (frameMod15 >= 4 && frameMod15 < 7) { contextSprites.drawImage(sprites1x1['fire3Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke1Canvas'], (x*game.tileSize)+1, (y*game.tileSize)-3); } else { contextSprites.drawImage(sprites1x1['fire5Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke3Canvas'], (x*game.tileSize)+9, (y*game.tileSize)-14); } } else if (thisFire === 2) { if (frameMod15 >= 13) { contextSprites.drawImage(sprites1x1['fire5Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke3Canvas'], (x*game.tileSize)+11, (y*game.tileSize)-12); } else if (frameMod15 >= 10 && frameMod15 < 13) { contextSprites.drawImage(sprites1x1['fire4Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke2Canvas'], (x*game.tileSize)+9, (y*game.tileSize)-10); } else if (frameMod15 >= 7 && frameMod15 < 10) { contextSprites.drawImage(sprites1x1['fire4Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke2Canvas'], (x*game.tileSize)+7, (y*game.tileSize)-7); } else if (frameMod15 >= 4 && frameMod15 < 7) { contextSprites.drawImage(sprites1x1['fire3Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke1Canvas'], (x*game.tileSize)+5, (y*game.tileSize)-5); } else { contextSprites.drawImage(sprites1x1['fire3Canvas'], x*game.tileSize, y*game.tileSize); contextCover.drawImage(sprites1x1['smoke1Canvas'], (x*game.tileSize)+3, (y*game.tileSize)-2); } } else { // fire === 1 if (frameMod9 >= 6) { contextSprites.drawImage(sprites1x1['fire3Canvas'], x*game.tileSize, y*game.tileSize); } else if (frameMod9 >= 3 && frameMod9 < 6) { contextSprites.drawImage(sprites1x1['fire2Canvas'], x*game.tileSize, y*game.tileSize); } else { contextSprites.drawImage(sprites1x1['fire1Canvas'], x*game.tileSize, y*game.tileSize); } } // if player is on tile which is on fire, and not on zip or on helicopter, lose energy rapidly if (x+mapOffsetX === you.tile.x && y+mapOffsetY === you.tile.y && you.on.zip === false && you.on.helicopter === false) { you.status.cold = false; you.updateEnergy(-4); } // fire has chance to spread var fireSpreadChance = randomBetween(0, 12); if (fireSpreadChance === 1) { var newFireTile = getRandomAdjacentFlammableTile(x+mapOffsetX, y+mapOffsetY); if (newFireTile) { var spreadFireId = 'X'+newFireTile.x+'Y'+newFireTile.y; if (typeof(fires[spreadFireId]) !== "undefined" && fires[spreadFireId] < 3) { fires[spreadFireId]++; } else { fires[spreadFireId] = 1; } } } // end if fireSpreadChance // fire has a chance to fade var fireFadeChance = randomBetween(0, 20); if (fireFadeChance === 1) { var fadeFireId = 'X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY); if (thisFire === 3) { fires[fadeFireId] -= 2; } else { fires[fadeFireId]--; } if (thisFire === 0) { // if tree has burned, generate stump; also redraw fog in case tree had flag if (thisObject.type === 'tree') { // if tree had flag, redraw fog if (thisObject.flagged === 'true') { if (admin.fog) { redrawFog = true; } } objects[fadeFireId] = {'type': 'tree', 'class': 'stump', 'x': (x+mapOffsetX), 'y': (y+mapOffsetY), 'collectable': true, 'collectItem': 'charcoal'}; if (thisObject.class !== 'fir' || thisObject.class !== 'birch') { delete trees[fadeFireId]; } // if bridge has burned, check if player falls in water } else if (thisObject.type === 'bridge' && x+mapOffsetX === you.tile.x && y+mapOffsetY === you.tile.y) { delete objects[fadeFireId]; you.on.water = true; you.status.cold = true; you.updateEnergy(); } else { delete objects[fadeFireId]; } delete fires[fadeFireId]; } } } } } } // end y loop } // end x loop // draw you // note: game.mapCanvasHalfTiles = you.tile.x - mapOffsetX // if animation if (you.animating.stand === 3) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep2Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.stand === 3) { you.animating.stand--; } }, game.loopRate); } else if (you.animating.stand === 2) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep3Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.stand === 2) { you.animating.stand--; } }, game.loopRate); } else if (you.animating.stand === 1) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep4Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.stand === 1) { you.animating.stand--; you.status.paused1 = false; } }, game.loopRate*2); } else if (you.animating.sleep === 3) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep4Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.sleep === 3) { you.animating.sleep--; } }, game.loopRate); } else if (you.animating.sleep === 2) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep3Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.sleep === 2) { you.animating.sleep--; } }, game.loopRate); } else if (you.animating.sleep === 1) { you.status.paused1 = true; contextSprites.drawImage(sprites1x1['youSleep2Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); requestTimeout(function() { if (you.animating.sleep === 1) { you.animating.sleep--; } }, game.loopRate); // else no animation } else { you.status.paused1 = false; if (you.on.zip) { if (you.status.cold) { contextCover.drawImage(sprites1x2['youColdZipCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { contextCover.drawImage(sprites1x2['youZipCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } else if (you.on.water) { contextSprites.drawImage(sprites1x1['youWaterCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else if (you.status.sleep) { contextSprites.drawImage(sprites1x1['youSleep1Canvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else if (you.on.raft) { if (you.status.cold) { contextSprites.drawImage(sprites1x1['youColdRaftCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { contextSprites.drawImage(sprites1x1['youRaftCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } else if (you.on.canoe) { if (you.status.cold) { contextSprites.drawImage(sprites1x1['youColdCanoeCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { contextSprites.drawImage(sprites1x1['youCanoeCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } else if (you.on.helicopter) { // drawn after ziplines } else { if (you.status.cold) { contextSprites.drawImage(sprites1x1['youColdCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { contextSprites.drawImage(sprites1x1['youCanvas'], game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } /* if (you.status.cold) { contextSprites.globalCompositeOperation = "source-in"; contextSprites.fillStyle = '#ace2ee'; contextSprites.fillRect(game.mapCanvasHalfTiles*game.tileSize, game.mapCanvasHalfTiles*game.tileSize, game.tileSize, game.tileSize); contextSprites.globalCompositeOperation = "source-over"; } // */ } // end if animation // check for nearby ziplines; buffer 7 tiles var nearbyNodes = []; for (var x=-7, xLimit=game.mapCanvasTileW+7; x<=xLimit; x++) { for (var y=-7, yLimit=game.mapCanvasTileH+7; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisPlatform = platforms['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; if (typeof(thisPlatform) !== "undefined") { if (thisPlatform.node1 !== false) { nearbyNodes.push(thisPlatform.node1); } if (thisPlatform.node2 !== false) { nearbyNodes.push(thisPlatform.node2); } if (thisPlatform.node3 !== false) { nearbyNodes.push(thisPlatform.node3); } } } } } // end y loop } // end x loop // draw ziplines var drawnNodes = []; if (nearbyNodes.length > 1) { contextCover.strokeStyle = "#282828"; // #fff also looks good for (var z=0, zLimit=nearbyNodes.length; z 0) { if (frameMod2 === 0) { contextCover.drawImage(sprites9x3['helicopterLeft1TiltCanvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } else { contextCover.drawImage(sprites9x3['helicopterLeft2TiltCanvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } contextCover.drawImage(sprites9x3['helicopterLeftShadowCanvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { if (frameMod2 === 0) { contextCover.drawImage(sprites9x3['helicopterLeft1Canvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } else { contextCover.drawImage(sprites9x3['helicopterLeft2Canvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } contextCover.drawImage(sprites9x3['helicopterLeftShadowCanvas'], (game.mapCanvasHalfTiles-2)*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } else { if (you.status.active > 0) { if (frameMod2 === 0) { contextCover.drawImage(sprites9x3['helicopterRight1TiltCanvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } else { contextCover.drawImage(sprites9x3['helicopterRight2TiltCanvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } contextCover.drawImage(sprites9x3['helicopterRightShadowCanvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } else { if (frameMod2 === 0) { contextCover.drawImage(sprites9x3['helicopterRight1Canvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } else { contextCover.drawImage(sprites9x3['helicopterRight2Canvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, (game.mapCanvasHalfTiles-5)*game.tileSize); } contextCover.drawImage(sprites9x3['helicopterRightShadowCanvas'], (game.mapCanvasHalfTiles-6)*game.tileSize, game.mapCanvasHalfTiles*game.tileSize); } } } // draw reach if (cursor.near) { contextCover.beginPath(); contextCover.arc(game.mapCanvasHalfTiles*game.tileSize + you.offset, game.mapCanvasHalfTiles*game.tileSize + you.offset, you.reach*game.tileSize + 3, 0, Math.PI*2, false); contextCover.strokeStyle = 'rgb(220,220,220)'; contextCover.stroke(); contextCover.closePath(); } if (admin.fog && redrawFog) { drawFog(); redrawFog = false; } if (admin.mini && redrawMiniMapCursor) { drawMiniMapCursor(); redrawMiniMapCursor = false; } //status(frameCount); frameCount++; $('#drawTime').text('draw time: ' + (clockTime()-drawTime) +'ms.'); } // end drawMap // draw terrain function drawTerrain() { // copy miniMap to map // see: http://stackoverflow.com/questions/6060881/html5-canvas-draw-image if (game.softMap) { var clearTerrain = false, sourceOffsetX, sourceOffsetY, sourceW, sourceH, copyX, copyY, copyW, copyH; // can't ask for source image data outside boundaries: http://stackoverflow.com/questions/7459240/canvas-drawimage-throws-index-size-err-when-run-locally-but-not-from-the-web if (mapOffsetX < 0) { clearTerrain = true; sourceOffsetX = 0; copyX = mapOffsetX*game.tileSize*-1; } else { sourceOffsetX = mapOffsetX; copyX = 0; } if (mapOffsetY < 0) { clearTerrain = true; sourceOffsetY = 0; copyY = mapOffsetY*game.tileSize*-1; } else { sourceOffsetY = mapOffsetY; copyY = 0; } if (sourceOffsetX + game.mapCanvasTileW > game.canvasMiniMapW) { clearTerrain = true; sourceW = game.mapCanvasTileW - (mapOffsetX + game.mapCanvasTileW - game.canvasMiniMapW); copyW = sourceW*game.tileSize; } else { sourceW = game.mapCanvasTileW; copyW = game.mapCanvasW; } if (sourceOffsetY + game.mapCanvasTileH > game.canvasMiniMapH) { clearTerrain = true; sourceH = game.mapCanvasTileH - (mapOffsetY + game.mapCanvasTileH - game.canvasMiniMapH); copyH = sourceH*game.tileSize; } else { sourceH = game.mapCanvasTileH; copyH = game.mapCanvasH; } // only need to clear canvas here if near edges of map; best clear canvas practice: http://stackoverflow.com/a/6722031/294189 if (clearTerrain) { contextTerrain.clearRect(0, 0, game.mapCanvasW, game.mapCanvasH); } contextTerrain.drawImage(canvasMiniMap, sourceOffsetX, sourceOffsetY, sourceW, sourceH, copyX, copyY, copyW, copyH); } // tiles // water, waves, icebergs, crash if (!game.softMap) { contextTerrain.fillStyle = '#5591b0'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if (mapArray[x+mapOffsetX][y+mapOffsetY] <= 0.45 || (mapArray[x+mapOffsetX][y+mapOffsetY] > 3 && mapArray[x+mapOffsetX][y+mapOffsetY] < 5)) { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } //else { contextSprites.clearRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } // clears areas outside map; unnecessary because of redraw changes? } //else { contextSprites.clearRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } // shallows contextTerrain.fillStyle = '#67A0B7'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if (mapArray[x+mapOffsetX][y+mapOffsetY] > 0.45 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 0.55) { if (game.softMap) { contextTerrain.fillRect(x*game.tileSize+1, y*game.tileSize+1, game.tileSize-2, game.tileSize-2); } else { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } } } // sand contextTerrain.fillStyle = '#D3D1A5'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if (mapArray[x+mapOffsetX][y+mapOffsetY] > 0.55 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 0.6) { if (game.softMap) { contextTerrain.fillRect(x*game.tileSize+1, y*game.tileSize+1, game.tileSize-2, game.tileSize-2); } else { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } } } // field, grass, flowers1, weeds, high field, rocks, hill1, hill2 contextTerrain.fillStyle = '#91B58C'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if ((mapArray[x+mapOffsetX][y+mapOffsetY] > 0.6 && mapArray[x+mapOffsetX][y+mapOffsetY] < 0.99 && airArray[x+mapOffsetX][y+mapOffsetY] > 0.5) || (mapArray[x+mapOffsetX][y+mapOffsetY] === 2.4 && airArray[x+mapOffsetX][y+mapOffsetY] > 0.5)) { if (game.softMap) { contextTerrain.fillRect(x*game.tileSize+1, y*game.tileSize+1, game.tileSize-2, game.tileSize-2); } else { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } } } // alternate field, grass, flowers2, weeds, high field, rocks, hill1, hill2, cave4, field station, platform contextTerrain.fillStyle = '#8AAD86'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if ((mapArray[x+mapOffsetX][y+mapOffsetY] > 0.6 && mapArray[x+mapOffsetX][y+mapOffsetY] < 0.99 && airArray[x+mapOffsetX][y+mapOffsetY] <= 0.5) || (mapArray[x+mapOffsetX][y+mapOffsetY] === 2.4 && airArray[x+mapOffsetX][y+mapOffsetY] <= 0.5) || (mapArray[x+mapOffsetX][y+mapOffsetY] >= 6 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 7.99)) { if (game.softMap) { contextTerrain.fillRect(x*game.tileSize+1, y*game.tileSize+1, game.tileSize-2, game.tileSize-2); } else { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } } } // mountain1, mountain2, range1, range2, cave1, cave2, cave3 contextTerrain.fillStyle = '#8c9074'; for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if ((mapArray[x+mapOffsetX][y+mapOffsetY] >= 0.99 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 1.4) || (mapArray[x+mapOffsetX][y+mapOffsetY] >= 2.1 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 2.3) || (mapArray[x+mapOffsetX][y+mapOffsetY] >= 5.1 && mapArray[x+mapOffsetX][y+mapOffsetY] <= 5.6)) { if (game.softMap) { contextTerrain.fillRect(x*game.tileSize+1, y*game.tileSize+1, game.tileSize-2, game.tileSize-2); } else { contextTerrain.fillRect(x*game.tileSize, y*game.tileSize, game.tileSize, game.tileSize); } } } } } } // 1x1 terrain for (var x=0; x<=game.mapCanvasTileW; x++) { for (var y=0; y<=game.mapCanvasTileH; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisTile = mapArray[x+mapOffsetX][y+mapOffsetY]; // grass if (thisTile > 0.71 && thisTile <= 0.735) { contextTerrain.drawImage(sprites1x1['grassCanvas'], x*game.tileSize, y*game.tileSize); // flowers1 and flowers2 } else if (thisTile > 0.735 && thisTile <= 0.74) { if (airArray[x+mapOffsetX][y+mapOffsetY] <= 0.5) { contextTerrain.drawImage(sprites1x1['flowers2Canvas'], x*game.tileSize, y*game.tileSize); } else { contextTerrain.drawImage(sprites1x1['flowers1Canvas'], x*game.tileSize, y*game.tileSize); } // weeds } else if (thisTile > 0.74 && thisTile <= 0.76) { contextTerrain.drawImage(sprites1x1['weedsCanvas'], x*game.tileSize, y*game.tileSize); // rocks } else if (thisTile > 0.85 && thisTile <= 0.88) { contextTerrain.drawImage(sprites1x1['rocksCanvas'], x*game.tileSize, y*game.tileSize); // hill 1 } else if (thisTile > 0.88 && thisTile <= 0.90) { contextTerrain.drawImage(sprites1x1['hill1Canvas'], x*game.tileSize, y*game.tileSize); // hill 2 } else if (thisTile > 0.90 && thisTile < 0.99) { contextTerrain.drawImage(sprites1x1['hill2Canvas'], x*game.tileSize, y*game.tileSize); // mountain 1 } else if (thisTile === 0.99) { contextTerrain.drawImage(sprites1x1['mountain1Canvas'], x*game.tileSize, y*game.tileSize); // mountain 2 } else if (thisTile === 1) { contextTerrain.drawImage(sprites1x1['mountain2Canvas'], x*game.tileSize, y*game.tileSize); } } } } // end y loop } // end x loop // terrain larger than 1x1; buffer 15 tiles because of field station; cover draw in drawMap loop for (var x=-15, xLimit=game.mapCanvasTileW+15; x<=xLimit; x++) { for (var y=-15, yLimit=game.mapCanvasTileH+15; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { var thisTile = mapArray[x+mapOffsetX][y+mapOffsetY]; // mountain range 1 if (thisTile === 1.1) { contextTerrain.drawImage(sprites2x2['range1Canvas'], x*game.tileSize, y*game.tileSize); // icebergs } else if (thisTile === 3.1) { contextTerrain.drawImage(sprites2x2['icebergCanvas'], x*game.tileSize, y*game.tileSize); // caves } else if (thisTile === 2.1) { contextTerrain.drawImage(sprites3x2['caveCanvas'], x*game.tileSize, y*game.tileSize); // crash } else if (thisTile === 4.10) { //contextCover.drawImage(sprites9x6['crashCoverCanvas'], (x-3)*game.tileSize, (y-3)*game.tileSize); contextTerrain.drawImage(sprites9x6['crashCanvas'], (x-3)*game.tileSize, y*game.tileSize); // mountain range 2 } else if (thisTile === 5.1) { //contextCover.drawImage(sprites3x3['range2CoverCanvas'], x*game.tileSize, (y-1)*game.tileSize); contextTerrain.drawImage(sprites3x3['range2Canvas'], x*game.tileSize, y*game.tileSize); // field station } else if (thisTile === 6.001) { // if player is inside station and not on zip or on helicopter, do not draw roof if (you.tile.x >= stationX && you.tile.x < (stationX*1+stationW) && you.tile.y >= stationY && you.tile.y < (stationY*1+stationH) && you.on.zip === false && you.on.helicopter === false) { contextTerrain.drawImage(sprites15x10['fieldStationCanvas'], x*game.tileSize, y*game.tileSize); } else { //contextCover.drawImage(sprites15x10['fieldStationCoverCanvas'], x*game.tileSize, y*game.tileSize); contextTerrain.drawImage(sprites15x10['fieldStationCanvas'], x*game.tileSize, y*game.tileSize); } } } } } // end y loop } // end x loop } // end drawTerrain // draw fog and miniMap fog function drawFog() { var visionRadius = you.getVisionRadius(); // fog layer; fill entire area contextFog.globalCompositeOperation = "source-over"; contextFog.fillStyle = fogColor; contextFog.fillRect(0, 0, game.mapCanvasW, game.mapCanvasH); // miniMapFog; fill only area represented by miniMapVis, so that fog from far-away camps is still cleared on miniMap if (admin.mini) { contextMiniMapFog.globalCompositeOperation = "source-over"; contextMiniMapFog.fillStyle = miniMapFogColor; //contextMiniMapFog.fillRect(0, 0, game.canvasMiniMapW, game.canvasMiniMapH); // clear full miniMap contextMiniMapFog.fillRect(Math.round(you.tile.x/game.mapTileMultiplier) - (game.miniMapVisW/2), Math.round(you.tile.y/game.mapTileMultiplier) - (game.miniMapVisH/2), game.miniMapVisW, game.miniMapVisH); // define clipping region for camp vision circles (otherwise nearby camp vision circles that fall outside miniMapVis are cleared over and over, creating pixellated effect) contextMiniMapFog.save(); contextMiniMapFog.beginPath(); contextMiniMapFog.rect(Math.round(you.tile.x/game.mapTileMultiplier) - (game.miniMapVisW/2)-1, Math.round(you.tile.y/game.mapTileMultiplier) - (game.miniMapVisH/2)-1, game.miniMapVisW+2, game.miniMapVisH+2); // a little bigger than fillRect above contextMiniMapFog.clip(); } // set globalCompositeOperation once before loop contextFog.globalCompositeOperation = "destination-out"; // 'copy' + alpha set to 0 also erases, but doesn't work in firefox if (admin.mini) { contextMiniMapFog.globalCompositeOperation = "destination-out"; } // clear fog around nearby camps; buffer 'game.mapCanvasHalfTiles' to include cleared fog from camps that are out of view for (var x=-game.mapCanvasHalfTiles, xLimit=game.mapCanvasTileW+game.mapCanvasHalfTiles; x<=xLimit; x++) { for (var y=-game.mapCanvasHalfTiles, yLimit=game.mapCanvasTileH+game.mapCanvasHalfTiles; y<=yLimit; y++) { if (typeof(mapArray[x+mapOffsetX]) !== "undefined" && x+mapOffsetX < game.mapTileCount) { if (typeof(mapArray[x+mapOffsetX][y+mapOffsetY]) !== "undefined" && y+mapOffsetY < game.mapTileCount) { if (typeof(objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]) !== "undefined") { var thisObject = objects['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; // camps if (thisObject.type === 'camp' && thisObject.part === 1) { var thisCamp = caches['X'+(x+mapOffsetX)+'Y'+(y+mapOffsetY)]; // camp: larger outer circle, partially transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + thisCamp.offset, y*game.tileSize + thisCamp.offset, thisCamp.vision+10, 0, Math.PI*2, false); contextFog.fillStyle = 'rgba(0,0,0,0.5)'; contextFog.fill(); contextFog.closePath(); // camp: smaller inner circle, entirely transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + thisCamp.offset, y*game.tileSize + thisCamp.offset, thisCamp.vision, 0, Math.PI*2, false); contextFog.fillStyle = 'rgb(0,0,0)'; contextFog.fill(); contextFog.closePath(); if (admin.mini) { // camp: miniMapFog circle contextMiniMapFog.beginPath(); contextMiniMapFog.arc(Math.round((thisObject.x / game.mapTileMultiplier)+1), Math.round((thisObject.y / game.mapTileMultiplier)+1), Math.round((thisCamp.vision / game.mapTileMultiplier)/16) + game.campVisionMiniAdjust, 0, Math.PI*2, false); contextMiniMapFog.fillStyle = 'rgb(0,0,0)'; contextMiniMapFog.fill(); contextMiniMapFog.closePath(); } // platforms } else if (thisObject.type === 'platform' && thisObject.part === 1) { // platform: larger outer circle, partially transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + platformOffset, y*game.tileSize + platformOffset, (platformVision/2)+10, 0, Math.PI*2, false); contextFog.fillStyle = 'rgba(0,0,0,0.5)'; contextFog.fill(); contextFog.closePath(); // platform: smaller inner circle, entirely transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + platformOffset, y*game.tileSize + platformOffset, platformVision/2, 0, Math.PI*2, false); contextFog.fillStyle = 'rgb(0,0,0)'; contextFog.fill(); contextFog.closePath(); if (admin.mini) { // platform: miniMapFog circle contextMiniMapFog.beginPath(); contextMiniMapFog.arc(Math.round((thisObject.x / game.mapTileMultiplier)+1), Math.round((thisObject.y / game.mapTileMultiplier)+1), Math.round((platformVision/2 / game.mapTileMultiplier)/16) + game.campVisionMiniAdjust, 0, Math.PI*2, false); contextMiniMapFog.fillStyle = 'rgb(0,0,0)'; contextMiniMapFog.fill(); contextMiniMapFog.closePath(); } // flagged trees } else if (thisObject.type === 'tree' && (thisObject.class === 'fir' || thisObject.class === 'birch') && thisObject.flagged === true) { // flag: larger outer circle, partially transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + you.offset, y*game.tileSize + you.offset, (flagVision/2)+10, 0, Math.PI*2, false); // you.offset works for flag too contextFog.fillStyle = 'rgba(0,0,0,0.5)'; contextFog.fill(); contextFog.closePath(); // flag: smaller inner circle, entirely transparent contextFog.beginPath(); contextFog.arc(x*game.tileSize + you.offset, y*game.tileSize + you.offset, flagVision/2, 0, Math.PI*2, false); contextFog.fillStyle = 'rgb(0,0,0)'; contextFog.fill(); contextFog.closePath(); } } } } } } // you: larger outer circle, partially transparent contextFog.beginPath(); contextFog.arc(game.mapCanvasHalfTiles*game.tileSize + you.offset, game.mapCanvasHalfTiles*game.tileSize + you.offset, visionRadius+10, 0, Math.PI*2, false); contextFog.fillStyle = 'rgba(0,0,0,0.5)'; contextFog.fill(); contextFog.closePath(); // you: smaller inner circle, entirely transparent contextFog.beginPath(); contextFog.arc(game.mapCanvasHalfTiles*game.tileSize + you.offset, game.mapCanvasHalfTiles*game.tileSize + you.offset, visionRadius, 0, Math.PI*2, false); contextFog.fillStyle = 'rgb(0,0,0)'; contextFog.fill(); contextFog.closePath(); if (admin.mini) { // you: miniMapFog circle contextMiniMapFog.beginPath(); contextMiniMapFog.arc(Math.round((you.tile.x / game.mapTileMultiplier)+1), Math.round((you.tile.y / game.mapTileMultiplier)+1), Math.round((visionRadius / game.mapTileMultiplier)/16), 0, Math.PI*2, false); // radius: 6 works for small map; game.mapFraction/2.5 works, but doesn't account for visionRadius contextMiniMapFog.fillStyle = 'rgb(0,0,0)'; contextMiniMapFog.fill(); contextMiniMapFog.closePath(); contextMiniMapFog.restore(); // works with .save() above } } // end drawFog // draw miniMap cursor function drawMiniMapCursor() { // clear canvas; only need to clear area around miniMapVis, plus a little larger to get border //contextMiniMapCursor.clearRect(0, 0, game.canvasMiniMapW, game.canvasMiniMapH); // clear entire canvas contextMiniMapCursor.clearRect(Math.round(you.tile.x/game.mapTileMultiplier) - (game.miniMapVisW/2) - 3, Math.round(you.tile.y/game.mapTileMultiplier) - (game.miniMapVisH/2) - 3, game.miniMapVisW+6, game.miniMapVisH+6); // you contextMiniMapCursor.fillStyle = 'rgb(255,255,255)'; contextMiniMapCursor.fillRect(Math.round(you.tile.x/game.mapTileMultiplier), Math.round(you.tile.y/game.mapTileMultiplier), game.markerSize, game.markerSize); // miniMapVis (adding 0.5 to avoid subpixel rendering) contextMiniMapCursor.beginPath(); contextMiniMapCursor.strokeStyle = 'rgb(52,66,81)'; contextMiniMapCursor.strokeRect(Math.round(Math.round(you.tile.x/game.mapTileMultiplier) - (game.miniMapVisW/2))+0.5, Math.round(Math.round(you.tile.y/game.mapTileMultiplier) - (game.miniMapVisH/2))+0.5, game.miniMapVisW, game.miniMapVisH); contextMiniMapCursor.closePath(); } // clear miniMapCursor function clearMiniMapCursor() { contextMiniMapCursor.clearRect(0, 0, game.canvasMiniMapW, game.canvasMiniMapH); } // draw minimap canvas function drawMiniMap() { var miniMapImage, miniMapImageData, miniMapMultiplier; // drawing each pixel in order using createImageData // see: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/ // could convert hex to rgb: http://stackoverflow.com/questions/4262417/jquery-hex-to-rgb-calculation-different-between-browsers if (game.softMap) { // for larger maps, 1x1 resized (much slower) $miniMapCanvas.attr({'width': game.mapTileCount, 'height': game.mapTileCount}); miniMapImage = contextMiniMap.createImageData(game.mapTileCount, game.mapTileCount); miniMapImageData = miniMapImage.data; miniMapMultiplier = 1; } else { miniMapImage = contextMiniMap.createImageData(game.canvasMiniMapPx, game.canvasMiniMapPx); miniMapImageData = miniMapImage.data; miniMapMultiplier = game.mapTileMultiplier; } var miniMapImageWidth = miniMapImage.width, miniMapImageHeight = miniMapImage.height; for (var x=0; x 3 && mapValue < 5)) { miniMapImageData[idx + 0] = 85; // red miniMapImageData[idx + 1] = 145; // green miniMapImageData[idx + 2] = 176; // blue miniMapImageData[idx + 3] = 255; // alpha } // shallows: 67A0B7 if (mapValue > 0.45 && mapValue <= 0.55) { miniMapImageData[idx + 0] = 103; // red miniMapImageData[idx + 1] = 160; // green miniMapImageData[idx + 2] = 183; // blue miniMapImageData[idx + 3] = 255; // alpha } // sand: D3D1A5 if (mapValue > 0.55 && mapValue <= 0.6) { miniMapImageData[idx + 0] = 211; // red miniMapImageData[idx + 1] = 209; // green miniMapImageData[idx + 2] = 165; // blue miniMapImageData[idx + 3] = 255; // alpha } // field & grass: 91B58C if ((mapValue > 0.6 && mapValue < 0.99 && airValue > 0.5) || (mapValue === 2.4 && airValue > 0.5)) { miniMapImageData[idx + 0] = 145; // red miniMapImageData[idx + 1] = 181; // green miniMapImageData[idx + 2] = 140; // blue miniMapImageData[idx + 3] = 255; // alpha } // field & grass (alternate): 8AAD86 if ((mapValue > 0.6 && mapValue < 0.99 && airValue <= 0.5) || (mapValue === 2.4 && airValue <= 0.5) || (mapValue >= 6 && mapValue <= 7.99)) { miniMapImageData[idx + 0] = 138; // red miniMapImageData[idx + 1] = 173; // green miniMapImageData[idx + 2] = 134; // blue miniMapImageData[idx + 3] = 255; // alpha } // hill & mountain: 8c9074 if ((mapValue >= 0.99 && mapValue <= 1.4) || (mapValue >= 2.1 && mapValue <= 2.3) || (mapValue >= 5.1 && mapValue <= 5.6)) { miniMapImageData[idx + 0] = 140; // red miniMapImageData[idx + 1] = 144; // green miniMapImageData[idx + 2] = 116; // blue miniMapImageData[idx + 3] = 255; // alpha } } } var miniMapImage = contextMiniMap.putImageData(miniMapImage, 0, 0); if (game.softMap) { $miniMapCanvas.width(128).height(128); // for larger maps, 1x1 resized (much slower) } // draw trees on miniMap (always uses game.mapTileMultiplier, not miniMapMultiplier) if (game.miniMapTrees) { contextMiniMapSprites.fillStyle = '#477747'; for (var x=0; x 3 && mapArray[x][y] < 5)) { miniMapPixelData[0] = 85; // red miniMapPixelData[1] = 145; // green miniMapPixelData[2] = 176; // blue miniMapPixelData[3] = 255; // alpha } // shallows: 67A0B7 if (mapArray[x][y] > 0.45 && mapArray[x][y] <= 0.55) { miniMapPixelData[0] = 103; // red miniMapPixelData[1] = 160; // green miniMapPixelData[2] = 183; // blue miniMapPixelData[3] = 255; // alpha } // sand: D3D1A5 if (mapArray[x][y] > 0.55 && mapArray[x][y] <= 0.6) { miniMapPixelData[0] = 211; // red miniMapPixelData[1] = 209; // green miniMapPixelData[2] = 165; // blue miniMapPixelData[3] = 255; // alpha } // field & grass: 91B58C if ((mapArray[x][y] > 0.6 && mapArray[x][y] < 0.99 && airArray[x][y] > 0.5) || (mapArray[x][y] === 2.4 && airArray[x][y] > 0.5)) { miniMapPixelData[0] = 145; // red miniMapPixelData[1] = 181; // green miniMapPixelData[2] = 140; // blue miniMapPixelData[3] = 255; // alpha } // field & grass (alternate): 8AAD86 if ((mapArray[x][y] > 0.6 && mapArray[x][y] < 0.99 && airArray[x][y] <= 0.5) || (mapArray[x][y] === 2.4 && airArray[x][y] <= 0.5) || (mapArray[x][y] >= 6 && mapArray[x][y] <= 7.99)) { miniMapPixelData[0] = 138; // red miniMapPixelData[1] = 173; // green miniMapPixelData[2] = 134; // blue miniMapPixelData[3] = 255; // alpha } // hill & mountain: 8c9074 if ((mapArray[x][y] >= 0.99 && mapArray[x][y] <= 1.4) || (mapArray[x][y] >= 2.1 && mapArray[x][y] <= 2.3) || (mapArray[x][y] >= 5.1 && mapArray[x][y] <= 5.6)) { miniMapPixelData[0] = 140; // red miniMapPixelData[1] = 144; // green miniMapPixelData[2] = 116; // blue miniMapPixelData[3] = 255; // alpha } contextMiniMap.putImageData(miniMapPixel, x, y); } // add marker to miniMap function miniMapMarker(x, y, color) { color = color || false; // set defaults if parameters are undefined if (admin.mini) { if (color) { $miniMap.append('
'); } else { $miniMap.append('
'); } } } // starts off the map generation, seeds the first 4 corners function seedMap(dataObject) { var x = game.mapSize, y = game.mapSize, tr, tl, t, br, bl, b, r, l, center; // top left dataObject[0][0] = Math.random(); tl = dataObject[0][0]; // bottom left dataObject[0][game.mapSize] = Math.random(); bl = dataObject[0][game.mapSize]; // top right dataObject[game.mapSize][0] = Math.random(); tr = dataObject[game.mapSize][0]; // bottom right dataObject[game.mapSize][game.mapSize] = Math.random(); br = dataObject[game.mapSize][game.mapSize] // center dataObject[game.mapSize / 2][game.mapSize / 2] = dataObject[0][0] + dataObject[0][game.mapSize] + dataObject[game.mapSize][0] + dataObject[game.mapSize][game.mapSize] / 4; dataObject[game.mapSize / 2][game.mapSize / 2] = normalize(dataObject[game.mapSize / 2][game.mapSize / 2]); center = dataObject[game.mapSize / 2][game.mapSize / 2]; dataObject[game.mapSize / 2][game.mapSize] = bl + br + center / 3; dataObject[game.mapSize / 2][0] = tl + tr + center / 3; dataObject[game.mapSize][game.mapSize / 2] = tr + br + center / 3; dataObject[0][game.mapSize / 2] = tl + bl + center / 3; // call displacment midpointDisplacement(dataObject, game.mapSize); } /* player generation and control */ // set up map, given tile location x, y, or a random suitable tile function loadPlayer() { // if startX and startY are defined, use starting tile, else find a random tile that is walkable by the player if (start.tile.x !== false && start.tile.y !== false) { // just use start.tile as is } else { start.tile = randomOneOf(startTilesArray); } // if can't get suitable starting tile, set coordinates to center if (!start.tile) { console.log('Couldn\'t locate suitable starting tile.'); status('Something went wrong... please reload the page.'); start.tile = {x: Math.round(game.mapTileCount/2), y: Math.round(game.mapTileCount/2)}; } you.tile.x = start.tile.x; you.tile.y = start.tile.y; mapOffsetX = you.tile.x - game.mapCanvasHalfTiles; mapOffsetY = you.tile.y - game.mapCanvasHalfTiles; drawOffsetX = mapOffsetX * game.tileSize; drawOffsetY = mapOffsetY * game.tileSize; // if player starts with radio, load radio if (you.inventory.radio.count >= 1) { loadRadio(); } // add trail data to starting tile //mapArray[start.tile.x][start.tile.y].trail = mapArray[start.tile.x][start.tile.y].trail*1 + 1; // preload sprites tiles // 1x1 sprites1x1Image = new Image(); sprites1x1Image.src = 'images/sprites-1x1.png'; sprites1x1Image.onload = function() { sprites1x1 = []; var names1x1 = [ 'you', 'youSleep1', 'youSleep2', 'youSleep3', 'youSleep4', 'youRaft', 'youCanoe', 'youWater', 'youCold', 'youColdRaft', 'youColdCanoe', 'waves1', 'waves2', 'waves3', 'waves4', 'waves5', 'waves6', 'waves7', 'waves8', 'waves9', 'waves10', 'grass', 'flowers1', 'flowers2', 'weeds', 'rocks', 'hill1', 'hill2', 'mountain1', 'mountain2', 'alderSeedling', 'alderTree', 'mapleSeedling', 'mapleTree', 'pineSeedling', 'pineTree', 'stump', 'berries', 'bone', 'ice', 'shell', 'stone1', 'stone2', 'slate', 'quartz', 'stepStone1', 'stepStone2', 'stepStone3', 'stepStone4', 'stepStone5', 'stepStone6', 'stepStone7', 'stepStone8', 'stepStone9', 'stepStone10', 'bridge', 'snare', 'snareRabbit', 'hole1', 'hole2', 'hole3', 'hole4', 'map', 'backpack', 'binoculars', 'radio', 'fire1', 'fire2', 'fire3', 'fire4', 'fire5', 'smoke1', 'smoke2', 'smoke3' ]; for (var i=0, iLimit=names1x1.length; i