Show a map of the outside of the village, with all the resource farms.

This commit is contained in:
Adrian 2024-10-24 16:24:39 +02:00
parent a47486973c
commit 756f2bc152
12 changed files with 145 additions and 31 deletions

View File

@ -5,3 +5,4 @@
</script>
<p>{ building.name }</p>
<p>{ building.level }</p>

48
src/board/Outside.svelte Normal file
View File

@ -0,0 +1,48 @@
<script lang="ts">
import gameTab from "../stores/gameTab";
import showBuildingPanel from "../stores/showBuildingPanel";
import { getBuilding, getKeysAsNumbers } from "../utils";
import village, { VILLAGE_TILE } from "../village";
import BuildingTile from "./BuildingTile.svelte";
import Tile from "./Tile.svelte";
function openBuildingPanel(buildingId: number) {
showBuildingPanel.set(buildingId);
}
</script>
<section class="outside-map">
<div>
{ #each getKeysAsNumbers($village.outsideTiles) as y }
<div>
{ #each getKeysAsNumbers($village.outsideTiles[y]) as x }
{ #if $village.outsideTiles[y][x] >= 0 }
<Tile
onTileClick={ () => openBuildingPanel($village.outsideTiles[y][x]) }
>
<BuildingTile building={ getBuilding($village, $village.outsideTiles[y][x]) } />
</Tile>
{ :else if $village.outsideTiles[y][x] === VILLAGE_TILE }
<Tile
onTileClick={ () => gameTab.set('village') }
/>
{ /if }
{ /each }
</div>
{ /each }
</div>
</section>
<style>
.outside-map {
display: grid;
height: 100%;
margin-top: 0.8em;
position: relative;
}
.outside-map > div {
margin: auto;
}
</style>

View File

@ -1,6 +1,5 @@
<script lang="ts">
import { Hex } from "../hexgrid";
import moves from "../moves";
import showBuildingCreator from "../stores/showBuildingCreator";
import showBuildingPanel from "../stores/showBuildingPanel";
import { getBuilding, getKeysAsNumbers } from "../utils";
@ -9,10 +8,6 @@
import Tile from "./Tile.svelte";
function upgradeBuilding(id: number) {
moves.upgradeBuilding(id);
}
function openBuildingCreator(tile: Hex) {
showBuildingCreator.set(tile);
}
@ -48,6 +43,7 @@
.village-map {
display: grid;
height: 100%;
margin-top: 0.8em;
position: relative;
}

View File

@ -1,11 +1,13 @@
import type { Building } from "./types";
import type { Building, BuildingSource } from "./types";
import { getEmptyResources } from "./utils";
import type { VillageState } from "./village";
export default {
'townhall': {
const buildings = [
{
type: 'townhall',
name: 'Town Hall',
autoBuilt: true,
cost: (level: number) => {
return {
wood: level * 10,
@ -25,8 +27,10 @@ export default {
},
},
},
'woodcutter': {
{
type: 'woodcutter',
name: 'Woodcutter',
autoBuilt: true,
cost: (level: number) => {
return {
wood: level * 10,
@ -48,8 +52,10 @@ export default {
},
},
},
'mine': {
{
type: 'mine',
name: 'Mine',
autoBuilt: true,
cost: (level: number) => {
return {
wood: level * 10,
@ -71,8 +77,10 @@ export default {
},
},
},
'pit': {
{
type: 'pit',
name: 'Pit',
autoBuilt: true,
cost: (level: number) => {
return {
wood: level * 10,
@ -94,8 +102,10 @@ export default {
},
},
},
'field': {
{
type: 'field',
name: 'Field',
autoBuilt: true,
cost: (level: number) => {
return {
wood: level * 10,
@ -113,7 +123,8 @@ export default {
},
},
},
'warehouse': {
{
type: 'warehouse',
name: 'Warehouse',
cost: (level: number) => {
return {
@ -136,7 +147,8 @@ export default {
},
},
},
'granary': {
{
type: 'granary',
name: 'Granary',
cost: (level: number) => {
return {
@ -159,4 +171,5 @@ export default {
},
},
},
};
];
export default buildings;

View File

@ -1,3 +1,4 @@
import buildings from "./buildings";
import { Hex } from "./hexgrid";
import type { Building, BuildingSource } from "./types";
@ -5,9 +6,22 @@ import type { Building, BuildingSource } from "./types";
let uid = 0;
export function createBuilding(building: BuildingSource): Building {
export function getBuildingSource(buildingType: string): BuildingSource {
const source: BuildingSource | undefined = buildings.find(b => b.type === buildingType);
if (source === undefined) {
throw new Error(`Unknown building type: "${buildingType}"`);
}
return source
}
export function createBuilding(buildingType: string): Building {
const source: BuildingSource = getBuildingSource(buildingType);
return {
...building,
...source,
id: uid++,
level: 1,
tile: new Hex(0, 0),

View File

@ -17,6 +17,8 @@
close();
}
}
const constructible = buildings.filter(b => !b.autoBuilt);
</script>
{ #if $showBuildingCreator !== null }
@ -29,10 +31,10 @@
</span>
</header>
<div class="buildings">
{ #each Object.entries(buildings) as [type, building] }
{ #each constructible as building }
<div>
<p>{ building.name }</p>
<button on:click={ () => build(type) }>Build</button>
<button on:click={ () => build(building.type) }>Build</button>
</div>
{ /each }
</div>

View File

@ -6,6 +6,10 @@
import BuildingCreator from "./BuildingCreator.svelte";
import Resources from "./Resources.svelte";
import BuildingPanel from "./BuildingPanel.svelte";
import Outside from "../board/Outside.svelte";
import Navigation from "./Navigation.svelte";
import type { GameTab } from "../types";
import gameTab from "../stores/gameTab";
onMount(() => {
@ -21,14 +25,23 @@
cancelAnimationFrame(frame);
}
});
function setTab(newTab: GameTab) {
gameTab.set(newTab);
}
</script>
<section class="hud">
<header>
<Resources />
<Navigation { setTab } />
</header>
<div class="buildings">
<div class="">
{ #if $gameTab === 'village' }
<Village />
{ :else if $gameTab === 'resources' }
<Outside />
{ /if }
</div>
</section>
<section class="overlay">
@ -37,10 +50,6 @@
</section>
<style>
.buildings {
margin-top: 2em;
}
.overlay {
left: 0;
position: absolute;

20
src/hud/Navigation.svelte Normal file
View File

@ -0,0 +1,20 @@
<script lang="ts">
import type { GameTab } from "../types";
export let setTab: (tab: GameTab) => void;
</script>
<nav>
<button
class="invisible"
on:click={ () => setTab('village') }
>
Village
</button>
<button
class="invisible"
on:click={ () => setTab('resources') }
>
Resources
</button>
</nav>

View File

@ -1,11 +1,11 @@
import buildings from "../buildings";
import { createBuilding } from "../create";
import { createBuilding, getBuildingSource } from "../create";
import type { Hex } from "../hexgrid";
import { DEFAULT_TILE, type VillageState } from "../village";
export default function build(V: VillageState, buildingType: keyof typeof buildings, tile: Hex) {
const building = buildings[buildingType];
export default function build(V: VillageState, buildingType: string, tile: Hex) {
const building = getBuildingSource(buildingType);
const cost = building.cost(1);
if (
@ -26,7 +26,7 @@ export default function build(V: VillageState, buildingType: keyof typeof buildi
V.resources.iron -= cost.iron;
V.resources.food -= cost.food;
const newBuilding = createBuilding(building);
const newBuilding = createBuilding(buildingType);
newBuilding.tile = tile;
V.buildings.push(newBuilding);

5
src/stores/gameTab.ts Normal file
View File

@ -0,0 +1,5 @@
import { writable } from "svelte/store";
import type { GameTab } from "../types";
export default writable<GameTab>('village');

View File

@ -1,5 +1,9 @@
import type { Hex } from "./hexgrid";
export type GameTab = 'village' | 'resources';
export interface Cost {
wood: number;
stone: number;
@ -13,6 +17,8 @@ export type Production = Cost;
export interface BuildingSource {
name: string;
type: string;
autoBuilt?: boolean;
cost: (level: number) => Cost;
behavior: {
production?: Function;

View File

@ -81,12 +81,12 @@ function getInitialState() {
};
// Create the Town hall.
const townhall = createBuilding(buildings.townhall);
const townhall = createBuilding('townhall');
state.villageTiles[0][0] = townhall.id;
state.buildings.push(townhall);
// Create all the resource buildings.
const resourceBuildingTypes: Array<keyof typeof buildings> = shuffle([
const resourceBuildingTypes: Array<string> = shuffle([
'woodcutter', 'woodcutter', 'woodcutter', 'woodcutter',
'mine', 'mine', 'mine', 'mine',
'pit', 'pit', 'pit', 'pit',
@ -102,7 +102,7 @@ function getInitialState() {
if (type === undefined) {
throw new Error("Not enough building types for outside resource buildings");
}
const newBuilding = createBuilding(buildings[type]);
const newBuilding = createBuilding(type);
newBuilding.tile = new Hex(x, y);
state.outsideTiles[y][x] = newBuilding.id;
state.buildings.push(newBuilding);