mirror of
https://github.com/doublespeakgames/adarkroom.git
synced 2026-05-28 00:01:54 +08:00
611 lines
16 KiB
JavaScript
611 lines
16 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 State.outside == 'undefined') {
|
|
State.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 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;
|
|
},
|
|
|
|
increasePopulation: function() {
|
|
var space = Outside.getMaxPopulation() - State.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);
|
|
State.outside.population += num;
|
|
Outside.updateVillage();
|
|
Outside.updateWorkersView();
|
|
Outside.updateVillageIncome();
|
|
}
|
|
Outside.schedulePopIncrease();
|
|
},
|
|
|
|
killVillagers: function(num) {
|
|
State.outside.population -= num;
|
|
if(State.outside.population < 0) {
|
|
State.outside.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];
|
|
if(num < gap) {
|
|
gap -= num;
|
|
State.outside.workers[k] = 0;
|
|
} else {
|
|
State.outside.workers[k] -= gap;
|
|
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() {
|
|
if(State.outside.population == 0) return;
|
|
var workers = $('div#workers');
|
|
var needsAppend = false;
|
|
if(workers.length == 0) {
|
|
needsAppend = true;
|
|
workers = $('<div>').attr('id', 'workers').css('opacity', 0);
|
|
}
|
|
|
|
var numGatherers = State.outside.population;
|
|
var gatherer = $('div#workers_row_gatherer', workers);
|
|
|
|
for(var k in State.outside.workers) {
|
|
var row = $('div#workers_row_' + k.replace(' ', '-'), workers);
|
|
if(row.length == 0) {
|
|
row = Outside.makeWorkerRow(k, State.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(State.outside.workers[k]);
|
|
}
|
|
numGatherers -= State.outside.workers[k];
|
|
if(State.outside.workers[k] == 0) {
|
|
$('.dnBtn', row).addClass('disabled');
|
|
} else {
|
|
$('.dnBtn', 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');
|
|
} else {
|
|
$('.upBtn', '#workers').removeClass('disabled');
|
|
}
|
|
|
|
|
|
if(needsAppend && workers.children().length > 0) {
|
|
workers.appendTo('#outsidePanel').animate({opacity:1}, 300, 'linear');
|
|
}
|
|
},
|
|
|
|
getNumGatherers: function() {
|
|
var num = State.outside.population;
|
|
for(var k in State.outside.workers) {
|
|
num -= State.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('upBtn').appendTo(val).click(Outside.increaseWorker);
|
|
$('<div>').addClass('dnBtn').appendTo(val).click(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) {
|
|
Engine.log('increasing ' + worker);
|
|
State.outside.workers[worker]++;
|
|
Outside.updateVillageIncome();
|
|
Outside.updateWorkersView();
|
|
}
|
|
},
|
|
|
|
decreaseWorker: function(btn) {
|
|
var worker = $(this).closest('.workerRow').children('.row_key').text();
|
|
if(State.outside.workers[worker] > 0) {
|
|
Engine.log('decreasing ' + worker);
|
|
State.outside.workers[worker]--;
|
|
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 State.outside.buildings) {
|
|
if(k == 'trap') {
|
|
var numTraps = State.outside.buildings[k];
|
|
var numBait = Engine.getStore('bait');
|
|
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, State.outside.buildings[k], village);
|
|
}
|
|
}
|
|
|
|
population.text('pop ' + State.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();
|
|
},
|
|
|
|
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 State.outside.buildings[name] == 'number' &&
|
|
typeof State.outside.workers[job] != 'number') {
|
|
Engine.log('adding ' + job + ' to the workers list')
|
|
State.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() : State.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 = Engine.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) {
|
|
Engine.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() {
|
|
Outside.setTitle();
|
|
if(!State.seenForest) {
|
|
Notifications.notify(Outside, "the sky is grey and the wind blows relentlessly");
|
|
State.seenForest = true;
|
|
}
|
|
Outside.updateTrapButton();
|
|
},
|
|
|
|
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));
|
|
},
|
|
|
|
checkTraps: function() {
|
|
var drops = {};
|
|
var msg = [];
|
|
var numTraps = Outside.numBuilding('trap');
|
|
var numBait = Engine.getStore('bait');
|
|
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);
|
|
Engine.addStores(drops);
|
|
}
|
|
} |