From a821094513b18e66af4065480c978c930719fb77 Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Sat, 31 May 2025 19:53:31 +0200 Subject: [PATCH] finish up base recruitment system --- src/App.vue | 49 ++++++++++++++----- src/GameData.ts | 16 ++++-- src/classes/Guild.ts | 4 +- .../RecruitmentCapacityUpgrade.ts | 36 ++++++++++++++ src/components/AdventurerDetails.vue | 9 +++- src/components/AdventurerRecruitment.vue | 49 ++++++++++++------- src/components/AdventurerTile.vue | 1 + src/components/UpgradesList.vue | 21 ++++++++ src/views/AdventurerView.vue | 2 + 9 files changed, 148 insertions(+), 39 deletions(-) create mode 100644 src/classes/guildUpgrades/RecruitmentCapacityUpgrade.ts diff --git a/src/App.vue b/src/App.vue index 190b5a7..58864bf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -51,8 +51,8 @@ import {version} from "@/../package.json"; :adventurersForHire="adventurersForHire" :news="news" @finalizeQuest="finalizeQuest($event)" - @recruitAdventurer="recruitAdventurer($event)" - @dismissRecruit="dismissRecruit($event)" + @hireAdventurer="recruitAdventurer($event)" + @dismissAdventurer="dismissRecruit($event)" /> @@ -101,6 +101,8 @@ export default defineComponent({ adventurers: {} as { [key: string]: Adventurer }, quests: {} as { [key: string]: { [key: string]: Quest } }, missives: [] as Array, + nextRecruitArrival: new Date() as Date, + tickCounter: 0 as number, }), methods: { async updateMissives() { @@ -123,24 +125,30 @@ export default defineComponent({ } } - }, - async checkForNewRecruit(currentTimestamp: number) { + async checkForNewRecruit(currentTimestamp: number, cooldownModifier: number = 1) { + const recruitCapacity = this.guild.recruitmentCapacity.getRecruitmentCapacity(); + + if (Object.keys(this.adventurersForHire).length >= recruitCapacity) return; + + const deltaTime = this.nextRecruitArrival.getTime() - currentTimestamp; + if (deltaTime > 0) return; // not yet time for a new recruit if (Object.keys(this.adventurers).length <= 0) { - const firstAdventurer = this.adventurersDatabase[0] + const firstAdventurer = this.adventurersDatabase[0]; this.adventurersForHire[firstAdventurer.id] = firstAdventurer; } - // TODO hiring capacity upgrade - if (Object.keys(this.adventurersForHire).length < 2) { - const newAdventurerForHire = getNewAdventurerForHire(Object.values(this.adventurersDatabase)); - if (newAdventurerForHire === null) return; - this.adventurersForHire[newAdventurerForHire.id] = newAdventurerForHire; - } + const newAdventurerForHire = getNewAdventurerForHire(Object.values(this.adventurersDatabase)); + if (newAdventurerForHire === null) return; + this.adventurersForHire[newAdventurerForHire.id] = newAdventurerForHire; + + const timerValue = ((5 + (Math.random() * 15)) * 60 * 1000) * cooldownModifier; + this.nextRecruitArrival = new Date(currentTimestamp + timerValue); }, recruitAdventurer(adventurer: Adventurer): void { this.adventurers[adventurer.id] = adventurer; + delete this.adventurersForHire[adventurer.id]; delete this.adventurersDatabase[adventurer.id]; }, dismissRecruit(adventurer: Adventurer): void { @@ -238,6 +246,8 @@ export default defineComponent({ } } + this.nextRecruitArrival = saveData.nextRecruitArrival ? new Date(saveData.nextRecruitArrival) : new Date(); + const recruits = {} as { [key: string]: Adventurer }; for (const id in saveData.adventurersForHire) { @@ -296,7 +306,7 @@ export default defineComponent({ }); this.quests = promises[0] as { [key: string]: { [key: string]: Quest } }; - this.adventurersDatabase = promises[1] as {[key: string]: Adventurer}; + this.adventurersDatabase = promises[1] as { [key: string]: Adventurer }; for (const adventurerId in this.adventurersDatabase) { const adventurer = this.adventurersDatabase[adventurerId]; this.allAdventurers[adventurer.id] = new Adventurer(adventurer.id, adventurer.name, adventurer.portrait, adventurer.attackExponent, adventurer.level, adventurer.exp, adventurer.prestige); @@ -306,6 +316,17 @@ export default defineComponent({ this.loadGame(); this.adventurersDatabase = removeAlreadyHiredAdventurers(this.adventurersDatabase, this.adventurers); + if (Object.keys(this.adventurersForHire).length < this.guild.recruitmentCapacity.getRecruitmentCapacity()) { + // check if more time passed than next recruit arrival and simulate next recruit arrivals up to now + const now = new Date(); + if (this.nextRecruitArrival.getTime() < now.getTime()) { + const slotsLeft = 2 - Object.keys(this.adventurersForHire).length; + for (let i = 0; i < slotsLeft; i++) { + await this.checkForNewRecruit(this.nextRecruitArrival.getTime()); + } + } + } + // Wait a second to make sure at least most images load in behind the loader setTimeout(() => { this.loading = false; @@ -318,15 +339,17 @@ export default defineComponent({ missives: this.missives, lastQuestGot: this.lastQuestGot, adventurersForHire: this.adventurersForHire ?? null, + nextRecruitArrival: this.nextRecruitArrival, })); }, 10 * 1000)); this.gameTickTask = Number(setInterval(() => { + this.tickCounter++; this.updateMissives(); const now = Number(new Date()); - this.checkForNewRecruit(now); + if (this.tickCounter % 8 === 0) this.checkForNewRecruit(now); for (const id in this.lastQuestGot) { const lastTime = this.lastQuestGot[getFromString(id as QuestRank)]; diff --git a/src/GameData.ts b/src/GameData.ts index b1d537e..03f0537 100644 --- a/src/GameData.ts +++ b/src/GameData.ts @@ -8,16 +8,21 @@ export class GameData { adventurers: { [key: string]: Adventurer }; missives: Array; lastQuestGot: { [key: string]: null | number }; - adventurersForHire: {[key: string]: Adventurer} | null; + adventurersForHire: {[key: string]: Adventurer}; + nextRecruitArrival: Date; constructor( data: any, ) { this.guild = data.guild ?? new Guild(1, 0); - this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer }; + this.adventurers = data.adventurers ?? {}; this.missives = data.missives ?? [] as Array; - this.lastQuestGot = data.lastQuestGot ?? {} as { [key: string]: null | number }; - this.adventurersForHire = data.adventurersForHire ?? null; + this.lastQuestGot = data.lastQuestGot ?? {}; + this.adventurersForHire = data.adventurersForHire ?? {}; + this.nextRecruitArrival = data.nextRecruitArrival ? new Date(data.nextRecruitArrival) : new Date(); + if (isNaN(this.nextRecruitArrival.getTime())) { + this.nextRecruitArrival = new Date(); + } } } @@ -49,7 +54,8 @@ export function saveGame( adventurers: adventurers, missives: data.missives, lastQuestGot: data.lastQuestGot, - adventurersForHire: adventurersForHire + adventurersForHire: adventurersForHire, + nextRecruitArrival: data.nextRecruitArrival.getTime(), })); } diff --git a/src/classes/Guild.ts b/src/classes/Guild.ts index e929129..f308dbe 100644 --- a/src/classes/Guild.ts +++ b/src/classes/Guild.ts @@ -4,6 +4,7 @@ import {formatGold} from "@/classes/NumberMagic"; import QuestExpUpgrade from "@/classes/guildUpgrades/QuestExpUpgrade"; import QuestGoldUpgrade from "@/classes/guildUpgrades/QuestGoldUpgrade"; import AutoFinishQuestsUpgrade from "@/classes/guildUpgrades/AutoFinishQuestsUpgrade"; +import RecruitmentCapacityUpgrade from "@/classes/guildUpgrades/RecruitmentCapacityUpgrade"; const MAX_LEVEL: number = 8; @@ -16,6 +17,7 @@ export class Guild { expModifier: QuestExpUpgrade; goldModifier: QuestGoldUpgrade; autoFinishQuestsUpgrade: AutoFinishQuestsUpgrade; + recruitmentCapacity: RecruitmentCapacityUpgrade; constructor(level: number, gold: number, upgrades: {[index:string]: GuildUpgrade} = {}) { this.gold = gold; @@ -28,7 +30,7 @@ export class Guild { this.expModifier = upgrades.expModifier as QuestExpUpgrade ?? new QuestExpUpgrade(); this.goldModifier = upgrades.goldModifier as QuestGoldUpgrade ?? new QuestGoldUpgrade(); this.autoFinishQuestsUpgrade = upgrades.autoFinishQuestsUpgrade as AutoFinishQuestsUpgrade ?? new AutoFinishQuestsUpgrade(); - + this.recruitmentCapacity = upgrades.recruitmentCapacityUpgrade as RecruitmentCapacityUpgrade ?? new RecruitmentCapacityUpgrade(); } upgrade(): void { diff --git a/src/classes/guildUpgrades/RecruitmentCapacityUpgrade.ts b/src/classes/guildUpgrades/RecruitmentCapacityUpgrade.ts new file mode 100644 index 0000000..32d6a6a --- /dev/null +++ b/src/classes/guildUpgrades/RecruitmentCapacityUpgrade.ts @@ -0,0 +1,36 @@ +import {GuildUpgrade} from "@/classes/GuildUpgrade"; +import type MaxLevellable from "@/classes/MaxLevellable"; + +export default class AdventurerCapacityUpgrade extends GuildUpgrade implements MaxLevellable { + + maxLevel: number; + + constructor(level: number = 1) { + super(); + this.level = level; + this.nextLevelCost = this.getCostForLevel(this.level); + this.guildLevelRequirement = 3; + this.maxLevel = 3; + } + + upgrade(): void { + this.level += 1; + this.nextLevelCost = this.getCostForLevel(this.level); + } + + getCostForLevel(level: number): number { + if (level === 1) return 1500; + return Math.floor(1500 * (level * 4)); + } + + /** + * Returns the number of adventurers the guild can have + */ + getRecruitmentCapacity(): number { + return this.level ; + } + + isMaxLevel(): boolean { + return this.level >= this.maxLevel; + } +} diff --git a/src/components/AdventurerDetails.vue b/src/components/AdventurerDetails.vue index af9e725..8684cdb 100644 --- a/src/components/AdventurerDetails.vue +++ b/src/components/AdventurerDetails.vue @@ -13,7 +13,10 @@

Exp: {{ adventurer.exp }} / {{ adventurer.getNextLevelExpRequirement() }}

DPS: {{ formatDamage(adventurer.getDPS()) }}

-
+
+
+ Recruitment capacity (level {{ guild.recruitmentCapacity.level }}) + Increases the maximum amount of adventurers that await recruitment + +
Auto-finish quests (level {{ guild.autoFinishQuestsUpgrade.level - 1 }}) Automatically finish quests when they are completed. @@ -75,6 +88,14 @@ export default defineComponent({ this.guild.gold -= this.guild.adventurerCapacity.nextLevelCost; this.guild.adventurerCapacity.upgrade(); }, + upgradeRecruitmentCapacity(): void { + if (!this.guild.recruitmentCapacity) return; + if (this.guild.recruitmentCapacity.isMaxLevel()) return; + if (!this.guild.recruitmentCapacity.nextLevelCost) return; + if (this.guild.gold < this.guild.recruitmentCapacity.nextLevelCost) return; + this.guild.gold -= this.guild.recruitmentCapacity.nextLevelCost; + this.guild.recruitmentCapacity.upgrade(); + }, upgradeAutoFinishQuests(): void { if (!this.guild.autoFinishQuestsUpgrade) return; if (this.guild.autoFinishQuestsUpgrade.isMaxLevel()) return; diff --git a/src/views/AdventurerView.vue b/src/views/AdventurerView.vue index 506ac9e..586f9e4 100644 --- a/src/views/AdventurerView.vue +++ b/src/views/AdventurerView.vue @@ -4,6 +4,7 @@ :adventurer="selectedAdventurer" v-if="selectedAdventurer !== null" @closeButtonClicked="selectedAdventurer = null" + :show-prestige-button="adventurers[selectedAdventurer?.id] !== undefined" />