Give heroes some health, a level and experience points. Make them lose health and gain experience when finishing a quest.
This commit is contained in:
parent
f7f86db510
commit
cb1f9480c3
@ -1,7 +1,7 @@
|
||||
import buildings from "./data/buildings";
|
||||
import { NAMES } from "./data/heroes";
|
||||
import { Hex } from "./hexgrid";
|
||||
import type { BuildingSource, BuildingType, HeroType, QuestType, ResourcesType } from "./types";
|
||||
import type { BuildingSource, BuildingType, HeroType, QuestType, Resource } from "./types";
|
||||
import { random, shuffle } from "./utils";
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ export function createBuilding(buildingType: string): BuildingType {
|
||||
}
|
||||
|
||||
|
||||
export function createQuest(resource: keyof ResourcesType, level: number): QuestType {
|
||||
export function createQuest(resource: Resource, level: number): QuestType {
|
||||
const adjustedLevel = Math.ceil((level * level + 3) / 3);
|
||||
const duration = Math.max(1, random(adjustedLevel - 2, adjustedLevel + 2));
|
||||
const reward = Math.max(10, random(
|
||||
@ -60,5 +60,8 @@ export function createHero(): HeroType {
|
||||
return {
|
||||
id: uid++,
|
||||
name: shuffle(NAMES)[0],
|
||||
health: 100.0,
|
||||
level: 1,
|
||||
experience: 0,
|
||||
};
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ export default [
|
||||
},
|
||||
description: {
|
||||
short: '',
|
||||
long: 'Increases the construction time of buildings by 2,5% per level, and unlocks new buildings.'
|
||||
long: 'Reduces the construction time of buildings by 2,5% per level, and unlocks new buildings.'
|
||||
},
|
||||
},
|
||||
{
|
||||
|
41
src/hud/Hero.svelte
Normal file
41
src/hud/Hero.svelte
Normal file
@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import heroes from "../modules/heroes";
|
||||
import type { HeroType } from "../types";
|
||||
|
||||
|
||||
export let hero: HeroType;
|
||||
</script>
|
||||
|
||||
<div class="hero">
|
||||
<span class="level">{ hero.level }</span>
|
||||
<p class="name">{ hero.name }</p>
|
||||
<p>Exp: { hero.experience } / { heroes.getExperienceNeeded(hero) }</p>
|
||||
<div class="health" style="--health-percent: { Math.floor(hero.health) }%;"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hero {
|
||||
margin: 1em auto;
|
||||
width: 80%;
|
||||
}
|
||||
.health {
|
||||
background-color: hsl(0, 86%, 33%);
|
||||
border: 1px solid hsl(61, 83%, 14%);
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.health::after {
|
||||
content: '';
|
||||
background-color: hsl(120, 41%, 53%);
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
scale: var(--health-percent) 1;
|
||||
transform-origin: left;
|
||||
transition: scale 400ms ease-in-out;
|
||||
}
|
||||
</style>
|
@ -2,6 +2,7 @@
|
||||
import units from "../data/units";
|
||||
import { getRemainingUnitCount } from "../utils";
|
||||
import village from "../village";
|
||||
import Hero from "./Hero.svelte";
|
||||
|
||||
$: currentUnits = Object.entries($village.units).map(([type, count]) => {
|
||||
const unit = units.find(u => u.type === type);
|
||||
@ -18,7 +19,7 @@
|
||||
|
||||
<section>
|
||||
{ #each $village.heroes as hero }
|
||||
<p>{ hero.name }</p>
|
||||
<Hero { hero } />
|
||||
{ /each }
|
||||
{ #each currentUnits as unit }
|
||||
<p>{ unit.name }: { getRemainingUnitCount($village, unit.type) } / { unit.count }</p>
|
||||
|
79
src/modules/heroes.ts
Normal file
79
src/modules/heroes.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import type { HeroType } from "../types";
|
||||
import type { VillageState } from "../village";
|
||||
|
||||
|
||||
const LEVELS = [
|
||||
0,
|
||||
10,
|
||||
25,
|
||||
50,
|
||||
100,
|
||||
250,
|
||||
500,
|
||||
1000,
|
||||
2500,
|
||||
5000,
|
||||
10000,
|
||||
];
|
||||
|
||||
|
||||
export function getHero(V: VillageState, heroId: number) {
|
||||
const hero = V.heroes.find(h => h.id === heroId);
|
||||
if (!hero) {
|
||||
throw new Error(`Cannot find hero with id "${heroId}"`);
|
||||
}
|
||||
return hero;
|
||||
}
|
||||
|
||||
|
||||
export function getMaxHealth(hero: HeroType): number {
|
||||
return 100.0 + (hero.level - 1) * 5.0;
|
||||
}
|
||||
|
||||
|
||||
export function hurt(hero: HeroType, damage: number) {
|
||||
hero.health -= damage;
|
||||
|
||||
if (hero.health <= 0) {
|
||||
hero.health = 0.0;
|
||||
|
||||
// Do something to show that the hero is dead.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function heal(hero: HeroType, health: number) {
|
||||
hero.health -= health;
|
||||
|
||||
const maxHealth = getMaxHealth(hero);
|
||||
if (hero.health > maxHealth) {
|
||||
hero.health = maxHealth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function gainExperience(hero: HeroType, xp: number) {
|
||||
hero.experience += xp;
|
||||
|
||||
if (hero.experience >= LEVELS[hero.level]) {
|
||||
hero.experience -= LEVELS[hero.level];
|
||||
|
||||
hero.level++;
|
||||
hero.health = getMaxHealth(hero);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function getExperienceNeeded(hero: HeroType) {
|
||||
return LEVELS[hero.level];
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
getHero,
|
||||
getExperienceNeeded,
|
||||
getMaxHealth,
|
||||
heal,
|
||||
hurt,
|
||||
gainExperience,
|
||||
};
|
@ -136,6 +136,9 @@ export type RegionType = EmptyRegionType | OasisType | BourgadeType;
|
||||
export interface HeroType {
|
||||
id: number;
|
||||
name: string;
|
||||
level: number;
|
||||
health: number;
|
||||
experience: number;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { resolveMission } from './missions';
|
||||
import type { ProductionType } from './types';
|
||||
import { getProduction, getRegionsWithMissions, getStorage, shuffle } from './utils';
|
||||
import village, { type VillageState } from "./village";
|
||||
import heroes from './modules/heroes';
|
||||
|
||||
|
||||
let lastFrame: number;
|
||||
@ -58,6 +59,10 @@ export default function update(timestamp: number) {
|
||||
if (quest.remainingTime <= 0) {
|
||||
V.resources[quest.resource] += quest.reward;
|
||||
|
||||
const hero = heroes.getHero(V, quest.hero as number);
|
||||
heroes.hurt(hero, 10.0);
|
||||
heroes.gainExperience(hero, 2);
|
||||
|
||||
// Replace the finished quest with a new one.
|
||||
const index = V.quests.findIndex(q => q.id === quest.id);
|
||||
V.quests[index] = createQuest(quest.resource, quest.level + 1);
|
||||
@ -116,6 +121,11 @@ export default function update(timestamp: number) {
|
||||
}
|
||||
});
|
||||
|
||||
// Heal heroes.
|
||||
V.heroes.forEach(h => {
|
||||
heroes.heal(h, delta / 5000.0)
|
||||
});
|
||||
|
||||
// Check if the game is won.
|
||||
if (V.resources.culture >= CULTURE_TO_WIN) {
|
||||
V.victory = true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { WORLD_MAP_HEIGHT, WORLD_MAP_WIDTH } from "./constants";
|
||||
import units from "./data/units";
|
||||
import { WORLDMAP_TYPES, type BuildingType, type CostType, type OasisType, type Point, type ProductionType, type ResourcesType } from "./types";
|
||||
import { WORLDMAP_TYPES, type BuildingType, type CostType, type HeroType, type OasisType, type Point, type ProductionType, type ResourcesType } from "./types";
|
||||
import type { VillageState } from "./village";
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user