Skip to content

Commit

Permalink
Finished appearance tab
Browse files Browse the repository at this point in the history
  • Loading branch information
colecrouter committed Jul 2, 2023
1 parent 0e4e713 commit 5690a07
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 63 deletions.
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.5",
"@types/node": "^18.15.11",
"@types/wicg-file-system-access": "^2020.9.6",
"fast-xml-parser": "^4.2.0",
"idb": "^7.1.1",
"svelte": "^4.0.0",
Expand All @@ -24,4 +25,4 @@
"vite": "^4.2.0"
},
"type": "module"
}
}
50 changes: 49 additions & 1 deletion src/lib/SaveFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,52 @@ class CharacterSelector {
}
}

export const Character = new CharacterSelector(SaveGame);
export const Character = new CharacterSelector(SaveGame);

export const Download = async (save: SaveFile, filename: string) => {
if (!save || !filename) {
console.error('Save or filename is undefined');
return;
}

const res = await fetch('/api/toXML', {
method: 'POST',
body: JSON.stringify(save),
headers: {
'Content-Type': 'application/json',
},
});

if (!res.ok) {
console.error(res);
return;
}

const blob = await res.blob();

// If supported, use file picker
if ('showSaveFilePicker' in window) {
const handle = await window.showSaveFilePicker({
types: [
{
description: 'Stardew Valley Save File',
accept: { 'text/text': [] },
},
],
suggestedName: filename,
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
return;
}

// Otherwise just download the file to downloads
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
a.remove();
};
24 changes: 2 additions & 22 deletions src/routes/(edit)/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { FileName, SaveGame, Character } from '$lib/SaveFile';
import { FileName, SaveGame, Character, Download } from '$lib/SaveFile';
import { get } from 'svelte/store';
import type { LayoutData } from './$types';
import { onDestroy, setContext } from 'svelte';
Expand Down Expand Up @@ -35,27 +35,7 @@
return;
}
const res = await fetch('/api/toXML', {
method: 'POST',
body: JSON.stringify(save),
headers: {
'Content-Type': 'application/json',
},
});
if (!res.ok) {
console.error(res);
return;
}
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
a.remove();
await Download(save, filename);
};
</script>

Expand Down
86 changes: 70 additions & 16 deletions src/routes/(edit)/appearance/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script lang="ts">
import { AccessoryIsTinted } from '$lib/CharacterColors';
import { Character } from '$lib/SaveFile';
import { HexToRGB, RGBToHex } from '$lib/Spritesheet';
import type { Player } from '$types/save/1.5';
import type { Writable } from 'svelte/store';
import Container from '../../Container.svelte';
import Preview from './Preview.svelte';
let character: Player | undefined;
let skinColor: number = 0;
let hairStyle: number = 0;
let shirt: number = 0;
let pants: number = 0;
let acc: number = 0;
Character.character.subscribe((c) => {
Expand All @@ -16,18 +19,20 @@
acc = c.accessory + 2;
});
import { Character } from '$lib/SaveFile';
import type { Player } from '$types/save/1.5';
import Container from '../../Container.svelte';
import Preview from './Preview.svelte';
// Need to rerender when hair/eye color changes, because that doesn't trigger a rerender
// TODO - Find a better way to do this
const rerender = () => {
if (!character) return;
(Character.character as Writable<Player>).set(character);
};
</script>

