Files
adarkroom/script/outside.js
T
LucidCrux dee7cbb9b3 refactor Engine.js for use with $SM
====functions removed====
//I just removed these because most were simpler or at least equal as
	direct $SM get/set/add calls, I realize the store ones are kind of
	subjective since calls were about equal, but oh well. If someone
	really 	feels we need the shortcut/named functions for manipulating
	stores specifically, it shouldn't be crazy to reimplement in $SM 
Engine.setStore >> $SM.set
Engine.setStores >> $SM.setM
Engine.addStore >> $SM.add
Engine.addStores >> $SM.addM
Engine.getStore >> $SM.get(requestZero = true)
Engine.storeAvailable >> $SM.get;
Engine.removeIncome >> $SM.remove //updates moved to handler


====functions moved====
//Any moved function I felt was more directly related to States or
	didn't belong where it was
Engine.addPerk > $SM.addPerk //kept function for now because of notify
	call inside, 'deep' state
Engine.hasPerk > $SM.hasPerk //kept function because of 'deep' state
	name
Engine.setIncome > $SM.setIncome //kept because it has internal logic
**Engine.getIncome > $SM.getIncome //**easily removable with
	Outside.updateVillageIncome refactor
Engine.openPath > Path.openPath //Since I'm refactoring anyways
Engine.addStolen > $SM.addStolen //internal logic
Engine.startThieves > $SM.startThieves //not sure $SM is a better place,
	but Engine should be nice and clean by the end of this, handling
	only engine mechanics
Engine.num > $SM.num //after Outside refacter, this is basically just a
	fancy $SM.get
Engine.upgradeState > $SM.updateOldState


====functions refactored====
$SM.addPerk; //updates moved to event handler, no check/create new perk
$SM.hasPerk; //don't need to check exist and ==true
$SM.collectIncome //removed changed check, update calls now handled by
	'stateUpdate' event listening
$SM.addStolen //fix to set stolen items in case a partial steal happens
$SM.startThieves //updates in handler
$SM.updateOldState //use $SM calls, add placeholder for updating to post
$SM state when more finalized 


====functions affected (by removed)====
Engine.init (Engine.getStore, Engine.storeAvailable)
Engine.collectIncome (Engine.addStores)
Engine.num (Engine.getStore)
Engine.travelTo (Engine.storeAvailable)

Room.init (Engine.getStore)
Room.unlockForest (Engine.setStore)
Room.lightFire (Engine.setStore, Engine.getStore, Engine.storeAvailable)
Room.stokeFire (Engine.setStore, Engine.getStore, Engine.storeAvailable)
Room.coolFire (Engine.setStore)
Room.buy (Engine.setStores, Engine.addStore, Engine.getStore)
Room.build (Engine.setStores, Engine.getStore)
Room.craftUnlocked (Engine.getStore, Engine.storeAvailable)
Room.buyUnlocked (Engine.storeAvailable)
Room.updateButton (Engine.storeAvailable)

Outside.gatherWood (Engine.addStores)
Outside.checkTraps (Engine.addStores, Engine.getStore)
Outside.updateVillage (Engine.getStore)

Path.embark (Engine.addStore)
Path.getCapacity (Engine.getStore)
Path.updateOutfitting (Engine.getStore)
Path.createOutfittingRow (Engine.getStore)
Path.increaseSupply (Engine.getStore)

World.goHome (Engine.addStore)
World.updateSupplies (Engine.getStore)
World.checkDanger (Engine.getStore)
World.getMaxHealth (Engine.getStore)
World.getMaxWater (Engine.getStore)

Ship.reinforceHull (Engine.addStore, Engine.getStore)
Ship.upgradeEngine (Engine.addStore, Engine.getStore)

Events.loadScene (Engine.addStores)
Events.updateButtons (Engine.getStore)
Events.buttonClick (Engine.getStore)

Events.Global (Engine.addStores, Engine.removeIncome)
Events.Room (Engine.addStore, Engine.addStores, Engine.getStore,
Engine.storeAvailable)
2013-07-24 17:41:36 -06:00

642 lines
18 KiB
JavaScript

