Compare commits

..

1 Commits

Author SHA1 Message Date
CI c07d6ac191 deploy 2025-06-03 05:47:31 +00:00
120 changed files with 116 additions and 9547 deletions
-16
View File
@@ -1,16 +0,0 @@
name: Build Vue
on:
release:
types: [published]
jobs:
build_vue:
runs-on: ubuntu-latest
name: Build Vue
steps:
- uses: actions/checkout@v2
- id: Build-Vue
uses: xRealNeon/VuePagesAction@1.0.1
with:
username: 'YouHaveTrouble'
reponame: 'GuildMaster'
token: ${{ secrets.GITHUB_TOKEN }}
-28
View File
@@ -1,28 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
Symlink
+1
View File
@@ -0,0 +1 @@
index.html
-6
View File
@@ -1,6 +0,0 @@
<h1>Guild Master</h1>
<h2>Adventurer's guild management game</h2>
<p>It's a game where you manage an adventurer's guild. You can hire adventurers, assign them to quests to send them on adventures. </p>
<h3>How to play</h3>
Game is playable on <a href="https://guildmaster.yht.one/">guildmaster.yht.one</a> and is always automatically updated when new release is made.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-21
View File
@@ -1,21 +0,0 @@
/**
* This file is used to import the character portraits to base64 from raw assets
*/
const fs = require('fs');
const characterData = require('./rawAssets/data/adventurers.json');
for (const character of characterData) {
try {
const base64 = base64_encode(`./rawAssets/img/portraits/${character.id}.png`);
character.portrait = "data:image/png;base64,"+base64;
} catch (e) {
console.error(`Error: Didn't find portrait for ${character.id}`);
}
}
fs.writeFileSync('./public/data/adventurers.json', JSON.stringify(characterData, null, 2), "utf-8");
function base64_encode(file) {
return fs.readFileSync(file, "base64");
}
+106
View File
@@ -0,0 +1,106 @@
{
"ranks": {
"A": [
{
"title": "Ogre king",
"text": "Ogres have chosen a new king through democratic vote. They all voted for the strongest ogre."
},
{
"title": "Devilish dungeon",
"text": "New dungeon was discovered. It needs to be mapped and explored so lower rank adventurers can enter."
},
{
"title": "Eater of Worlds",
"text": "A giant worm emerged from the ground and appears to be consuming the ground itself."
}
],
"B": [
{
"title": "Undead horde",
"text": "Due to the spillage of necromancy potion at nearby graveyard we now have an undead army on our doorstep."
},
{
"title": "Runaway prisoner",
"text": "During the last prison guard strike a prisoner managed to escape. Bring them back to their cell."
},
{
"title": "The aristocrats",
"text": "Royalty wants an escort for one of their carriages."
}
],
"C": [
{
"title": "Scratchy, the butcher",
"text": "Scratchy turned evil and is terrorizing its victims. Put a stop to it!"
},
{
"title": "Hobgnoblin subjugation",
"text": "Gnoblins evolved and are back for vengeance."
},
{
"title": "Holy",
"text": "Gnoblins summoned their machine god and it started going haywire on everything around it. Destroy it!"
}
],
"D": [
{
"title": "Caravan escort",
"text": "Escort a merchant caravan."
},
{
"title": "Rare ore",
"text": "Obtain laudanium ore for town's blacksmith."
},
{
"title": "Demonic pests!",
"text": "Clear the fields from cabbage imps."
}
],
"E": [
{
"title": "Gnoblin subjugation",
"text": "Kill 3 gnoblins."
},
{
"title": "Phantom menace",
"text": "Exorcise ghosts out of someone's apartment."
},
{
"title": "Scratchy in peril",
"text": "Get Scratchy the cat from the tree safe onto the ground."
}
],
"F": [
{
"title": "Frog Frenzy",
"text": "Kill 10 demon frogs."
},
{
"title": "Rats!",
"text": "Get rid of the rats from someone's basement."
},
{
"title": "Herb gathering",
"text": "Collect medicinal herbs."
},
{
"title": "Big pile of rubble",
"text": "Tavern collapsed. Again. Help clean up the debris."
}
],
"S": [
{
"title": "The Demon King",
"text": "Demon King has awoken and is a threat to whole existence. Heroes needed."
},
{
"title": "Scratchy, Destruction Incarnate",
"text": "Scratchy was reborn as a machine of pure destruction and needs to be stopped."
},
{
"title": "Jiggly Jungle",
"text": "A jungle south began rapidly expanding and experts think arson is our only option."
}
]
}
}
Vendored
-1
View File
@@ -1 +0,0 @@
/// <reference types="vite/client" />
View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 304 KiB

After

Width:  |  Height:  |  Size: 304 KiB

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

