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 AutoFinishQuestsUpgrade from "@/classes/guildUpgrades/AutoFinishQuestsUpgrade";
import RecruitmentCapacityUpgrade from "@/classes/guildUpgrades/RecruitmentCapacityUpgrade";
import QuestPhase from "@/classes/quests/QuestPhase";
import {PhaseType} from "@/classes/quests/QuestPhaseType";
export default defineComponent({
name: "GuildView",
@@ -121,23 +123,22 @@ export default defineComponent({
async updateMissives() {
for (const missive of this.missives) {
if (missive.adventurers.length < missive.maxAdventurers) {
missive.progressPoints = 0;
missive.phases.forEach(phase => {
phase.points = 0;
});
continue;
}
for (const adventurerId in missive.adventurers) {
const adventurer = missive.adventurers[adventurerId];
const attack = adventurer.getAttack();
adventurer.busy = true;
missive.progressPoints = Math.min(missive.progressPoints + attack, missive.maxProgress);
for (const phase of missive.phases) {
if (phase.completed()) continue;
phase.tick(missive.adventurers);
}
if (
missive.progressPoints >= missive.maxProgress
missive.isCompleted()
&& this.guild.autoFinishQuestsUpgrade.getRanksToAutoFinishQuestsIn().includes(missive.rank)
) {
this.finalizeQuest(missive);
}
}
},
async checkForNewRecruit(currentTimestamp: number, cooldownModifier: number = 1) {
const recruitCapacity = this.guild.recruitmentCapacity.getRecruitmentCapacity();
@@ -178,7 +179,6 @@ export default defineComponent({
delete this.adventurersForHire[adventurer.id];
},
finalizeQuest(missive: Quest) {
missive.progressPoints = 0;
this.guild.gold += missive.goldReward;
for (const adventurerId in missive.adventurers) {
const adventurer = missive.adventurers[adventurerId];
@@ -257,9 +257,26 @@ export default defineComponent({
if (Array.isArray(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);
quest.progressPoints = data.progressPoints;
if (data.adventurers.length > 0) {
const phases: Array<QuestPhase> = [];
if (Array.isArray(data.phases)) {
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) {
const adventurerId = adventurer.id;
if (this.adventurers[adventurerId] == null) continue;
+27
View File
@@ -2,6 +2,8 @@ import {Guild} from "@/classes/Guild";
import {Adventurer} from "@/classes/Adventurer";
import {Quest} from "@/classes/quests/Quest";
import {getFromString, QuestRank} from "@/classes/QuestRank";
import QuestPhase from "@/classes/quests/QuestPhase";
import {PhaseType} from "@/classes/quests/QuestPhaseType";
export class GameData {
guild: Guild;
@@ -98,11 +100,36 @@ export async function loadAvailableQuests(): Promise<{ [key: string]: { [key: st
for (const quest of questRankData) {
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(
id,
questRank,
quest.title,
quest.text,
phases,
);
}
}
+47 -17
View File
@@ -1,5 +1,6 @@
import type {Adventurer} from "@/classes/Adventurer";
import {QuestRank} from "@/classes/QuestRank";
import QuestPhase from "@/classes/quests/QuestPhase";
export class Quest {
id: string;
@@ -7,9 +8,8 @@ export class Quest {
title: string;
text: string;
adventurers: Array<Adventurer>;
phases: QuestPhase[] = [];
maxAdventurers: number;
progressPoints: number;
maxProgress: number;
expReward: number;
goldReward: number;
@@ -18,7 +18,7 @@ export class Quest {
rank: QuestRank,
title: string,
text: string,
maxProgress: number = 1,
phases: QuestPhase[],
expReward: number = 0,
goldReward: number = 0,
maxAdventurers: number = 1
@@ -27,16 +27,46 @@ export class Quest {
this.rank = rank;
this.title = title;
this.text = text;
this.maxProgress = maxProgress;
this.expReward = expReward;
this.goldReward = goldReward;
this.progressPoints = 0;
this.adventurers = [];
this.maxAdventurers = maxAdventurers;
for (const phase of phases) {
this.phases.push(new QuestPhase(Array.from(phase.types), phase.maxPoints, phase.points));
}
}
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) {
let maxProgress = 1;
let rewardValue = 1;
switch (quest.rank) {
case QuestRank.S:
// at level 30 adventurers have ~6513 dps, this will take 30 seconds on level 30
maxProgress = 195390;
rewardValue = 195390;
break;
case QuestRank.A:
// at level 25 adventurers have ~2051 dps, this will take 15 seconds on level 25
maxProgress = 30770;
rewardValue = 30770;
break;
case QuestRank.B:
// at level 20 adventurers have ~645 dps, this will take 15 seconds on level 20
maxProgress = 9690;
rewardValue = 9690;
break;
case QuestRank.C:
// at level 15 adventurers have ~203 dps, this will take 15 seconds on level 15
maxProgress = 3045;
rewardValue = 3045;
break;
case QuestRank.D:
// at level 10 adventurers have ~64 dps, this will take 15 seconds on level 10
maxProgress = 960;
rewardValue = 960;
break;
case QuestRank.E:
// at level 5 adventurers have ~20 dps, this will take 15 seconds on level 5
maxProgress = 300;
rewardValue = 300;
break;
case QuestRank.F:
// at level 1 adventurers have ~8 dps, this will take 15 seconds on level 1
maxProgress = 120;
rewardValue = 120;
break;
}
let goldReward = Math.floor(maxProgress/6 * goldModifier);
let expReward = Math.floor((Math.floor(maxProgress/120) - maxProgress/1000) * expModifier);
let goldReward = Math.floor(rewardValue/6 * goldModifier);
let expReward = Math.floor((Math.floor(rewardValue/120) - rewardValue/1000) * expModifier);
// add some randomness to the rewards
goldReward = Math.floor(randomNumberBetween(goldReward * 0.95, goldReward * 1.1));
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) {
+4 -4
View File
@@ -2,17 +2,17 @@
<section>
<QuestGroup
:adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints < quest.maxProgress)"
:quests="quests.filter(quest => quest.getProgress() < quest.getMaxProgress())"
:finalizeQuest="finalizeQuest"
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
:finalize-quest="finalizeQuest"
:adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints >= quest.maxProgress)"
:quests="quests.filter(quest => quest.getProgress() >= quest.getMaxProgress())"
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>
</template>