switch quest logic to work with phase system

This commit is contained in:
2025-06-16 20:26:05 +02:00
parent 96eb036a8e
commit c836eb4632
4 changed files with 107 additions and 33 deletions
+29 -12
View File
@@ -84,6 +84,8 @@ import QuestExpUpgrade from "@/classes/guildUpgrades/QuestExpUpgrade";
import QuestGoldUpgrade from "@/classes/guildUpgrades/QuestGoldUpgrade"; import QuestGoldUpgrade from "@/classes/guildUpgrades/QuestGoldUpgrade";
import AutoFinishQuestsUpgrade from "@/classes/guildUpgrades/AutoFinishQuestsUpgrade"; import AutoFinishQuestsUpgrade from "@/classes/guildUpgrades/AutoFinishQuestsUpgrade";
import RecruitmentCapacityUpgrade from "@/classes/guildUpgrades/RecruitmentCapacityUpgrade"; import RecruitmentCapacityUpgrade from "@/classes/guildUpgrades/RecruitmentCapacityUpgrade";
import QuestPhase from "@/classes/quests/QuestPhase";
import {PhaseType} from "@/classes/quests/QuestPhaseType";
export default defineComponent({ export default defineComponent({
name: "GuildView", name: "GuildView",
@@ -121,23 +123,22 @@ export default defineComponent({
async updateMissives() { async updateMissives() {
for (const missive of this.missives) { for (const missive of this.missives) {
if (missive.adventurers.length < missive.maxAdventurers) { if (missive.adventurers.length < missive.maxAdventurers) {
missive.progressPoints = 0; missive.phases.forEach(phase => {
phase.points = 0;
});
continue; continue;
} }
for (const adventurerId in missive.adventurers) { for (const phase of missive.phases) {
const adventurer = missive.adventurers[adventurerId]; if (phase.completed()) continue;
const attack = adventurer.getAttack(); phase.tick(missive.adventurers);
adventurer.busy = true;
missive.progressPoints = Math.min(missive.progressPoints + attack, missive.maxProgress);
} }
if ( if (
missive.progressPoints >= missive.maxProgress missive.isCompleted()
&& this.guild.autoFinishQuestsUpgrade.getRanksToAutoFinishQuestsIn().includes(missive.rank) && this.guild.autoFinishQuestsUpgrade.getRanksToAutoFinishQuestsIn().includes(missive.rank)
) { ) {
this.finalizeQuest(missive); this.finalizeQuest(missive);
} }
} }
}, },
async checkForNewRecruit(currentTimestamp: number, cooldownModifier: number = 1) { async checkForNewRecruit(currentTimestamp: number, cooldownModifier: number = 1) {
const recruitCapacity = this.guild.recruitmentCapacity.getRecruitmentCapacity(); const recruitCapacity = this.guild.recruitmentCapacity.getRecruitmentCapacity();
@@ -178,7 +179,6 @@ export default defineComponent({
delete this.adventurersForHire[adventurer.id]; delete this.adventurersForHire[adventurer.id];
}, },
finalizeQuest(missive: Quest) { finalizeQuest(missive: Quest) {
missive.progressPoints = 0;
this.guild.gold += missive.goldReward; this.guild.gold += missive.goldReward;
for (const adventurerId in missive.adventurers) { for (const adventurerId in missive.adventurers) {
const adventurer = missive.adventurers[adventurerId]; const adventurer = missive.adventurers[adventurerId];
@@ -257,9 +257,26 @@ export default defineComponent({
if (Array.isArray(saveData.missives)) { if (Array.isArray(saveData.missives)) {
for (const data of saveData.missives) { for (const data of saveData.missives) {
const quest = new Quest(data.id, getFromString(data.rank), data.title, data.text, data.maxProgress, data.expReward, data.goldReward); const phases: Array<QuestPhase> = [];
quest.progressPoints = data.progressPoints; if (Array.isArray(data.phases)) {
if (data.adventurers.length > 0) { for (const phaseData of data.phases) {
const types: Array<PhaseType> = [];
if (Array.isArray(phaseData.types)) {
for (const type of phaseData.types) {
try {
const phaseType = PhaseType[type as keyof typeof PhaseType];
types.push(phaseType);
} catch (e) {
console.error("Error creating phase type", e);
}
}
}
const phase = new QuestPhase(types, phaseData.maxPoints, phaseData.points);
phases.push(phase);
}
}
const quest = new Quest(data.id, getFromString(data.rank), data.title, data.text, phases, data.expReward, data.goldReward);
if (Array.isArray(data?.adventurers)) {
for (const adventurer of data.adventurers) { for (const adventurer of data.adventurers) {
const adventurerId = adventurer.id; const adventurerId = adventurer.id;
if (this.adventurers[adventurerId] == null) continue; if (this.adventurers[adventurerId] == null) continue;
+27
View File
@@ -2,6 +2,8 @@ import {Guild} from "@/classes/Guild";
import {Adventurer} from "@/classes/Adventurer"; import {Adventurer} from "@/classes/Adventurer";
import {Quest} from "@/classes/quests/Quest"; import {Quest} from "@/classes/quests/Quest";
import {getFromString, QuestRank} from "@/classes/QuestRank"; import {getFromString, QuestRank} from "@/classes/QuestRank";
import QuestPhase from "@/classes/quests/QuestPhase";
import {PhaseType} from "@/classes/quests/QuestPhaseType";
export class GameData { export class GameData {
guild: Guild; guild: Guild;
@@ -98,11 +100,36 @@ export async function loadAvailableQuests(): Promise<{ [key: string]: { [key: st
for (const quest of questRankData) { for (const quest of questRankData) {
const id = quest.id; const id = quest.id;
const phases = [] as Array<QuestPhase>;
if (Array.isArray(quest?.phases)) {
for (const phase of quest.phases) {
const phaseTypes: PhaseType[] = [];
if (Array.isArray(phase?.types)) {
for (const type of phase.types) {
const phaseType = PhaseType[type as keyof typeof PhaseType];
if (!phaseType) {
console.error(`Invalid phase type: ${type}`);
continue;
}
phaseTypes.push(phaseType);
}
}
phases.push(new QuestPhase(
phaseTypes,
phase.maxPoints,
0,
));
}
}
quests[questRank][id] = new Quest( quests[questRank][id] = new Quest(
id, id,
questRank, questRank,
quest.title, quest.title,
quest.text, quest.text,
phases,
); );
} }
} }
+47 -17
View File
@@ -1,5 +1,6 @@
import type {Adventurer} from "@/classes/Adventurer"; import type {Adventurer} from "@/classes/Adventurer";
import {QuestRank} from "@/classes/QuestRank"; import {QuestRank} from "@/classes/QuestRank";
import QuestPhase from "@/classes/quests/QuestPhase";
export class Quest { export class Quest {
id: string; id: string;
@@ -7,9 +8,8 @@ export class Quest {
title: string; title: string;
text: string; text: string;
adventurers: Array<Adventurer>; adventurers: Array<Adventurer>;
phases: QuestPhase[] = [];
maxAdventurers: number; maxAdventurers: number;
progressPoints: number;
maxProgress: number;
expReward: number; expReward: number;
goldReward: number; goldReward: number;
@@ -18,7 +18,7 @@ export class Quest {
rank: QuestRank, rank: QuestRank,
title: string, title: string,
text: string, text: string,
maxProgress: number = 1, phases: QuestPhase[],
expReward: number = 0, expReward: number = 0,
goldReward: number = 0, goldReward: number = 0,
maxAdventurers: number = 1 maxAdventurers: number = 1
@@ -27,16 +27,46 @@ export class Quest {
this.rank = rank; this.rank = rank;
this.title = title; this.title = title;
this.text = text; this.text = text;
this.maxProgress = maxProgress;
this.expReward = expReward; this.expReward = expReward;
this.goldReward = goldReward; this.goldReward = goldReward;
this.progressPoints = 0;
this.adventurers = []; this.adventurers = [];
this.maxAdventurers = maxAdventurers; this.maxAdventurers = maxAdventurers;
for (const phase of phases) {
this.phases.push(new QuestPhase(Array.from(phase.types), phase.maxPoints, phase.points));
}
} }
getPercentProgress(): number { getPercentProgress(): number {
return Math.round(this.progressPoints / this.maxProgress * 100); let maxProgress = 0;
let progressPoints = 0;
for (const phase of this.phases) {
maxProgress += phase.maxPoints;
progressPoints += phase.points;
}
return Math.round(progressPoints / maxProgress * 100);
}
isCompleted(): boolean {
for (const phase of this.phases) {
if (!phase.completed()) return false;
}
return true;
}
getMaxProgress(): number {
let maxProgress = 0;
for (const phase of this.phases) {
maxProgress += phase.maxPoints;
}
return maxProgress;
}
getProgress(): number {
let progressPoints = 0;
for (const phase of this.phases) {
progressPoints += phase.points;
}
return progressPoints;
} }
} }
@@ -49,47 +79,47 @@ export class Quest {
*/ */
export function getQuestWithRewards(quest: Quest, expModifier: number = 1, goldModifier: number = 1) { export function getQuestWithRewards(quest: Quest, expModifier: number = 1, goldModifier: number = 1) {
let maxProgress = 1; let rewardValue = 1;
switch (quest.rank) { switch (quest.rank) {
case QuestRank.S: case QuestRank.S:
// at level 30 adventurers have ~6513 dps, this will take 30 seconds on level 30 // at level 30 adventurers have ~6513 dps, this will take 30 seconds on level 30
maxProgress = 195390; rewardValue = 195390;
break; break;
case QuestRank.A: case QuestRank.A:
// at level 25 adventurers have ~2051 dps, this will take 15 seconds on level 25 // at level 25 adventurers have ~2051 dps, this will take 15 seconds on level 25
maxProgress = 30770; rewardValue = 30770;
break; break;
case QuestRank.B: case QuestRank.B:
// at level 20 adventurers have ~645 dps, this will take 15 seconds on level 20 // at level 20 adventurers have ~645 dps, this will take 15 seconds on level 20
maxProgress = 9690; rewardValue = 9690;
break; break;
case QuestRank.C: case QuestRank.C:
// at level 15 adventurers have ~203 dps, this will take 15 seconds on level 15 // at level 15 adventurers have ~203 dps, this will take 15 seconds on level 15
maxProgress = 3045; rewardValue = 3045;
break; break;
case QuestRank.D: case QuestRank.D:
// at level 10 adventurers have ~64 dps, this will take 15 seconds on level 10 // at level 10 adventurers have ~64 dps, this will take 15 seconds on level 10
maxProgress = 960; rewardValue = 960;
break; break;
case QuestRank.E: case QuestRank.E:
// at level 5 adventurers have ~20 dps, this will take 15 seconds on level 5 // at level 5 adventurers have ~20 dps, this will take 15 seconds on level 5
maxProgress = 300; rewardValue = 300;
break; break;
case QuestRank.F: case QuestRank.F:
// at level 1 adventurers have ~8 dps, this will take 15 seconds on level 1 // at level 1 adventurers have ~8 dps, this will take 15 seconds on level 1
maxProgress = 120; rewardValue = 120;
break; break;
} }
let goldReward = Math.floor(maxProgress/6 * goldModifier); let goldReward = Math.floor(rewardValue/6 * goldModifier);
let expReward = Math.floor((Math.floor(maxProgress/120) - maxProgress/1000) * expModifier); let expReward = Math.floor((Math.floor(rewardValue/120) - rewardValue/1000) * expModifier);
// add some randomness to the rewards // add some randomness to the rewards
goldReward = Math.floor(randomNumberBetween(goldReward * 0.95, goldReward * 1.1)); goldReward = Math.floor(randomNumberBetween(goldReward * 0.95, goldReward * 1.1));
expReward = Math.max(1, Math.floor(randomNumberBetween(expReward * 0.95, expReward * 1.2))); expReward = Math.max(1, Math.floor(randomNumberBetween(expReward * 0.95, expReward * 1.2)));
return new Quest(quest.id, quest.rank, quest.title, quest.text, maxProgress, expReward, goldReward); return new Quest(quest.id, quest.rank, quest.title, quest.text, quest.phases, expReward, goldReward);
} }
function randomNumberBetween(min: number, max: number) { function randomNumberBetween(min: number, max: number) {
+4 -4
View File
@@ -2,17 +2,17 @@
<section> <section>
<QuestGroup <QuestGroup
:adventurers="adventurers" :adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints < quest.maxProgress)" :quests="quests.filter(quest => quest.getProgress() < quest.getMaxProgress())"
:finalizeQuest="finalizeQuest" :finalizeQuest="finalizeQuest"
label="Quests" label="Quests"
v-show="quests.filter(quest => quest.progressPoints < quest.maxProgress).length > 0" v-show="quests.filter(quest => quest.getProgress() < quest.getMaxProgress()).length > 0"
/> />
<QuestGroup <QuestGroup
:finalize-quest="finalizeQuest" :finalize-quest="finalizeQuest"
:adventurers="adventurers" :adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints >= quest.maxProgress)" :quests="quests.filter(quest => quest.getProgress() >= quest.getMaxProgress())"
label="Completed Quests" label="Completed Quests"
v-show="quests.filter(quest => quest.progressPoints >= quest.maxProgress).length > 0" v-show="quests.filter(quest => quest.getProgress() >= quest.getMaxProgress()).length > 0"
/> />
</section> </section>
</template> </template>