+3 -1
View File
@@ -20,12 +20,14 @@
<meta property="og:description" <meta property="og:description"
content="Guild Master is a browser game where you manage your own adventurer's guild!"/> content="Guild Master is a browser game where you manage your own adventurer's guild!"/>
<meta property="og:image" content="https://guildmaster.yht.one/img/app-icons/icon.png"/> <meta property="og:image" content="https://guildmaster.yht.one/img/app-icons/icon.png"/>
<script type="module" crossorigin src="/assets/index-981baea9.js"></script>
<link rel="stylesheet" href="/assets/index-87987ee1.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<noscript> <noscript>
This is a javascript game. You need to enable javascript for it to work. This is a javascript game. You need to enable javascript for it to work.
</noscript> </noscript>
<script type="module" src="/src/main.ts"></script>
</body> </body>
</html> </html>
-1
View File
@@ -1 +0,0 @@
Major rewrite possibly, probably soon!
-5991
View File
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
{
"name": "adventurers-guild",
"version": "0.13.0",
"private": true,
"scripts": {
"dev": "vite",
"dev-public": "vite --host",
"build": "run-p type-check build-only && cp -r CNAME dist/CNAME",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"gen-character-data": "node characterDataGenerator.js"
},
"dependencies": {
"@vueuse/components": "^9.13.0",
"sass": "^1.66.1",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@types/node": "^18.17.6",
"@vitejs/plugin-vue": "^4.3.1",
"@vue/tsconfig": "^0.4.0",
"eslint": "^8.47.0",
"eslint-plugin-vue": "^9.17.0",
"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"
}
}
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "Ogre king",
"text": "Ogres have chosen a new king through democratic vote. They all voted for the strongest ogre."
},
{
"title": "Devilish dungeon",
"text": "New dungeon was discovered. It needs to be mapped and explored so lower rank adventurers can enter."
},
{
"title": "Eater of Worlds",
"text": "A giant worm emerged from the ground and appears to be consuming the ground itself."
}
]
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "Undead horde",
"text": "Due to the spillage of necromancy potion at nearby graveyard we now have an undead army on our doorstep."
},
{
"title": "Runaway prisoner",
"text": "During the last prison guard strike a prisoner managed to escape. Bring them back to their cell."
},
{
"title": "The aristocrats",
"text": "Royalty wants an escort for one of their carriages."
}
]
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "Scratchy, the butcher",
"text": "Scratchy turned evil and is terrorizing its victims. Put a stop to it!"
},
{
"title": "Hobgnoblin subjegation",
"text": "Gnoblins evolved and are back for vengeance."
},
{
"title": "Holy",
"text": "Gnoblins summoned their machine god and it started going haywire on everything around it. Destroy it!"
}
]
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "Caravan escort",
"text": "Escort a merchant caravan."
},
{
"title": "Rare ore",
"text": "Obtain laudanium ore for town's blacksmith."
},
{
"title": "Demonic pests!",
"text": "Clear the fields from cabbage imps."
}
]
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "Gnoblin subjegation",
"text": "Kill 3 gnoblins."
},
{
"title": "Phantom menace",
"text": "Exorcise ghosts out of someone's apartment."
},
{
"title": "Scratchy in peril",
"text": "Get Scratchy the cat from the tree safe onto the ground."
}
]
-18
View File
@@ -1,18 +0,0 @@
[
{
"title": "Frog Frenzy",
"text": "Kill 10 demon frogs."
},
{
"title": "Rats!",
"text": "Get rid of the rats from someone's basement."
},
{
"title": "Herb gathering",
"text": "Collect medicinal herbs."
},
{
"title": "Big pile of rubble",
"text": "Tavern collapsed. Again. Help clean up the debris."
}
]
-14
View File
@@ -1,14 +0,0 @@
[
{
"title": "The Demon King",
"text": "Demon King has awoken and is a threat to whole existence. Heroes needed."
},
{
"title": "Scratchy, Destruction Incarnate",
"text": "Scratchy was reborn as a machine of pure destruction and needs to be stopped."
},
{
"title": "Jiggly Jungle",
"text": "A jungle south began rapidly expanding and experts think arson is our only option."
}
]
-102
View File
@@ -1,102 +0,0 @@
[
{
"id": "aldek",
"name": "Aldek",
"attackExponent": 1.1
},
{
"id": "aria",
"name": "Aria",
"attackExponent": 1.1
},
{
"id": "burnett",
"name": "Burnett",
"attackExponent": 1.1
},
{
"id": "charlotte",
"name": "Charlotte",
"attackExponent": 1.1
},
{
"id": "ella",
"name": "Ella",
"attackExponent": 1.1
},
{
"id": "elyza",
"name": "Elyza",
"attackExponent": 1.1
},
{
"id": "emille",
"name": "Emille",
"attackExponent": 1.1
},
{
"id": "garret",
"name": "Garret",
"attackExponent": 1.1
},
{
"id": "gryza",
"name": "Gryza",
"attackExponent": 1.1
},
{
"id": "lestat",
"name": "Lestat",
"attackExponent": 1.1
},
{
"id": "lydia",
"name": "Lydia",
"attackExponent": 1.1
},
{
"id": "noor",
"name": "Noor",
"attackExponent": 1.1
},
{
"id": "noron",
"name": "Noron",
"attackExponent": 1.1
},
{
"id": "oola",
"name": "Oola",
"attackExponent": 1.1
},
{
"id": "owen",
"name": "Owen",
"attackExponent": 1.1
},
{
"id": "ryslette",
"name": "Ryslette",
"attackExponent": 1.1
},
{
"id": "sally",
"name": "Sally",
"attackExponent": 1.1
},
{
"id": "tovu",
"name": "Tovu",
"attackExponent": 1.1
},
{
"id": "wrydio",
"name": "Wrydio",
"attackExponent": 1.1
},
{
"id": "xarya",
"name": "Xarya",
"attackExponent": 1.1
}
]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="800px" height="800px" viewBox="0 0 569.613 569.614"
xml:space="preserve">
<g>
<g>
<path d="M371.49,563.638l113.052-65.854c5.26-3.063,9.088-8.094,10.64-13.975c1.555-5.888,0.701-12.148-2.359-17.405
l-30.769-52.807c4.789-6.524,9.083-13.115,12.972-19.918c3.893-6.799,7.405-13.84,10.606-21.275l61.114-0.221
c6.086-0.021,11.915-2.464,16.202-6.781c4.287-4.32,6.687-10.165,6.665-16.255l-0.48-130.833
c-0.024-6.089-2.464-11.919-6.784-16.206c-4.299-4.269-10.113-6.662-16.166-6.662c-0.03,0-0.062,0-0.089,0l-61.182,0.242
c-6.444-14.462-14.428-28.14-23.871-40.913l30.417-53.143c6.294-11.001,2.481-25.025-8.52-31.316L369.403,5.335
c-5.281-3.023-11.545-3.822-17.424-2.231c-5.872,1.598-10.872,5.462-13.892,10.747L307.665,67
c-15.766-1.662-31.653-1.613-47.363,0.144l-30.796-52.892c-3.063-5.263-8.094-9.091-13.975-10.646
c-5.884-1.551-12.148-0.704-17.408,2.359L85.068,71.823c-10.949,6.38-14.657,20.429-8.28,31.38l30.765,52.831
c-4.761,6.484-9.048,13.076-12.953,19.899c-3.904,6.824-7.417,13.855-10.6,21.255l-61.139,0.235
C10.187,197.472-0.046,207.785,0,220.456L0.48,351.29c0.024,6.086,2.463,11.919,6.784,16.206
c4.299,4.269,10.11,6.661,16.166,6.661c0.028,0,0.058,0,0.086,0l61.203-0.229c6.432,14.452,14.413,28.131,23.868,40.915
l-30.413,53.141c-3.023,5.284-3.825,11.548-2.231,17.423c1.597,5.872,5.462,10.872,10.747,13.896l113.535,64.977
c3.596,2.056,7.513,3.032,11.38,3.032c7.962,0,15.701-4.146,19.942-11.552l30.417-53.149c15.799,1.671,31.684,1.619,47.348-0.144
l30.799,52.89c3.066,5.26,8.094,9.088,13.978,10.643C359.967,567.552,366.23,566.705,371.49,563.638z M341.129,465.911
c-4.902-8.418-14.599-12.815-24.137-10.994c-20.588,3.935-42.174,3.999-63.128,0.202c-9.572-1.735-19.184,2.741-24.015,11.181
l-26.748,46.745l-73.694-42.18l26.75-46.741c4.832-8.439,3.819-19.006-2.521-26.371c-13.978-16.239-24.685-34.594-31.818-54.554
c-3.265-9.131-11.918-15.227-21.61-15.227c-0.027,0-0.058,0-0.085,0l-53.825,0.199l-0.315-84.937l53.819-0.205
c9.722-0.04,18.366-6.197,21.576-15.374c3.69-10.557,7.962-20.019,13.06-28.917c5.101-8.914,11.089-17.387,18.311-25.897
c6.294-7.417,7.225-17.993,2.334-26.396l-27.081-46.509l73.385-42.754l27.078,46.497c4.893,8.4,14.544,12.821,24.095,11.004
c20.716-3.911,42.317-3.978,63.189-0.19c9.557,1.753,19.189-2.742,24.019-11.178l26.753-46.744l73.697,42.179l-26.753,46.742
c-4.826,8.437-3.816,19,2.521,26.368c13.956,16.221,24.669,34.587,31.842,54.59c3.271,9.119,11.919,15.202,21.604,15.202
c0.031,0,0.062,0,0.092,0l53.789-0.214l0.315,84.927l-53.783,0.192c-9.712,0.037-18.351,6.182-21.569,15.347
c-3.746,10.654-8.023,20.131-13.082,28.975c-5.064,8.847-11.067,17.338-18.356,25.958c-6.271,7.418-7.194,17.978-2.305,26.368
l27.078,46.472l-73.391,42.749L341.129,465.911z"/>
<path d="M392.531,346.458c16.472-28.773,20.746-62.24,12.047-94.232s-29.342-58.685-58.115-75.151
c-18.761-10.74-40.05-16.417-61.562-16.417c-44.446,0-85.762,23.944-107.822,62.485c-33.994,59.404-13.327,135.39,46.071,169.386
c18.764,10.737,40.052,16.411,61.564,16.411C329.158,408.943,370.475,385.001,392.531,346.458z M352.696,323.658
c-13.902,24.293-39.955,39.385-67.985,39.385c-13.528,0-26.934-3.58-38.764-10.349c-37.433-21.426-50.456-69.312-29.033-106.751
c13.905-24.291,39.958-39.385,67.987-39.385c13.528,0,26.932,3.58,38.762,10.355c18.136,10.379,31.142,27.197,36.628,47.359
C365.771,284.435,363.075,305.524,352.696,323.658z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

