Compare commits

...

3 Commits

Author SHA1 Message Date
YouHaveTrouble 20567be96d new experimental quest view 2025-05-08 21:08:03 +02:00
YouHaveTrouble 3c79074c4c create GDD for the next iteration of the game 2024-11-19 20:35:55 +01:00
YouHaveTrouble 571dee6cc9 update news 2024-08-23 23:55:24 +02:00
8 changed files with 171 additions and 170 deletions
+23
View File
@@ -0,0 +1,23 @@
# Game Design Document
## 1. Introduction
Guild Master is a game simulating being a fantasy guild master. The player will be able to recruit adventurers,
send them on quests, and manage the guild's resources.
## 2. Gameplay
Player will recruit adventurers and assign then to quests. Adventurers will have different statistics and a passive
ability that will make each character unique. Player will have to manage guild's resources to complete more and more
resource intensive quests and assignments.
## 3. Mechanics
Menus. Lots of menus. Possibly with fancy animations.
## 4. Characters
Set amount of available adventurers. Each with their own inventory and passive ability. Items in the inventory will
boost specific statistics of the character. They will be scaled based on level and the xp curve will be exponential.
## 5. Quests
There will always be a minimum set amount of quests available. Adventurers will have to be assigned to a quest that is
within their level range. Quests will come in different difficulties within the level range.
+1 -1
View File
@@ -1 +1 @@
Looking for artists for assets for this game! Need backgrounds and icons! Join discord for more info! Almost complete rewrite coming soon. Probably. Maybe. Not sure yet.
+82 -104
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -6,7 +6,7 @@ import {getFromString, QuestRank} from "@/classes/QuestRank";
export class GameData { export class GameData {
guild: Guild; guild: Guild;
adventurers: { [key: string]: Adventurer }; adventurers: { [key: string]: Adventurer };
missives: { [key: string]: { [key: string]: Quest } }; missives: Array<Quest>;
lastQuestGot: { [key: string]: null | number }; lastQuestGot: { [key: string]: null | number };
lastRecruitAction: null | number; lastRecruitAction: null | number;
adventurerForHireId: string | null; adventurerForHireId: string | null;
@@ -16,7 +16,7 @@ export class GameData {
) { ) {
this.guild = data.guild ?? new Guild(1, 0); this.guild = data.guild ?? new Guild(1, 0);
this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer }; this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer };
this.missives = data.missives ?? {} as { [key: string]: { [key: string]: Quest } }; this.missives = data.missives ?? [] as Array<Quest>;
this.lastQuestGot = data.lastQuestGot ?? {} as { [key: string]: null | number }; this.lastQuestGot = data.lastQuestGot ?? {} as { [key: string]: null | number };
this.lastRecruitAction = data.lastRecruitAction ?? null; this.lastRecruitAction = data.lastRecruitAction ?? null;
this.adventurerForHireId = data.adventurerForHireId ?? null; this.adventurerForHireId = data.adventurerForHireId ?? null;
+12 -1
View File
@@ -7,12 +7,22 @@ export class Quest {
title: string; title: string;
text: string; text: string;
adventurers: Array<Adventurer>; adventurers: Array<Adventurer>;
maxAdventurers: number;
progressPoints: number; progressPoints: number;
maxProgress: number; maxProgress: number;
expReward: number; expReward: number;
goldReward: number; goldReward: number;
constructor(id: string, rank: QuestRank, title: string, text: string, maxProgress: number, expReward: number, goldReward: number) { constructor(
id: string,
rank: QuestRank,
title: string,
text: string,
maxProgress: number,
expReward: number,
goldReward: number,
maxAdventurers: number = 1
) {
this.id = id; this.id = id;
this.rank = rank; this.rank = rank;
this.title = title; this.title = title;
@@ -22,6 +32,7 @@ export class Quest {
this.goldReward = goldReward; this.goldReward = goldReward;
this.progressPoints = 0; this.progressPoints = 0;
this.adventurers = []; this.adventurers = [];
this.maxAdventurers = maxAdventurers;
} }
getPercentProgress(): number { getPercentProgress(): number {
+11 -7
View File
@@ -59,27 +59,31 @@ h1 {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: start; justify-content: flex-start;
align-items: stretch;
gap: 1rem; gap: 1rem;
padding-block: 0.5rem; padding-block: 0.5rem;
padding-inline: 40%; padding-inline: 5rem;
overflow-x: auto; overflow-x: auto;
scroll-snap-type: x mandatory; scroll-snap-type: x mandatory;
width: max-content; width: 100vw;
max-width: 100%; max-width: 100%;
} }
@media(min-width: 800px) { @media(min-width: 800px) {
.missives-wrapper { .missives-wrapper {
padding-inline: 1rem; padding-inline: 1rem;
max-width: 100vw;
overflow-x: hidden;
} }
.missives { .missives {
justify-content: center; display: grid;
flex-wrap: wrap;
overflow-x: inherit;
padding-inline: 0; padding-inline: 0;
max-width: 1200px;
grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
grid-auto-rows: auto;
gap: 1rem;
} }
} }
</style> </style>
+22 -6
View File
@@ -12,6 +12,7 @@
<div class="drink-stain" v-if="drinkStain.exists"> <div class="drink-stain" v-if="drinkStain.exists">
<DrinkStain/> <DrinkStain/>
</div> </div>
<div class="rank">{{missive.rank}}</div>
<h2>{{ missive.title }}</h2> <h2>{{ missive.title }}</h2>
<p>{{ missive.text }}</p> <p>{{ missive.text }}</p>
<div class="slots"> <div class="slots">
@@ -36,7 +37,7 @@
</div> </div>
<div class="progressWrap"> <div class="progressWrap">
<span class="progress"></span> <span class="progress"></span>
<span class="percentage">{{ progressPercentage }}</span> <span class="percentage">{{ `${progressPercentage.toFixed(2)}%` }}</span>
</div> </div>
<h3>Rewards</h3> <h3>Rewards</h3>
<div class="rewards"> <div class="rewards">
@@ -58,6 +59,11 @@ import Parchment from "@/components/misc/Parchment.vue";
export default defineComponent({ export default defineComponent({
name: "QuestMissive", name: "QuestMissive",
components: {Parchment, WaterStain, DrinkStain, AdventurerComponent}, components: {Parchment, WaterStain, DrinkStain, AdventurerComponent},
computed: {
progressPercentageValue(): string {
return `${this.missive.progressPoints / this.missive.maxProgress * 100}%`;
},
},
props: { props: {
missive: { missive: {
type: Object as PropType<Quest | any>, type: Object as PropType<Quest | any>,
@@ -73,7 +79,7 @@ export default defineComponent({
}, },
data: () => { data: () => {
return { return {
progressPercentage: "0%", progressPercentage: 0,
stain: false, stain: false,
drinkStain: { drinkStain: {
exists: false, exists: false,
@@ -85,8 +91,7 @@ export default defineComponent({
methods: { methods: {
updateProgress() { updateProgress() {
if (this.missive === undefined) return; if (this.missive === undefined) return;
const progress = (this.missive.progressPoints / this.missive.maxProgress * 100).toFixed(2); this.progressPercentage = this.missive.progressPoints / this.missive.maxProgress * 100;
this.progressPercentage = `${progress}%`;
}, },
randomNumber(min: number, max: number) { randomNumber(min: number, max: number) {
return Math.random() * (max - min) + min; return Math.random() * (max - min) + min;
@@ -102,7 +107,7 @@ export default defineComponent({
} }
}, },
watch: { watch: {
missive: { "missive.progressPoints": {
handler() { handler() {
this.updateProgress(); this.updateProgress();
}, },
@@ -121,6 +126,7 @@ export default defineComponent({
padding: 0.5rem; padding: 0.5rem;
position: relative; position: relative;
scroll-snap-align: center; scroll-snap-align: center;
margin: 0 auto;
.parchment { .parchment {
position: absolute; position: absolute;
@@ -161,7 +167,7 @@ export default defineComponent({
left: 0; left: 0;
height: 100%; height: 100%;
display: block; display: block;
width: v-bind(progressPercentage); width: v-bind(progressPercentageValue);
background-color: rgba(0, 128, 0, 0.65); background-color: rgba(0, 128, 0, 0.65);
transition: width 250ms linear; transition: width 250ms linear;
} }
@@ -178,6 +184,16 @@ export default defineComponent({
} }
} }
.rank {
position: absolute;
top: -0.5rem;
left: 0.25rem;
font-size: 3rem;
font-weight: bold;
color: #ab0707;
z-index: -1;
}
.rewards { .rewards {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
+17 -48
View File
@@ -1,55 +1,18 @@
<template> <template>
<section> <section>
<QuestGroup <QuestGroup
v-if="guild.level >= 7 && Object.keys(quests.S).length > 0"
:adventurers="adventurers" :adventurers="adventurers"
:quests="quests.S" :quests="quests.filter(quest => quest.progressPoints < quest.maxProgress)"
:finalizeQuest="finalizeQuest" :finalizeQuest="finalizeQuest"
label="Rank S Quests" label="Quests"
v-show="quests.filter(quest => quest.progressPoints < quest.maxProgress).length > 0"
/> />
<QuestGroup <QuestGroup
v-if="guild.level >= 6 && Object.keys(quests.A).length > 0" :finalize-quest="finalizeQuest"
:adventurers="adventurers" :adventurers="adventurers"
:quests="quests.A" :quests="quests.filter(quest => quest.progressPoints >= quest.maxProgress)"
:finalizeQuest="finalizeQuest" label="Completed Quests"
label="Rank A Quests" v-show="quests.filter(quest => quest.progressPoints >= quest.maxProgress).length > 0"
/>
<QuestGroup
v-if="guild.level >= 5 && Object.keys(quests.B).length > 0"
:adventurers="adventurers"
:quests="quests.B"
:finalizeQuest="finalizeQuest"
label="Rank B Quests"
/>
<QuestGroup
v-if="guild.level >= 4 && Object.keys(quests.C).length > 0"
:adventurers="adventurers"
:quests="quests.C"
:finalizeQuest="finalizeQuest"
label="Rank C Quests"
/>
<QuestGroup
v-if="guild.level >= 3 && Object.keys(quests.D).length > 0"
:adventurers="adventurers"
:quests="quests.D"
:finalizeQuest="finalizeQuest"
label="Rank D Quests"
/>
<QuestGroup
v-if="guild.level >= 2 && Object.keys(quests.E).length > 0"
:adventurers="adventurers"
:quests="quests.E"
:finalizeQuest="finalizeQuest"
label="Rank E Quests"
/>
<QuestGroup
v-if="Object.keys(quests.F).length > 0"
:adventurers="adventurers"
:quests="quests.F"
:finalizeQuest="finalizeQuest"
label="Rank F Quests"
/> />
</section> </section>
</template> </template>
@@ -76,7 +39,7 @@ export default defineComponent({
required: true, required: true,
}, },
quests: { quests: {
type: Object as PropType<{ [key: string]: Quest }>, type: Object as PropType<Array<Quest>>,
required: true, required: true,
}, },
lastRecruitTime: { lastRecruitTime: {
@@ -98,13 +61,19 @@ export default defineComponent({
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.guild { section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-start;
align-items: center; align-items: center;
width: 100%; width: 100%;
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
@media(min-width: 800px) {
section {
flex-direction: column-reverse;
}
}
</style> </style>