diff --git a/src/app.css b/src/app.css
index b92576c..37629e7 100644
--- a/src/app.css
+++ b/src/app.css
@@ -37,9 +37,6 @@ h1 {
}
#app {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
text-align: center;
}
diff --git a/src/board/Outside.svelte b/src/board/Outside.svelte
index ec618df..ce43ecf 100644
--- a/src/board/Outside.svelte
+++ b/src/board/Outside.svelte
@@ -40,7 +40,6 @@
.outside-map {
display: grid;
height: 100%;
- margin-top: 0.8em;
position: relative;
}
diff --git a/src/board/Village.svelte b/src/board/Village.svelte
index b5bbba0..85b45af 100644
--- a/src/board/Village.svelte
+++ b/src/board/Village.svelte
@@ -43,7 +43,6 @@
.village-map {
display: grid;
height: 100%;
- margin-top: 0.8em;
position: relative;
}
diff --git a/src/board/Worldmap.svelte b/src/board/Worldmap.svelte
index 0c8d33d..ee9caec 100644
--- a/src/board/Worldmap.svelte
+++ b/src/board/Worldmap.svelte
@@ -17,7 +17,9 @@
diff --git a/src/hud/Resources.svelte b/src/hud/Resources.svelte
index f475c55..522c044 100644
--- a/src/hud/Resources.svelte
+++ b/src/hud/Resources.svelte
@@ -38,8 +38,8 @@
diff --git a/src/moves/index.ts b/src/moves/index.ts
index 25d916f..64ad62f 100644
--- a/src/moves/index.ts
+++ b/src/moves/index.ts
@@ -2,9 +2,10 @@ import { produce } from 'immer';
import village, { type VillageState } from '../village';
import build from './build';
-import upgradeBuilding from './upgradeBuilding';
-import recruitUnits from './recruitUnits';
import pillage from './pillage';
+import recruitUnits from './recruitUnits';
+import startQuest from './startQuest';
+import upgradeBuilding from './upgradeBuilding';
// Encapsulates a move function into a store update, where the data is made
@@ -34,4 +35,5 @@ export default {
upgradeBuilding: makeMove(upgradeBuilding),
pillage: makeMove(pillage),
recruitUnits: makeMove(recruitUnits),
+ startQuest: makeMove(startQuest),
};
diff --git a/src/moves/startQuest.ts b/src/moves/startQuest.ts
new file mode 100644
index 0000000..7656d79
--- /dev/null
+++ b/src/moves/startQuest.ts
@@ -0,0 +1,13 @@
+import type { VillageState } from "../village";
+
+export default function startQuest(V: VillageState, questId: number) {
+ const quest = V.quests.find(q => q.id === questId);
+ if (!quest) {
+ return false;
+ }
+
+ quest.started = true;
+ quest.remainingTime = quest.duration * 1000;
+
+ return true;
+}
diff --git a/src/quests.ts b/src/quests.ts
new file mode 100644
index 0000000..6b60503
--- /dev/null
+++ b/src/quests.ts
@@ -0,0 +1,34 @@
+import type { QuestType, ResourcesType } from "./types";
+import { getEmptyResources, random } from "./utils";
+
+
+let uid = 0;
+
+
+export function createQuest(level: number): QuestType {
+ const reward = getEmptyResources();
+ const adjustedLevel = level * 2 + 5;
+ const duration = random(adjustedLevel - 2, adjustedLevel + 2);
+ Object.keys(reward).forEach(r => {
+ const resource = r as keyof ResourcesType;
+ reward[resource] = random(
+ duration * 5 - level * 10,
+ duration * 5 + level * 10,
+ );
+
+ if (resource === 'food') {
+ reward[resource] = Math.round(reward[resource] / 3);
+ }
+ else if (resource === 'culture') {
+ reward[resource] = Math.round(reward[resource] / 20);
+ }
+ });
+
+ return {
+ id: uid++,
+ duration,
+ reward,
+ level,
+ started: false,
+ };
+}
diff --git a/src/types.ts b/src/types.ts
index 976af09..71c27c3 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -95,3 +95,18 @@ export interface BourgadeType extends BaseRegionType {
export type RegionType = OasisType | BourgadeType;
+
+
+export interface HeroType {
+ id: number;
+}
+
+
+export interface QuestType {
+ id: number;
+ duration: number;
+ reward: ResourcesType;
+ level: number;
+ started: boolean;
+ remainingTime?: number;
+}
diff --git a/src/update.ts b/src/update.ts
index c00fdbe..6ea9aa0 100644
--- a/src/update.ts
+++ b/src/update.ts
@@ -5,6 +5,7 @@ import { resolveMission } from './missions';
import type { ProductionType } from './types';
import { getProduction, getStorage, shuffle } from './utils';
import village, { type VillageState } from "./village";
+import { createQuest } from './quests';
let lastFrame: number;
@@ -46,6 +47,26 @@ export default function update(timestamp: number) {
}
});
+ // Advance quests.
+ V.quests.filter(q => q.started).forEach(quest => {
+ if (!quest.remainingTime) {
+ return;
+ }
+
+ quest.remainingTime -= delta;
+ if (quest.remainingTime <= 0) {
+ V.resources.wood += quest.reward.wood;
+ V.resources.stone += quest.reward.stone;
+ V.resources.iron += quest.reward.iron;
+ V.resources.food += quest.reward.food;
+ V.resources.culture += quest.reward.culture;
+
+ // Replace the finished quest with a new one.
+ V.quests = V.quests.filter(q => q.id !== quest.id);
+ V.quests.push(createQuest(quest.level + 1));
+ }
+ });
+
// Make all buildings and units produce and consume.
const productionPerMinute = getProduction(V);
const storage = getStorage(V);
diff --git a/src/utils.ts b/src/utils.ts
index 814b27a..16d97fa 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -130,6 +130,21 @@ export function shuffle(array: Array): Array {
}
+/**
+ * Return a random integer in the range [ min, max ] (min and max can be returned).
+ * @param min integer
+ * @param max integer
+ * @returns integer
+ */
+export function random(min: number, max?: number) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1.0));
+}
+
+
export function getBuildingUpgradeCost(_V: VillageState, building: BuildingType): CostType {
const level = building.level + 1;
return building.cost(level);
diff --git a/src/village.ts b/src/village.ts
index e9b4952..ada6414 100644
--- a/src/village.ts
+++ b/src/village.ts
@@ -3,8 +3,9 @@ import { writable } from "svelte/store";
import { createBuilding } from "./create";
import worldmap from "./data/worldmap";
import { getTilesAtDistance, Hex } from "./hexgrid";
-import type { BuildingType, RegionType, ResourcesType } from "./types";
+import type { BuildingType, QuestType, RegionType, ResourcesType } from "./types";
import { getKeysAsNumbers, shuffle } from "./utils";
+import { createQuest } from "./quests";
type Board = {
@@ -23,6 +24,7 @@ export interface VillageState {
villageTiles: Board;
outsideTiles: Board;
worldmap: RegionType[];
+ quests: QuestType[];
victory: boolean;
}
@@ -78,6 +80,15 @@ function getInitialWorldmap(): RegionType[] {
}
+function getInitialQuests(): QuestType[] {
+ return [
+ createQuest(1),
+ createQuest(1),
+ createQuest(1),
+ ];
+}
+
+
function getInitialState() {
const state: VillageState = {
buildings: [],
@@ -92,6 +103,7 @@ function getInitialState() {
villageTiles: getInitialVillageBoard(),
outsideTiles: getInitialOutsideBoard(),
worldmap: getInitialWorldmap(),
+ quests: getInitialQuests(),
victory: false,
};