Commit 1b9504b2 authored by Matthew Odle's avatar Matthew Odle

add death mechanics

energy and warmth stats are in; if either reaches 0, the villager dies
clothing reduces the rate at which warmth decays
villagers consume firewood for warmth, food for energy
on death, a villager will be relieved of their current assignment
parent c29d67fe
......@@ -32,3 +32,13 @@ update:
* Added pretty colors to indicate production status
* Added sorting and priority adjustment; it's somewhat fragile: if there is no building with a priority 1 higher, the building will not move; this means if building a has priority 5 and building b has priority 10, nothing will happen when the up/down buttons are pushed. If there is any break in the sequence of priorities in the buildings array, reassignment of priority will not work. A better approach would be to find the next highest value.
* Fixed this by using filter and reduce
2017-11-03
* Visual changes
* Updated the css formatting
* Added villager components
* Used gradients to show durability of tools and progress of production
2017-11-05
* Implement warmth mechanic
* Have the villager consume firewood to increase warmth stat
......@@ -8,6 +8,9 @@
</head>
<body>
<h2>Generate resources to keep your villagers alive.</h2>
<div>Food provides energy.</div>
<div>Clothing provides warmth.</div>
<div>If energy or warmth drops to 0, the villager dies.</div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
......
......@@ -25,7 +25,7 @@ export class Village extends React.Component {
//----- push button functions -----//
getUnassignedVillagers = () => {
return this.props.villagers.slice().filter( villager => villager.assignment === 'none')
return this.props.villagers.slice().filter( villager => villager.assignment === 'IDLE')
}
updateTheBuildings = (building) => {
......@@ -58,7 +58,7 @@ export class Village extends React.Component {
}
const allVillagers = this.props.villagers.slice();
const selectedVillager = allVillagers.find( villager => villager.assignment === 'none' && amount > 0)
const selectedVillager = allVillagers.find( villager => villager.assignment === 'IDLE' && amount > 0)
selectedVillager.assignment = building.name;
building.assignedVillagers.push(selectedVillager);
......@@ -78,7 +78,7 @@ export class Village extends React.Component {
}
const removedVillager = building.assignedVillagers.pop();
removedVillager.assignment = 'none';
removedVillager.assignment = 'IDLE';
this.updateTheBuildings(building);
this.updateTheVillagers(removedVillager);
......@@ -263,9 +263,105 @@ export class Village extends React.Component {
}
}
checkVillagerTool = (villagers) => {
checkVillagerTool = (villager) => {
// only equip tools to villagers that are assigned to a building
villagers.map( villager => villager.toolDurability <= 0 && villager.assignment !== "none" ? villager = this.getTool(villager) : null);
// eslint-disable-next-line
villager.toolDurability <= 0 && villager.assignment !== "IDLE" ? villager = this.getTool(villager) : null;
}
getWarm = (villager) => {
const villageStore = this.state.villageStore.slice();
let firewood = villageStore.find( material => material.name === 'firewood')
if (firewood.count > 0) {
villager.warmth += this.props.knobsAndLevers.warmthPerFirewood;
firewood.count -= 1;
}
}
consumeFirewoodIfNeeded = (villager) => {
const warmthReplenishThreshold = this.props.knobsAndLevers.warmthReplenishThreshold;
if (villager.warmth >= warmthReplenishThreshold) {
return;
}
this.getWarm(villager);
}
checkVillagerWarmth = (villager) => {
const baseWarmthDecayRate = this.props.knobsAndLevers.baseWarmthDecayRate;
const clothingWarmthDecayReduction = this.props.knobsAndLevers.clothingWarmthDecayReduction;
villager.warmth -= villager.clothed ? Math.ceil(baseWarmthDecayRate / clothingWarmthDecayReduction) : baseWarmthDecayRate;
// eslint-disable-next-line
villager.warmth < 0 ? villager.warmth = 0 : null;
this.consumeFirewoodIfNeeded(villager);
}
getClothing = (villager) => {
const villageStore = this.state.villageStore.slice();
let clothing = villageStore.find( material => material.name === 'clothing')
if (clothing.count > 0) {
villager.clothingDurability = 100;
villager.clothed = true;
clothing.count -= 1;
}
}
manageVillagerClothing = (villager) => {
// eslint-disable-next-line
villager.clothingDurability > 0 ? villager.clothingDurability -= this.props.knobsAndLevers.clothingDegradeRate : null;
// eslint-disable-next-line
villager.clothingDurability <= 0 ? villager = this.getClothing(villager) : null;
}
getFood = (villager) => {
const villageStore = this.state.villageStore.slice();
let food = villageStore.find( material => material.name === 'food')
if (food.count > 0) {
villager.energy += this.props.knobsAndLevers.energyPerFood;
food.count -= 1;
}
}
consumeFoodIfNeeded = (villager) => {
const energyReplenishThreshold = this.props.knobsAndLevers.energyReplenishThreshold;
if (villager.energy >= energyReplenishThreshold) {
return;
}
this.getFood(villager);
}
checkVillagerEnergy = (villager) => {
const baseEnergyDegradeRate = this.props.knobsAndLevers.baseEnergyDegradeRate;
const assignmentEnergyMultiplier = this.props.knobsAndLevers.assignmentEnergyMultiplier;
const multiplier = villager.assignment !== "IDLE" ? assignmentEnergyMultiplier : 1;
villager.energy -= baseEnergyDegradeRate * multiplier;
// eslint-disable-next-line
villager.energy < 0 ? villager.energy = 0 : null;
this.consumeFoodIfNeeded(villager);
}
removeVillager = (villager) => {
const buildings = this.state.buildings.slice();
const targetBuilding = buildings.find( building => villager.assignment === building.name );
const villagerIndex = targetBuilding.assignedVillagers.findIndex(assignedVillager => assignedVillager.id === villager.id);
targetBuilding.assignedVillagers = [
...targetBuilding.assignedVillagers.slice(0, villagerIndex),
...targetBuilding.assignedVillagers.slice(villagerIndex + 1),
]
this.updateTheBuildings(targetBuilding);
}
killVillager = (villager) => {
// eslint-disable-next-line
villager.assignment !== "IDLE" ? this.removeVillager(villager) : null;
villager.assignment = "DEAD";
}
bringOutYourDead = (villager) => {
let timeToDie = false;
villager.assignment !== "DEAD" && (villager.energy <= 0 || villager.warmth <= 0) ? timeToDie = true : timeToDie = false;
// eslint-disable-next-line
timeToDie ? this.killVillager(villager) : null;
}
updateAllVillagers = (villagers) => {
......@@ -276,7 +372,14 @@ export class Village extends React.Component {
manageVillagerConditions = () => {
const villagers = this.state.villagers.slice();
this.checkVillagerTool(villagers);
// eslint-disable-next-line
villagers.map( villager => {
this.checkVillagerTool(villager);
this.checkVillagerWarmth(villager);
this.manageVillagerClothing(villager);
this.checkVillagerEnergy(villager);
this.bringOutYourDead(villager);
});
this.updateAllVillagers(villagers);
}
......@@ -304,7 +407,8 @@ export class Village extends React.Component {
const villagers = this.props.villagers.slice();
return (
<div className="village">
<span>Elapsed: { Math.floor(this.state.elapsed / 1000) }</span>
<span>Elapsed: { Math.floor(this.state.elapsed / 1000) }</span>
{/* <button type="button" id="restart" onClick={() => this.props.restart()}>Restart</button> */}
<h3>Stock</h3>
<div className="stock">
{ villageStore.map( item =>
......
......@@ -4,14 +4,32 @@ export class Villager extends React.Component {
render(props) {
var villager = this.props.villager;
var durabilityStyle = {
var toolDegradeStyle = {
background: 'linear-gradient(to right, aquamarine 0%, aquamarine ' + villager.toolDurability + '%, bisque ' + villager.toolDurability + '%, bisque 100%)'
};
var clothingDegradeStyle = {
background: 'linear-gradient(to right, aquamarine 0%, aquamarine ' + villager.clothingDurability + '%, bisque ' + villager.clothingDurability + '%, bisque 100%)'
};
var warmthDegradeStyle = {
background: 'linear-gradient(to right, aquamarine 0%, aquamarine ' + villager.warmth + '%, bisque ' + villager.warmth + '%, bisque 100%)'
};
var energyDegradeStyle = {
background: 'linear-gradient(to right, aquamarine 0%, aquamarine ' + villager.energy + '%, bisque ' + villager.energy + '%, bisque 100%)'
};
return <div className="villager">
<div className={villager.assignment !== "none" ? "active" : "inactive"}>
Villager {villager.id}{villager.assignment === "none" ? ": IDLE" : ": " + villager.assignment}
<div
className={
villager.assignment === "DEAD"
? "terminated"
: (villager.assignment === "IDLE" ? "inactive" : "active" )
}
>
Villager {villager.id}: {villager.assignment}
</div>
<div className={villager.toolDurability > 0 ? "active" : "inactive"} style={durabilityStyle}>Tool: {villager.toolDurability + "%"}</div>
<div style={toolDegradeStyle}>Tool: {villager.toolDurability}</div>
<div style={clothingDegradeStyle}>Clothing: {villager.clothingDurability}</div>
<div style={warmthDegradeStyle}>Warmth: {villager.warmth}</div>
<div style={energyDegradeStyle}>Energy: {villager.energy}</div>
</div>
}
}
......@@ -49,6 +49,9 @@ button {
background-color: bisque;
}
.terminated {
background-color: tomato;
}
.building {
width: 200px;
margin-right: none;
......
......@@ -6,98 +6,184 @@ import './index.css';
import { Village } from './components/village';
const knobsAndLevers = {
unassignedVillagers: 5,
interval: 1000,
elapsed: 0,
unassignedVillagers: 6,
villagerHasTool: true,
toolMultiplier: 4,
toolDurability: 100,
toolDegradeRate: 1,
interval: 1000,
productionComplete: 100,
defaultCapacity: 50,
defaultProductionRate: 1,
elapsed: 0,
villagerClothed: true,
clothingDegradeRate: 1,
clothingWarmthDecayReduction: 5,
baseWarmthDecayRate: 10,
warmthReplenishThreshold: 10,
warmthPerFirewood: 80,
baseEnergyDegradeRate: 1,
assignmentEnergyMultiplier: 2,
energyReplenishThreshold: 10,
energyPerFood: 80,
defaultToolStores: 20,
defaultFirewoodStores: 20,
defaultFoodStores: 20,
defaultClothingStores: 0,
defaultLeatherStores: 0,
defaultIronStores: 0,
defaultWoodStores: 0,
}
const villageStore = [
{name: 'wood', count: 0, source: 'FORESTER_HUT'},
{name: 'tool', count: 5, source: 'SMITHY'},
{name: 'iron', count: 0, source: 'MINE'},
{name: 'firewood', count: 0, source: 'WOODCUTTER_HUT'},
{name: 'wood', count: knobsAndLevers.defaultWoodStores, source: 'FORESTER_HUT'},
{name: 'tool', count: knobsAndLevers.defaultToolStores, source: 'SMITHY'},
{name: 'iron', count: knobsAndLevers.defaultIronStores, source: 'MINE'},
{name: 'firewood', count: knobsAndLevers.defaultFirewoodStores, source: 'WOODCUTTER_HUT'},
{name: 'food', count: knobsAndLevers.defaultFoodStores, source: 'GATHERER_HUT, HUNTER_LODGE'},
{name: 'leather', count: knobsAndLevers.defaultLeatherStores, source: 'HUNTER_LODGE'},
{name: 'clothing', count: knobsAndLevers.defaultClothingStores, source: 'TAILOR'},
];
const villagers = []
const addVillager = () => {
let nextId = villagers.length > 0 ? Math.max(...villagers.map(v => v.id)) + 1 : 0;
const villager = {"id": nextId, "hasTool": knobsAndLevers.villagerHasTool, "toolDurability": knobsAndLevers.toolDurability, "assignment": "none"};
const villager = {
id: nextId,
hasTool: knobsAndLevers.villagerHasTool,
toolDurability: knobsAndLevers.toolDurability,
assignment: "IDLE",
warmth: 100,
energy: 100,
clothed: knobsAndLevers.villagerClothed,
clothingDurability: 100,
// clothed: nextId % 2 === 0 ? knobsAndLevers.villagerClothed : false,
// clothingDurability: nextId % 2 === 0 ? 100 : 0,
};
villagers.push(villager);
if (villagers.length < knobsAndLevers['unassignedVillagers']) {
addVillager();
}
}
const restart = () => {
init();
}
let villagers = []
let buildings = []
const init = () => {
villagers = []
buildings = []
addVillager();
generateBuildings();
}
const buildings = []
buildings.push({type: 'production',
id: 1,
name: 'SMITHY',
label: 'Smithy',
description: 'workers are more efficient with the right tools',
priority: 8,
materials: ['wood', 'iron'],
goods: ['tool'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 2,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 2,
name: 'FORESTER_HUT',
label: "Forester's Hut",
description: "it's big, it's heavy, it's wood",
priority: 0,
goods: ['wood'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 3,
name: 'MINE',
label: "Mine",
description: "the strength of the earth to forge the tools",
priority: 1,
goods: ['iron'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'production',
id: 4,
name: 'WOODCUTTER',
label: 'Woodcutter',
description: "it's big, it's heavy, it's wood",
priority: 3,
materials: ['wood'],
goods: ['firewood'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
const generateBuildings = () => {
buildings.push({type: 'production',
id: 100,
priority: 100,
name: 'SMITHY',
label: 'Smithy',
description: 'workers are more efficient with the right tools',
materials: ['wood', 'iron'],
goods: ['tool'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 10,
priority: 10,
name: 'FORESTER_HUT',
label: "Forester's Hut",
description: "it's big, it's heavy, it's wood",
goods: ['wood'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 20,
priority: 20,
name: 'GATHERER_HUT',
label: "Gatherer's Hut",
description: "nuts, berries, and tubers are packed with nutrients",
goods: ['food'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 30,
priority: 30,
name: 'HUNTER_LODGE',
label: "Hunter's Lodge",
description: "take advantage of nature's bounty",
goods: ['food', 'leather'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'extraction',
id: 40,
priority: 40,
name: 'MINE',
label: "Mine",
description: "the strength of the earth to forge the tools",
goods: ['iron'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'production',
id: 110,
priority: 110,
name: 'WOODCUTTER',
label: 'Woodcutter',
description: "it's big, it's heavy, it's wood",
materials: ['wood'],
goods: ['firewood'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
buildings.push({type: 'production',
id: 120,
priority: 120,
name: 'TAILOR',
label: 'Tailor',
description: "clothing to keep warm",
materials: ['leather'],
goods: ['clothing'],
assignedVillagers: [],
capacity: knobsAndLevers.defaultCapacity,
progress: 0,
baseProductionRate: knobsAndLevers.defaultProductionRate,
producing: false
});
init();
ReactDOM.render(
<Village buildings={buildings} villageStore={villageStore} villagers={villagers} knobsAndLevers={knobsAndLevers} start={Date.now()} restart={restart}/>,
document.getElementById('root')
);
}
ReactDOM.render(
<Village buildings={buildings} villageStore={villageStore} villagers={villagers} knobsAndLevers={knobsAndLevers} start={Date.now()} />,
document.getElementById('root')
);
init();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment