Compare commits
No commits in common. "80867d6ccf171d7a8044bc3079c327eb6c8f6781" and "b564520d569a56bf113ad9f5da3f2d5ad81f6ee5" have entirely different histories.
80867d6ccf
...
b564520d56
@ -1,11 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
import Resources from "./hud/Resources.svelte";
|
|
||||||
import moves from "./moves";
|
import moves from "./moves";
|
||||||
import update from "./update";
|
import update from "./update";
|
||||||
import village from "./village";
|
import village from "./village";
|
||||||
import BuildingCreator from "./hud/BuildingCreator.svelte";
|
|
||||||
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -26,24 +24,22 @@
|
|||||||
function upgradeBuilding(id: number) {
|
function upgradeBuilding(id: number) {
|
||||||
moves.upgradeBuilding(id);
|
moves.upgradeBuilding(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let showBuildingCreator = false;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{ #if showBuildingCreator }
|
|
||||||
<BuildingCreator close={ () => { showBuildingCreator = false } } />
|
|
||||||
{ /if }
|
|
||||||
<main>
|
<main>
|
||||||
<header>
|
|
||||||
<Resources />
|
|
||||||
</header>
|
|
||||||
<div>
|
<div>
|
||||||
<button on:click={ () => { showBuildingCreator = true } }>Create building</button>
|
<ul>
|
||||||
|
<li>Wood: { Math.floor($village.resources.wood) }</li>
|
||||||
|
<li>Stone: { Math.floor($village.resources.stone) }</li>
|
||||||
|
<li>Iron: { Math.floor($village.resources.iron) }</li>
|
||||||
|
<li>Food: { Math.floor($village.resources.food) }</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="buildings">
|
<div class="buildings">
|
||||||
{ #each $village.buildings as building }
|
{ #each $village.buildings as building }
|
||||||
<div>
|
<div>
|
||||||
<p>{ building.name } ({ building.level })</p>
|
<p>{ building.name }</p>
|
||||||
|
<p>Level: { building.level }</p>
|
||||||
<p>
|
<p>
|
||||||
<button on:click={ () => upgradeBuilding(building.id) }>
|
<button on:click={ () => upgradeBuilding(building.id) }>
|
||||||
Upgrade
|
Upgrade
|
||||||
@ -56,8 +52,7 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.buildings {
|
.buildings {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -24,6 +24,9 @@ a:hover {
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
min-width: 320px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { Building } from "./types";
|
|
||||||
import { getEmptyResources } from "./utils";
|
|
||||||
import type { VillageState } from "./village";
|
import type { VillageState } from "./village";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'woodcutter': {
|
'woodcutter': {
|
||||||
name: 'Woodcutter',
|
name: 'Woodcutter',
|
||||||
|
level: 1,
|
||||||
cost: (level: number) => {
|
cost: (level: number) => {
|
||||||
return {
|
return {
|
||||||
wood: level * 10,
|
wood: level * 10,
|
||||||
@ -15,16 +14,16 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
behavior: {
|
behavior: {
|
||||||
production: (V: VillageState, self: Building) => {
|
production: (V: VillageState, self: any, delta: number) => {
|
||||||
const prod = getEmptyResources();
|
|
||||||
const outputPerMinute = 5 * (self.level * self.level);
|
const outputPerMinute = 5 * (self.level * self.level);
|
||||||
prod.wood = outputPerMinute;
|
const outputPerMilisecond = outputPerMinute / 60.0 / 1000.0;
|
||||||
return prod;
|
V.resources.wood += outputPerMilisecond * delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'mine': {
|
'mine': {
|
||||||
name: 'Mine',
|
name: 'Mine',
|
||||||
|
level: 1,
|
||||||
cost: (level: number) => {
|
cost: (level: number) => {
|
||||||
return {
|
return {
|
||||||
wood: level * 10,
|
wood: level * 10,
|
||||||
@ -34,16 +33,16 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
behavior: {
|
behavior: {
|
||||||
production: (V: VillageState, self: Building) => {
|
production: (V: VillageState, self: any, delta: number) => {
|
||||||
const prod = getEmptyResources();
|
|
||||||
const outputPerMinute = 5 * (self.level * self.level);
|
const outputPerMinute = 5 * (self.level * self.level);
|
||||||
prod.iron = outputPerMinute;
|
const outputPerMilisecond = outputPerMinute / 60.0 / 1000.0;
|
||||||
return prod;
|
V.resources.iron += outputPerMilisecond * delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'pit': {
|
'pit': {
|
||||||
name: 'Pit',
|
name: 'Pit',
|
||||||
|
level: 1,
|
||||||
cost: (level: number) => {
|
cost: (level: number) => {
|
||||||
return {
|
return {
|
||||||
wood: level * 10,
|
wood: level * 10,
|
||||||
@ -53,58 +52,11 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
behavior: {
|
behavior: {
|
||||||
production: (V: VillageState, self: Building) => {
|
production: (V: VillageState, self: any, delta: number) => {
|
||||||
const prod = getEmptyResources();
|
|
||||||
const outputPerMinute = 5 * (self.level * self.level);
|
const outputPerMinute = 5 * (self.level * self.level);
|
||||||
prod.stone = outputPerMinute;
|
const outputPerMilisecond = outputPerMinute / 60.0 / 1000.0;
|
||||||
return prod;
|
V.resources.stone += outputPerMilisecond * delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'warehouse': {
|
|
||||||
name: 'Warehouse',
|
|
||||||
cost: (level: number) => {
|
|
||||||
return {
|
|
||||||
wood: level * 10,
|
|
||||||
stone: level * 10,
|
|
||||||
iron: level * 10,
|
|
||||||
food: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
behavior: {
|
|
||||||
storage: (V: VillageState, self: Building) => {
|
|
||||||
const x = self.level;
|
|
||||||
const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 25;
|
|
||||||
return {
|
|
||||||
'wood': capacity,
|
|
||||||
'stone': capacity,
|
|
||||||
'iron': capacity,
|
|
||||||
'food': 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'granary': {
|
|
||||||
name: 'Granary',
|
|
||||||
cost: (level: number) => {
|
|
||||||
return {
|
|
||||||
wood: level * 10,
|
|
||||||
stone: level * 10,
|
|
||||||
iron: level * 10,
|
|
||||||
food: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
behavior: {
|
|
||||||
storage: (V: VillageState, self: Building) => {
|
|
||||||
const x = self.level;
|
|
||||||
const capacity = ( ( ( x + ( x * x ) ) / 2 ) + 3 ) * 25;
|
|
||||||
return {
|
|
||||||
'wood': 0,
|
|
||||||
'stone': 0,
|
|
||||||
'iron': 0,
|
|
||||||
'food': capacity,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import buildings from "../buildings";
|
|
||||||
import moves from "../moves";
|
|
||||||
|
|
||||||
export let close: () => void;
|
|
||||||
|
|
||||||
|
|
||||||
function build(type: string) {
|
|
||||||
if (moves.createBuilding(type)) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<div class="building-creator">
|
|
||||||
<header>
|
|
||||||
<h1>Build</h1>
|
|
||||||
<span class="close">
|
|
||||||
<button on:click={ close }>X</button>
|
|
||||||
</span>
|
|
||||||
</header>
|
|
||||||
<div class="buildings">
|
|
||||||
{ #each Object.entries(buildings) as [type, building] }
|
|
||||||
<div>
|
|
||||||
<p>{ building.name }</p>
|
|
||||||
<button on:click={ () => build(type) }>Build</button>
|
|
||||||
</div>
|
|
||||||
{ /each }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
section {
|
|
||||||
background-color: hsl(0, 0%, 10%, 0.8);
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.building-creator {
|
|
||||||
background-color: hsl(0, 0%, 20%);
|
|
||||||
border: 0.2em solid grey;
|
|
||||||
border-radius: .4em;
|
|
||||||
width: 80%;
|
|
||||||
height: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.building-creator header {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.building-creator header .close {
|
|
||||||
position: absolute;
|
|
||||||
right: 1em;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.building-creator .buildings {
|
|
||||||
display: grid;
|
|
||||||
gap: 1em;
|
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,21 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { getStorage } from "../utils";
|
|
||||||
import village from "../village";
|
|
||||||
|
|
||||||
|
|
||||||
$: capacity = getStorage($village);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="resources">
|
|
||||||
<div>Wood: { Math.floor($village.resources.wood) } / { capacity.wood }</div>
|
|
||||||
<div>Stone: { Math.floor($village.resources.stone) } / { capacity.stone }</div>
|
|
||||||
<div>Iron: { Math.floor($village.resources.iron) } / { capacity.iron }</div>
|
|
||||||
<div>Food: { Math.floor($village.resources.food) } / { capacity.food }</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.resources {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,34 +0,0 @@
|
|||||||
import buildings from "../buildings";
|
|
||||||
import type { VillageState } from "../village";
|
|
||||||
|
|
||||||
|
|
||||||
let uid = 0;
|
|
||||||
|
|
||||||
|
|
||||||
export default function createBuilding(V: VillageState, buildingType: keyof typeof buildings) {
|
|
||||||
const building = buildings[buildingType];
|
|
||||||
const cost = building.cost(1);
|
|
||||||
|
|
||||||
if (
|
|
||||||
cost.wood > V.resources.wood
|
|
||||||
|| cost.stone > V.resources.stone
|
|
||||||
|| cost.iron > V.resources.iron
|
|
||||||
|| cost.food > V.resources.food
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
V.resources.wood -= cost.wood;
|
|
||||||
V.resources.stone -= cost.stone;
|
|
||||||
V.resources.iron -= cost.iron;
|
|
||||||
V.resources.food -= cost.food;
|
|
||||||
|
|
||||||
const newBuilding = {
|
|
||||||
...building,
|
|
||||||
level: 1,
|
|
||||||
id: uid++,
|
|
||||||
};
|
|
||||||
V.buildings.push(newBuilding);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
|
|
||||||
import village, { type VillageState } from '../village';
|
import village, { type VillageState } from '../village';
|
||||||
import createBuilding from './createBuilding';
|
|
||||||
import upgradeBuilding from './upgradeBuilding';
|
import upgradeBuilding from './upgradeBuilding';
|
||||||
|
|
||||||
|
|
||||||
@ -17,8 +16,8 @@ export function makeMove(move: (...args: any[]) => boolean) {
|
|||||||
// That updates the game state.
|
// That updates the game state.
|
||||||
village.update(state => {
|
village.update(state => {
|
||||||
// With an immutable state.
|
// With an immutable state.
|
||||||
return produce(state, (V: VillageState) => {
|
return produce(state, (G: VillageState) => {
|
||||||
result = move(V, ...args);
|
result = move(G, ...args);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -28,6 +27,5 @@ export function makeMove(move: (...args: any[]) => boolean) {
|
|||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
createBuilding: makeMove(createBuilding),
|
|
||||||
upgradeBuilding: makeMove(upgradeBuilding),
|
upgradeBuilding: makeMove(upgradeBuilding),
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ export default function upgradeBuilding(V: VillageState, buildingId: number) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cost = building.cost(building.level + 1);
|
const cost = building.cost(building.level);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
cost.wood > V.resources.wood
|
cost.wood > V.resources.wood
|
||||||
|
@ -6,16 +6,12 @@ export interface Cost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type Production = Cost;
|
|
||||||
|
|
||||||
|
|
||||||
export interface BuildingSource {
|
export interface BuildingSource {
|
||||||
name: string;
|
name: string;
|
||||||
level: number;
|
level: number;
|
||||||
cost: (level: number) => Cost;
|
cost: (level: number) => Cost;
|
||||||
behavior: {
|
behavior: {
|
||||||
production?: Function;
|
production?: Function;
|
||||||
storage?: Function;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
|
|
||||||
import { getProduction, getStorage } from './utils';
|
|
||||||
import village, { type VillageState } from "./village";
|
import village, { type VillageState } from "./village";
|
||||||
import type { Production } from './types';
|
|
||||||
|
|
||||||
|
|
||||||
let lastFrame: number;
|
let lastFrame: number;
|
||||||
@ -18,20 +16,11 @@ export default function update(timestamp: number) {
|
|||||||
|
|
||||||
village.update(state => {
|
village.update(state => {
|
||||||
return produce(state, (V: VillageState) => {
|
return produce(state, (V: VillageState) => {
|
||||||
const productionPerMinute = getProduction(V);
|
V.buildings.forEach(b => {
|
||||||
const storage = getStorage(V);
|
if (b.behavior.production) {
|
||||||
|
b.behavior.production(V, b, delta);
|
||||||
Object.keys(productionPerMinute).forEach((key) => {
|
|
||||||
const resource = key as keyof Production;
|
|
||||||
const outputPerMinute = productionPerMinute[resource];
|
|
||||||
const outputPerMilisecond = outputPerMinute / 60.0 / 1000.0;
|
|
||||||
V.resources[resource] += outputPerMilisecond * delta;
|
|
||||||
|
|
||||||
if (V.resources[resource] > storage[resource]) {
|
|
||||||
V.resources[resource] = storage[resource];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return V;
|
return V;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
46
src/utils.ts
46
src/utils.ts
@ -1,46 +0,0 @@
|
|||||||
import type { Production } from "./types";
|
|
||||||
import type { VillageState } from "./village";
|
|
||||||
|
|
||||||
|
|
||||||
function _reduceResources(acc: Production, item: Production): Production {
|
|
||||||
return {
|
|
||||||
wood: acc.wood + item.wood,
|
|
||||||
stone: acc.stone + item.stone,
|
|
||||||
iron: acc.iron + item.iron,
|
|
||||||
food: acc.food + item.food,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function getEmptyResources(): Production {
|
|
||||||
return {
|
|
||||||
wood: 0,
|
|
||||||
stone: 0,
|
|
||||||
iron: 0,
|
|
||||||
food: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function getProduction(villageState: VillageState): Production {
|
|
||||||
return villageState.buildings
|
|
||||||
.filter(b => b.behavior.production)
|
|
||||||
.map(b => {
|
|
||||||
if (b.behavior.production) {
|
|
||||||
return b.behavior.production(villageState, b);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.reduce(_reduceResources, getEmptyResources());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function getStorage(villageState: VillageState): Production {
|
|
||||||
return villageState.buildings
|
|
||||||
.filter(b => b.behavior.storage)
|
|
||||||
.map(b => {
|
|
||||||
if (b.behavior.storage) {
|
|
||||||
return b.behavior.storage(villageState, b);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.reduce(_reduceResources, getEmptyResources());
|
|
||||||
}
|
|
@ -11,27 +11,25 @@ export interface VillageState {
|
|||||||
iron: number;
|
iron: number;
|
||||||
food: number;
|
food: number;
|
||||||
culture: number;
|
culture: number;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let uid = 0;
|
let uid = 0;
|
||||||
|
|
||||||
const village = writable<VillageState>({
|
const village = writable<VillageState>({
|
||||||
buildings: [
|
buildings: [
|
||||||
{ ...buildings.woodcutter, level: 1, id: uid++ },
|
{ ...buildings.woodcutter, id: uid++ },
|
||||||
{ ...buildings.woodcutter, level: 1, id: uid++ },
|
{ ...buildings.woodcutter, id: uid++ },
|
||||||
{ ...buildings.woodcutter, level: 1, id: uid++ },
|
{ ...buildings.woodcutter, id: uid++ },
|
||||||
{ ...buildings.woodcutter, level: 1, id: uid++ },
|
{ ...buildings.woodcutter, id: uid++ },
|
||||||
{ ...buildings.mine, level: 1, id: uid++ },
|
{ ...buildings.mine, id: uid++ },
|
||||||
{ ...buildings.mine, level: 1, id: uid++ },
|
{ ...buildings.mine, id: uid++ },
|
||||||
{ ...buildings.mine, level: 1, id: uid++ },
|
{ ...buildings.mine, id: uid++ },
|
||||||
{ ...buildings.mine, level: 1, id: uid++ },
|
{ ...buildings.mine, id: uid++ },
|
||||||
{ ...buildings.pit, level: 1, id: uid++ },
|
{ ...buildings.pit, id: uid++ },
|
||||||
{ ...buildings.pit, level: 1, id: uid++ },
|
{ ...buildings.pit, id: uid++ },
|
||||||
{ ...buildings.pit, level: 1, id: uid++ },
|
{ ...buildings.pit, id: uid++ },
|
||||||
{ ...buildings.pit, level: 1, id: uid++ },
|
{ ...buildings.pit, id: uid++ },
|
||||||
{ ...buildings.warehouse, level: 1, id: uid++ },
|
|
||||||
{ ...buildings.granary, level: 1, id: uid++ },
|
|
||||||
],
|
],
|
||||||
resources: {
|
resources: {
|
||||||
wood: 100,
|
wood: 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user