-1
View File
@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Discord</title><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="none"/>
<path d="M12,2A10,10,0,0,0,8.84,21.5c.5.08.66-.23.66-.5V19.31C6.73,19.91,6.14,18,6.14,18A2.69,2.69,0,0,0,5,16.5c-.91-.62.07-.6.07-.6a2.1,2.1,0,0,1,1.53,1,2.15,2.15,0,0,0,2.91.83,2.16,2.16,0,0,1,.63-1.34C8,16.17,5.62,15.31,5.62,11.5a3.87,3.87,0,0,1,1-2.71,3.58,3.58,0,0,1,.1-2.64s.84-.27,2.75,1a9.63,9.63,0,0,1,5,0c1.91-1.29,2.75-1,2.75-1a3.58,3.58,0,0,1,.1,2.64,3.87,3.87,0,0,1,1,2.71c0,3.82-2.34,4.66-4.57,4.91a2.39,2.39,0,0,1,.69,1.85V21c0,.27.16.59.67.5A10,10,0,0,0,12,2Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1018 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

-538
View File
File diff suppressed because one or more lines are too long
-131
View File
@@ -1,131 +0,0 @@
import {Guild} from "@/classes/Guild";
import {Adventurer} from "@/classes/Adventurer";
import {Quest} from "@/classes/Quest";
import {getFromString, QuestRank} from "@/classes/QuestRank";
export class GameData {
guild: Guild;
adventurers: { [key: string]: Adventurer };
missives: { [key: string]: { [key: string]: Quest } };
lastQuestGot: { [key: string]: null | number };
lastRecruitAction: null | number;
adventurerForHireId: string | null;
constructor(
data: any,
) {
this.guild = data.guild ?? new Guild(1, 0);
this.adventurers = data.adventurers ?? {} as { [key: string]: Adventurer };
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;
}
}
/**
* Save the game to local storage
*/
export function saveGame(
data: GameData
): void {
console.debug("Saving game...");
const adventurers = {} as { [key: string]: any };
for (const adventurerId in data.adventurers) {
const adventurer: {[key: string]: any} = JSON.parse(JSON.stringify(data.adventurers[adventurerId]));
delete adventurer.portrait;
adventurers[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,
}));
}
export function loadGame(): GameData | null {
const savedGame = window.localStorage.getItem("savedGame");
if (!savedGame) return null;
const parsedGame = JSON.parse(savedGame);
console.debug("Loading game...");
return new GameData(parsedGame);
}
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
);
}
}
return quests;
}
export async function loadAdventurersForHire(): 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: Array<Adventurer> = [];
for (const adventurer of adventurerData) {
adventurers.push(new Adventurer(
adventurer.id,
adventurer.name,
adventurer.portrait,
adventurer.attackExponent,
adventurer.level,
adventurer.exp,
));
}
return adventurers;
}
export function removeAlreadyHiredAdventurers(
adventurers: Array<Adventurer>,
adventurersHired: { [key: string]: Adventurer }
): Array<Adventurer> {
const adventurersForHire: Array<Adventurer> = [];
for (const adventurer of adventurers) {
if (adventurersHired[adventurer.id]) continue;
adventurersForHire.push(adventurer);
}
return adventurersForHire;
}
File diff suppressed because one or more lines are too long
-92
View File
@@ -1,92 +0,0 @@
export class Adventurer {
id: string;
name: string;
portrait: string;
level: number;
exp: number;
attackExponent: number;
prestige: number;
busy: boolean;
constructor(
id: string,
name: string,
portrait: string,
attackExponent: number,
level: number = 1,
exp: number = 0,
prestige: number = 0
) {
this.id = id;
this.name = name;
this.portrait = portrait;
this.attackExponent = attackExponent;
this.level = level;
this.exp = exp;
this.prestige = prestige;
this.busy = false;
}
levelUp(): void {
this.exp = 0;
this.level += 1;
}
prestigeUp(): void {
this.level = 1;
this.exp = 0;
this.prestige += 1;
}
canLevelUp(): boolean {
if (this.level >= this.getMaxLevel()) return false;
return this.exp >= this.getNextLevelExpRequirement();
}
canPrestigeUp(): boolean {
if (this.busy) return false;
if (this.level < getMaxLevelForPrestige(this.prestige)) return false;
return this.prestige < 5
}
getNextLevelExpRequirement(): number {
return Math.max(1, Math.floor((3 * Math.pow(1.2, this.level - 1)) * Math.pow(1.025, this.level - 1)));
}
/**
* Returns the percentage of exp to the next level
*/
getExpPercentage(): number {
return (this.exp / this.getNextLevelExpRequirement()) * 100;
}
addExp(exp: number): void {
if (this.isMaxLevel()) return;
this.exp += exp;
if (this.canLevelUp()) {
this.levelUp();
}
}
getAttack(): number {
const scalingFactor = Math.pow(1.05, this.level - 1);
return (2 * scalingFactor) * Math.pow(this.attackExponent, this.level - 1);
}
getDPS(): number {
return this.getAttack() * 4;
}
getMaxLevel(): number {
return getMaxLevelForPrestige(this.prestige);
}
isMaxLevel(): boolean {
return this.level >= this.getMaxLevel();
}
}
function getMaxLevelForPrestige(prestige: number): number {
return 25 + (prestige * 5);
}
-68
View File
@@ -1,68 +0,0 @@
import type {GuildUpgrade} from "@/classes/GuildUpgrade";
import AdventurerCapacityUpgrade from "@/classes/guildUpgrades/AdventurerCapacityUpgrade";
import {formatGold} from "@/classes/NumberMagic";
import QuestExpUpgrade from "@/classes/guildUpgrades/QuestExpUpgrade";
import QuestGoldUpgrade from "@/classes/guildUpgrades/QuestGoldUpgrade";
import AutoFinishQuestsUpgrade from "@/classes/guildUpgrades/AutoFinishQuestsUpgrade";
const MAX_LEVEL: number = 8;
export class Guild {
gold: number;
level: number;
displayUpgradeCost: number|string;
upgradeCost: number|null = null;
adventurerCapacity: AdventurerCapacityUpgrade;
expModifier: QuestExpUpgrade;
goldModifier: QuestGoldUpgrade;
autoFinishQuestsUpgrade: AutoFinishQuestsUpgrade;
constructor(level: number, gold: number, upgrades: {[index:string]: GuildUpgrade} = {}) {
this.gold = gold;
this.level = level;
const rawDisplayUpgradeCost = this.getUpgradeCost();
this.displayUpgradeCost = rawDisplayUpgradeCost ? formatGold(rawDisplayUpgradeCost) : "Max level";
this.upgradeCost = this.getUpgradeCost();
this.adventurerCapacity = upgrades.adventurerCapacity as AdventurerCapacityUpgrade ?? new AdventurerCapacityUpgrade();
this.expModifier = upgrades.expModifier as QuestExpUpgrade ?? new QuestExpUpgrade();
this.goldModifier = upgrades.goldModifier as QuestGoldUpgrade ?? new QuestGoldUpgrade();
this.autoFinishQuestsUpgrade = upgrades.autoFinishQuestsUpgrade as AutoFinishQuestsUpgrade ?? new AutoFinishQuestsUpgrade();
}
upgrade(): void {
const cost = this.getUpgradeCost();
if (cost === null) return;
if (this.gold < cost) return;
this.gold -= cost;
this.level += 1;
if (this.level >= MAX_LEVEL) {
this.displayUpgradeCost = "Max level";
this.upgradeCost = null;
} else {
const newCost = this.getUpgradeCost();
if (newCost === null) return;
this.displayUpgradeCost = formatGold(newCost);
this.upgradeCost = newCost;
}
}
getUpgradeCost(): number|null {
return upgradeCosts[this.level] ?? null;
}
isMaxLevel(): boolean {
return this.level >= MAX_LEVEL;
}
}
const upgradeCosts = {
"1": 1000,
"2": 2500,
"3": 5000,
"4": 10000,
"5": 25000,
"6": 100000,
"7": 750000,
} as {[index:string]: number}
-7
View File
@@ -1,7 +0,0 @@
export class GuildUpgrade {
level: number = 1;
nextLevelCost: number | null = null;
guildLevelRequirement: number = 1;
}
-7
View File
@@ -1,7 +0,0 @@
export default interface MaxLevellable {
maxLevel: number;
isMaxLevel(): boolean;
}
-21
View File
@@ -1,21 +0,0 @@
const goldFormatter = new Intl.NumberFormat('en-US', {
maximumFractionDigits: 3,
// @ts-ignore - typescript doesn't know about this option for some godforsaken reason
notation: "compact",
useGrouping: true,
});
const damageFormatter = new Intl.NumberFormat('en-US', {
maximumFractionDigits: 2,
// @ts-ignore - typescript doesn't know about this option for some godforsaken reason
notation: "compact",
});
export function formatGold(number: number | null): string {
if (number === null) return "";
return goldFormatter.format(number);
}
export function formatDamage(number: number): string {
return damageFormatter.format(number);
}
-86
View File
@@ -1,86 +0,0 @@
import type {Adventurer} from "@/classes/Adventurer";
import {QuestRank} from "@/classes/QuestRank";
export class Quest {
id: string;
rank: QuestRank;
title: string;
text: string;
adventurers: Array<Adventurer>;
progressPoints: number;
maxProgress: number;
expReward: number;
goldReward: number;
constructor(id: string, rank: QuestRank, title: string, text: string, maxProgress: number, expReward: number, goldReward: number) {
this.id = id;
this.rank = rank;
this.title = title;
this.text = text;
this.maxProgress = maxProgress;
this.expReward = expReward;
this.goldReward = goldReward;
this.progressPoints = 0;
this.adventurers = [];
}
getPercentProgress(): number {
return Math.round(this.progressPoints / this.maxProgress * 100);
}
}
/**
* Generate rewards for a quest and return it
* @param quest
* @param expModifier - multiplification modifier for the exp reward
* @param goldModifier - multiplification modifier for the gold reward
*/
export function getQuestWithRewards(quest: Quest, expModifier: number = 1, goldModifier: number = 1) {
let maxProgress = 1;
switch (quest.rank) {
case QuestRank.S:
// at level 30 adventurers have ~6513 dps, this will take 30 seconds on level 30
maxProgress = 195390;
break;
case QuestRank.A:
// at level 25 adventurers have ~2051 dps, this will take 15 seconds on level 25
maxProgress = 30770;
break;
case QuestRank.B:
// at level 20 adventurers have ~645 dps, this will take 15 seconds on level 20
maxProgress = 9690;
break;
case QuestRank.C:
// at level 15 adventurers have ~203 dps, this will take 15 seconds on level 15
maxProgress = 3045;
break;
case QuestRank.D:
// at level 10 adventurers have ~64 dps, this will take 15 seconds on level 10
maxProgress = 960;
break;
case QuestRank.E:
// at level 5 adventurers have ~20 dps, this will take 15 seconds on level 5
maxProgress = 300;
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 * goldModifier);
let expReward = Math.floor((Math.floor(maxProgress/120) - maxProgress/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);
}
function randomNumberBetween(min: number, max: number) {
return Math.random() * (max - min) + min;
}
-13
View File
@@ -1,13 +0,0 @@
export enum QuestRank {
S = "S",
A = "A",
B = "B",
C = "C",
D = "D",
E = "E",
F = "F",
}
export function getFromString(string: keyof typeof QuestRank): QuestRank {
return QuestRank[string];
}
-13
View File
@@ -1,13 +0,0 @@
import type {Adventurer} from "@/classes/Adventurer";
/**
* Get a random adventurer from the pool
* @param adventurerPool
* @returns {Adventurer|null} null if the pool is empty
*/
export function getNewAdventurerForHire(adventurerPool: Array<Adventurer>): Adventurer|null {
if (adventurerPool.length <= 0) return null;
const randomId = adventurerPool.length * Math.random() << 0;
return adventurerPool[randomId];
}
@@ -1,27 +0,0 @@
import {GuildUpgrade} from "@/classes/GuildUpgrade";
export default class AdventurerCapacityUpgrade extends GuildUpgrade {
constructor(level: number = 1) {
super();
this.level = level;
this.nextLevelCost = this.getCostForLevel(this.level);
this.guildLevelRequirement = 1;
}
upgrade(): void {
this.level += 1;
this.nextLevelCost = this.getCostForLevel(this.level);
}
getCostForLevel(level: number): number {
if (level === 1) return 1500;
return Math.floor(1500 * (level * 4));
}
/**
* Returns the number of adventurers the guild can have
*/
getAdventurerCapacity(): number {
return 1 + this.level ;
}
}
@@ -1,70 +0,0 @@
import {GuildUpgrade} from "@/classes/GuildUpgrade";
import type MaxLevellable from "@/classes/MaxLevellable";
import {QuestRank} from "@/classes/QuestRank";
export default class AutoFinishQuestsUpgrade extends GuildUpgrade implements MaxLevellable {
maxLevel: number;
constructor(level: number = 1) {
super();
this.level = level;
this.nextLevelCost = this.getCostForLevel(this.level);
this.guildLevelRequirement = 7;
this.maxLevel = 8;
}
upgrade(): void {
this.level += 1;
this.nextLevelCost = this.getCostForLevel(this.level);
}
getCostForLevel(level: number): number {
switch (level) {
case 1:
return 25000;
case 2:
return 50000;
case 3:
return 75000;
case 4:
return 150000;
case 5:
return 275000;
case 6:
return 750000;
case 7:
return 1500000;
case 8:
return 2500000;
default:
return 0;
}
}
isMaxLevel(): boolean {
return this.level >= this.maxLevel;
}
getRanksToAutoFinishQuestsIn(): Array<QuestRank> {
switch (this.level) {
case 1:
default:
return [];
case 2:
return [QuestRank.F];
case 3:
return [QuestRank.F, QuestRank.E];
case 4:
return [QuestRank.F, QuestRank.E, QuestRank.D];
case 5:
return [QuestRank.F, QuestRank.E, QuestRank.D, QuestRank.C];
case 6:
return [QuestRank.F, QuestRank.E, QuestRank.D, QuestRank.C, QuestRank.B];
case 7:
return [QuestRank.F, QuestRank.E, QuestRank.D, QuestRank.C, QuestRank.B, QuestRank.A];
case 8:
return [QuestRank.F, QuestRank.E, QuestRank.D, QuestRank.C, QuestRank.B, QuestRank.A, QuestRank.S];
}
}
}
@@ -1,24 +0,0 @@
import {GuildUpgrade} from "@/classes/GuildUpgrade";
export default class QuestExpUpgrade extends GuildUpgrade {
constructor(level: number = 1) {
super();
this.level = level;
this.nextLevelCost = this.getCostForLevel(this.level);
this.guildLevelRequirement = 8;
}
upgrade(): void {
this.level += 1;
this.nextLevelCost = this.getCostForLevel(this.level);
}
getCostForLevel(level: number): number {
if (level === 1) return 1000000;
return Math.floor(1000000 * (level * 1.05));
}
getModifier(): number {
return 1 + (this.level * 0.1);
}
}
@@ -1,24 +0,0 @@
import {GuildUpgrade} from "@/classes/GuildUpgrade";
export default class QuestGoldUpgrade extends GuildUpgrade {
constructor(level: number = 1) {
super();
this.level = level;
this.nextLevelCost = this.getCostForLevel(this.level);
this.guildLevelRequirement = 8;
}
upgrade(): void {
this.level += 1;
this.nextLevelCost = this.getCostForLevel(this.level);
}
getCostForLevel(level: number): number {
if (level === 1) return 1000000;
return Math.floor(1000000 * (level * 1.05));
}
getModifier(): number {
return 1 + (this.level * 0.1);
}
}
File diff suppressed because one or more lines are too long
-53
View File
@@ -1,53 +0,0 @@
<template>
<div class="slots">
<button class="slot" v-for="adventurer in adventurers" :key="adventurer.id">
<AdventurerMiniComponent
:adventurer="currentAdventurer"
:all-adventurers="adventurers"
/>
</button>
</div>
</template>
<script lang="ts">
import {defineComponent, type PropType} from "vue";
import AdventurerMiniComponent from "@/components/AdventurerMiniComponent.vue";
import type {Adventurer} from "@/classes/Adventurer";
export default defineComponent({
name: "AdventurerList",
components: {AdventurerMiniComponent},
data: () => ({
currentAdventurer: null as Adventurer | null
}),
props: {
adventurers: {
type: Object as PropType<{ [key: string]: Adventurer }>,
default() {
return {} as { [key: string]: Adventurer };
},
},
},
})
</script>
<style lang="scss" scoped>
.slots {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
.slot {
padding: 0;
width: 5rem;
height: 5rem;
border: 2px solid #000;
background-color: rgba(0, 0, 0, 0.2);
cursor: pointer;
border-radius: 0.2rem;
}
}
</style>
-136
View File
@@ -1,136 +0,0 @@
<script setup lang="ts">
import { vOnClickOutside } from '@vueuse/components'
</script>
<template>
<AdventurerTile
v-if="adventurer"
:adventurer="adventurer"
@click="() => {
$emit('freeAdventurer', adventurer.id)
}"
/>
<article
class="select"
v-else
@click="() => {
if (Object.keys(allAdventurers).length <= 0) return;
selection = !selection;
}"
>
<span>+</span>
</article>
<div class="selection" v-if="selection" v-on-click-outside="closeSelect">
<button
class="slot"
v-for="adventurer in allAdventurers"
:key="adventurer.id"
:class="{busy: adventurer.busy}"
@click="() => {
if (adventurer.busy) return;
$emit('hireAdventurer', adventurer.id);
selection = false;
}"
>
<AdventurerTile
:adventurer="adventurer"
/>
</button>
</div>
</template>
<script lang="ts">
import {defineComponent, type PropType} from "vue";
import type {Adventurer} from "@/classes/Adventurer";
import AdventurerTile from "@/components/AdventurerTile.vue";
export default defineComponent({
name: "AdventurerMiniComponent",
components: {AdventurerTile},
emits: [ "freeAdventurer", "hireAdventurer" ],
data: () => {
return {
selection: false,
}
},
props: {
adventurer: {
type: Object as PropType<Adventurer|null|any>,
default() {
return null as Adventurer|null;
},
},
allAdventurers: {
type: Object as PropType<{[key: string]: Adventurer}>,
default() {
return {} as {[key: string]: Adventurer};
},
},
},
methods: {
closeSelect() {
setTimeout(() => {
this.selection = false;
}, 0);
}
}
})
</script>
<style lang="scss" scoped>
.selection {
position: absolute;
bottom: 0;
left: 50%;
width: max-content;
max-width: 17rem;
transform: translateX(-50%) translateY(104%);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.5rem;
background-color: rgba(0,0,0, 0.2);
z-index: 2;
cursor: default;
max-height: 12rem;
overflow-y: auto;
.slot {
width: 5rem;
height: 5rem;
cursor: pointer;
padding: 0;
border-color: #000;
background-color: transparent;
background-blend-mode: darken;
transition: background-color 0.25s linear, filter 0.25s linear;
&.busy {
filter: grayscale(1);
background-color: rgba(0,0,0, 0.6);
&:hover {
cursor: not-allowed;
border-color: #000;
}
}
&:hover {
border-color: #fff;
}
img {
width: 100%;
height: 100%;
}
}
}
.select {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
font-size: 4.5rem;
color: #000;
}
</style>
-83
View File
@@ -1,83 +0,0 @@
<template>
<article
class="adventurer"
:title="adventurer.name + (adventurer.busy ? ' (busy)' : '')"
>
<img :src="adventurer.portrait" :alt="adventurer.name" draggable="false">
<div class="level" :title="adventurer.isMaxLevel() ? 'Max level' : ''">{{ adventurer.level }}<span
v-if="adventurer.isMaxLevel()"></span></div>
<div class="exp"></div>
</article>
</template>
<script lang="ts">
import type {Adventurer} from "@/classes/Adventurer";
import {defineComponent, type PropType} from "vue";
export default defineComponent({
name: "AdventurerTile",
props: {
adventurer: {
type: Object as PropType<Adventurer>,
required: true,
}
},
data: () => ({
expProgress: "0%",
}),
watch: {
adventurer: {
deep: true,
handler: function (adventurer: Adventurer) {
this.expProgress = adventurer.getExpPercentage() + "%";
},
}
},
mounted() {
if (this.adventurer === undefined) return;
this.expProgress = this.adventurer.getExpPercentage() + "%";
}
});
</script>
<style lang="scss" scoped>
.adventurer {
width: 100%;
height: 100%;
overflow: clip;
font-size: 5rem;
line-height: 1;
color: rgba(0, 0, 0, 0.75);
position: relative;
background: rgb(2,0,36);
background: radial-gradient(circle, rgba(2,0,36,1) 0%, rgb(69, 69, 84) 57%, rgb(85, 112, 117) 100%);
.level {
position: absolute;
top: 0;
left: 0;
font-size: 1rem;
min-width: 1rem;
background-color: rgba(0, 0, 0, 0.75);
border-bottom-right-radius: 0.2rem;
padding: 0.1rem;
color: #fff;
}
.exp {
position: absolute;
bottom: 0;
left: 0;
width: v-bind(expProgress);
height: 3.5%;
background-color: rgba(203, 33, 213, 0.75);
transition: width 1s linear;
}
img {
width: 100%;
height: 100%;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More