<Container>
{#if character}
<div class="wrapper">
<div class="editor1">
<Preview isMale={character.isMale} skinColor={character.skinColor} hairStyle={character.hair} acc={character.accessory} />
<div class="gender">
<div class="selector">
<label>
🚹
<input type="radio" name="gender" value="male" checked={character && character.isMale} on:click={() => character && (character.isMale = true)} />
Expand Down Expand Up @@ -72,6 +77,53 @@
<input type="text" bind:value={character.favoriteThing} />
</label>
</div>
<div>
<label>
<small>Animal Preference</small>
<div class="selector">
<label>
🐱
<input type="radio" name="pet" value="cat" checked={character && character.catPerson} on:click={() => character && (character.catPerson = true)} />
</label>
<label>
🐶
<input type="radio" name="pet" value="dog" checked={character && !character.catPerson} on:click={() => character && (character.catPerson = false)} />
</label>
</div>
</label>
</div>
<div>
<label>
<small>Eye Color</small>
<div class="selector">
<input
type="color"
value={RGBToHex(character?.newEyeColor ?? { R: 255, G: 255, B: 255, A: 255, PackedValue: 0 })}
on:change={(e) => {
if (!character) return;
// @ts-expect-error
character.newEyeColor = HexToRGB(e.target.value ?? '#000000');
rerender();
}} />
</div>
</label>
</div>
<div>
<label>
<small>Hair Color</small>
<div class="selector">
<input
type="color"
value={RGBToHex(character?.hairstyleColor ?? { R: 255, G: 255, B: 255, A: 255, PackedValue: 0 })}
on:change={(e) => {
if (!character) return;
// @ts-expect-error
character.hairstyleColor = HexToRGB(e.target.value ?? '#000000');
rerender();
}} />
</div>
</label>
</div>
</div>
</div>
{/if}
Expand All @@ -81,6 +133,7 @@
.wrapper {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 16px;
}
.editor1 {
Expand Down Expand Up @@ -116,18 +169,17 @@
text-align: center;
}
.gender {
.selector {
display: flex;
gap: 8px;
flex-direction: row;
justify-content: center;
width: 100%;
}
.gender input {
.selector input {
appearance: none;
}
.gender label {
.selector label {
border-radius: 4px;
display: flex;
justify-content: center;
Expand All @@ -136,17 +188,19 @@
padding-bottom: 0.1em;
font-size: 1.5em;
cursor: pointer;
/* Beef up the text shadow a little bit, some emojis might blend into the bg too much */
text-shadow: -0.05em 0.05em 0.1em rgba(0, 0, 0, 0.6);
}
.gender label:has(input:checked) {
.selector label:has(input:checked) {
border: solid 3px #d93703;
}
.gender label:has(input:not(:checked)) {
.selector label:has(input:not(:checked)) {
border: solid 3px #00000000;
}
.gender label input {
.selector label input {
position: absolute;
}
Expand Down
8 changes: 2 additions & 6 deletions src/routes/(edit)/character/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@
Golden Walnuts
<input type="number" min="0" max="130" bind:value={save.goldenWalnuts} />
</label>
<label>
Favorite Thing
<input type="text" bind:value={player.favoriteThing} />
</label>
</div>

<h3>Wallet</h3>
Expand Down Expand Up @@ -151,9 +147,9 @@
align-items: center;
}
.stats > label:last-child {
/* .stats > label:last-child {
grid-column: 1 / -1;
}
} */
input[type='number'] {
width: 4em;
Expand Down
36 changes: 19 additions & 17 deletions src/routes/(edit)/inventory/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,24 @@
break;
}
const newItem: Item = {
name: newItemName,
stack: 1,
parentSheetIndex: 'parentSheetIndex' in newItemData ? newItemData.parentSheetIndex : 0,
category: category,
hasBeenInInventory: true,
hasBeenPickedUpByFarmer: true,
DisplayName: newItemData.name,
SpecialVariable: 0, // TODO ?
indexInColorSheet: 0, // TODO
isLostItem: false,
specialItem: false,
tileLocation: { X: 0, Y: 0 },
boundingBox: { X: 0, Y: 0, Width: 64, Height: 64, Location: { X: 0, Y: 0 } },
canBeSetDown: true,
canBeGrabbed: true,
};
let type: string | undefined;
switch (newItemData._type) {
case 'ObjectInformation':
Expand Down Expand Up @@ -159,24 +177,8 @@
break;
}
const newItem: Item = {
name: newItemName,
stack: 1,
parentSheetIndex: 'parentSheetIndex' in newItemData ? newItemData.parentSheetIndex : 0,
category: category,
hasBeenInInventory: true,
hasBeenPickedUpByFarmer: true,
DisplayName: newItemData.name,
SpecialVariable: 0, // TODO ?
indexInColorSheet: 0, // TODO
isLostItem: false,
specialItem: false,
tileLocation: { X: 0, Y: 0 },
canBeSetDown: true,
canBeGrabbed: true,
};
if (type) {
// This is required for the game to recognize the item as the correct type, but isn't part of the XML structureS
// @ts-expect-error
newItem['@_xsi:type'] = type;
}
Expand Down

0 comments on commit 5690a07

Please sign in to comment.