/**
* Module that registers the outdoors functionality
*/
var Outside = {
name: "Outside",
_GATHER_DELAY: 60,
_TRAPS_DELAY: 90,
_POP_DELAY: [0.5, 3],
_INCOME: {
'gatherer': {
delay: 10,
stores: {
'wood': 1
}
},
'hunter': {
delay: 10,
stores: {
'fur': 0.5,
'meat': 0.5
}
},
'trapper': {
delay: 10,
stores: {
'meat': -1,
'bait': 1
}
},
'tanner': {
delay: 10,
stores: {
'fur': -5,
'leather': 1
}
},
'charcutier': {
delay: 10,
stores: {
'meat': -5,
'wood': -5,
'cured meat': 1
}
},
'iron miner': {
delay: 10,
stores: {
'cured meat': -1,
'iron': 1
}
},
'coal miner': {
delay: 10,
stores: {
'cured meat': -1,
'coal': 1
}
},
'sulphur miner': {
delay: 10,
stores: {
'cured meat': -1,
'sulphur': 1
}
},
'steelworker': {
delay: 10,
stores: {
'iron': -1,
'coal': -1,
'steel': 1
}
},
'armourer': {
delay: 10,
stores: {
'steel': -1,
'sulphur': -1,
'bullets': 1
}
}
},
TrapDrops: [
{
rollUnder: 0.5,
name: 'fur',
message: 'scraps of fur'
},
{
rollUnder: 0.75,
name: 'meat',
message: 'bits of meat'
},
{
rollUnder: 0.85,
name: 'scales',
message: 'strange scales'
},
{
rollUnder: 0.93,
name: 'teeth',
message: 'scattered teeth'
},
{
rollUnder: 0.995,
name: 'cloth',
message: 'tattered cloth'
},
{
rollUnder: 1.0,
name: 'charm',
message: 'a crudely made charm'
}
],
init: function(options) {
this.options = $.extend(
this.options,
options
);
if(Engine._debug) {
this._GATHER_DELAY = 0;
this._TRAPS_DELAY = 0;
}
// Create the outside tab
this.tab = Header.addLocation("A Silent Forest", "outside", Outside);
// Create the Outside panel
this.panel = $('<div>').attr('id', "outsidePanel")
.addClass('location')
.appendTo('div#locationSlider');
if(typeof $SM.get('features.location.outside') == 'undefined') {
$SM.set('features.location.outside', true);
$SM.setM('game.outside', {
buildings: {},
population: 0,
workers: {}
});
}
this.updateVillage();
Outside.updateWorkersView();
Engine.updateSlider();
// Create the gather button
new Button.Button({
id: 'gatherButton',
text: "gather wood",
click: Outside.gatherWood,
cooldown: Outside._GATHER_DELAY,
width: '80px'
}).appendTo('div#outsidePanel');
},
numBuilding: function(bName) {
return $SM.get('features.location.outside') &&
$SM.get('game.outside.buildings') &&
$SM.get('game.outside.buildings[\''+bName+'\']', true);
},
addBuilding: function(bName, num) {
var cur = $SM.get('game.outside.buildings[\''+bName+'\']');
if(typeof cur != 'number') cur = 0;
cur += num;
if(cur < 0) cur = 0;
$SM.set('game.outside.buildings[\''+bName+'\']', cur);
this.updateVillage();
Engine.saveGame();
},
addBuildings: function(list) {
for(k in list) {
var num = $SM.get('game.outside.buildings[\''+k+'\']');
if(typeof num != 'number') num = 0;
num += list[k];
$SM.set('game.outside.buildings[\''+k+'\']', num);
}
this.updateVillage();
Engine.saveGame();
},
getMaxPopulation: function() {
return Outside.numBuilding('hut') * 4;
},
getPopulation: function() {
if($SM.get('features.location.outside') && $SM.get('game.outside.population')) {
return $SM.get('game.outside.population');
}
return 0;
},
increasePopulation: function() {
var space = Outside.getMaxPopulation() - $SM.get('game.outside.population');
if(space > 0) {
var num = Math.floor(Math.random()*(space/2) + space/2);
if(num == 0) num = 1;
if(num == 1) {
Notifications.notify(null, 'a stranger arrives in the night');
} else if(num < 5) {
Notifications.notify(null, 'a weathered family takes up in one of the huts.');
} else if(num < 10) {
Notifications.notify(null, 'a small group arrives, all dust and bones.');
} else if(num < 30) {
Notifications.notify(null, 'a convoy lurches in, equal parts worry and hope.');
} else {
Notifications.notify(null, "the town's booming. word does get around.");
}
Engine.log('population increased by ' + num);
$SM.add('game.outside.population', num);
Outside.updateVillage();
Outside.updateWorkersView();
Outside.updateVillageIncome();
}
Outside.schedulePopIncrease();
},
killVillagers: function(num) {
$SM.add('game.outside.population', num * -1);
if($SM.get('game.outside.population') < 0) {
$SM.set('game.outside.population', 0);
}
var remaining = Outside.getNumGatherers();
if(remaining < 0) {
var gap = -remaining;
for(var k in $SM.get('game.outside.workers')) {
var num = $SM.get('game.outside.workers[\''+k+'\']');
if(num < gap) {
gap -= num;
$SM.set('game.outside.workers[\''+k+'\']', 0);
} else {
$SM.add('game.outside.workers[\''+k+'\']', gap * -1);
break;
}
}
}
Outside.updateVillage();
Outside.updateWorkersView();
Outside.updateVillageIncome();
},
schedulePopIncrease: function() {
var nextIncrease = Math.floor(Math.random()*(Outside._POP_DELAY[1] - Outside._POP_DELAY[0])) + Outside._POP_DELAY[0];
Engine.log('next population increase scheduled in ' + nextIncrease + ' minutes');
Outside._popTimeout = setTimeout(Outside.increasePopulation, nextIncrease * 60 * 1000);
},
updateWorkersView: function() {
var workers = $('div#workers');
// If our population is 0 and we don't already have a workers view,
// there's nothing to do here.
if(!workers.length && $SM.get('game.outside.population') == 0) return;
var needsAppend = false;
if(workers.length == 0) {
needsAppend = true;
workers = $('<div>').attr('id', 'workers').css('opacity', 0);
}
var numGatherers = $SM.get('game.outside.population');
var gatherer = $('div#workers_row_gatherer', workers);
for(var k in $SM.get('game.outside.workers')) {
var row = $('div#workers_row_' + k.replace(' ', '-'), workers);
if(row.length == 0) {
row = Outside.makeWorkerRow(k, $SM.get('game.outside.workers[\''+k+'\']'));
var curPrev = null;
workers.children().each(function(i) {
var child = $(this);
var cName = child.attr('id').substring(12).replace('-', ' ');
if(cName != 'gatherer') {
if(cName < k && (curPrev == null || cName > curPrev)) {
curPrev = cName;
}
}
});
if(curPrev == null && gatherer.length == 0) {
row.prependTo(workers);
}
else if(curPrev == null)
{
row.insertAfter(gatherer);
}
else
{
row.insertAfter(workers.find('#workers_row_' + curPrev.replace(' ', '-')));
}
} else {
$('div#' + row.attr('id') + ' > div.row_val > span', workers).text($SM.get('game.outside.workers[\''+k+'\']'));
}
numGatherers -= $SM.get('game.outside.workers[\''+k+'\']');
if($SM.get('game.outside.workers[\''+k+'\']') == 0) {
$('.dnBtn', row).addClass('disabled');
$('.dnManyBtn', row).addClass('disabled');
} else {
$('.dnBtn', row).removeClass('disabled');
$('.dnManyBtn', row).removeClass('disabled');
}
}
if(gatherer.length == 0) {
gatherer = Outside.makeWorkerRow('gatherer', numGatherers);
gatherer.prependTo(workers);
} else {
$('div#workers_row_gatherer > div.row_val > span', workers).text(numGatherers);
}
if(numGatherers == 0) {
$('.upBtn', '#workers').addClass('disabled');
$('.upManyBtn', '#workers').addClass('disabled');
} else {
$('.upBtn', '#workers').removeClass('disabled');
$('.upManyBtn', '#workers').removeClass('disabled');
}
if(needsAppend && workers.children().length > 0) {
workers.appendTo('#outsidePanel').animate({opacity:1}, 300, 'linear');
}
},
getNumGatherers: function() {
var num = $SM.get('game.outside.population');
for(var k in $SM.get('game.outside.workers')) {
num -= $SM.get('game.outside.workers[\''+k+'\']');
}
return num;
},
makeWorkerRow: function(name, num) {
var row = $('<div>')
.attr('id', 'workers_row_' + name.replace(' ','-'))
.addClass('workerRow');
$('<div>').addClass('row_key').text(name).appendTo(row);
var val = $('<div>').addClass('row_val').appendTo(row);
$('<span>').text(num).appendTo(val);
if(name != 'gatherer') {
$('<div>').addClass('upManyBtn').appendTo(val).click([10], Outside.increaseWorker);
$('<div>').addClass('upBtn').appendTo(val).click([1], Outside.increaseWorker);
$('<div>').addClass('dnBtn').appendTo(val).click([1], Outside.decreaseWorker);
$('<div>').addClass('dnManyBtn').appendTo(val).click([10], Outside.decreaseWorker);
}
$('<div>').addClass('clear').appendTo(row);
var tooltip = $('<div>').addClass('tooltip bottom right').appendTo(row);
var income = Outside._INCOME[name];
for(var s in income.stores) {
var r = $('<div>').addClass('storeRow');
$('<div>').addClass('row_key').text(s).appendTo(r);
$('<div>').addClass('row_val').text(Engine.getIncomeMsg(income.stores[s], income.delay)).appendTo(r);
r.appendTo(tooltip);
}
return row;
},
increaseWorker: function(btn) {
var worker = $(this).closest('.workerRow').children('.row_key').text();
if(Outside.getNumGatherers() > 0) {
var increaseAmt = Math.min(Outside.getNumGatherers(), btn.data);
Engine.log('increasing ' + worker + ' by ' + increaseAmt);
$SM.add('game.outside.workers[\''+worker+'\']', increaseAmt);
Outside.updateVillageIncome();
Outside.updateWorkersView();
}
},
decreaseWorker: function(btn) {
var worker = $(this).closest('.workerRow').children('.row_key').text();
if($SM.get('game.outside.workers[\''+worker+'\']') > 0) {
var decreaseAmt = Math.min($SM.get('game.outside.workers[\''+worker+'\']') || 0, btn.data);
Engine.log('decreasing ' + worker + ' by ' + decreaseAmt);
$SM.add('game.outside.workers[\''+worker+'\']', decreaseAmt * -1);
Outside.updateVillageIncome();
Outside.updateWorkersView();
}
},
updateVillageRow: function(name, num, village) {
var id = 'building_row_' + name.replace(' ', '-');
var row = $('div#' + id, village);
if(row.length == 0 && num > 0) {
var row = $('<div>').attr('id', id).addClass('storeRow');
$('<div>').addClass('row_key').text(name).appendTo(row);
$('<div>').addClass('row_val').text(num).appendTo(row);
$('<div>').addClass('clear').appendTo(row);
var curPrev = null;
village.children().each(function(i) {
var child = $(this);
if(child.attr('id') != 'population') {
var cName = child.attr('id').substring(13).replace('-', ' ');
if(cName < name && (curPrev == null || cName > curPrev)) {
curPrev = cName;
}
}
});
if(curPrev == null) {
row.prependTo(village);
} else {
row.insertAfter('#building_row_' + curPrev.replace(' ', '-'));
}
} else if(num > 0) {
$('div#' + row.attr('id') + ' > div.row_val', village).text(num);
} else if(num == 0) {
row.remove();
}
},
updateVillage: function() {
var village = $('div#village');
var pop = $('div#population');
var needsAppend = false;
if(village.length == 0) {
needsAppend = true;
village = $('<div>').attr('id', 'village').css('opacity', 0);
population = $('<div>').attr('id', 'population').appendTo(village);
}
for(var k in $SM.get('game.outside.buildings')) {
if(k == 'trap') {
var numTraps = $SM.get('game.outside.buildings[\''+k+'\']');
var numBait = $SM.get('stores.bait', true);
var traps = numTraps - numBait;
traps = traps < 0 ? 0 : traps;
Outside.updateVillageRow(k, traps, village);
Outside.updateVillageRow('baited trap', numBait > numTraps ? numTraps : numBait, village);
} else {
if(Outside.checkWorker(k)) {
Outside.updateWorkersView();
}
Outside.updateVillageRow(k, $SM.get('game.outside.buildings[\''+k+'\']'), village);
}
}
population.text('pop ' + $SM.get('game.outside.population') + '/' + this.getMaxPopulation());
var hasPeeps;
if(Outside.numBuilding('hut') == 0) {
hasPeeps = false;
village.addClass('noHuts');
} else {
hasPeeps = true;
village.removeClass('noHuts');
}
if(needsAppend && village.children().length > 1) {
village.appendTo('#outsidePanel');
village.animate({opacity:1}, 300, 'linear');
}
if(hasPeeps && typeof Outside._popTimeout == 'undefined') {
Outside.schedulePopIncrease();
}
this.setTitle();
if(Engine.activeModule === Outside && village.children().length > 1) {
$('#storesContainer').css({top: village.height() + 26 + 'px'});
}
},
checkWorker: function(name) {
var jobMap = {
'lodge': ['hunter', 'trapper'],
'tannery': ['tanner'],
'smokehouse': ['charcutier'],
'iron mine': ['iron miner'],
'coal mine': ['coal miner'],
'sulphur mine': ['sulphur miner'],
'steelworks': ['steelworker'],
'armoury' : ['armourer']
}
var jobs = jobMap[name];
var added = false;
if(typeof jobs == 'object') {
for(var i = 0, len = jobs.length; i < len; i++) {
var job = jobs[i];
if(typeof $SM.get('game.outside.buildings[\''+name+'\']') == 'number' &&
typeof $SM.get('game.outside.workers[\''+job+'\']') != 'number') {
Engine.log('adding ' + job + ' to the workers list')
$SM.set('game.outside.workers[\''+job+'\']', 0);
added = true;
}
}
}
return added;
},
updateVillageIncome: function() {
for(var worker in Outside._INCOME) {
var income = Outside._INCOME[worker];
var num = worker == 'gatherer' ? Outside.getNumGatherers() : $SM.get('game.outside.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 = $SM.getIncome(worker);
for(var store in income.stores) {
stores[store] = income.stores[store] * num;
if(curIncome[store] != stores[store]) needsUpdate = true;
var row = $('<div>').addClass('storeRow');
$('<div>').addClass('row_key').text(store).appendTo(row);
$('<div>').addClass('row_val').text(Engine.getIncomeMsg(stores[store], income.delay)).appendTo(row);
row.appendTo(tooltip);
}
if(needsUpdate) {
$SM.setIncome(worker, {
delay: income.delay,
stores: stores
});
}
}
}
Room.updateIncomeView();
},
updateTrapButton: function() {
var btn = $('div#trapsButton');
if(Outside.numBuilding('trap') > 0) {
if(btn.length == 0) {
new Button.Button({
id: 'trapsButton',
text: "check traps",
click: Outside.checkTraps,
cooldown: Outside._TRAPS_DELAY,
width: '80px'
}).appendTo('div#outsidePanel');
} else {
Button.setDisabled(btn, false);
}
} else {
if(btn.length > 0) {
Button.setDisabled(btn, true);
}
}
},
setTitle: function() {
var numHuts = this.numBuilding('hut');
var title;
if(numHuts == 0) {
title = "A Silent Forest";
} else if(numHuts == 1) {
title = "A Lonely Hut";
} else if(numHuts <= 4) {
title = "A Tiny Village";
} else if(numHuts <= 8) {
title = "A Modest Village";
} else if(numHuts <= 14) {
title = "A Large Village";
} else {
title = "A Raucous Village";
}
if(Engine.activeModule == this) {
document.title = title;
}
$('#location_outside').text(title);
},
onArrival: function(transition_diff) {
Outside.setTitle();
if(!$SM.get('game.outside.seenForest')) {
Notifications.notify(Outside, "the sky is grey and the wind blows relentlessly");
$SM.set('game.outside.seenForest', true);
}
Outside.updateTrapButton();
Outside.updateVillage();
Engine.moveStoresView($('#village'), transition_diff);
},
gatherWood: function() {
Notifications.notify(Outside, "dry brush and dead branches litter the forest floor")
var gatherAmt = Outside.numBuilding('cart') > 0 ? 50 : 10;
$SM.add('stores.wood', gatherAmt);
},
checkTraps: function() {
var drops = {};
var msg = [];
var numTraps = Outside.numBuilding('trap');
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();
for(var j in Outside.TrapDrops) {
var drop = Outside.TrapDrops[j];
if(roll < drop.rollUnder) {
var num = drops[drop.name]
if(typeof num == 'undefined') {
num = 0;
msg.push(drop.message);
}
drops[drop.name] = num + 1;
break;
}
}
}
var s = 'the traps contain ';
for(var i = 0, len = msg.length; i < len; i++) {
if(len > 1 && i > 0 && i < len - 1) {
s += ", ";
} else if(len > 1 && i == len - 1) {
s += " and ";
}
s += msg[i];
}
var baitUsed = numBait < numTraps ? numBait : numTraps;
drops['bait'] = -baitUsed;
Notifications.notify(Outside, s);
$SM.addM('stores', drops);
},
handleStateUpdates: function(e){
//updates to run on stores changes
if(e.stateName.indexOf('stores') == 0){
Outside.updateVillage();
}
},
};
//listener for StateManager update events
$(Outside).on('stateUpdate', Outside.handleStateUpdates);