Compare commits

..

2 Commits

Author SHA1 Message Date
YouHaveTrouble c26c425c6d update news 2024-08-23 23:01:07 +02:00
YouHaveTrouble 423444a139 configure vite plugin for pwa handling 2023-09-24 23:56:10 +02:00
10 changed files with 183 additions and 172 deletions
-23
View File
@@ -1,23 +0,0 @@
# 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 @@
Almost complete rewrite coming soon. Probably. Maybe. Not sure yet.
Major rewrite possibly, probably soon!
+1
View File
@@ -26,6 +26,7 @@
"npm-run-all": "^4.1.5",
"typescript": "~5.1.6",
"vite": "4.4.9",
"vite-plugin-pwa": "^0.16.5",
"vue-tsc": "^1.8.3"
}
}
+75 -53
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 {
guild: Guild;
adventurers: { [key: string]: Adventurer };
missives: Array<Quest>;
missives: { [key: string]: { [key: string]: Quest } };
lastQuestGot: { [key: string]: null | number };
lastRecruitAction: null | number;
adventurerForHireId: string | null;
@@ -16,7 +16,7 @@ export class GameData {
) {
this.guild = data.guild ?? new Guild(1, 0);
this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer };
this.missives = data.missives ?? [] as Array<Quest>;
this.missives = data.missives ?? {} as { [key: string]: { [key: string]: Quest } };
this.lastQuestGot = data.lastQuestGot ?? {} as { [key: string]: null | number };
this.lastRecruitAction = data.lastRecruitAction ?? null;
this.adventurerForHireId = data.adventurerForHireId ?? null;
+1 -12
View File
@@ -7,22 +7,12 @@ export class Quest {
title: string;
text: string;
adventurers: Array<Adventurer>;
maxAdventurers: number;
progressPoints: number;
maxProgress: number;
expReward: number;
goldReward: number;
constructor(
id: string,
rank: QuestRank,
title: string,
text: string,
maxProgress: number,
expReward: number,
goldReward: number,
maxAdventurers: number = 1
) {
constructor(id: string, rank: QuestRank, title: string, text: string, maxProgress: number, expReward: number, goldReward: number) {
this.id = id;
this.rank = rank;
this.title = title;
@@ -32,7 +22,6 @@ export class Quest {
this.goldReward = goldReward;
this.progressPoints = 0;
this.adventurers = [];
this.maxAdventurers = maxAdventurers;
}
getPercentProgress(): number {
+7 -11
View File
@@ -59,31 +59,27 @@ h1 {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
justify-content: start;
align-items: stretch;
gap: 1rem;
padding-block: 0.5rem;
padding-inline: 5rem;
padding-inline: 40%;
overflow-x: auto;
scroll-snap-type: x mandatory;
width: 100vw;
width: max-content;
max-width: 100%;
}
@media(min-width: 800px) {
.missives-wrapper {
padding-inline: 1rem;
max-width: 100vw;
overflow-x: hidden;
}
.missives {
display: grid;
justify-content: center;
flex-wrap: wrap;
overflow-x: inherit;
padding-inline: 0;
max-width: 1200px;
grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
grid-auto-rows: auto;
gap: 1rem;
}
}
</style>
+6 -22
View File
@@ -12,7 +12,6 @@
<div class="drink-stain" v-if="drinkStain.exists">
<DrinkStain/>
</div>
<div class="rank">{{missive.rank}}</div>
<h2>{{ missive.title }}</h2>
<p>{{ missive.text }}</p>
<div class="slots">
@@ -37,7 +36,7 @@
</div>
<div class="progressWrap">
<span class="progress"></span>
<span class="percentage">{{ `${progressPercentage.toFixed(2)}%` }}</span>
<span class="percentage">{{ progressPercentage }}</span>
</div>
<h3>Rewards</h3>
<div class="rewards">
@@ -59,11 +58,6 @@ import Parchment from "@/components/misc/Parchment.vue";
export default defineComponent({
name: "QuestMissive",
components: {Parchment, WaterStain, DrinkStain, AdventurerComponent},
computed: {
progressPercentageValue(): string {
return `${this.missive.progressPoints / this.missive.maxProgress * 100}%`;
},
},
props: {
missive: {
type: Object as PropType<Quest | any>,
@@ -79,7 +73,7 @@ export default defineComponent({
},
data: () => {
return {
progressPercentage: 0,
progressPercentage: "0%",
stain: false,
drinkStain: {
exists: false,
@@ -91,7 +85,8 @@ export default defineComponent({
methods: {
updateProgress() {
if (this.missive === undefined) return;
this.progressPercentage = this.missive.progressPoints / this.missive.maxProgress * 100;
const progress = (this.missive.progressPoints / this.missive.maxProgress * 100).toFixed(2);
this.progressPercentage = `${progress}%`;
},
randomNumber(min: number, max: number) {
return Math.random() * (max - min) + min;
@@ -107,7 +102,7 @@ export default defineComponent({
}
},
watch: {
"missive.progressPoints": {
missive: {
handler() {
this.updateProgress();
},
@@ -126,7 +121,6 @@ export default defineComponent({
padding: 0.5rem;
position: relative;
scroll-snap-align: center;
margin: 0 auto;
.parchment {
position: absolute;
@@ -167,7 +161,7 @@ export default defineComponent({
left: 0;
height: 100%;
display: block;
width: v-bind(progressPercentageValue);
width: v-bind(progressPercentage);
background-color: rgba(0, 128, 0, 0.65);
transition: width 250ms linear;
}
@@ -184,16 +178,6 @@ export default defineComponent({
}
}
.rank {
position: absolute;
top: -0.5rem;
left: 0.25rem;
font-size: 3rem;
font-weight: bold;
color: #ab0707;
z-index: -1;
}
.rewards {
display: flex;
flex-direction: row;
+47 -16
View File
@@ -1,18 +1,55 @@
<template>
<section>
<QuestGroup
v-if="guild.level >= 7 && Object.keys(quests.S).length > 0"
:adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints < quest.maxProgress)"
:quests="quests.S"
:finalizeQuest="finalizeQuest"
label="Quests"
v-show="quests.filter(quest => quest.progressPoints < quest.maxProgress).length > 0"
label="Rank S Quests"
/>
<QuestGroup
:finalize-quest="finalizeQuest"
v-if="guild.level >= 6 && Object.keys(quests.A).length > 0"
:adventurers="adventurers"
:quests="quests.filter(quest => quest.progressPoints >= quest.maxProgress)"
label="Completed Quests"
v-show="quests.filter(quest => quest.progressPoints >= quest.maxProgress).length > 0"
:quests="quests.A"
:finalizeQuest="finalizeQuest"
label="Rank A Quests"
/>
<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>
</template>
@@ -39,7 +76,7 @@ export default defineComponent({
required: true,
},
quests: {
type: Object as PropType<Array<Quest>>,
type: Object as PropType<{ [key: string]: Quest }>,
required: true,
},
lastRecruitTime: {
@@ -61,19 +98,13 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
section {
.guild {
display: flex;
flex-direction: column;
justify-content: flex-start;
justify-content: center;
align-items: center;
width: 100%;
padding-bottom: 0.5rem;
}
@media(min-width: 800px) {
section {
flex-direction: column-reverse;
}
}
</style>
+12 -1
View File
@@ -2,10 +2,21 @@ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {VitePWA} from "vite-plugin-pwa";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
plugins: [
vue(),
VitePWA({
registerType: 'prompt',
injectRegister: 'script',
filename: 'service-worker.js',
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,jpeg,svg,json}'],
}
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))