Upload files to "js"
This commit is contained in:
279
js/simulation.js
Normal file
279
js/simulation.js
Normal file
@@ -0,0 +1,279 @@
|
||||
// Game Simulation / Logic
|
||||
const Simulation = {
|
||||
gameTime: 0,
|
||||
gameSpeed: 1,
|
||||
|
||||
// Manual mining state
|
||||
mining: {
|
||||
active: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
progress: 0
|
||||
},
|
||||
|
||||
// Initialize
|
||||
init() {
|
||||
this.gameTime = 0;
|
||||
this.gameSpeed = 1;
|
||||
this.mining = { active: false, x: 0, y: 0, progress: 0 };
|
||||
},
|
||||
|
||||
// Main update function
|
||||
update(dt) {
|
||||
dt *= this.gameSpeed;
|
||||
this.gameTime += dt;
|
||||
|
||||
this.updateManualMining(dt);
|
||||
this.updateMiners(dt);
|
||||
this.updateFurnaces(dt);
|
||||
this.updateAssemblers(dt);
|
||||
this.updateInserters(dt);
|
||||
this.updateBelts(dt);
|
||||
this.updateChests(dt);
|
||||
},
|
||||
|
||||
// Manual mining update
|
||||
updateManualMining(dt) {
|
||||
if (!this.mining.active) return;
|
||||
|
||||
const tile = Terrain.getTile(this.mining.x, this.mining.y);
|
||||
if (!tile || !tile.resource || tile.amount <= 0) {
|
||||
this.mining.active = false;
|
||||
this.mining.progress = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.mining.progress += dt / CONFIG.MANUAL_MINE_RATE;
|
||||
|
||||
// Play mine sound periodically
|
||||
this.mining.soundTimer = (this.mining.soundTimer || 0) + dt;
|
||||
if (this.mining.soundTimer > 0.3) {
|
||||
this.mining.soundTimer = 0;
|
||||
Audio.playMine();
|
||||
}
|
||||
|
||||
if (this.mining.progress >= 1) {
|
||||
this.mining.progress = 0;
|
||||
const result = Terrain.mine(this.mining.x, this.mining.y, CONFIG.MANUAL_MINE_AMOUNT);
|
||||
if (result) {
|
||||
Resources.add(result.type, result.amount);
|
||||
Audio.playMineComplete();
|
||||
}
|
||||
|
||||
// Check if resource depleted
|
||||
if (!Terrain.hasResource(this.mining.x, this.mining.y)) {
|
||||
this.mining.active = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Start manual mining at position
|
||||
startMining(x, y) {
|
||||
if (Terrain.hasResource(x, y) && !Buildings.getAt(x, y)) {
|
||||
this.mining.active = true;
|
||||
this.mining.x = x;
|
||||
this.mining.y = y;
|
||||
this.mining.progress = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// Stop manual mining
|
||||
stopMining() {
|
||||
this.mining.active = false;
|
||||
this.mining.progress = 0;
|
||||
},
|
||||
|
||||
// Update miners
|
||||
updateMiners(dt) {
|
||||
Buildings.getByType('miner').forEach(miner => {
|
||||
const size = Utils.getBuildingSize('miner');
|
||||
let resourceType = null;
|
||||
let hasResource = false;
|
||||
|
||||
// Find resource under miner
|
||||
for (let dy = 0; dy < size.h && !hasResource; dy++) {
|
||||
for (let dx = 0; dx < size.w && !hasResource; dx++) {
|
||||
const tile = Terrain.getTile(miner.x + dx, miner.y + dy);
|
||||
if (tile?.resource && tile.amount > 0) {
|
||||
resourceType = tile.resource;
|
||||
hasResource = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasResource && resourceType) {
|
||||
miner.progress += dt * CONFIG.SPEEDS.miner;
|
||||
if (miner.progress >= 1) {
|
||||
miner.progress = 0;
|
||||
Buildings.addToOutput(miner, resourceType);
|
||||
|
||||
// Deplete resource
|
||||
for (let dy = 0; dy < size.h; dy++) {
|
||||
for (let dx = 0; dx < size.w; dx++) {
|
||||
const result = Terrain.mine(miner.x + dx, miner.y + dy, 1);
|
||||
if (result) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Update furnaces
|
||||
updateFurnaces(dt) {
|
||||
Buildings.getByType('furnace').forEach(furnace => {
|
||||
const hasCoal = Buildings.getInventoryCount(furnace, 'coal') > 0;
|
||||
const hasIron = Buildings.getInventoryCount(furnace, 'iron') > 0;
|
||||
const hasCopper = Buildings.getInventoryCount(furnace, 'copper') > 0;
|
||||
|
||||
if (hasCoal && (hasIron || hasCopper)) {
|
||||
furnace.progress += dt * CONFIG.SPEEDS.furnace;
|
||||
if (furnace.progress >= 1) {
|
||||
furnace.progress = 0;
|
||||
Buildings.removeFromInventory(furnace, 'coal');
|
||||
|
||||
if (hasIron) {
|
||||
Buildings.removeFromInventory(furnace, 'iron');
|
||||
Buildings.addToOutput(furnace, 'iron-plate');
|
||||
} else if (hasCopper) {
|
||||
Buildings.removeFromInventory(furnace, 'copper');
|
||||
Buildings.addToOutput(furnace, 'copper-plate');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Update assemblers
|
||||
updateAssemblers(dt) {
|
||||
Buildings.getByType('assembler').forEach(asm => {
|
||||
if (!asm.recipe) return;
|
||||
|
||||
const recipe = CONFIG.RECIPES[asm.recipe];
|
||||
if (!recipe) return;
|
||||
|
||||
// Check if can craft
|
||||
let canCraft = true;
|
||||
for (const [item, amount] of Object.entries(recipe.inputs)) {
|
||||
if (Buildings.getInventoryCount(asm, item) < amount) {
|
||||
canCraft = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canCraft) {
|
||||
asm.progress += dt * CONFIG.SPEEDS.assembler;
|
||||
if (asm.progress >= 1) {
|
||||
asm.progress = 0;
|
||||
|
||||
// Consume inputs
|
||||
for (const [item, amount] of Object.entries(recipe.inputs)) {
|
||||
Buildings.removeFromInventory(asm, item, amount);
|
||||
}
|
||||
|
||||
// Produce output
|
||||
Buildings.addToOutput(asm, recipe.output, recipe.outputCount);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Update inserters
|
||||
updateInserters(dt) {
|
||||
Buildings.getByType('inserter').forEach(ins => {
|
||||
const dir = CONFIG.DIR[ins.rotation];
|
||||
const pickupX = ins.x - dir.x;
|
||||
const pickupY = ins.y - dir.y;
|
||||
const dropX = ins.x + dir.x;
|
||||
const dropY = ins.y + dir.y;
|
||||
|
||||
const source = Buildings.getAt(pickupX, pickupY);
|
||||
const dest = Buildings.getAt(dropX, dropY);
|
||||
|
||||
if (!source) return;
|
||||
|
||||
// Find item to transfer from source output
|
||||
for (const [item, count] of Object.entries(source.output || {})) {
|
||||
if (count > 0) {
|
||||
ins.progress += dt * CONFIG.SPEEDS.inserter;
|
||||
if (ins.progress >= 1) {
|
||||
ins.progress = 0;
|
||||
Buildings.removeFromOutput(source, item);
|
||||
|
||||
if (dest) {
|
||||
// Drop into building
|
||||
Buildings.addToInventory(dest, item);
|
||||
} else if (source.type === 'chest') {
|
||||
// Only chests can output to player inventory
|
||||
Resources.add(item, 1);
|
||||
}
|
||||
// If no dest and not chest, item is lost
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Update belts
|
||||
updateBelts(dt) {
|
||||
Buildings.getByType('belt').forEach(belt => {
|
||||
const dir = CONFIG.DIR[belt.rotation];
|
||||
const nextX = belt.x + dir.x;
|
||||
const nextY = belt.y + dir.y;
|
||||
const nextBuilding = Buildings.getAt(nextX, nextY);
|
||||
|
||||
// Move items from output to next building
|
||||
for (const [item, count] of Object.entries(belt.output || {})) {
|
||||
if (count > 0 && nextBuilding) {
|
||||
Buildings.removeFromOutput(belt, item);
|
||||
Buildings.addToInventory(nextBuilding, item);
|
||||
}
|
||||
}
|
||||
|
||||
// Move items through belt (inventory -> output)
|
||||
belt.progress = (belt.progress || 0) + dt * CONFIG.SPEEDS.belt;
|
||||
if (belt.progress >= 1) {
|
||||
belt.progress = 0;
|
||||
for (const [item, count] of Object.entries(belt.inventory || {})) {
|
||||
if (count > 0) {
|
||||
Buildings.removeFromInventory(belt, item);
|
||||
Buildings.addToOutput(belt, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Update chests (move inventory to output for inserters)
|
||||
updateChests(dt) {
|
||||
Buildings.getByType('chest').forEach(chest => {
|
||||
for (const [item, count] of Object.entries(chest.inventory)) {
|
||||
if (count > 0) {
|
||||
chest.output[item] = (chest.output[item] || 0) + count;
|
||||
chest.inventory[item] = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Set game speed
|
||||
setSpeed(speed) {
|
||||
this.gameSpeed = speed;
|
||||
},
|
||||
|
||||
// Get state for saving
|
||||
getData() {
|
||||
return {
|
||||
gameTime: this.gameTime
|
||||
};
|
||||
},
|
||||
|
||||
// Load state
|
||||
setData(data) {
|
||||
this.gameTime = data.gameTime || 0;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user