diff --git a/.project b/.project index d6959e1..33ac207 100644 --- a/.project +++ b/.project @@ -5,7 +5,13 @@ + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + org.eclipse.wst.jsdt.core.jsNature diff --git a/index.html b/index.html index 78e532c..719d16b 100644 --- a/index.html +++ b/index.html @@ -16,11 +16,13 @@ + + diff --git a/script/engine.js b/script/engine.js index 189454b..2c6d3b1 100644 --- a/script/engine.js +++ b/script/engine.js @@ -7,8 +7,12 @@ var Engine = { * That would be so elegant and awesome. */ SITE_URL: encodeURIComponent("http://adarkroom.doublespeakgames.com"), + VERSION: 1.3, MAX_STORE: 99999999999999, SAVE_DISPLAY: 30 * 1000, + + //object event types + topics: {}, Perks: { 'boxer': { @@ -111,18 +115,22 @@ var Engine = { swipeElement.on('swiperight', Engine.swipeRight); swipeElement.on('swipeup', Engine.swipeUp); swipeElement.on('swipedown', Engine.swipeDown); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Engine.handleStateUpdates); + $SM.init(); Notifications.init(); Events.init(); Room.init(); - if(Engine.storeAvailable('wood')) { + if($SM.get('stores.wood')) { Outside.init(); } - if(Engine.getStore('compass') > 0) { + if($SM.get('stores.compass', true) > 0) { Path.init(); } - if(State.ship) { + if($SM.get('features.location.spaceShip')) { Ship.init(); } @@ -159,43 +167,16 @@ var Engine = { var savedState = JSON.parse(localStorage.gameState); if(savedState) { State = savedState; - Engine.upgradeState(); + $SM.updateOldState(); Engine.log("loaded save!"); } } catch(e) { - State = { - version: 1.2, - stores: {}, - perks: {} - }; + State = {}; + $SM.set('version', Engine.VERSION); Engine.event('progress', 'new game'); } }, - upgradeState: function() { - /* Use this function to make old - * save games compatible with newer versions */ - if(typeof State.version != 'number') { - Engine.log('upgraded save to v1.0'); - State.version = 1.0; - } - if(State.version == 1.0) { - // v1.1 introduced the Lodge, so get rid of lodgeless hunters - delete State.outside.workers.hunter; - delete State.income.hunter; - Engine.log('upgraded save to v1.1'); - State.version = 1.1; - } - if(State.version == 1.1) { - //v1.2 added the Swamp to the map, so add it to already generated maps - if(State.world) { - World.placeLandmark(15, World.RADIUS * 1.5, World.TILE.SWAMP, State.world.map); - } - Engine.log('upgraded save to v1.2'); - State.version = 1.2; - } - }, - event: function(cat, act) { if(typeof ga === 'function') { ga('send', 'event', cat, act); @@ -298,7 +279,7 @@ var Engine = { var diff = Math.abs(panelIndex - currentIndex); slider.animate({left: -(panelIndex * 700) + 'px'}, 300 * diff); - if(Engine.storeAvailable('wood')) { + if($SM.get('stores.wood') != undefined) { // FIXME Why does this work if there's an animation queue...? stores.animate({right: -(panelIndex * 700) + 'px'}, 300 * diff); } @@ -322,204 +303,6 @@ var Engine = { Notifications.printQueue(module); } }, - - addPerk: function(name) { - if(!State.perks) { - State.perks = {}; - } - State.perks[name] = true; - Notifications.notify(null, Engine.Perks[name].notify); - if(Engine.activeModule == Path) { - Path.updatePerks(); - } - }, - - hasPerk: function(name) { - return typeof State.perks == 'object' && State.perks[name] == true; - }, - - setStore: function(name, number) { - if(typeof State.stores == 'undefined') { - State.stores = {}; - } - if(number > Engine.MAX_STORE) number = Engine.MAX_STORE; - State.stores[name] = number; - Room.updateStoresView(); - Room.updateBuildButtons(); - if(State.outside) { - Outside.updateVillage(); - } - Engine.saveGame(); - }, - - setStores: function(list) { - if(typeof State.stores == 'undefined') { - State.stores = {}; - } - for(k in list) { - State.stores[k] = list[k] > Engine.MAX_STORE ? Engine.MAX_STORE : list[k]; - } - Room.updateStoresView(); - Room.updateBuildButtons(); - if(State.outside) { - Outside.updateVillage(); - } - Engine.saveGame(); - }, - - addStore: function(name, number) { - if(typeof State.stores == 'undefined') { - State.stores = {}; - } - var num = State.stores[name]; - if(typeof num != 'number' || isNaN(num) || num < 0) num = 0; - num += number; - if(num > Engine.MAX_STORE) num = Engine.MAX_STORE; - State.stores[name] = num; - Room.updateStoresView(); - Room.updateBuildButtons(); - Outside.updateVillage(); - if(Engine.activeModule == Path) { - Path.updateOutfitting(); - } - Engine.saveGame(); - }, - - addStores: function(list, ignoreCosts) { - if(typeof State.stores == 'undefined') { - State.stores = {}; - } - - // Make sure any income costs can be paid - if(!ignoreCosts) { - for(k in list) { - var num = State.stores[k]; - if(typeof num != 'number' || isNaN(num) || num < 0) num = 0; - if(num + list[k] < 0) { - return false; - } - } - } - - // Actually do the update - for(k in list) { - var num = State.stores[k]; - if(typeof num != 'number') num = 0; - num += list[k]; - num = num < 0 ? 0 : num; - num = num > Engine.MAX_STORE ? Engine.MAX_STORE : num; - State.stores[k] = num; - } - Room.updateStoresView(); - Room.updateBuildButtons(); - Outside.updateVillage(); - if(Engine.activeModule == Path) { - Path.updateOutfitting(); - } - Engine.saveGame(); - return true; - }, - - storeAvailable: function(name) { - return typeof State.stores[name] == 'number'; - }, - - getStore: function(name) { - if(typeof State.stores == 'undefined' || typeof State.stores[name] == 'undefined' ) { - return 0; - } - return State.stores[name]; - }, - - setIncome: function(source, options) { - if(typeof State.income == 'undefined') { - State.income = {}; - } - var existing = State.income[source]; - if(typeof existing != 'undefined') { - options.timeLeft = existing.timeLeft; - } - State.income[source] = options; - }, - - getIncome: function(source) { - if(typeof State.income == 'undefined') { - State.income = {}; - } - var existing = State.income[source]; - if(typeof existing != 'undefined') { - return existing; - } - return {}; - }, - - removeIncome: function(source) { - if(State.income) { - delete State.income[source]; - } - Room.updateIncomeView(); - }, - - collectIncome: function() { - if(typeof State.income != 'undefined' && Engine.activeModule != Space) { - var changed = false; - for(var source in State.income) { - var income = State.income[source]; - if(typeof income.timeLeft != 'number') - { - income.timeLeft = 0; - } - income.timeLeft--; - - if(income.timeLeft <= 0) { - Engine.log('collection income from ' + source); - if(source == 'thieves') { - Engine.addStolen(income.stores); - } - changed = Engine.addStores(income.stores) || changed; - if(typeof income.delay == 'number') { - income.timeLeft = income.delay; - } - } - } - if(changed) { - Room.updateStoresView(); - Room.updateBuildButtons(); - Engine.saveGame(); - if(Events.activeEvent() != null) { - Events.updateButtons(); - } - } - } - Engine._incomeTimeout = setTimeout(Engine.collectIncome, 1000); - }, - - openPath: function() { - Path.init(); - Engine.event('progress', 'path'); - Notifications.notify(Room, 'the compass points ' + World.dir); - }, - - addStolen: function(stores) { - if(!State.stolen) State.stolen = {}; - for(var k in stores) { - if(!State.stolen[k]) State.stolen[k] = 0; - State.stolen[k] -= stores[k]; - } - }, - - startThieves: function() { - State.thieves = 1; - Engine.setIncome('thieves', { - delay: 10, - stores: { - 'wood': -10, - 'fur': -5, - 'meat': -5 - } - }); - Room.updateIncomeView(); - }, // Move the stores panel beneath top_container (or to top: 0px if top_container // either hasn't been filled in or is null) using transition_diff to sync with @@ -544,18 +327,6 @@ var Engine = { } }, - num: function(name, craftable) { - switch(craftable.type) { - case 'good': - case 'tool': - case 'weapon': - case 'upgrade': - return Engine.getStore(name); - case 'building': - return Outside.numBuilding(name); - } - }, - log: function(msg) { if(this._log) { console.log(msg); @@ -616,9 +387,32 @@ var Engine = { if(Engine.activeModule.swipeDown) { Engine.activeModule.swipeDown(e); } + }, + + handleStateUpdates: function(e){ + } }; +//create jQuery Callbacks() to handle object events +$.Dispatch = function( id ) { + var callbacks, + method, + topic = id && Engine.topics[ id ]; + if ( !topic ) { + callbacks = jQuery.Callbacks(); + topic = { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove + }; + if ( id ) { + Engine.topics[ id ] = topic; + } + } + return topic; +}; + $(function() { Engine.init(); }); \ No newline at end of file diff --git a/script/events.js b/script/events.js index 7ee53b2..b78d483 100644 --- a/script/events.js +++ b/script/events.js @@ -26,6 +26,9 @@ var Events = { Events.eventStack = []; Events.scheduleNextEvent(); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Events.handleStateUpdates); }, options: {}, // Nothing for now @@ -41,7 +44,7 @@ var Events = { // Scene reward if(scene.reward) { - Engine.addStores(scene.reward, true); + $SM.addM('stores', scene.reward); } // onLoad @@ -157,7 +160,7 @@ var Events = { var weapon = World.Weapons[weaponName]; var cd = weapon.cooldown; if(weapon.type == 'unarmed') { - if(Engine.hasPerk('unarmed master')) { + if($SM.hasPerk('unarmed master')) { cd /= 2; } } @@ -243,14 +246,14 @@ var Events = { var weaponName = btn.attr('id').substring(7).replace('-', ' '); var weapon = World.Weapons[weaponName]; if(weapon.type == 'unarmed') { - if(!State.punches) State.punches = 0; - State.punches++; - if(State.punches == 50 && !Engine.hasPerk('boxer')) { - Engine.addPerk('boxer'); - } else if(State.punches == 150 && !Engine.hasPerk('martial artist')) { - Engine.addPerk('martial artist'); - } else if(State.punches == 300 && !Engine.hasPerk('unarmed master')) { - Engine.addPerk('unarmed master'); + if(!$SM.get('character.punches')) $SM.set('character.punches', 0); + $SM.add('character.punches', 1); + if($SM.get('character.punches') == 50 && !$SM.hasPerk('boxer')) { + $SM.addPerk('boxer'); + } else if($SM.get('character.punches') == 150 && !$SM.hasPerk('martial artist')) { + $SM.addPerk('martial artist'); + } else if($SM.get('character.punches') == 300 && !$SM.hasPerk('unarmed master')) { + $SM.addPerk('unarmed master'); } } @@ -294,16 +297,16 @@ var Events = { if(Math.random() <= World.getHitChance()) { dmg = weapon.damage; if(typeof dmg == 'number') { - if(weapon.type == 'unarmed' && Engine.hasPerk('boxer')) { + if(weapon.type == 'unarmed' && $SM.hasPerk('boxer')) { dmg *= 2 } - if(weapon.type == 'unarmed' && Engine.hasPerk('martial artist')) { + if(weapon.type == 'unarmed' && $SM.hasPerk('martial artist')) { dmg *= 3; } - if(weapon.type == 'unarmed' && Engine.hasPerk('unarmed master')) { + if(weapon.type == 'unarmed' && $SM.hasPerk('unarmed master')) { dmg *= 2; } - if(weapon.type == 'melee' && Engine.hasPerk('barbarian')) { + if(weapon.type == 'melee' && $SM.hasPerk('barbarian')) { dmg = Math.floor(dmg * 1.5); } } @@ -417,7 +420,7 @@ var Events = { if(!$('#enemy').data('stunned')) { var toHit = scene.hit; - toHit *= Engine.hasPerk('evasive') ? 0.8 : 1; + toHit *= $SM.hasPerk('evasive') ? 0.8 : 1; var dmg = -1; if(Math.random() <= toHit) { dmg = scene.damage; @@ -646,7 +649,7 @@ var Events = { } else if(b.cost) { var disabled = false; for(var store in b.cost) { - var num = Engine.activeModule == World ? Path.outfit[store] : Engine.getStore(store); + var num = Engine.activeModule == World ? Path.outfit[store] : $SM.get('stores["'+store+'"]', true); if(typeof num != 'number') num = 0; if(num < b.cost[store]) { // Too expensive @@ -665,7 +668,7 @@ var Events = { var costMod = {}; if(info.cost) { for(var store in info.cost) { - var num = Engine.activeModule == World ? Path.outfit[store] : Engine.getStore(store); + var num = Engine.activeModule == World ? Path.outfit[store] : $SM.get('stores["'+store+'"]', true); if(typeof num != 'number') num = 0; if(num < info.cost[store]) { // Too expensive @@ -679,7 +682,7 @@ var Events = { } World.updateSupplies(); } else { - Engine.addStores(costMod); + $SM.addM('stores', costMod); } } @@ -689,7 +692,7 @@ var Events = { // Reward if(info.reward) { - Engine.addStores(info.reward); + $SM.addM('stores', info.reward); } Events.updateButtons(); @@ -802,6 +805,12 @@ var Events = { Engine.keyLock = false; // Force refocus on the body. I hate you, IE. $('body').focus(); - }); - } -}; + }); + }, + + handleStateUpdates: function(e){ + if(e.category == 'stores' && Events.activeEvent() != null){ + Events.updateButtons(); + } + } +}; \ No newline at end of file diff --git a/script/events/global.js b/script/events/global.js index 64f4021..85ca99a 100644 --- a/script/events/global.js +++ b/script/events/global.js @@ -5,7 +5,7 @@ Events.Global = [ { /* The Thief */ title: 'The Thief', isAvailable: function() { - return (Engine.activeModule == Room || Engine.activeModule == Outside) && State.thieves == 1; + return (Engine.activeModule == Room || Engine.activeModule == Outside) && $SM.get('game.thieves') == 1; }, scenes: { 'start': { @@ -32,9 +32,9 @@ Events.Global = [ 'the point is made. in the next few days, the missing supplies are returned.' ], onLoad: function() { - State.thieves = 2; - Engine.removeIncome('thieves'); - Engine.addStores(State.stolen); + $SM.set('game.thieves', 2); + $SM.remove('income.thieves'); + $SM.addM('stores', $SM.get('game.stolen')); }, buttons: { 'leave': { @@ -49,9 +49,9 @@ Events.Global = [ "shares what he knows about sneaking before he goes." ], onLoad: function() { - State.thieves = 2; - Engine.removeIncome('thieves'); - Engine.addPerk('stealthy'); + $SM.set('game.thieves', 2); + $SM.remove('income.thieves'); + $SM.addPerk('stealthy'); }, buttons: { 'leave': { diff --git a/script/events/outside.js b/script/events/outside.js index aa1b7c7..83cbefb 100644 --- a/script/events/outside.js +++ b/script/events/outside.js @@ -5,7 +5,7 @@ Events.Outside = [ { /* Ruined traps */ title: 'A Ruined Trap', isAvailable: function() { - return Engine.activeModule == Outside && Outside.numBuilding('trap') > 0; + return Engine.activeModule == Outside && $SM.get('game.buildings["trap"]', true) > 0; }, scenes: { 'start': { @@ -14,8 +14,8 @@ Events.Outside = [ 'large prints lead away, into the forest.' ], onLoad: function() { - var numWrecked = Math.floor(Math.random() * Outside.numBuilding('trap')) + 1; - Outside.addBuilding('trap', -numWrecked); + var numWrecked = Math.floor(Math.random() * $SM.get('game.buildings["trap"]', true)) + 1; + $SM.add('game.buildings["trap"]', -numWrecked); Outside.updateVillage(); Outside.updateTrapButton(); }, @@ -66,7 +66,7 @@ Events.Outside = [ { /* Sickness */ title: 'Sickness', isAvailable: function() { - return Engine.activeModule == Outside && Outside.getPopulation() > 10 && Outside.getPopulation() < 50; + return Engine.activeModule == Outside && $SM.get('game.population', true) > 10 && $SM.get('game.population', true) < 50; }, scenes: { 'start': { @@ -120,7 +120,7 @@ Events.Outside = [ { /* Plague */ title: 'Plague', isAvailable: function() { - return Engine.activeModule == Outside && Outside.getPopulation() > 50; + return Engine.activeModule == Outside && $SM.get('game.population', true) > 50; }, scenes: { 'start': { @@ -180,7 +180,7 @@ Events.Outside = [ { /* Beast attack */ title: 'A Beast Attack', isAvailable: function() { - return Engine.activeModule == Outside && Outside.getPopulation() > 0; + return Engine.activeModule == Outside && $SM.get('game.population', true) > 0; }, scenes: { 'start': { @@ -211,7 +211,7 @@ Events.Outside = [ { /* Soldier attack */ title: 'A Military Raid', isAvailable: function() { - return Engine.activeModule == Outside && Outside.getPopulation() > 0 && State.cityCleared; + return Engine.activeModule == Outside && $SM.get('game.population', true) > 0 && $SM.get('game.cityCleared');; }, scenes: { 'start': { diff --git a/script/events/room.js b/script/events/room.js index cb9ea1c..fcd4beb 100644 --- a/script/events/room.js +++ b/script/events/room.js @@ -5,7 +5,7 @@ Events.Room = [ { /* The Nomad -- Merchant */ title: 'The Nomad', isAvailable: function() { - return Engine.activeModule == Room && Engine.getStore('fur') > 0; + return Engine.activeModule == Room && $SM.get('stores.fur', true) > 0; }, scenes: { 'start': { @@ -33,13 +33,13 @@ Events.Room = [ }, 'buyCompass': { available: function() { - return Engine.getStore('compass') < 1; + return $SM.get('stores.compass', true) < 1; }, text: 'buy compass', cost: { fur: 300, scales: 15, teeth: 5 }, reward: { 'compass': 1 }, notification: 'the old compass is dented and dusty, but it looks to work.', - onChoose: Engine.openPath + onChoose: Path.openPath }, 'goodbye': { text: 'say goodbye', @@ -51,7 +51,7 @@ Events.Room = [ }, { /* Noises Outside -- gain wood/fur */ title: 'Noises', isAvailable: function() { - return Engine.activeModule == Room && Engine.storeAvailable('wood'); + return Engine.activeModule == Room && $SM.get('stores.wood'); }, scenes: { 'start': { @@ -101,7 +101,7 @@ Events.Room = [ { /* Noises Inside -- trade wood for better good */ title: 'Noises', isAvailable: function() { - return Engine.activeModule == Room && Engine.storeAvailable('wood'); + return Engine.activeModule == Room && $SM.get('stores.wood'); }, scenes: { start: { @@ -127,12 +127,12 @@ Events.Room = [ 'the ground is littered with small scales' ], onLoad: function() { - var numWood = Engine.getStore('wood'); + var numWood = $SM.get('stores.wood', true); numWood = Math.floor(numWood * 0.1); if(numWood == 0) numWood = 1; var numScales = Math.floor(numWood / 5); if(numScales == 0) numScales = 1; - Engine.addStores({wood: -numWood, scales: numScales}); + $SM.addM('stores', {'wood': -numWood, 'scales': numScales}); }, buttons: { 'leave': { @@ -147,12 +147,12 @@ Events.Room = [ 'the ground is littered with small teeth' ], onLoad: function() { - var numWood = Engine.getStore('wood'); + var numWood = $SM.get('stores.wood', true); numWood = Math.floor(numWood * 0.1); if(numWood == 0) numWood = 1; var numTeeth = Math.floor(numWood / 5); if(numTeeth == 0) numTeeth = 1; - Engine.addStores({wood: -numWood, teeth: numTeeth}); + $SM.addM('stores', {'wood': -numWood, 'teeth': numTeeth}); }, buttons: { 'leave': { @@ -167,12 +167,12 @@ Events.Room = [ 'the ground is littered with scraps of cloth' ], onLoad: function() { - var numWood = Engine.getStore('wood'); + var numWood = $SM.get('stores.wood', true); numWood = Math.floor(numWood * 0.1); if(numWood == 0) numWood = 1; var numCloth = Math.floor(numWood / 5); if(numCloth == 0) numCloth = 1; - Engine.addStores({wood: -numWood, cloth: numCloth}); + $SM.addM('stores', {'wood': -numWood, 'cloth': numCloth}); }, buttons: { 'leave': { @@ -186,7 +186,7 @@ Events.Room = [ { /* The Beggar -- trade fur for better good */ title: 'The Beggar', isAvailable: function() { - return Engine.activeModule == Room && Engine.storeAvailable('fur'); + return Engine.activeModule == Room && $SM.get('stores.fur'); }, scenes: { start: { @@ -257,7 +257,7 @@ Events.Room = [ { /* Mysterious Wanderer -- wood gambling */ title: 'The Mysterious Wanderer', isAvailable: function() { - return Engine.activeModule == Room && Engine.storeAvailable('wood'); + return Engine.activeModule == Room && $SM.get('stores.wood'); }, scenes: { start: { @@ -290,7 +290,7 @@ Events.Room = [ onLoad: function() { if(Math.random() < 0.5) { setTimeout(function() { - Engine.addStore('wood', 300); + $SM.add('stores.wood', 300); Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with wood.'); }, 60 * 1000); } @@ -309,7 +309,7 @@ Events.Room = [ onLoad: function() { if(Math.random() < 0.3) { setTimeout(function() { - Engine.addStore('wood', 1500); + $SM.add('stores.wood', 1500); Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with wood.'); }, 60 * 1000); } @@ -327,7 +327,7 @@ Events.Room = [ { /* Mysterious Wanderer -- fur gambling */ title: 'The Mysterious Wanderer', isAvailable: function() { - return Engine.activeModule == Room && Engine.storeAvailable('fur'); + return Engine.activeModule == Room && $SM.get('stores.fur'); }, scenes: { start: { @@ -360,7 +360,7 @@ Events.Room = [ onLoad: function() { if(Math.random() < 0.5) { setTimeout(function() { - Engine.addStore('fur', 300); + $SM.add('stores.fur', 300); Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with furs.'); }, 60 * 1000); } @@ -379,7 +379,7 @@ Events.Room = [ onLoad: function() { if(Math.random() < 0.3) { setTimeout(function() { - Engine.addStore('fur', 1500); + $SM.add('stores.fur', 1500); Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with furs.'); }, 60 * 1000); } @@ -397,7 +397,7 @@ Events.Room = [ { /* The Scout -- Map Merchant */ title: 'The Scout', isAvailable: function() { - return Engine.activeModule == Room && typeof State.world == 'object'; + return Engine.activeModule == Room && $SM.get('features.location.world'); }, scenes: { 'start': { @@ -417,10 +417,10 @@ Events.Room = [ text: 'learn scouting', cost: { 'fur': 1000, 'scales': 50, 'teeth': 20 }, available: function() { - return !Engine.hasPerk('scout'); + return !$SM.hasPerk('scout'); }, onChoose: function() { - Engine.addPerk('scout'); + $SM.addPerk('scout'); } }, 'leave': { @@ -435,7 +435,7 @@ Events.Room = [ { /* The Wandering Master */ title: 'The Master', isAvailable: function() { - return Engine.activeModule == Room && typeof State.world == 'object'; + return Engine.activeModule == Room && $SM.get('features.location.world'); }, scenes: { 'start': { @@ -468,30 +468,30 @@ Events.Room = [ 'evasion': { text: 'evasion', available: function() { - return !Engine.hasPerk('evasive'); + return !$SM.hasPerk('evasive'); }, onChoose: function() { - Engine.addPerk('evasive'); + $SM.addPerk('evasive'); }, nextScene: 'end' }, 'precision': { text: 'precision', available: function() { - return !Engine.hasPerk('precise'); + return !$SM.hasPerk('precise'); }, onChoose: function() { - Engine.addPerk('precise'); + $SM.addPerk('precise'); }, nextScene: 'end' }, 'force': { text: 'force', available: function() { - return !Engine.hasPerk('barbarian'); + return !$SM.hasPerk('barbarian'); }, onChoose: function() { - Engine.addPerk('barbarian'); + $SM.addPerk('barbarian'); }, nextScene: 'end' }, @@ -507,7 +507,7 @@ Events.Room = [ { /* The Sick Man */ title: 'The Sick Man', isAvailable: function() { - return Engine.activeModule == Room && typeof State.world == 'object'; + return Engine.activeModule == Room && $SM.get('features.location.world'); }, scenes: { 'start': { @@ -536,7 +536,7 @@ Events.Room = [ 'some weird metal he picked up on his travels.' ], onLoad: function() { - Engine.addStore('alien alloy', 1); + $SM.add('stores["alien alloy"]', 1); }, buttons: { 'bye': { @@ -552,7 +552,7 @@ Events.Room = [ 'some weird glowing boxes he picked up on his travels.' ], onLoad: function() { - Engine.addStore('energy cell', 3); + $SM.add('stores["energy cell"]', 3); }, buttons: { 'bye': { @@ -568,7 +568,7 @@ Events.Room = [ 'all he has are some scales.' ], onLoad: function() { - Engine.addStore('scales', 5); + $SM.add('stores.scales', 5); }, buttons: { 'bye': { diff --git a/script/events/setpieces.js b/script/events/setpieces.js index 9ba8a83..4227ff0 100644 --- a/script/events/setpieces.js +++ b/script/events/setpieces.js @@ -74,7 +74,7 @@ Events.Setpieces = { 'his time here, now, is his penance.' ], onLoad: function() { - Engine.addPerk('gastronome'); + $SM.addPerk('gastronome'); World.markVisited(World.curPos[0], World.curPos[1]); }, buttons: { @@ -2244,7 +2244,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { bullets: { @@ -2278,7 +2278,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { torch: { @@ -2308,7 +2308,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { rifle: { @@ -2354,7 +2354,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { rifle: { @@ -2389,7 +2389,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { rifle: { @@ -2429,7 +2429,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'laser rifle': { @@ -2464,7 +2464,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'steel sword': { @@ -2499,7 +2499,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'steel sword': { @@ -2534,7 +2534,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'rifle': { @@ -2574,7 +2574,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'energy cell': { @@ -2613,7 +2613,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'energy cell': { @@ -2646,7 +2646,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'energy cell': { @@ -2695,7 +2695,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'steel sword': { @@ -2739,7 +2739,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'energy cell': { @@ -2782,7 +2782,7 @@ Events.Setpieces = { ], onLoad: function() { World.clearDungeon(); - State.cityCleared = true; + $SM.set('game.cityCleared', true); }, loot: { 'alien alloy': { diff --git a/script/outside.js b/script/outside.js index 23daebd..5903c20 100644 --- a/script/outside.js +++ b/script/outside.js @@ -135,12 +135,14 @@ var Outside = { .addClass('location') .appendTo('div#locationSlider'); - if(typeof State.outside == 'undefined') { - State.outside = { - buildings: {}, - population: 0, - workers: {} - } + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Outside.handleStateUpdates); + + if(typeof $SM.get('features.location.outside') == 'undefined') { + $SM.set('features.location.outside', true); + if(!$SM.get('game.buildings')) $SM.set('game.buildings', {}); + if(!$SM.get('game.population')) $SM.set('game.population', 0); + if(!$SM.get('game.workers')) $SM.set('game.workers', {}); } this.updateVillage(); @@ -158,46 +160,12 @@ var Outside = { }).appendTo('div#outsidePanel'); }, - numBuilding: function(bName) { - return State.outside && - State.outside.buildings && - State.outside.buildings[bName] ? State.outside.buildings[bName] : 0; - }, - - addBuilding: function(bName, num) { - var cur = State.outside.buildings[bName]; - if(typeof cur != 'number') cur = 0; - cur += num; - if(cur < 0) cur = 0; - State.outside.buildings[bName] = cur; - this.updateVillage(); - Engine.saveGame(); - }, - - addBuildings: function(list) { - for(k in list) { - var num = State.outside.buildings[k]; - if(typeof num != 'number') num = 0; - num += list[k]; - State.outside.buildings[k] = num; - } - this.updateVillage(); - Engine.saveGame(); - }, - getMaxPopulation: function() { - return Outside.numBuilding('hut') * 4; - }, - - getPopulation: function() { - if(State.outside && State.outside.population) { - return State.outside.population; - } - return 0; + return $SM.get('game.buildings["hut"]', true) * 4; }, increasePopulation: function() { - var space = Outside.getMaxPopulation() - State.outside.population; + var space = Outside.getMaxPopulation() - $SM.get('game.population'); if(space > 0) { var num = Math.floor(Math.random()*(space/2) + space/2); if(num == 0) num = 1; @@ -213,36 +181,30 @@ var Outside = { Notifications.notify(null, "the town's booming. word does get around."); } Engine.log('population increased by ' + num); - State.outside.population += num; - Outside.updateVillage(); - Outside.updateWorkersView(); - Outside.updateVillageIncome(); + $SM.add('game.population', num); } Outside.schedulePopIncrease(); }, killVillagers: function(num) { - State.outside.population -= num; - if(State.outside.population < 0) { - State.outside.population = 0; + $SM.add('game.population', num * -1); + if($SM.get('game.population') < 0) { + $SM.set('game.population', 0); } var remaining = Outside.getNumGatherers(); if(remaining < 0) { var gap = -remaining; - for(var k in State.outside.workers) { - var num = State.outside.workers[k]; + for(var k in $SM.get('game.workers')) { + var num = $SM.get('game.workers["'+k+'"]'); if(num < gap) { gap -= num; - State.outside.workers[k] = 0; + $SM.set('game.workers["'+k+'"]', 0); } else { - State.outside.workers[k] -= gap; + $SM.add('game.workers["'+k+'"]', gap * -1); break; } } } - Outside.updateVillage(); - Outside.updateWorkersView(); - Outside.updateVillageIncome(); }, schedulePopIncrease: function() { @@ -256,7 +218,7 @@ var Outside = { // If our population is 0 and we don't already have a workers view, // there's nothing to do here. - if(!workers.length && State.outside.population == 0) return; + if(!workers.length && $SM.get('game.population') == 0) return; var needsAppend = false; if(workers.length == 0) { @@ -264,13 +226,14 @@ var Outside = { workers = $('
').attr('id', 'workers').css('opacity', 0); } - var numGatherers = State.outside.population; + var numGatherers = $SM.get('game.population'); var gatherer = $('div#workers_row_gatherer', workers); - for(var k in State.outside.workers) { + for(var k in $SM.get('game.workers')) { + var workerCount = $SM.get('game.workers["'+k+'"]'); var row = $('div#workers_row_' + k.replace(' ', '-'), workers); if(row.length == 0) { - row = Outside.makeWorkerRow(k, State.outside.workers[k]); + row = Outside.makeWorkerRow(k, workerCount); var curPrev = null; workers.children().each(function(i) { @@ -295,10 +258,10 @@ var Outside = { } } else { - $('div#' + row.attr('id') + ' > div.row_val > span', workers).text(State.outside.workers[k]); + $('div#' + row.attr('id') + ' > div.row_val > span', workers).text(workerCount); } - numGatherers -= State.outside.workers[k]; - if(State.outside.workers[k] == 0) { + numGatherers -= workerCount; + if(workerCount == 0) { $('.dnBtn', row).addClass('disabled'); $('.dnManyBtn', row).addClass('disabled'); } else { @@ -329,9 +292,9 @@ var Outside = { }, getNumGatherers: function() { - var num = State.outside.population; - for(var k in State.outside.workers) { - num -= State.outside.workers[k]; + var num = $SM.get('game.population'); + for(var k in $SM.get('game.workers')) { + num -= $SM.get('game.workers["'+k+'"]'); } return num; }, @@ -371,20 +334,16 @@ var Outside = { if(Outside.getNumGatherers() > 0) { var increaseAmt = Math.min(Outside.getNumGatherers(), btn.data); Engine.log('increasing ' + worker + ' by ' + increaseAmt); - State.outside.workers[worker] += increaseAmt; - Outside.updateVillageIncome(); - Outside.updateWorkersView(); + $SM.add('game.workers["'+worker+'"]', increaseAmt); } }, decreaseWorker: function(btn) { var worker = $(this).closest('.workerRow').children('.row_key').text(); - if(State.outside.workers[worker] > 0) { - var decreaseAmt = Math.min(State.outside.workers[worker] || 0, btn.data); + if($SM.get('game.workers["'+worker+'"]') > 0) { + var decreaseAmt = Math.min($SM.get('game.workers["'+worker+'"]') || 0, btn.data); Engine.log('decreasing ' + worker + ' by ' + decreaseAmt); - State.outside.workers[worker] -= decreaseAmt; - Outside.updateVillageIncome(); - Outside.updateWorkersView(); + $SM.add('game.workers["'+worker+'"]', decreaseAmt * -1); } }, @@ -428,10 +387,10 @@ var Outside = { population = $('
').attr('id', 'population').appendTo(village); } - for(var k in State.outside.buildings) { + for(var k in $SM.get('game.buildings')) { if(k == 'trap') { - var numTraps = State.outside.buildings[k]; - var numBait = Engine.getStore('bait'); + var numTraps = $SM.get('game.buildings["'+k+'"]'); + var numBait = $SM.get('stores.bait', true); var traps = numTraps - numBait; traps = traps < 0 ? 0 : traps; Outside.updateVillageRow(k, traps, village); @@ -440,14 +399,14 @@ var Outside = { if(Outside.checkWorker(k)) { Outside.updateWorkersView(); } - Outside.updateVillageRow(k, State.outside.buildings[k], village); + Outside.updateVillageRow(k, $SM.get('game.buildings["'+k+'"]'), village); } } - population.text('pop ' + State.outside.population + '/' + this.getMaxPopulation()); + population.text('pop ' + $SM.get('game.population') + '/' + this.getMaxPopulation()); var hasPeeps; - if(Outside.numBuilding('hut') == 0) { + if($SM.get('game.buildings["hut"]', true) == 0) { hasPeeps = false; village.addClass('noHuts'); } else { @@ -488,10 +447,10 @@ var Outside = { if(typeof jobs == 'object') { for(var i = 0, len = jobs.length; i < len; i++) { var job = jobs[i]; - if(typeof State.outside.buildings[name] == 'number' && - typeof State.outside.workers[job] != 'number') { + if(typeof $SM.get('game.buildings["'+name+'"]') == 'number' && + typeof $SM.get('game.workers["'+job+'"]') != 'number') { Engine.log('adding ' + job + ' to the workers list') - State.outside.workers[job] = 0; + $SM.set('game.workers["'+job+'"]', 0); added = true; } } @@ -502,14 +461,14 @@ var Outside = { updateVillageIncome: function() { for(var worker in Outside._INCOME) { var income = Outside._INCOME[worker]; - var num = worker == 'gatherer' ? Outside.getNumGatherers() : State.outside.workers[worker]; + var num = worker == 'gatherer' ? Outside.getNumGatherers() : $SM.get('game.workers["'+worker+'"]'); if(typeof num == 'number') { var stores = {}; if(num < 0) num = 0; var tooltip = $('.tooltip', 'div#workers_row_' + worker.replace(' ', '-')); tooltip.empty(); var needsUpdate = false; - var curIncome = Engine.getIncome(worker); + var curIncome = $SM.getIncome(worker); for(var store in income.stores) { stores[store] = income.stores[store] * num; if(curIncome[store] != stores[store]) needsUpdate = true; @@ -519,7 +478,7 @@ var Outside = { row.appendTo(tooltip); } if(needsUpdate) { - Engine.setIncome(worker, { + $SM.setIncome(worker, { delay: income.delay, stores: stores }); @@ -531,7 +490,7 @@ var Outside = { updateTrapButton: function() { var btn = $('div#trapsButton'); - if(Outside.numBuilding('trap') > 0) { + if($SM.get('game.buildings["trap"]', true) > 0) { if(btn.length == 0) { new Button.Button({ id: 'trapsButton', @@ -551,7 +510,7 @@ var Outside = { }, setTitle: function() { - var numHuts = this.numBuilding('hut'); + var numHuts = $SM.get('game.buildings["hut"]', true); var title; if(numHuts == 0) { title = "A Silent Forest"; @@ -575,9 +534,9 @@ var Outside = { onArrival: function(transition_diff) { Outside.setTitle(); - if(!State.seenForest) { + if(!$SM.get('game.outside.seenForest')) { Notifications.notify(Outside, "the sky is grey and the wind blows relentlessly"); - State.seenForest = true; + $SM.set('game.outside.seenForest', true); } Outside.updateTrapButton(); Outside.updateVillage(); @@ -587,14 +546,15 @@ var Outside = { gatherWood: function() { Notifications.notify(Outside, "dry brush and dead branches litter the forest floor") - Engine.setStore('wood', Engine.getStore('wood') + (Outside.numBuilding('cart') > 0 ? 50 : 10)); + var gatherAmt = $SM.get('game.buildings["cart"]', true) > 0 ? 50 : 10; + $SM.add('stores.wood', gatherAmt); }, checkTraps: function() { var drops = {}; var msg = []; - var numTraps = Outside.numBuilding('trap'); - var numBait = Engine.getStore('bait'); + var numTraps = $SM.get('game.buildings["trap"]', true); + var numBait = $SM.get('stores.bait', true); var numDrops = numTraps + (numBait < numTraps ? numBait : numTraps); for(var i = 0; i < numDrops; i++) { var roll = Math.random(); @@ -625,6 +585,17 @@ var Outside = { drops['bait'] = -baitUsed; Notifications.notify(Outside, s); - Engine.addStores(drops); + $SM.addM('stores', drops); + }, + + handleStateUpdates: function(e){ + if(e.category == 'stores'){ + Outside.updateVillage(); + } else if(e.stateName.indexOf('game.workers') == 0 + || e.stateName.indexOf('game.population') == 0){ + Outside.updateVillage(); + Outside.updateWorkersView(); + Outside.updateVillageIncome(); + }; } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/script/path.js b/script/path.js index 17abf0b..efbf081 100644 --- a/script/path.js +++ b/script/path.js @@ -49,6 +49,15 @@ var Path = { Path.outfit = {}; Engine.updateSlider(); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Path.handleStateUpdates); + }, + + openPath: function() { + Path.init(); + Engine.event('progress', 'path'); + Notifications.notify(Room, 'the compass points ' + World.dir); }, getWeight: function(thing) { @@ -59,11 +68,11 @@ var Path = { }, getCapacity: function() { - if(Engine.getStore('convoy') > 0) { + if($SM.get('stores.convoy', true) > 0) { return Path.DEFAULT_BAG_SPACE + 60; - } else if(Engine.getStore('wagon') > 0) { + } else if($SM.get('stores.wagon', true) > 0) { return Path.DEFAULT_BAG_SPACE + 30; - } else if(Engine.getStore('rucksack') > 0) { + } else if($SM.get('stores.rucksack', true) > 0) { return Path.DEFAULT_BAG_SPACE + 10; } return Path.DEFAULT_BAG_SPACE; @@ -85,17 +94,17 @@ var Path = { }, updatePerks: function() { - if(State.perks) { + if($SM.get('character.perks')) { var perks = $('#perks'); var needsAppend = false; if(perks.length == 0) { needsAppend = true; perks = $('
').attr('id', 'perks'); } - for(var k in State.perks) { + for(var k in $SM.get('character.perks')) { var id = 'perk_' + k.replace(' ', '-'); var r = $('#' + id); - if(State.perks[k] && r.length == 0) { + if($SM.get('character.perks["'+k+'"]') && r.length == 0) { r = $('
').attr('id', id).addClass('perkRow').appendTo(perks); $('
').addClass('row_key').text(k).appendTo(r); $('
').addClass('tooltip bottom right').text(Engine.Perks[k].desc).appendTo(r); @@ -121,11 +130,11 @@ var Path = { // Add the armour row var armour = "none"; - if(Engine.getStore('s armour') > 0) + if($SM.get('stores["s armour"]', true) > 0) armour = "steel"; - else if(Engine.getStore('i armour') > 0) + else if($SM.get('stores["i armour"]', true) > 0) armour = "iron"; - else if(Engine.getStore('l armour') > 0) + else if($SM.get('stores["l armour"]', true) > 0) armour = "leather"; var aRow = $('#armourRow'); if(aRow.length == 0) { @@ -166,10 +175,10 @@ var Path = { for(var k in carryable) { var store = carryable[k]; - var have = State.stores[k]; + var have = $SM.get('stores["'+k+'"]'); var num = Path.outfit[k]; num = typeof num == 'number' ? num : 0; - var numAvailable = Engine.getStore(k); + var numAvailable = $SM.get('stores["'+k+'"]', true); var row = $('div#outfit_row_' + k.replace(' ', '-'), outfit); if((store.type == 'tool' || store.type == 'weapon') && have > 0) { total += num * Path.getWeight(k); @@ -238,7 +247,7 @@ var Path = { $('
').addClass('dnManyBtn').appendTo(val).click([10], Path.decreaseSupply); $('
').addClass('clear').appendTo(row); - var numAvailable = Engine.getStore(name); + var numAvailable = $SM.get('stores["'+name+'"]', true); var tt = $('
').addClass('tooltip bottom right').appendTo(row); $('
').addClass('row_key').text('weight').appendTo(tt); $('
').addClass('row_val').text(Path.getWeight(name)).appendTo(tt); @@ -253,9 +262,9 @@ var Path = { Engine.log('increasing ' + supply + ' by up to ' + btn.data); var cur = Path.outfit[supply]; cur = typeof cur == 'number' ? cur : 0; - if(Path.getFreeSpace() >= Path.getWeight(supply) && cur < Engine.getStore(supply)) { + if(Path.getFreeSpace() >= Path.getWeight(supply) && cur < $SM.get('stores["'+supply+'"]', true)) { var maxExtraByWeight = Math.floor(Path.getFreeSpace() / Path.getWeight(supply)); - var maxExtraByStore = Engine.getStore(supply) - cur; + var maxExtraByStore = $SM.get('stores["'+supply+'"]', true) - cur; var maxExtraByBtn = btn.data; Path.outfit[supply] = cur + Math.min(maxExtraByBtn, Math.min(maxExtraByWeight, maxExtraByStore)); Path.updateOutfitting(); @@ -287,10 +296,16 @@ var Path = { embark: function() { for(var k in Path.outfit) { - Engine.addStore(k, -Path.outfit[k]); + $SM.add('stores["'+k+'"]', -Path.outfit[k]); } World.onArrival(); $('#outerSlider').animate({left: '-700px'}, 300); Engine.activeModule = World; + }, + + handleStateUpdates: function(e){ + if(e.category == 'character' && e.stateName.indexOf('character.perks') == 0 && Engine.activeModule == Path){ + Path.updatePerks(); + }; } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/script/room.js b/script/room.js index aff291d..3bbe2ed 100644 --- a/script/room.js +++ b/script/room.js @@ -9,6 +9,10 @@ var Room = { _STOKE_COOLDOWN: 10, // cooldown to stoke the fire _NEED_WOOD_DELAY: 15 * 1000, // from when the stranger shows up, to when you need wood + fire:null, + temperature:null, + buttons:{}, + Craftables: { 'trap': { button: null, @@ -18,7 +22,7 @@ var Room = { maxMsg: "more traps won't help now", type: 'building', cost: function() { - var n = Outside.numBuilding('trap'); + var n = $SM.get('game.buildings["trap"]', true); return { 'wood': 10 + (n*10) }; @@ -44,7 +48,7 @@ var Room = { maxMsg: 'no more room for huts.', type: 'building', cost: function() { - var n = Outside.numBuilding('hut'); + var n = $SM.get('game.buildings["hut"]', true); return { 'wood': 100 + (n*50) }; @@ -437,21 +441,21 @@ var Room = { ); if(Engine._debug) { - this._ROOM_WARM_DELAY = 1; - this._BUILDER_STATE_DELAY = 1; + this._ROOM_WARM_DELAY = 5000; + this._BUILDER_STATE_DELAY = 5000; this._STOKE_COOLDOWN = 0; - this._NEED_WOOD_DELAY = 1; + this._NEED_WOOD_DELAY = 5000; } - if(typeof State.room == 'undefined') { - State.room = { - temperature: this.TempEnum.Cold, - fire: this.FireEnum.Dead, - buttons: {}, - builder: -1 - }; + if(typeof $SM.get('features.location.room') == 'undefined') { + $SM.set('features.location.room', true); + $SM.set('game.builder.level', -1); } + Room.temperature = this.TempEnum.Cold; + Room.fire = this.FireEnum.Dead; + + // Create the room tab this.tab = Header.addLocation("A Dark Room", "room", Room); @@ -486,6 +490,9 @@ var Room = { // Create the stores container $('
').attr('id', 'storesContainer').appendTo('div#roomPanel'); + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Room.handleStateUpdates); + Room.updateButton(); Room.updateStoresView(); Room.updateIncomeView(); @@ -502,16 +509,16 @@ var Room = { * 3 - Sleeping * 4 - Helping */ - if(State.room.builder >= 0 && State.room.builder < 3) { + if($SM.get('game.builder.level') >= 0 && $SM.get('game.builder.level') < 3) { Room._builderTimer = setTimeout(Room.updateBuilderState, Room._BUILDER_STATE_DELAY); } - if(State.room.builder == 1 && Engine.getStore('wood') < 0) { + if($SM.get('game.builder.level') == 1 && $SM.get('stores.wood', true) < 0) { setTimeout(Room.unlockForest, Room._NEED_WOOD_DELAY); } - setTimeout(Engine.collectIncome, 1000); + setTimeout($SM.collectIncome, 1000); - Notifications.notify(Room, "the room is " + State.room.temperature.text); - Notifications.notify(Room, "the fire is " + State.room.fire.text); + Notifications.notify(Room, "the room is " + Room.temperature.text); + Notifications.notify(Room, "the fire is " + Room.fire.text); }, options: {}, // Nothing for now @@ -519,13 +526,13 @@ var Room = { onArrival: function(transition_diff) { Room.setTitle(); if(Room.changed) { - Notifications.notify(Room, "the fire is " + State.room.fire.text); - Notifications.notify(Room, "the room is " + State.room.temperature.text); + Notifications.notify(Room, "the fire is " + Room.fire.text); + Notifications.notify(Room, "the room is " + Room.temperature.text); Room.changed = false; } - if(State.room.builder == 3) { - State.room.builder++; - Engine.setIncome('builder', { + if($SM.get('game.builder.level') == 3) { + $SM.add('game.builder.level', 1); + $SM.setIncome('builder', { delay: 10, stores: {'wood' : 2 } }); @@ -569,7 +576,7 @@ var Room = { }, setTitle: function() { - var title = State.room.fire.value < 2 ? "A Dark Room" : "A Firelit Room"; + var title = Room.fire.value < 2 ? "A Dark Room" : "A Firelit Room"; if(Engine.activeModule == this) { document.title = title; } @@ -579,7 +586,7 @@ var Room = { updateButton: function() { var light = $('#lightButton.button'); var stoke = $('#stokeButton.button'); - if(State.room.fire.value == Room.FireEnum.Dead.value && stoke.css('display') != 'none') { + if(Room.fire.value == Room.FireEnum.Dead.value && stoke.css('display') != 'none') { stoke.hide(); light.show(); if(stoke.hasClass('disabled')) { @@ -593,7 +600,7 @@ var Room = { } } - if(!Engine.storeAvailable('wood')) { + if(!$SM.get('stores.wood')) { light.addClass('free'); stoke.addClass('free'); } else { @@ -605,30 +612,30 @@ var Room = { _fireTimer: null, _tempTimer: null, lightFire: function() { - var wood = Engine.getStore('wood'); - if(Engine.storeAvailable('wood') && wood < 5) { + var wood = $SM.get('stores.wood'); + if(wood < 5) { Notifications.notify(Room, "not enough wood to get the fire going"); Button.clearCooldown($('#lightButton.button')); return; } else if(wood > 4) { - Engine.setStore('wood', wood - 5); + $SM.set('stores.wood', wood - 5); } - State.room.fire = Room.FireEnum.Burning; + Room.fire = Room.FireEnum.Burning; Room.onFireChange(); }, stokeFire: function() { - var wood = Engine.getStore('wood'); - if(Engine.storeAvailable('wood') && wood == 0) { + var wood = $SM.get('stores.wood'); + if(wood === 0) { Notifications.notify(Room, "the wood has run out"); Button.clearCooldown($('#stokeButton.button')); return; } if(wood > 0) { - Engine.setStore('wood', wood - 1); + $SM.set('stores.wood', wood - 1); } - if(State.room.fire.value < 4) { - State.room.fire = Room.FireEnum.fromInt(State.room.fire.value + 1); + if(Room.fire.value < 4) { + Room.fire = Room.FireEnum.fromInt(Room.fire.value + 1); } Room.onFireChange(); }, @@ -637,9 +644,9 @@ var Room = { if(Engine.activeModule != Room) { Room.changed = true; } - Notifications.notify(Room, "the fire is " + State.room.fire.text, true); - if(State.room.fire.value > 1 && State.room.builder < 0) { - State.room.builder = 0; + Notifications.notify(Room, "the fire is " + Room.fire.text, true); + if(Room.fire.value > 1 && $SM.get('game.builder.level') < 0) { + $SM.set('game.builder.level', 0); Notifications.notify(Room, "the light from the fire spills from the windows, out into the dark"); setTimeout(Room.updateBuilderState, Room._BUILDER_STATE_DELAY); } @@ -650,54 +657,54 @@ var Room = { }, coolFire: function() { - if(State.room.fire.value <= Room.FireEnum.Flickering.value && - State.room.builder > 3 && Engine.getStore('wood') > 0) { + var wood = $SM.get('stores.wood'); + if(Room.fire.value <= Room.FireEnum.Flickering.value && + $SM.get('game.builder.level') > 3 && wood > 0) { Notifications.notify(Room, "builder stokes the fire", true); - Engine.setStore('wood', Engine.getStore('wood') - 1); - State.room.fire = Room.FireEnum.fromInt(State.room.fire.value + 1); + $SM.set('stores.wood', wood - 1); + Room.fire = Room.FireEnum.fromInt(Room.fire.value + 1); } - if(State.room.fire.value > 0) { - State.room.fire = Room.FireEnum.fromInt(State.room.fire.value - 1); + if(Room.fire.value > 0) { + Room.fire = Room.FireEnum.fromInt(Room.fire.value - 1); Room._fireTimer = setTimeout(Room.coolFire, Room._FIRE_COOL_DELAY); Room.onFireChange(); } }, adjustTemp: function() { - var old = State.room.temperature.value; - if(State.room.temperature.value > 0 && State.room.temperature.value > State.room.fire.value) { - State.room.temperature = Room.TempEnum.fromInt(State.room.temperature.value - 1); - Notifications.notify(Room, "the room is " + State.room.temperature.text, true); + var old = Room.temperature.value; + if(Room.temperature.value > 0 && Room.temperature.value > Room.fire.value) { + Room.temperature = Room.TempEnum.fromInt(Room.temperature.value - 1); + Notifications.notify(Room, "the room is " + Room.temperature.text, true); } - if(State.room.temperature.value < 4 && State.room.temperature.value < State.room.fire.value) { - State.room.temperature = Room.TempEnum.fromInt(State.room.temperature.value + 1); - Notifications.notify(Room, "the room is " + State.room.temperature.text, true); + if(Room.temperature.value < 4 && Room.temperature.value < Room.fire.value) { + Room.temperature = Room.TempEnum.fromInt(Room.temperature.value + 1); + Notifications.notify(Room, "the room is " + Room.temperature.text, true); } - if(State.room.temperature.value != old) { + if(Room.temperature.value != old) { Room.changed = true; } Room._tempTimer = setTimeout(Room.adjustTemp, Room._ROOM_WARM_DELAY); }, unlockForest: function() { - Engine.setStore('wood', 4); - Room.updateButton(); + $SM.set('stores.wood', 4); Outside.init(); - Room.updateStoresView(); Notifications.notify(Room, "the wind howls outside"); Notifications.notify(Room, "the wood is running out"); Engine.event('progress', 'outside'); }, updateBuilderState: function() { - if(State.room.builder == 0) { + var lBuilder = $SM.get('game.builder.level'); + if(lBuilder == 0) { Notifications.notify(Room, "a ragged stranger stumbles through the door and collapses in the corner"); - State.room.builder = 1; + lBuilder = $SM.setget('game.builder.level', 1); setTimeout(Room.unlockForest, Room._NEED_WOOD_DELAY); } - else if(State.room.builder < 3 && State.room.temperature.value >= Room.TempEnum.Warm.value) { + else if(lBuilder < 3 && Room.temperature.value >= Room.TempEnum.Warm.value) { var msg; - switch(State.room.builder) { + switch(lBuilder) { case 1: msg = "the stranger shivers, and mumbles quietly. her words are unintelligible."; break; @@ -706,11 +713,11 @@ var Room = { break; } Notifications.notify(Room, msg); - if(State.room.builder < 3) { - State.room.builder++; + if(lBuilder < 3) { + lBuilder = $SM.setget('game.builder.level', lBuilder + 1); } } - if(State.room.builder < 3) { + if(lBuilder < 3) { setTimeout(Room.updateBuilderState, Room._BUILDER_STATE_DELAY); } Engine.saveGame(); @@ -732,7 +739,7 @@ var Room = { }).css('opacity', 0); wNeedsAppend = true; } - for(var k in State.stores) { + for(var k in $SM.get('stores')) { var type = null; if(Room.Craftables[k]) { @@ -758,18 +765,19 @@ var Room = { var id = "row_" + k.replace(' ', '-'); var row = $('div#' + id, location); - var num = State.stores[k]; + var num = $SM.get('stores["'+k+'"]'); if(typeof num != 'number' || isNaN(num)) { // No idea how counts get corrupted, but I have reason to believe that they occassionally do. // Build a little fence around it! - num = State.stores[k] = 0; + num = 0; + $SM.set('stores["'+k+'"]', 0); } // thieves? - if(typeof State.thieves == 'undefined' && num > 5000 && State.world) { - Engine.startThieves(); + if(typeof $SM.get('game.thieves') == 'undefined' && num > 5000 && $SM.get('features.location.world')) { + $SM.startThieves(); } if(row.length == 0 && num > 0) { @@ -791,10 +799,8 @@ var Room = { row.insertAfter(location.find('#row_' + curPrev.replace(' ', '-'))); } newRow = true; - } else if(num> 0){ + } else if(num>= 0){ $('div#' + row.attr('id') + ' > div.row_val', location).text(Math.floor(num)); - } else if(num == 0) { - row.remove(); } } @@ -819,14 +825,14 @@ var Room = { updateIncomeView: function() { var stores = $('div#stores'); - if(stores.length == 0 || typeof State.income == 'undefined') return; + if(stores.length == 0 || typeof $SM.get('income') == 'undefined') return; $('div.storeRow', stores).each(function(index, el) { el = $(el); $('div.tooltip', el).remove(); var tt = $('
').addClass('tooltip bottom right'); var storeName = el.attr('id').substring(4).replace('-', ' '); - for(var incomeSource in State.income) { - var income = State.income[incomeSource]; + for(var incomeSource in $SM.get('income')) { + var income = $SM.get('income["'+incomeSource+'"]'); for(var store in income.stores) { if(store == storeName && income.stores[store] != 0) { $('
').addClass('row_key').text(incomeSource).appendTo(tt); @@ -846,7 +852,7 @@ var Room = { buy: function(buyBtn) { var thing = $(buyBtn).attr('buildThing'); var good = Room.TradeGoods[thing]; - var numThings = Engine.getStore(thing); + var numThings = $SM.get('stores["'+thing+'"]', true); if(numThings < 0) numThings = 0; if(good.maximum <= numThings) { return; @@ -855,7 +861,7 @@ var Room = { var storeMod = {}; var cost = good.cost(); for(var k in cost) { - var have = Engine.getStore(k) + var have = $SM.get('stores["'+k+'"]', true); if(have < cost[k]) { Notifications.notify(Room, "not enough " + k); return false; @@ -863,22 +869,20 @@ var Room = { storeMod[k] = have - cost[k]; } } - Engine.setStores(storeMod); + $SM.setM('stores', storeMod); Notifications.notify(Room, good.buildMsg); - Engine.addStore(thing, 1); - - Room.updateBuildButtons(); + $SM.add('stores["'+thing+'"]', 1); if(thing == 'compass') { - Engine.openPath(); + Path.openPath(); } }, build: function(buildBtn) { var thing = $(buildBtn).attr('buildThing'); - if(State.room.temperature.value <= Room.TempEnum.Cold.value) { + if(Room.temperature.value <= Room.TempEnum.Cold.value) { Notifications.notify(Room, "builder just shivers"); return false; } @@ -890,10 +894,10 @@ var Room = { case 'weapon': case 'tool': case 'upgrade': - numThings = Engine.getStore(thing); + numThings = $SM.get('stores["'+thing+'"]', true); break; case 'building': - numThings = Outside.numBuilding(thing); + numThings = $SM.get('game.buildings["'+thing+'"]', true); break; } @@ -905,7 +909,7 @@ var Room = { var storeMod = {}; var cost = craftable.cost(); for(var k in cost) { - var have = Engine.getStore(k) + var have = $SM.get('stores["'+k+'"]', true); if(have < cost[k]) { Notifications.notify(Room, "not enough " + k); return false; @@ -913,7 +917,7 @@ var Room = { storeMod[k] = have - cost[k]; } } - Engine.setStores(storeMod); + $SM.setM('stores', storeMod); Notifications.notify(Room, craftable.buildMsg); @@ -922,15 +926,12 @@ var Room = { case 'weapon': case 'upgrade': case 'tool': - Engine.addStore(thing, 1); + $SM.add('stores["'+thing+'"]', 1); break; case 'building': - Outside.addBuilding(thing, 1); + $SM.add('game.buildings["'+thing+'"]', 1); break; - } - - Room.updateBuildButtons(); - + } }, needsWorkshop: function(type) { @@ -938,38 +939,42 @@ var Room = { }, craftUnlocked: function(thing) { - if(typeof State.room != 'undefined' && - typeof State.room.buttons != 'undefined' && - State.room.buttons[thing]) { + if(Room.buttons[thing]) { return true; } - if(State.room.builder < 4) return false; + if($SM.get('game.builder.level') < 4) return false; var craftable = Room.Craftables[thing]; - if(Room.needsWorkshop(craftable.type) && Outside.numBuilding('workshop') == 0) return false; + if(Room.needsWorkshop(craftable.type) && $SM.get('game.buildings["workshop"]', true) == 0) return false; var cost = craftable.cost(); + //show button if one has already been built + if($SM.get('game.buildings["'+thing+'"]') > 0){ + Room.buttons[thing] = true; + return true; + } // Show buttons if we have at least 1/2 the wood, and all other components have been seen. - if(Engine.getStore('wood') < cost['wood'] * 0.5) { + if($SM.get('stores.wood', true) < cost['wood'] * 0.5) { return false; } for(var c in cost) { - if(!Engine.storeAvailable(c)) { + if(!$SM.get('stores["'+c+'"]')) { return false; } } - State.room.buttons[thing] = true; - Notifications.notify(Room, craftable.availableMsg); + Room.buttons[thing] = true; + //don't notify if it has already been built before + if(!$SM.get('game.buildings["'+thing+'"]')){ + Notifications.notify(Room, craftable.availableMsg); + } return true; }, buyUnlocked: function(thing) { - if(typeof State.room != 'undefined' && - typeof State.room.buttons != 'undefined' && - State.room.buttons[thing]) { + if(Room.buttons[thing]) { return true; - } else if(Outside.numBuilding('trading post') > 0) { - if(thing == 'compass' || Engine.storeAvailable(thing)) { + } else if($SM.get('game.buildings["trading post"]', true) > 0) { + if(thing == 'compass' || $SM.get('stores["'+thing+'"]')) { // Allow the purchase of stuff once you've seen it return true; } @@ -987,21 +992,21 @@ var Room = { var craftSection = $('#craftBtns'); var cNeedsAppend = false; - if(craftSection.length == 0 && Outside.numBuilding('workshop') > 0) { + if(craftSection.length == 0 && $SM.get('game.buildings["workshop"]', true) > 0) { craftSection = $('
').attr('id', 'craftBtns').css('opacity', 0); cNeedsAppend = true; } var buySection = $('#buyBtns'); var bNeedsAppend = false; - if(buySection.length == 0 && Outside.numBuilding('trading post') > 0) { + if(buySection.length == 0 && $SM.get('game.buildings["trading post"]', true) > 0) { buySection = $('
').attr('id', 'buyBtns').css('opacity', 0); bNeedsAppend = true; } for(var k in Room.Craftables) { craftable = Room.Craftables[k]; - var max = Engine.num(k, craftable) + 1 > craftable.maximum; + var max = $SM.num(k, craftable) + 1 > craftable.maximum; if(craftable.button == null) { if(Room.craftUnlocked(k)) { var loc = Room.needsWorkshop(craftable.type) ? craftSection : buildSection; @@ -1036,7 +1041,7 @@ var Room = { for(var k in Room.TradeGoods) { good = Room.TradeGoods[k]; - var max = Engine.num(k, good) + 1 > good.maximum; + var max = $SM.num(k, good) + 1 > good.maximum; if(good.button == null) { if(Room.buyUnlocked(k)) { good.button = new Button.Button({ @@ -1076,5 +1081,16 @@ var Room = { if(bNeedsAppend && buildSection.children().length > 0) { buySection.appendTo('div#roomPanel').animate({opacity: 1}, 300, 'linear'); } + }, + + handleStateUpdates: function(e){ + if(e.category == 'stores'){ + Room.updateStoresView(); + Room.updateBuildButtons(); + } else if(e.category == 'income'){ + Room.updateIncomeView(); + } else if(e.stateName.indexOf('game.buildings') == 0){ + Room.updateBuildButtons(); + } } }; \ No newline at end of file diff --git a/script/ship.js b/script/ship.js index 0fad202..3a1885f 100644 --- a/script/ship.js +++ b/script/ship.js @@ -15,11 +15,12 @@ var Ship = { options ); - if(!State.ship) { - State.ship = { + if(!$SM.get('features.location.spaceShip')) { + $SM.set('features.location.spaceShip', true); + $SM.setM('game.spaceShip', { hull: Ship.BASE_HULL, thrusters: Ship.BASE_THRUSTERS - } + }); } // Create the Ship tab @@ -35,13 +36,13 @@ var Ship = { // Draw the hull label var hullRow = $('
').attr('id', 'hullRow').appendTo('div#shipPanel'); $('
').addClass('row_key').text('hull:').appendTo(hullRow); - $('
').addClass('row_val').text(State.ship.hull).appendTo(hullRow); + $('
').addClass('row_val').text($SM.get('game.spaceShip.hull')).appendTo(hullRow); $('
').addClass('clear').appendTo(hullRow); // Draw the thrusters label var engineRow = $('
').attr('id', 'engineRow').appendTo('div#shipPanel'); $('
').addClass('row_key').text('engine:').appendTo(engineRow); - $('
').addClass('row_val').text(State.ship.thrusters).appendTo(engineRow); + $('
').addClass('row_val').text($SM.get('game.spaceShip.thrusters')).appendTo(engineRow); $('
').addClass('clear').appendTo(engineRow); // Draw the reinforce button @@ -71,22 +72,24 @@ var Ship = { cooldown: Ship.LIFTOFF_COOLDOWN }).appendTo('div#shipPanel'); - if(State.ship.hull <= 0) { + if($SM.get('game.spaceShip.hull') <= 0) { Button.setDisabled(b, true); } // Init Space Space.init(); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Ship.handleStateUpdates); }, options: {}, // Nothing for now onArrival: function(transition_diff) { Ship.setTitle(); - if(!State.seenShip) { + if(!$SM.get('game.spaceShip.seenShip')) { Notifications.notify(Ship, 'somewhere above the debris cloud, the wanderer fleet hovers. been on this rock too long.'); - State.seenShip = true; - Engine.saveGame(); + $SM.set('game.spaceShip.seenShip', true); } Engine.moveStoresView(null, transition_diff); @@ -99,34 +102,34 @@ var Ship = { }, reinforceHull: function() { - if(Engine.getStore('alien alloy') < Ship.ALLOY_PER_HULL) { + if($SM.get('stores["alien alloy"]', true) < Ship.ALLOY_PER_HULL) { Notifications.notify(Ship, "not enough alien alloy"); return false; } - Engine.addStore('alien alloy', -Ship.ALLOY_PER_HULL); - State.ship.hull++; - if(State.ship.hull > 0) { + $SM.add('stores["alien alloy"]', -Ship.ALLOY_PER_HULL); + $SM.add('game.spaceShip.hull', 1); + if($SM.get('game.spaceShip.hull') > 0) { Button.setDisabled($('#liftoffButton', Ship.panel), false); } - $('#hullRow .row_val', Ship.panel).text(State.ship.hull); + $('#hullRow .row_val', Ship.panel).text($SM.get('game.spaceShip.hull')); }, upgradeEngine: function() { - if(Engine.getStore('alien alloy') < Ship.ALLOY_PER_THRUSTER) { + if($SM.get('stores["alien alloy"]', true) < Ship.ALLOY_PER_THRUSTER) { Notifications.notify(Ship, "not enough alien alloy"); return false; } - Engine.addStore('alien alloy', -Ship.ALLOY_PER_THRUSTER); - State.ship.thrusters++; - $('#engineRow .row_val', Ship.panel).text(State.ship.thrusters); + $SM.add('stores["alien alloy"]', -Ship.ALLOY_PER_THRUSTER); + $SM.add('game.spaceShip.thrusters', 1) + $('#engineRow .row_val', Ship.panel).text($SM.get('game.spaceShip.thrusters')); }, getMaxHull: function() { - return State.ship.hull; + return $SM.get('game.spaceShip.hull'); }, checkLiftOff: function() { - if(!State.ship.seenWarning) { + if(!$SM.get('game.spaceShip.seenWarning')) { Events.startEvent({ title: 'Ready to Leave?', scenes: { @@ -138,7 +141,7 @@ var Ship = { 'fly': { text: 'lift off', onChoose: function() { - State.ship.seenWarning = true; + $SM.set('game.spaceShip.seenWarning', true); Ship.liftOff(); }, nextScene: 'end' @@ -163,5 +166,9 @@ var Ship = { $('#outerSlider').animate({top: '700px'}, 300); Space.onArrival(); Engine.activeModule = Space; + }, + + handleStateUpdates: function(e){ + } }; \ No newline at end of file diff --git a/script/space.js b/script/space.js index bd9dc3c..cf8df77 100644 --- a/script/space.js +++ b/script/space.js @@ -41,6 +41,9 @@ var Space = { var h = $('
').attr('id', 'hullRemaining').appendTo(this.panel); $('
').addClass('row_key').text('hull: ').appendTo(h); $('
').addClass('row_val').appendTo(h); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(Space.handleStateUpdates); }, options: {}, // Nothing for now @@ -87,7 +90,7 @@ var Space = { }, getSpeed: function() { - return Space.SHIP_SPEED + State.ship.thrusters; + return Space.SHIP_SPEED + $SM.get('game.spaceShip.thrusters'); }, updateHull: function() { @@ -445,5 +448,9 @@ var Space = { Engine.log('right off'); break; } + }, + + handleStateUpdates: function(e){ + } }; diff --git a/script/state_manager.js b/script/state_manager.js new file mode 100644 index 0000000..0495e19 --- /dev/null +++ b/script/state_manager.js @@ -0,0 +1,404 @@ +/* + * Module for handling States + * + * All states should be get and set through the StateManager ($SM). + * + * The manager is intended to handle all needed checks and error catching. + * This includes creating the parents of layered/deep states so undefined states + * do not need to be tested for and created beforehand. + * + * When a state is changed, an update event is sent out containing the name of the state + * changed or in the case of multiple changes (.setM, .addM) the parent class changed. + * Event: type: 'stateUpdate', stateName: + * + * Original file created by: Michael Galusha + */ + +var StateManager = { + + MAX_STORE: 99999999999999, + + options: {}, + + init: function(options) { + this.options = $.extend( + this.options, + options + ); + + //create categories + var cats = [ + 'features', //big features like buildings, location availability, unlocks, etc + 'stores', //little stuff, items, weapons, etc + 'character', //this is for player's character stats such as perks + 'income', + 'timers', + 'game', //mostly location related: fire temp, workers, population, world map, etc + 'playStats' //anything play related: play time, loads, etc + ]; + + for(var which in cats) { + if(!$SM.get(cats[which])) $SM.set(cats[which], {}); + }; + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe($SM.handleStateUpdates); + }, + + //create all parents and then set state + createState: function(stateName, value) { + var words = stateName.split(/[.\[\]'"]+/); + //for some reason there are sometimes empty strings + for (var i = 0; i < words.length; i++) { + if (words[i] == '') { + words.splice(i, 1); + i--; + } + }; + var obj = State; + var w = null; + for(var i=0, len=words.length-1;i $SM.MAX_STORE) value = $SM.MAX_STORE; + + try{ + eval('('+fullPath+') = value'); + } catch (e) { + //parent doesn't exist, so make parent + $SM.createState(stateName, value); + } + + //stores values can not be negative + if(stateName.indexOf('stores') == 0 && $SM.get(stateName, true) < 0) { + eval('('+fullPath+') = 0');; + Engine.log('WARNING: state:' + stateName + ' can not be a negative value. Set to 0 instead.') + } + + if(!noEvent) { + Engine.saveGame(); + $SM.fireUpdate(stateName); + } + }, + + //sets a list of states + setM: function(parentName, list, noEvent) { + var whichParent = $SM.buildPath(parentName); + + //make sure the state exists to avoid errors, + if($SM.get(parentName) == undefined) $SM.set(parentName, {}, true); + + for(var k in list){ + $SM.set(parentName+'["'+k+'"]', list[k], true); + } + + if(!noEvent) { + Engine.saveGame(); + $SM.fireUpdate(parentName); + } + }, + + //shortcut for altering number values, return 1 if state wasn't a number + add: function(stateName, value, noEvent) { + var err = 0; + //0 if undefined, null (but not {}) should allow adding to new objects + //could also add in a true = 1 thing, to have something go from existing (true) + //to be a count, but that might be unwanted behavior (add with loose eval probably will happen anyways) + var old = $SM.get(stateName, true); + + //check for NaN (old != old) and non number values + if(old != old){ + Engine.log('WARNING: '+stateName+' was corrupted (NaN). Resetting to 0.'); + old = 0; + $SM.set(stateName, old + value, noEvent); + } else if(typeof old != 'number' || typeof value != 'number'){ + Engine.log('WARNING: Can not do math with state:'+stateName+' or value:'+value+' because at least one is not a number.'); + err = 1 + } else { + $SM.set(stateName, old + value, noEvent); //setState handles event and save + } + + return err; + }, + + //alters multiple number values, return number of fails + addM: function(parentName, list, noEvent) { + var err = 0; + + //make sure the parent exists to avoid errors + if($SM.get(parentName) == undefined) $SM.set(parentName, {}, true); + + for(var k in list){ + if(!$SM.add(parentName+'["'+k+'"]', list[k], true)) err++; + } + + if(!noEvent) { + Engine.saveGame(); + $SM.fireUpdate(parentName); + } + return err; + }, + + //return state, undefined or 0 + get: function(stateName, requestZero) { + var whichState = null; + var fullPath = $SM.buildPath(stateName); + + //catch errors if parent of state doesn't exist + try{ + eval('whichState = ('+fullPath+')'); + } catch (e) { + whichState = undefined; + } + + //prevents repeated if undefined, null, false or {}, then x = 0 situations + if((!whichState || whichState == {}) && requestZero) return 0; + else return whichState; + }, + + //mainly for local copy use, add(M) can fail so we can't shortcut them + //since set does not fail, we know state exists and can simply return the object + setget: function(stateName, value, noEvent){ + $SM.set(stateName, value, noEvent); + return eval('('+$SM.buildPath(stateName)+')'); + }, + + remove: function(stateName, noEvent) { + var whichState = $SM.buildPath(stateName); + try{ + eval('(delete '+whichState+')'); + } catch (e) { + //it didn't exist in the first place + Engine.log('WARNING: Tried to remove non-existant state \''+stateName+'\'.'); + } + if(!noEvent){ + Engine.saveGame(); + $SM.fireUpdate(stateName); + }; + }, + + //creates full reference from input + //hopefully this won't ever need to be more complicated + buildPath: function(input){ + var dot = (input.charAt(0) == '[')? '' : '.'; //if it starts with [foo] no dot to join + return 'State' + dot + input; + }, + + fireUpdate: function(stateName, save){ + var category = $SM.getCategory(stateName); + if(stateName == undefined) stateName = category = 'all'; //best if this doesn't happen as it will trigger more stuff + $.Dispatch('stateUpdate').publish({'category': category, 'stateName':stateName}) + if(save) Engine.saveGame(); + }, + + getCategory: function(stateName){ + var firstOB = stateName.indexOf('['); + var firstDot = stateName.indexOf('.'); + var cutoff = null; + if(firstOB == -1 || firstDot == -1){ + cutoff = firstOB > firstDot ? firstOB : firstDot; + } else { + cutoff = firstOB < firstDot ? firstOB : firstDot; + } + if (cutoff == -1){ + return stateName; + } else { + return stateName.substr(0,cutoff); + } + }, + + //Use this function to make old save games compatible with new version + updateOldState: function(){ + var version = $SM.get('version'); + if(typeof version != 'number') version = 1.0; + if(version == 1.0) { + // v1.1 introduced the Lodge, so get rid of lodgeless hunters + $SM.remove('outside.workers.hunter', true); + $SM.remove('income.hunter', true); + Engine.log('upgraded save to v1.1'); + version = 1.1; + }; + if(version == 1.1) { + //v1.2 added the Swamp to the map, so add it to already generated maps + if($SM.get('world')) { + World.placeLandmark(15, World.RADIUS * 1.5, World.TILE.SWAMP, $SM.get('world.map')); + } + Engine.log('upgraded save to v1.2'); + version = 1.2; + }; + if(version == 1.2) { + //StateManager added, so move data to new locations + $SM.remove('room.fire'); + $SM.remove('room.temperature'); + $SM.remove('room.buttons'); + if($SM.get('room')){ + $SM.set('features.location.room', true); + $SM.set('game.builder.level', $SM.get('room.builder')); + $SM.remove('room'); + }; + if($SM.get('outside')){ + $SM.set('features.location.outside', true); + $SM.set('game.population', $SM.get('outside.population')); + $SM.set('game.buildings', $SM.get('outside.buildings')); + $SM.set('game.workers', $SM.get('outside.workers')); + $SM.set('game.outside.seenForest', $SM.get('outside.seenForest')); + $SM.remove('outside'); + }; + if($SM.get('world')){ + $SM.set('features.location.world', true); + $SM.set('game.world.map', $SM.get('world.map')); + $SM.set('game.world.mask', $SM.get('world.mask')); + $SM.set('starved', $SM.get('character.starved', true)); + $SM.set('dehydrated', $SM.get('character.dehydrated', true)); + $SM.remove('world'); + $SM.remove('starved'); + $SM.remove('dehydrated'); + }; + if($SM.get('ship')){ + $SM.set('features.location.spaceShip', true); + $SM.set('game.spaceShip.hull', $SM.get('ship.hull', true)); + $SM.set('game.spaceShip.thrusters', $SM.get('ship.thrusters', true)); + $SM.set('game.spaceShip.seenWarning', $SM.get('ship.seenWarning')); + $SM.set('game.spaceShip.seenShip', $SM.get('ship.seenShip')); + $SM.remove('ship'); + }; + if($SM.get('punches')){ + $SM.set('character.punches', $SM.get('punches')); + $SM.remove('punches'); + }; + if($SM.get('perks')){ + $SM.set('character.perks', $SM.get('perks')); + $SM.remove('perks'); + }; + if($SM.get('thieves')){ + $SM.set('game.thieves', $SM.get('thieves')); + $SM.remove('thieves'); + }; + if($SM.get('stolen')){ + $SM.set('game.stolen', $SM.get('stolen')); + $SM.remove('stolen'); + }; + if($SM.get('cityCleared')){ + $SM.set('character.cityCleared', $SM.get('cityCleared')); + $SM.remove('cityCleared'); + }; + $SM.set('version', 1.3); + }; + }, + + /****************************************************************** + * Start of specific state functions + ******************************************************************/ + //PERKS + addPerk: function(name) { + $SM.set('character.perks["'+name+'"]', true); + Notifications.notify(null, Engine.Perks[name].notify); + }, + + hasPerk: function(name) { + return $SM.get('character.perks["'+name+'"]'); + }, + + //INCOME + setIncome: function(source, options) { + var existing = $SM.get('income["'+source+'"]'); + if(typeof existing != 'undefined') { + options.timeLeft = existing.timeLeft; + } + $SM.set('income["'+source+'"]', options); + }, + + getIncome: function(source) { + var existing = $SM.get('income["'+source+'"]'); + if(typeof existing != 'undefined') { + return existing; + } + return {}; + }, + + collectIncome: function() { + var changed = false; + if(typeof $SM.get('income') != 'undefined' && Engine.activeModule != Space) { + for(var source in $SM.get('income')) { + var income = $SM.get('income["'+source+'"]'); + if(typeof income.timeLeft != 'number') + { + income.timeLeft = 0; + } + income.timeLeft--; + + if(income.timeLeft <= 0) { + Engine.log('collection income from ' + source); + if(source == 'thieves') $SM.addStolen(income.stores); + $SM.addM('stores', income.stores, true); + changed = true; + if(typeof income.delay == 'number') { + income.timeLeft = income.delay; + } + } + } + } + if(changed){ + $SM.fireUpdate('income', true); + }; + Engine._incomeTimeout = setTimeout($SM.collectIncome, 1000); + }, + + //Thieves + addStolen: function(stores) { + for(var k in stores) { + var old = $SM.get('stores["'+k+'"]', true); + var short = old - stores[k]; + //if they would steal more than actually owned + if(short < 0){ + $SM.add('game.stolen["'+k+'"]', (stores[k] * -1) + short); + } else { + $SM.add('game.stolen["'+k+'"]', stores[k] * -1); + } + }; + }, + + startThieves: function() { + $SM.set('game.thieves', 1); + $SM.setIncome('thieves', { + delay: 10, + stores: { + 'wood': -10, + 'fur': -5, + 'meat': -5 + } + }); + }, + + //Misc + num: function(name, craftable) { + switch(craftable.type) { + case 'good': + case 'tool': + case 'weapon': + case 'upgrade': + return $SM.get('stores["'+name+'"]', true); + case 'building': + return $SM.get('game.buildings["'+name+'"]', true); + } + }, + + handleStateUpdates: function(e){ + + } +}; + +//alias +var $SM = StateManager; \ No newline at end of file diff --git a/script/world.js b/script/world.js index d20f6b6..6c95f6e 100644 --- a/script/world.js +++ b/script/world.js @@ -128,11 +128,12 @@ var World = { World.LANDMARKS[World.TILE.BATTLEFIELD] = {num: 5, minRadius: 18, maxRadius: World.RADIUS * 1.5, scene: 'battlefield', label: 'A Battlefield'}; World.LANDMARKS[World.TILE.SWAMP] = {num: 1, minRadius: 15, maxRadius: World.RADIUS * 1.5, scene: 'swamp', label: 'A Murky Swamp'}; - if(typeof State.world == 'undefined') { - State.world = { + if(typeof $SM.get('features.location.world') == 'undefined') { + $SM.set('features.location.world', true); + $SM.setM('game.world', { map: World.generateMap(), mask: World.newMask() - }; + }); } // Create the World panel @@ -148,6 +149,9 @@ var World = { $('
').attr('id', 'healthCounter').appendTo(outer); Engine.updateOuterSlider(); + + //subscribe to stateUpdates + $.Dispatch('stateUpdate').subscribe(World.handleStateUpdates); }, clearDungeon: function() { @@ -265,7 +269,7 @@ var World = { // Update label var t = 'pockets'; - if(Engine.getStore('rucksack') > 0) { + if($SM.get('stores.rucksack', true) > 0) { t = 'rucksack'; } $('#backpackTitle').text(t); @@ -400,11 +404,11 @@ var World = { checkDanger: function() { World.danger = typeof World.danger == 'undefined' ? false: World.danger; if(!World.danger) { - if(!Engine.getStore('i armour') > 0 && World.getDistance() >= 8) { + if(!$SM.get('stores["i armour"]', true) > 0 && World.getDistance() >= 8) { World.danger = true; return true; } - if(!Engine.getStore('s armour') > 0 && World.getDistance() >= 18) { + if(!$SM.get('stores["s armour"]', true) > 0 && World.getDistance() >= 18) { World.danger = true; return true; } @@ -413,7 +417,7 @@ var World = { World.danger = false; return true; } - if(World.getDistance < 18 && Engine.getStore('i armour') > 0) { + if(World.getDistance < 18 && $SM.get('stores["i armour"]', true) > 0) { World.danger = false; return true; } @@ -426,7 +430,7 @@ var World = { World.waterMove++; // Food var movesPerFood = World.MOVES_PER_FOOD; - movesPerFood *= Engine.hasPerk('slow metabolism') ? 2 : 1; + movesPerFood *= $SM.hasPerk('slow metabolism') ? 2 : 1; if(World.foodMove >= movesPerFood) { World.foodMove = 0; var num = Path.outfit['cured meat']; @@ -440,10 +444,10 @@ var World = { Notifications.notify(World, 'starvation sets in') World.starvation = true; } else { - State.starved = State.starved ? State.starved : 0; - State.starved++; - if(State.starved >= 10 && !Engine.hasPerk('slow metabolism')) { - Engine.addPerk('slow metabolism'); + $SM.set('character.starved', $SM.get('character.starved', true)); + $SM.add('character.starved', 1); + if($SM.get('character.starved') >= 10 && !$SM.hasPerk('slow metabolism')) { + $SM.addPerk('slow metabolism'); } World.die(); return false; @@ -456,7 +460,7 @@ var World = { } // Water var movesPerWater = World.MOVES_PER_WATER; - movesPerWater *= Engine.hasPerk('desert rat') ? 2 : 1; + movesPerWater *= $SM.hasPerk('desert rat') ? 2 : 1; if(World.waterMove >= movesPerWater) { World.waterMove = 0; var water = World.water; @@ -469,10 +473,10 @@ var World = { Notifications.notify(World, 'the thirst becomes unbearable'); World.thirst = true; } else { - State.dehydrated = State.dehydrated ? State.dehydrated : 0; - State.dehydrated++; - if(State.dehydrated >= 10 && !Engine.hasPerk('desert rat')) { - Engine.addPerk('desert rat'); + $SM.set('character.dehydrated', $SM.get('character.dehydrated', true)); + $SM.add('character.dehydrated', 1); + if($SM.get('character.dehydrated') >= 10 && !$SM.hasPerk('desert rat')) { + $SM.addPerk('desert rat'); } World.die(); return false; @@ -487,7 +491,7 @@ var World = { }, meatHeal: function() { - return World.MEAT_HEAL * (Engine.hasPerk('gastronome') ? 2 : 1); + return World.MEAT_HEAL * ($SM.hasPerk('gastronome') ? 2 : 1); }, medsHeal: function() { @@ -499,7 +503,7 @@ var World = { World.fightMove++; if(World.fightMove > World.FIGHT_DELAY) { var chance = World.FIGHT_CHANCE; - chance *= Engine.hasPerk('stealthy') ? 0.5 : 1; + chance *= $SM.hasPerk('stealthy') ? 0.5 : 1; if(Math.random() < chance) { World.fightMove = 0; Events.triggerFight(); @@ -583,7 +587,7 @@ var World = { lightMap: function(x, y, mask) { var r = World.LIGHT_RADIUS; - r *= Engine.hasPerk('scout') ? 2 : 1; + r *= $SM.hasPerk('scout') ? 2 : 1; World.uncoverMap(x, y, r, mask); return mask; }, @@ -604,7 +608,7 @@ var World = { applyMap: function() { var x = Math.floor(Math.random() * (World.RADIUS * 2) + 1); var y = Math.floor(Math.random() * (World.RADIUS * 2) + 1); - World.uncoverMap(x, y, 5, State.world.mask); + World.uncoverMap(x, y, 5, $SM.get('game.world.mask')); }, generateMap: function() { @@ -822,20 +826,20 @@ var World = { goHome: function() { // Home safe! Commit the changes. - State.world = World.state; - if(World.state.sulphurmine && Outside.numBuilding('sulphur mine') == 0) { - Outside.addBuilding('sulphur mine', 1); + $SM.setM('game.world', World.state); + if(World.state.sulphurmine && $SM.get('game.buildings["sulphur mine"]', true) == 0) { + $SM.add('game.buildings["sulphur mine"]', 1); Engine.event('progress', 'sulphur mine'); } - if(World.state.ironmine && Outside.numBuilding('iron mine') == 0) { - Outside.addBuilding('iron mine', 1); + if(World.state.ironmine && $SM.get('game.buildings["iron mine"]', true) == 0) { + $SM.add('game.buildings["iron mine"]', 1); Engine.event('progress', 'iron mine'); } - if(World.state.coalmine && Outside.numBuilding('coal mine') == 0) { - Outside.addBuilding('coal mine', 1); + if(World.state.coalmine && $SM.get('game.buildings["coal mine"]', true) == 0) { + $SM.add('game.buildings["coal mine"]', 1); Engine.event('progress', 'coal mine'); } - if(World.state.ship && !State.ship) { + if(World.state.ship && !$SM.get('features.location.spaceShip')) { Ship.init(); Engine.event('progress', 'ship'); } @@ -848,7 +852,7 @@ var World = { } for(var k in Path.outfit) { - Engine.addStore(k, Path.outfit[k]); + $SM.add('stores["'+k+'"]', Path.outfit[k]); if(World.leaveItAtHome(k)) { Path.outfit[k] = 0; } @@ -865,29 +869,29 @@ var World = { }, getMaxHealth: function() { - if(Engine.getStore('s armour') > 0) { + if($SM.get('stores["s armour"]', true) > 0) { return World.BASE_HEALTH + 35; - } else if(Engine.getStore('i armour') > 0) { + } else if($SM.get('stores["i armour"]', true) > 0) { return World.BASE_HEALTH + 15; - } else if(Engine.getStore('l armour') > 0) { + } else if($SM.get('stores["l armour"]', true) > 0) { return World.BASE_HEALTH + 5; } return World.BASE_HEALTH; }, getHitChance: function() { - if(Engine.hasPerk('precise')) { + if($SM.hasPerk('precise')) { return World.BASE_HIT_CHANCE + 0.1; } return World.BASE_HIT_CHANCE; }, getMaxWater: function() { - if(Engine.getStore('water tank') > 0) { + if($SM.get('stores["water tank"]', true) > 0) { return World.BASE_WATER + 50; - } else if(Engine.getStore('cask') > 0) { + } else if($SM.get('stores.cask', true) > 0) { return World.BASE_WATER + 20; - } else if(Engine.getStore('waterskin') > 0) { + } else if($SM.get('stores.waterskin', true) > 0) { return World.BASE_WATER + 10; } return World.BASE_WATER; @@ -904,7 +908,7 @@ var World = { Notifications.notify(null, 'water replenished'); World.setWater(World.getMaxWater()); // Save progress at outposts - State.world = World.state; + $SM.setM('game.world', World.state); // Mark this outpost as used World.usedOutposts[World.curPos[0] + ',' + World.curPos[1]] = true; }, @@ -912,7 +916,7 @@ var World = { onArrival: function() { Engine.keyLock = false; // Explore in a temporary world-state. We'll commit the changes if you return home safe. - World.state = $.extend(true, {}, State.world); + World.state = $.extend(true, {}, $SM.get('game.world')); World.setWater(World.getMaxWater()); World.setHp(World.getMaxHealth()); World.foodMove = 0; @@ -935,5 +939,9 @@ var World = { copyPos: function(pos) { return [pos[0], pos[1]]; + }, + + handleStateUpdates: function(e){ + } }; \ No newline at end of file