mirror of
https://github.com/YouHaveTrouble/GuildMaster.git
synced 2026-05-12 06:26:59 +00:00
hook in data sources for adventurers and quests,
programatically generate quest rewards, change damage math,
This commit is contained in:
@@ -3,36 +3,36 @@
|
|||||||
"id": "rincewind-diskworld",
|
"id": "rincewind-diskworld",
|
||||||
"name": "Rincewind",
|
"name": "Rincewind",
|
||||||
"portrait": "/img/adventurers/rincewind.png",
|
"portrait": "/img/adventurers/rincewind.png",
|
||||||
"attackPerLevel": 1.7
|
"attackExponent": 1.09
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "fran-sword-isekai",
|
"id": "fran-sword-isekai",
|
||||||
"name": "Fran",
|
"name": "Fran",
|
||||||
"portrait": "/img/adventurers/fran.png",
|
"portrait": "/img/adventurers/fran.png",
|
||||||
"attackPerLevel": 2.2
|
"attackExponent": 1.115
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "kazuma-konosuba",
|
"id": "kazuma-konosuba",
|
||||||
"name": "Kazuma",
|
"name": "Kazuma",
|
||||||
"portrait": "/img/adventurers/kazuma.png",
|
"portrait": "/img/adventurers/kazuma.png",
|
||||||
"attackPerLevel": 1.8
|
"attackExponent": 1.1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "rein-beast-tamer",
|
"id": "rein-beast-tamer",
|
||||||
"name": "Rein",
|
"name": "Rein",
|
||||||
"portrait": "/img/adventurers/rein.png",
|
"portrait": "/img/adventurers/rein.png",
|
||||||
"attackPerLevel": 1.9
|
"attackExponent": 1.1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "momon-overlord",
|
"id": "momon-overlord",
|
||||||
"name": "Momon",
|
"name": "Momon",
|
||||||
"portrait": "/img/adventurers/momon.png",
|
"portrait": "/img/adventurers/momon.png",
|
||||||
"attackPerLevel": 2.1
|
"attackExponent": 1.11
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "goblin-slayer",
|
"id": "goblin-slayer",
|
||||||
"name": "Goblin Slayer",
|
"name": "Goblin Slayer",
|
||||||
"portrait": "/img/adventurers/goblin-slayer.png",
|
"portrait": "/img/adventurers/goblin-slayer.png",
|
||||||
"attackPerLevel": 2
|
"attackExponent": 1.1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
+19
-10
@@ -24,10 +24,10 @@ import {RouterLink, RouterView} from 'vue-router'</script>
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent} from "vue";
|
import {defineComponent} from "vue";
|
||||||
import {Adventurer} from "@/classes/Adventurer";
|
import {Adventurer} from "@/classes/Adventurer";
|
||||||
import {Quest} from "@/classes/Quest";
|
import {getQuestWithRewards, Quest} from "@/classes/Quest";
|
||||||
import {Guild} from "@/classes/Guild";
|
import {Guild} from "@/classes/Guild";
|
||||||
import {getFromString, QuestRank} from "@/classes/QuestRank";
|
import {getFromString, QuestRank} from "@/classes/QuestRank";
|
||||||
import {GameData, loadGame, saveGame} from "@/GameData";
|
import {GameData, loadAvailableQuests, loadGame, saveGame} from "@/GameData";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "GuildView",
|
name: "GuildView",
|
||||||
@@ -56,8 +56,7 @@ export default defineComponent({
|
|||||||
F: null as null|number,
|
F: null as null|number,
|
||||||
} as { [key: string]: null|number },
|
} as { [key: string]: null|number },
|
||||||
lastRecruitHandled: null as null|number,
|
lastRecruitHandled: null as null|number,
|
||||||
adventurers: {
|
adventurers: {} as { [key: string]: Adventurer },
|
||||||
} as { [key: string]: Adventurer },
|
|
||||||
quests: {
|
quests: {
|
||||||
F: {
|
F: {
|
||||||
"1": new Quest("1", QuestRank.F, "Frog Frenzy", "Kill 10 demon frogs.", 120, 1, 25),
|
"1": new Quest("1", QuestRank.F, "Frog Frenzy", "Kill 10 demon frogs.", 120, 1, 25),
|
||||||
@@ -118,7 +117,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
for (const adventurerId in missive.adventurers) {
|
for (const adventurerId in missive.adventurers) {
|
||||||
const adventurer = missive.adventurers[adventurerId];
|
const adventurer = missive.adventurers[adventurerId];
|
||||||
const attack = adventurer.attackPerLevel * adventurer.level;
|
const attack = adventurer.getAttack();
|
||||||
missive.progressPoints = Math.min(missive.progressPoints + attack, missive.maxProgress);
|
missive.progressPoints = Math.min(missive.progressPoints + attack, missive.maxProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +141,7 @@ export default defineComponent({
|
|||||||
const questsForRank = this.quests[rank] as { [key: string]: Quest };
|
const questsForRank = this.quests[rank] as { [key: string]: Quest };
|
||||||
const randomId = keys.length * Math.random() << 0;
|
const randomId = keys.length * Math.random() << 0;
|
||||||
const randomIdString = keys[randomId] as string;
|
const randomIdString = keys[randomId] as string;
|
||||||
return questsForRank[randomIdString];
|
return getQuestWithRewards(questsForRank[randomIdString]);
|
||||||
},
|
},
|
||||||
createMissive(questToAdd: Quest, rank: QuestRank) {
|
createMissive(questToAdd: Quest, rank: QuestRank) {
|
||||||
const quest = JSON.parse(JSON.stringify(questToAdd));
|
const quest = JSON.parse(JSON.stringify(questToAdd));
|
||||||
@@ -162,9 +161,18 @@ export default defineComponent({
|
|||||||
|
|
||||||
for (const id in saveData.adventurers) {
|
for (const id in saveData.adventurers) {
|
||||||
const data = saveData.adventurers[id];
|
const data = saveData.adventurers[id];
|
||||||
const adventurer = new Adventurer(data.id, data.name, data.portrait, data.attackPerLevel, data.level, data.exp);
|
try {
|
||||||
adventurer.busy = data.busy;
|
const adventurer = new Adventurer(
|
||||||
adventurers[data.id] = adventurer;
|
data.id,
|
||||||
|
data.name,
|
||||||
|
data.portrait,
|
||||||
|
data.attackExponent ?? 1.1,
|
||||||
|
data.level ?? 1,
|
||||||
|
data.exp ?? 0
|
||||||
|
);
|
||||||
|
adventurer.busy = data.busy;
|
||||||
|
adventurers[data.id] = adventurer;
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
this.adventurers = adventurers;
|
this.adventurers = adventurers;
|
||||||
|
|
||||||
@@ -194,8 +202,9 @@ export default defineComponent({
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.loadGame();
|
this.loadGame();
|
||||||
|
this.quests = await loadAvailableQuests();
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
saveGame(new GameData(
|
saveGame(new GameData(
|
||||||
|
|||||||
+67
-4
@@ -1,6 +1,7 @@
|
|||||||
import type {Guild} from "@/classes/Guild";
|
import type {Guild} from "@/classes/Guild";
|
||||||
import type {Adventurer} from "@/classes/Adventurer";
|
import {Adventurer} from "@/classes/Adventurer";
|
||||||
import type {Quest} from "@/classes/Quest";
|
import {Quest} from "@/classes/Quest";
|
||||||
|
import {getFromString, QuestRank} from "@/classes/QuestRank";
|
||||||
|
|
||||||
export class GameData {
|
export class GameData {
|
||||||
guild: Guild;
|
guild: Guild;
|
||||||
@@ -47,7 +48,69 @@ export function loadGame(): GameData | null {
|
|||||||
parsedGame.lastQuestGot,
|
parsedGame.lastQuestGot,
|
||||||
parsedGame.lastRecruitAction
|
parsedGame.lastRecruitAction
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function loadAvailableQuests(): Promise<{ [key: string]: { [key: string]: Quest } }> {
|
||||||
|
const quests = {
|
||||||
|
S: {} as { [key: string]: Quest },
|
||||||
|
A: {} as { [key: string]: Quest },
|
||||||
|
B: {} as { [key: string]: Quest },
|
||||||
|
C: {} as { [key: string]: Quest },
|
||||||
|
D: {} as { [key: string]: Quest },
|
||||||
|
E: {} as { [key: string]: Quest },
|
||||||
|
F: {} as { [key: string]: Quest },
|
||||||
|
} as { [key: string]: { [key: string]: Quest } };
|
||||||
|
|
||||||
|
for (const rank in quests) {
|
||||||
|
const response = await fetch(`data/quests/Rank${rank}.json`);
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.error("Failed to load quests");
|
||||||
|
alert("Failed to load quests. Please try refreshing the page.");
|
||||||
|
return quests;
|
||||||
|
}
|
||||||
|
const questData = await response.json();
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
for (const quest of questData) {
|
||||||
|
id++;
|
||||||
|
quests[rank.toString()][id] = new Quest(
|
||||||
|
id.toString(),
|
||||||
|
getFromString(rank as QuestRank),
|
||||||
|
quest.title,
|
||||||
|
quest.text,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(quests);
|
||||||
|
|
||||||
|
return quests;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadAdventurersForHire(currentAdventurerIds: Array<string> = []): Promise<Array<Adventurer>> {
|
||||||
|
const response = await fetch("data/adventurers.json");
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.error("Failed to load adventurers");
|
||||||
|
alert("Failed to load adventurers. Please try refreshing the page.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const adventurerData = await response.json();
|
||||||
|
|
||||||
|
const adventurers = [] as Array<Adventurer>;
|
||||||
|
for (const adventurer of adventurerData) {
|
||||||
|
if (currentAdventurerIds.includes(adventurer.id)) continue;
|
||||||
|
adventurers.push(new Adventurer(
|
||||||
|
adventurer.id,
|
||||||
|
adventurer.name,
|
||||||
|
adventurer.portrait,
|
||||||
|
adventurer.attackExponent,
|
||||||
|
adventurer.level,
|
||||||
|
adventurer.exp,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return adventurers;
|
||||||
|
}
|
||||||
@@ -4,21 +4,21 @@ export class Adventurer {
|
|||||||
portrait: string;
|
portrait: string;
|
||||||
level: number;
|
level: number;
|
||||||
exp: number;
|
exp: number;
|
||||||
attackPerLevel: number;
|
attackExponent: number;
|
||||||
busy: boolean;
|
busy: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
name: string,
|
name: string,
|
||||||
portrait: string,
|
portrait: string,
|
||||||
attackPerLevel: number,
|
attackExponent: number,
|
||||||
level: number = 1,
|
level: number = 1,
|
||||||
exp: number = 0
|
exp: number = 0
|
||||||
) {
|
) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.portrait = portrait;
|
this.portrait = portrait;
|
||||||
this.attackPerLevel = attackPerLevel;
|
this.attackExponent = attackExponent;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.exp = exp;
|
this.exp = exp;
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
@@ -44,4 +44,12 @@ export class Adventurer {
|
|||||||
return (this.exp / this.getNextLevelExpRequirement()) * 100;
|
return (this.exp / this.getNextLevelExpRequirement()) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAttack(): number {
|
||||||
|
return Math.floor(2 * this.level ^ this.attackExponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDPS(): number {
|
||||||
|
return this.getAttack() * 4;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-1
@@ -1,5 +1,5 @@
|
|||||||
import type {Adventurer} from "@/classes/Adventurer";
|
import type {Adventurer} from "@/classes/Adventurer";
|
||||||
import type {QuestRank} from "@/classes/QuestRank";
|
import {QuestRank} from "@/classes/QuestRank";
|
||||||
|
|
||||||
export class Quest {
|
export class Quest {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -29,3 +29,56 @@ export class Quest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate rewards for a quest and return it
|
||||||
|
* @param quest
|
||||||
|
*/
|
||||||
|
export function getQuestWithRewards(quest: Quest) {
|
||||||
|
|
||||||
|
let maxProgress = 1;
|
||||||
|
|
||||||
|
switch (quest.rank) {
|
||||||
|
case QuestRank.S:
|
||||||
|
// at level 30 adventurers have ~2353 dps, this will take 30 seconds on level 30
|
||||||
|
maxProgress = 70590
|
||||||
|
break;
|
||||||
|
case QuestRank.A:
|
||||||
|
// at level 25 adventurers have ~1122 dps, this will take 15 seconds on level 25
|
||||||
|
maxProgress = 16800
|
||||||
|
break;
|
||||||
|
case QuestRank.B:
|
||||||
|
// at level 20 adventurers have ~564 dps, this will take 15 seconds on level 20
|
||||||
|
maxProgress = 8460;
|
||||||
|
break;
|
||||||
|
case QuestRank.C:
|
||||||
|
// at level 15 adventurers have ~256 dps, this will take 15 seconds on level 15
|
||||||
|
maxProgress = 3840;
|
||||||
|
break;
|
||||||
|
case QuestRank.D:
|
||||||
|
// at level 10 adventurers have ~103 dps, this will take 15 seconds on level 10
|
||||||
|
maxProgress = 1545;
|
||||||
|
break;
|
||||||
|
case QuestRank.E:
|
||||||
|
// at level 5 adventurers have ~45 dps, this will take 15 seconds on level 5
|
||||||
|
maxProgress = 675;
|
||||||
|
break;
|
||||||
|
case QuestRank.F:
|
||||||
|
// at level 1 adventurers have ~8 dps, this will take 15 seconds on level 1
|
||||||
|
maxProgress = 120;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let goldReward = Math.floor(maxProgress/6);
|
||||||
|
let expReward = Math.floor(Math.floor(maxProgress/120) - maxProgress/1000);
|
||||||
|
|
||||||
|
// 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.1)));
|
||||||
|
|
||||||
|
return new Quest(quest.id, quest.rank, quest.title, quest.text, maxProgress, expReward, goldReward);
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomNumberBetween(min: number, max: number) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ import type {PropType} from "vue";
|
|||||||
import {defineComponent} from "vue";
|
import {defineComponent} from "vue";
|
||||||
import AdventurerTile from "@/components/AdventurerTile.vue";
|
import AdventurerTile from "@/components/AdventurerTile.vue";
|
||||||
import {Adventurer} from "@/classes/Adventurer";
|
import {Adventurer} from "@/classes/Adventurer";
|
||||||
|
import { loadAdventurersForHire } from "@/GameData";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "RecruitView",
|
name: "RecruitView",
|
||||||
@@ -51,13 +52,7 @@ export default defineComponent({
|
|||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
currentlyForHire: null as Adventurer|null,
|
currentlyForHire: null as Adventurer|null,
|
||||||
adventurersForHire: [
|
adventurersForHire: [] as Array<Adventurer>,
|
||||||
new Adventurer("rincewind-diskworld", "Rincewind", "/img/adventurers/rincewind.png", 2),
|
|
||||||
new Adventurer("fran-sword-isekai", "Fran", "/img/adventurers/fran.png", 3),
|
|
||||||
new Adventurer("kazuma-konosuba", "Kazuma", "/img/adventurers/kazuma.png", 2),
|
|
||||||
new Adventurer("rein-beast-tamer", "Rein", "/img/adventurers/rein.png", 2),
|
|
||||||
new Adventurer("momon-overlord", "Momon", "/img/adventurers/momon.png", 2),
|
|
||||||
] as Array<Adventurer>,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@@ -109,7 +104,10 @@ export default defineComponent({
|
|||||||
window.localStorage.removeItem("currentlyForHire");
|
window.localStorage.removeItem("currentlyForHire");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
|
|
||||||
|
this.adventurersForHire = await loadAdventurersForHire();
|
||||||
|
|
||||||
if (Object.keys(this.adventurers).length <= 0) {
|
if (Object.keys(this.adventurers).length <= 0) {
|
||||||
this.currentlyForHire = this.adventurersForHire[0];
|
this.currentlyForHire = this.adventurersForHire[0];
|
||||||
window.localStorage.setItem("currentlyForHire", this.adventurersForHire[0].id);
|
window.localStorage.setItem("currentlyForHire", this.adventurersForHire[0].id);
|
||||||
|
|||||||
Reference in New Issue
Block a user