js13kgames2015-reverse/src/main.js

355 lines
10 KiB
JavaScript

// Theme: Reversed
// https://en.wikipedia.org/wiki/Asteroid_mining
let MINI = require('minified');
let _=MINI._, $=MINI.$, $$=MINI.$$, EE=MINI.EE, HTML=MINI.HTML;
class Engine {
constructor() {
this.ticks = 0;
this.current_asteroid = new Asteroid();
this.station = new Station();
this.ship = new Ship(this.current_asteroid, this.station);
this.asteroids = [this.current_asteroid];
this.game_running = true;
this.init_sequence_run = true;
}
tick() {
this.ticks++;
}
update() {
// Endgame?
if (!this.game_running) {
$('#ship, #asteroid, #station, #startgame, nav').hide();
$('#endgame').show();
return;
}
if (this.init_sequence_run) {
$('#ship, #asteroid, #station, #endgame, nav').hide();
$('#startgame').show();
return;
}
// Resources
_.eachObj(this.ship.resources, (key, value) => {
$('nav .res-' + key).fill(value);
});
$('nav .cbtc').fill(this.ship.cbtc);
// The ship
$('#active-tool').fill(this.ship.active_tool);
if (_.keys(engine.ship.equipment).length != $('#ship-equipment > li').length) {
$('#ship-equipment').fill();
_.eachObj(engine.ship.equipment, (item) => {
// Skip if it is not a tool to mount
let type = this.ship.equipment[item]['type'];
// Tools can mount on the ship
if (type == 'tool') {
// Add the tool to the DOM inventory and add a mount button
let mount_button = EE('a', {'@href': '#', '%tool': item}, 'mount').onClick((e) => {
engine.ship.active_tool = item;
engine.update();
});
$('#ship-equipment').add(EE('li', item+' ').add(mount_button));
}
// Bots can deploy on an asteroid
if (type == 'bot') {
let deploy_button = EE('a', {'@href': '#'}, 'deploy').onClick((e) => {
// This only works on asteroids
if (engine.ship.docked_to instanceof Asteroid) {
let bot = new Bot(item, engine.ship.equipment[item]['capability']);
engine.ship.docked_to.deploy_bot(bot);
delete engine.ship.equipment[item];
engine.update();
} else {
alert('You need to land on an asteroid first.');
}
});
$('#ship-equipment').add(EE('li', item+' ').add(deploy_button));
}
});
}
if (this.ship.docked_to instanceof Station) {
$('#asteroid').hide();
$('#station').show();
}
if (this.ship.docked_to instanceof Asteroid) {
$('#station').hide();
$('#asteroid').show();
$('#time').fill((this.ticks-this.current_asteroid.landed_on) + ' hours');
$('#asteroid-classification').fill(this.current_asteroid.classification);
$('#bots').fill();
_.eachObj(this.current_asteroid.bots, (i, bot) => {
let destroy_button = EE('a', {'@href': '#'}, 'destroy').onClick((e) => {
bot.docked_to.bots.splice(i, 1);
engine.update();
});
$('#bots').add(EE('li', bot.model+' ').add(destroy_button));
});
}
}
}
class Ship {
constructor(asteroid, station) {
this.docked_to = asteroid;
this.active_tool = 'probe';
this.equipment = {
'probe': station.inventory['probe']
};
this.upgrades = {
};
this.resources = {
dust: 0,
stone: 0,
carbon: 0,
metal: 0
};
this.cbtc = 430;
}
mount(tool) {
this.active_tool = tool;
}
equip(tool, props) {
this.equipment[tool] = props;
}
mine() {
if (this.docked_to instanceof Asteroid) {
let [type, amount] = this.docked_to.harvest(this.equipment[this.active_tool]);
this.resources[type] += amount;
}
}
}
class Bot {
constructor(model) {
this.model = model;
this.tool = {'name': 'probe', 'capability': engine.station.inventory['probe'] };
this.docked_to = false;
}
// TODO: Build a gui for this
mount(tool, props) {
this.tool = {'name': tool, 'capability': props};
}
mine() {
if (this.docked_to instanceof Asteroid &&
engine.ship.docked_to == this.docked_to) {
let [type, amount] = this.docked_to.harvest(this.tool['capability']);
engine.ship.resources[type] += amount;
}
}
}
class Asteroid {
constructor() {
this.landed_on = 0;
this.bots = [];
// Determine the class
this.classification = [
'A', // small, stone, dust, random
'C', // dark carbon
'S', // stone
'X' // metal
][Helper.random_number(0, 4)];
}
harvest(tool) {
let resources = {
'A': ['dust', 'dust', 'stone'],
'C': ['dust', 'carbon', 'carbon', 'carbon'],
'S': ['dust', 'stone', 'stone'],
'X': ['metal']
}[this.classification];
let res_type = resources[Helper.random_number(0, resources.length)];
let amount = tool['capability'][this.classification];
return [res_type, amount];
}
deploy_bot(bot) {
bot.docked_to = this;
this.bots.push(bot);
}
}
class Station {
constructor() {
this.inventory = {
// take probes from the asteroid
'probe': {
'price': 10,
'type': 'tool',
'capability': {'A': 1, 'C': 1, 'S': 1, 'X': 1}
},
// mine on surface
'conveyor': {
'price': 500,
'type': 'tool',
'capability': {'A': 2, 'C': 8, 'S': 4, 'X': 1}
},
// shaft mining into the asteroid
'pipe-drill': {
'price': 3000,
'type': 'tool',
'capability': {'A': 3, 'C': 15, 'S': 12, 'X': 2}
},
// pick up loose grains with magnet, x-class asteroids only
'magnet': {
'price': 4500,
'type': 'tool',
'capability': {'A': 3, 'C': 1, 'S': 1, 'X': 20}
},
// melt the matrix
'vaporizer': {
'price': 4000,
'type': 'tool',
'capability': {'A': 4, 'C': 7, 'S': 6, 'X': 5}
},
'mining-bot': {
'price': 20000,
'type': 'bot',
'capability': {'A': 8, 'C': 8, 'S': 8, 'X': 8}
},
'reverser': {
'price': 90000,
'type': 'part',
'capability': {}
}
};
this.market = {
'dust': 1,
'stone': 3,
'carbon': 20,
'metal': 45
};
}
sell(ship, tool) {
// Tools can't be buy multiple times
if (!_.keys(this.inventory).contains(tool) ||
_.keys(ship.equipment).contains(tool)) {
alert('You already own this tool.');
return;
}
let price = this.inventory[tool].price;
if (price > ship.cbtc) {
alert('You have not enough cBTC!');
return;
}
// Endgame?
if (tool == 'reverser')
engine.game_running = false;
ship.equip(tool, this.inventory[tool]);
ship.cbtc -= price;
}
buy(ship, resource, amount) {
if (ship.resources[resource] < amount || amount < 0) {
alert('You have not enough resources loaded');
return;
}
let price = this.market[resource];
ship.cbtc += price*amount;
ship.resources[resource] -= amount;
}
}
var engine = new Engine();
$(() => {
$('#btn-mine').onClick(() => {
engine.ship.mine();
engine.update();
});
$('#btn-to-station').onClick(() => {
engine.ship.docked_to = engine.station;
engine.current_asteroid = null;
// Update the resources to sell. If the ship is docked to a station,
// the resources do not change because we can't mine.
_.eachObj(engine.ship.resources, (key, value) => {
$('#ship-inventory .res-' + key).set('value', value);
});
engine.update();
});
$('#btn-to-asteroid').onClick(() => {
engine.ship.docked_to = engine.asteroids[0];
engine.current_asteroid = engine.asteroids[0];
engine.current_asteroid.landed_on = engine.ticks;
engine.update();
});
_.eachObj(engine.station.inventory, (tool, props) => {
let buy_button = EE('a', {'@href': '#', '%tool': tool}, ' buy for '+props.price+' cBTC').onClick((e) => {
let tool = $(e.target).get('%tool');
engine.station.sell(engine.ship, tool);
engine.update();
})
$('#station-inventory').add(EE('li', tool).add(buy_button));
});
$('#ship-inventory a').onClick((e) => {
let res = $(e.target).get('%res');
let input = $('#ship-inventory input[name="sell-res-'+res+'"]');
let amount = input.get('value');
let rest = engine.ship.resources[res] - amount;
if (rest < 0) rest = engine.ship.resources[res];
input.set('value', rest);
engine.station.buy(engine.ship, res, amount);
engine.update();
});
$('#startgame button').onClick((e) => {
$('#startgame').hide();
$('#ship, nav').show();
engine.init_sequence_run = false;
engine.update();
setInterval(() => {
engine.tick();
_.each(engine.asteroids, (asteroid) => {
_.each(asteroid.bots, (bot) => {
bot.mine();
})
});
engine.update();
}, 1000);
});
engine.update();
})