allowed more than 1 recruit to show up

This commit is contained in:
2025-05-28 19:52:28 +02:00
parent 85ed1224c0
commit 2cb9221da1
4 changed files with 215 additions and 109 deletions
+43 -35
View File
@@ -48,10 +48,11 @@ import {version} from "@/../package.json";
:guild="guild"
:adventurers="adventurers"
:quests="missives"
:adventurerForHire="adventurerForHire"
:adventurersForHire="adventurersForHire"
:news="news"
@finalizeQuest="finalizeQuest($event)"
@recruitActionTaken="recruitAction($event)"
@recruitAdventurer="recruitAdventurer($event)"
@dismissRecruit="dismissRecruit($event)"
/>
</template>
@@ -94,9 +95,8 @@ export default defineComponent({
E: null as null | number,
F: null as null | number,
} as { [key: string]: null | number },
lastRecruitHandled: null as null | number,
adventurerForHire: null as Adventurer | null,
adventurersDatabase: {} as Array<Adventurer>,
adventurersForHire: {} as { [key: string]: Adventurer },
adventurersDatabase: {} as { [key: string]: Adventurer },
allAdventurers: {} as { [key: string]: Adventurer },
adventurers: {} as { [key: string]: Adventurer },
quests: {} as { [key: string]: { [key: string]: Quest } },
@@ -127,31 +127,26 @@ export default defineComponent({
},
async checkForNewRecruit(currentTimestamp: number) {
if (this.lastRecruitHandled == null) {
this.lastRecruitHandled = 0;
}
if (Object.keys(this.adventurers).length <= 0) {
this.adventurerForHire = this.adventurersDatabase[0];
const firstAdventurer = this.adventurersDatabase[0]
this.adventurersForHire[firstAdventurer.id] = firstAdventurer;
}
if (currentTimestamp - this.lastRecruitHandled >= 1000 * 60 * 30 && this.adventurerForHire == null) {
this.adventurerForHire = getNewAdventurerForHire(this.adventurersDatabase);
// 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;
}
},
recruitAction(adventurer: Adventurer | null): void {
this.lastRecruitHandled = Number(new Date());
this.adventurerForHire = null;
if (adventurer === null) return;
recruitAdventurer(adventurer: Adventurer): void {
this.adventurers[adventurer.id] = adventurer;
for (const id in this.adventurersDatabase) {
const databaseAdventurer = this.adventurersDatabase[id];
if (databaseAdventurer.id === adventurer.id) {
this.adventurersDatabase.splice(Number(id), 1);
break;
}
}
delete this.adventurersDatabase[adventurer.id];
},
dismissRecruit(adventurer: Adventurer): void {
if (adventurer == null) return;
if (this.adventurersForHire[adventurer.id] == null) return;
delete this.adventurersForHire[adventurer.id];
},
finalizeQuest(missive: Quest) {
missive.progressPoints = 0;
@@ -243,17 +238,31 @@ export default defineComponent({
}
}
this.lastRecruitHandled = saveData.lastRecruitAction ?? 0;
const recruits = {} as { [key: string]: Adventurer };
if (saveData.adventurerForHireId != null) {
for (const id in this.adventurersDatabase) {
const adventurer = this.adventurersDatabase[id];
if (adventurer.id === saveData.adventurerForHireId) {
this.adventurerForHire = adventurer;
return;
}
for (const id in saveData.adventurersForHire) {
const data = saveData.adventurersForHire[id];
let portrait: string = "";
const adventurer = this.allAdventurers[data.id];
if (adventurer) {
portrait = adventurer.portrait;
}
try {
recruits[data.id] = new Adventurer(
data.id,
data.name,
portrait,
data.attackExponent ?? 1.1,
data.level ?? 1,
data.exp ?? 0,
data.prestige ?? 0,
);
} catch (e) {
}
}
this.adventurersForHire = recruits;
},
async updateNews() {
const result = await fetch("https://raw.githubusercontent.com/YouHaveTrouble/GuildMaster/master/news.txt").catch(() => {
@@ -287,7 +296,7 @@ export default defineComponent({
});
this.quests = promises[0] as { [key: string]: { [key: string]: Quest } };
this.adventurersDatabase = promises[1] as Array<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);
@@ -308,8 +317,7 @@ export default defineComponent({
guild: this.guild,
missives: this.missives,
lastQuestGot: this.lastQuestGot,
lastRecruitAction: this.lastRecruitHandled,
adventurerForHireId: this.adventurerForHire?.id ?? null,
adventurersForHire: this.adventurersForHire ?? null,
}));
}, 10 * 1000));
+21 -17
View File
@@ -8,8 +8,7 @@ export class GameData {
adventurers: { [key: string]: Adventurer };
missives: Array<Quest>;
lastQuestGot: { [key: string]: null | number };
lastRecruitAction: null | number;
adventurerForHireId: string | null;
adventurersForHire: {[key: string]: Adventurer} | null;
constructor(
data: any,
@@ -18,8 +17,7 @@ export class GameData {
this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer };
this.missives = data.missives ?? [] as Array<Quest>;
this.lastQuestGot = data.lastQuestGot ?? {} as { [key: string]: null | number };
this.lastRecruitAction = data.lastRecruitAction ?? null;
this.adventurerForHireId = data.adventurerForHireId ?? null;
this.adventurersForHire = data.adventurersForHire ?? null;
}
}
@@ -39,13 +37,19 @@ export function saveGame(
adventurers[adventurerId] = adventurer;
}
const adventurersForHire = {} as { [key: string]: any };
for (const adventurerId in data.adventurersForHire) {
const adventurer: {[key: string]: any} = JSON.parse(JSON.stringify(data.adventurersForHire[adventurerId]));
delete adventurer.portrait;
adventurersForHire[adventurerId] = adventurer;
}
window.localStorage.setItem("savedGame", JSON.stringify({
guild: data.guild,
adventurers: adventurers,
missives: data.missives,
lastQuestGot: data.lastQuestGot,
lastRecruitAction: data.lastRecruitAction,
adventurerForHireId: data.adventurerForHireId,
adventurersForHire: adventurersForHire
}));
}
@@ -99,38 +103,38 @@ export async function loadAvailableQuests(): Promise<{ [key: string]: { [key: st
return quests;
}
export async function loadAdventurersForHire(): Promise<Array<Adventurer>> {
export async function loadAdventurersForHire(): Promise<{[key: string]: 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 [];
return {};
}
const adventurerData = await response.json();
const adventurers: Array<Adventurer> = [];
const adventurers: {[key: string]: Adventurer} = {};
for (const adventurer of adventurerData) {
adventurers.push(new Adventurer(
const loadedAdventurer = new Adventurer(
adventurer.id,
adventurer.name,
adventurer.portrait,
adventurer.attackExponent,
adventurer.level,
adventurer.exp,
));
)
adventurers[loadedAdventurer.id] = loadedAdventurer;
}
return adventurers;
}
export function removeAlreadyHiredAdventurers(
adventurers: Array<Adventurer>,
adventurers: { [key: string]: Adventurer },
adventurersHired: { [key: string]: Adventurer }
): Array<Adventurer> {
const adventurersForHire: Array<Adventurer> = [];
for (const adventurer of adventurers) {
): { [key: string]: Adventurer } {
const adventurersForHire: { [key: string]: Adventurer } = {};
for (const adventurer of Object.values(adventurers)) {
if (adventurersHired[adventurer.id]) continue;
adventurersForHire.push(adventurer);
adventurersForHire[adventurer.id] = adventurer;
}
return adventurersForHire;
}
+129
View File
@@ -0,0 +1,129 @@
<template>
<section class="recruit panel pinned-paper">
<h1>Applying adventurers</h1>
<div class="adventurers">
<div v-for="adventurerForHire in currentlyForHire" :key="adventurerForHire.id">
<div class="adventurer-tile">
<adventurer-tile class="hire-tile" :adventurer="adventurerForHire"/>
<div class="decision">
<span
title="Hire"
@click="hireAdventurer(adventurerForHire)"
:class="{disabled: Object.keys(adventurersForHire).length >= guild.adventurerCapacity.getAdventurerCapacity()}"
>
</span>
<span
:title="Object.keys(adventurersForHire).length > 0 ? 'Dismiss' : ''"
:class="{disabled: Object.keys(adventurersForHire).length <= 0}"
@click="dismissAdventurer(adventurerForHire)"
>
</span>
</div>
</div>
</div>
<div v-if="Object.keys(adventurersForHire).length == 0">
<span>Noone applied as of now. Check back later!</span>
</div>
</div>
</section>
</template>
<script lang="ts">
import {defineComponent, type PropType} from "vue";
import AdventurerTile from "@/components/AdventurerTile.vue";
import type {Guild} from "@/classes/Guild";
import type {Adventurer} from "@/classes/Adventurer";
export default defineComponent({
name: "RecruitView",
components: {AdventurerTile},
computed: {
currentlyForHire(): Array<Adventurer> {
return Object.values(this.adventurersForHire);
},
},
methods: {
hireAdventurer(adventurer: Adventurer): void {
if (Object.keys(this.adventurersForHire).length >= this.guild.adventurerCapacity.getAdventurerCapacity()) return;
this.$emit("hireAdventurer", adventurer);
},
dismissAdventurer(adventurer: Adventurer) {
if (Object.keys(this.adventurersForHire).length <= 0) return;
this.$emit("dismissAdventurer", adventurer);
}
},
props: {
guild: {
type: Object as PropType<Guild>,
required: true,
},
adventurersForHire: {
type: Object as PropType<{ [key: string]: Adventurer }>,
required: true,
},
},
emits: ["dismissAdventurer", "hireAdventurer"],
})
</script>
<style scoped lang="scss">
.adventurers {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
.adventurer-tile {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 0.25rem;
font-size: 1.1rem;
cursor: pointer;
.entry {
height: 7rem;
width: 7rem;
}
b {
line-height: 1;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
}
}
}
.decision {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 2rem;
gap: 1rem;
span {
cursor: pointer;
&:hover {
color: #fff;
}
&.disabled {
color: rgba(0, 0, 0, 0.5);
cursor: default;
}
}
}
</style>
+15 -50
View File
@@ -6,37 +6,16 @@
@closeButtonClicked="selectedAdventurer = null"
/>
<section class="recruit panel pinned-paper">
<h1>Applying adventurers</h1>
<div class="adventurers">
<div v-if="adventurerForHire">
<adventurer-tile class="hire-tile" :adventurer="adventurerForHire"/>
<div class="decision">
<span
title="Hire"
@click="hireAdventurer()"
:class="{disabled: Object.keys(adventurers).length >= guild.adventurerCapacity.getAdventurerCapacity()}"
>
</span>
<span
:title="Object.keys(adventurers).length > 0 ? 'Dismiss' : ''"
:class="{disabled: Object.keys(adventurers).length <= 0}"
@click="dismissAdventurer()"
>
</span>
</div>
</div>
<div v-else>
<span>Noone applied as of now. Check back later!</span>
</div>
</div>
</section>
<AdventurerRecruitment
:guild="guild"
:adventurers-for-hire="adventurersForHire"
@hireAdventurer="$emit('hireAdventurer', $event)"
@dismissAdventurer="$emit('dismissAdventurer', $event)"
/>
<section class="collection panel pinned-paper">
<h1>
Recruited adventurers ({{ Object.keys(adventurers).length }} / {{ guild.adventurerCapacity.getAdventurerCapacity() }})
Recruited adventurers ({{ Object.keys(adventurers).length }} /
{{ guild.adventurerCapacity.getAdventurerCapacity() }})
</h1>
<small>Click an adventurer to see details about them</small>
<div class="adventurers">
@@ -61,14 +40,13 @@ import AdventurerTile from "@/components/AdventurerTile.vue";
import type {Adventurer} from "@/classes/Adventurer";
import type {Guild} from "@/classes/Guild";
import AdventurerDetails from "@/components/AdventurerDetails.vue";
import AdventurerRecruitment from "@/components/AdventurerRecruitment.vue";
export default defineComponent({
name: "RecruitView",
components: {AdventurerDetails, AdventurerTile},
name: "AdventurerView",
components: {AdventurerDetails, AdventurerTile, AdventurerRecruitment},
data: () => {
return {
currentlyForHire: null as Adventurer | null,
adventurersForHire: [] as Array<Adventurer>,
selectedAdventurer: null as Adventurer | null,
}
},
@@ -81,27 +59,14 @@ export default defineComponent({
type: Object as PropType<{ [key: string]: Adventurer }>,
required: true,
},
adventurerForHire: {
type: Object as PropType<Adventurer | null>,
adventurersForHire: {
type: Object as PropType<{ [key: string]: Adventurer }>,
default() {
return null;
return {};
}
},
},
methods: {
hireAdventurer(): void {
if (Object.keys(this.adventurers).length >= this.guild.adventurerCapacity.getAdventurerCapacity()) return;
this.$emit("recruitActionTaken", this.adventurerForHire);
},
dismissAdventurer() {
if (Object.keys(this.adventurers).length <= 0) return;
this.$emit("recruitActionTaken", null);
}
},
async mounted() {
},
emits: ["recruitActionTaken"]
emits: ["hireAdventurer", "dismissAdventurer"],
});
</script>