Moved properties from player data to new settings and state objects
This commit is contained in:
parent
bc808098ff
commit
eaf47bb946
25 changed files with 367 additions and 285 deletions
10
src/App.vue
10
src/App.vue
|
@ -11,11 +11,11 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import themes from "./data/themes";
|
||||
import player from "./game/player";
|
||||
import modInfo from "./data/modInfo.json";
|
||||
import { mapState } from "./util/vue";
|
||||
import themes from "./data/themes";
|
||||
import settings from "./game/settings";
|
||||
import "./main.css";
|
||||
import { mapSettings } from "./util/vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App",
|
||||
|
@ -23,9 +23,9 @@ export default defineComponent({
|
|||
return { useHeader: modInfo.useHeader };
|
||||
},
|
||||
computed: {
|
||||
...mapState(["showTPS"]),
|
||||
...mapSettings(["showTPS"]),
|
||||
theme() {
|
||||
return themes[player.theme].variables;
|
||||
return themes[settings.theme].variables;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -178,6 +178,7 @@ import themes from "@/data/themes";
|
|||
import { ProgressDisplay, Shape } from "@/game/enums";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import { BoardNode, BoardNodeAction, NodeLabel, NodeType } from "@/typings/features/board";
|
||||
import { getNodeTypeProperty } from "@/util/features";
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
@ -279,18 +280,18 @@ export default defineComponent({
|
|||
return getNodeTypeProperty(this.nodeType, this.node, "progress") || 0;
|
||||
},
|
||||
backgroundColor(): string {
|
||||
return themes[player.theme].variables["--background"];
|
||||
return themes[settings.theme].variables["--background"];
|
||||
},
|
||||
outlineColor(): string {
|
||||
return (
|
||||
getNodeTypeProperty(this.nodeType, this.node, "outlineColor") ||
|
||||
themes[player.theme].variables["--outline"]
|
||||
themes[settings.theme].variables["--outline"]
|
||||
);
|
||||
},
|
||||
fillColor(): string {
|
||||
return (
|
||||
getNodeTypeProperty(this.nodeType, this.node, "fillColor") ||
|
||||
themes[player.theme].variables["--raised-background"]
|
||||
themes[settings.theme].variables["--raised-background"]
|
||||
);
|
||||
},
|
||||
progressColor(): string {
|
||||
|
@ -299,7 +300,7 @@ export default defineComponent({
|
|||
titleColor(): string {
|
||||
return (
|
||||
getNodeTypeProperty(this.nodeType, this.node, "titleColor") ||
|
||||
themes[player.theme].variables["--foreground"]
|
||||
themes[settings.theme].variables["--foreground"]
|
||||
);
|
||||
},
|
||||
progressDisplay(): ProgressDisplay {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import themes from "@/data/themes";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import { Infobox } from "@/typings/features/infobox";
|
||||
import { coerceComponent, InjectLayerMixin } from "@/util/vue";
|
||||
import { Component, defineComponent } from "vue";
|
||||
|
@ -67,7 +68,7 @@ export default defineComponent({
|
|||
return player.layers[this.layer].infoboxes[this.id];
|
||||
},
|
||||
stacked(): boolean {
|
||||
return themes[player.theme].stackedInfoboxes;
|
||||
return themes[settings.theme].stackedInfoboxes;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<template>
|
||||
<label class="field">
|
||||
<input type="checkbox" class="toggle" :checked="value" @input="handleInput" />
|
||||
<span>{{ title }}</span>
|
||||
<component :is="display" />
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { coerceComponent } from "@/util/vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
// Reference: https://codepen.io/finnhvman/pen/pOeyjE
|
||||
|
@ -16,6 +17,11 @@ export default defineComponent({
|
|||
value: Boolean
|
||||
},
|
||||
emits: ["change"],
|
||||
computed: {
|
||||
display() {
|
||||
return coerceComponent(this.title || "", "span");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleInput(e: InputEvent) {
|
||||
this.$emit("change", (e.target as HTMLInputElement).checked);
|
||||
|
|
|
@ -49,6 +49,7 @@ import modInfo from "@/data/modInfo.json";
|
|||
import themes from "@/data/themes";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import { Subtab } from "@/typings/features/subtab";
|
||||
import { coerceComponent } from "@/util/vue";
|
||||
import { Component, defineComponent } from "vue";
|
||||
|
@ -76,7 +77,7 @@ export default defineComponent({
|
|||
return layers[this.layer].name || this.layer;
|
||||
},
|
||||
floating(): boolean {
|
||||
return themes[player.theme].floatingTabs;
|
||||
return themes[settings.theme].floatingTabs;
|
||||
},
|
||||
style(): Array<Partial<CSSStyleDeclaration> | undefined> {
|
||||
const style = [];
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
import themes from "@/data/themes";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import { Microtab, MicrotabFamily } from "@/typings/features/subtab";
|
||||
import settings from "@/game/settings";
|
||||
import { Microtab } from "@/typings/features/subtab";
|
||||
import { coerceComponent, InjectLayerMixin } from "@/util/vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
|
@ -40,9 +41,9 @@ export default defineComponent({
|
|||
inject: ["tab"],
|
||||
computed: {
|
||||
floating() {
|
||||
return themes[player.theme].floatingTabs;
|
||||
return themes[settings.theme].floatingTabs;
|
||||
},
|
||||
tabFamily(): MicrotabFamily {
|
||||
tabFamily() {
|
||||
return layers[this.layer].microtabs![this.family];
|
||||
},
|
||||
microtabs() {
|
||||
|
@ -61,13 +62,13 @@ export default defineComponent({
|
|||
activeMicrotab() {
|
||||
return this.id != undefined
|
||||
? this.tabFamily.data[this.id]
|
||||
: this.tabFamily.activeMicrotab;
|
||||
: this.tabFamily.activeMicrotab!;
|
||||
},
|
||||
embed() {
|
||||
return this.activeMicrotab!.embedLayer;
|
||||
},
|
||||
display() {
|
||||
return this.activeMicrotab!.display && coerceComponent(this.activeMicrotab!.display!);
|
||||
return this.activeMicrotab!.display && coerceComponent(this.activeMicrotab!.display);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -46,8 +46,9 @@
|
|||
<script lang="ts">
|
||||
import modInfo from "@/data/modInfo.json";
|
||||
import player from "@/game/player";
|
||||
import state from "@/game/state";
|
||||
import Decimal, { format } from "@/util/bignum";
|
||||
import { mapState } from "@/util/vue";
|
||||
import { mapPlayer, mapState } from "@/util/vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -57,13 +58,14 @@ export default defineComponent({
|
|||
return { discordName, discordLink, format, showSaves: false };
|
||||
},
|
||||
computed: {
|
||||
...mapState(["hasNaN", "autosave"]),
|
||||
...mapPlayer(["autosave"]),
|
||||
...mapState(["hasNaN"]),
|
||||
path(): string | undefined {
|
||||
return player.NaNPath?.join(".");
|
||||
return state.NaNPath?.join(".");
|
||||
},
|
||||
previous(): any {
|
||||
if (player.NaNReceiver && this.property) {
|
||||
return player.NaNReceiver[this.property];
|
||||
previous(): unknown {
|
||||
if (state.NaNReceiver && this.property) {
|
||||
return state.NaNReceiver[this.property];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
@ -71,29 +73,29 @@ export default defineComponent({
|
|||
return player.devSpeed === 0;
|
||||
},
|
||||
property(): string | undefined {
|
||||
return player.NaNPath?.slice(-1)[0];
|
||||
return state.NaNPath?.slice(-1)[0];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setZero() {
|
||||
if (player.NaNReceiver && this.property) {
|
||||
player.NaNReceiver[this.property] = new Decimal(0);
|
||||
player.hasNaN = false;
|
||||
if (state.NaNReceiver && this.property) {
|
||||
state.NaNReceiver[this.property] = new Decimal(0);
|
||||
state.hasNaN = false;
|
||||
}
|
||||
},
|
||||
setOne() {
|
||||
if (player.NaNReceiver && this.property) {
|
||||
player.NaNReceiver[this.property] = new Decimal(1);
|
||||
player.hasNaN = false;
|
||||
if (state.NaNReceiver && this.property) {
|
||||
state.NaNReceiver[this.property] = new Decimal(1);
|
||||
state.hasNaN = false;
|
||||
}
|
||||
},
|
||||
setPrev() {
|
||||
player.hasNaN = false;
|
||||
state.hasNaN = false;
|
||||
},
|
||||
ignore() {
|
||||
if (player.NaNReceiver && this.property) {
|
||||
player.NaNReceiver[this.property] = new Decimal(NaN);
|
||||
player.hasNaN = false;
|
||||
if (state.NaNReceiver && this.property) {
|
||||
state.NaNReceiver[this.property] = new Decimal(NaN);
|
||||
state.hasNaN = false;
|
||||
}
|
||||
},
|
||||
setAutosave(autosave: boolean) {
|
||||
|
|
|
@ -20,18 +20,26 @@
|
|||
@change="setMSDisplay"
|
||||
default="all"
|
||||
/>
|
||||
<Toggle
|
||||
title="Offline Production"
|
||||
:value="offlineProd"
|
||||
@change="toggleOption('offlineProd')"
|
||||
/>
|
||||
<Toggle title="Autosave" :value="autosave" @change="toggleOption('autosave')" />
|
||||
<Toggle title="Pause game" :value="paused" @change="togglePaused" />
|
||||
<Toggle title="Show TPS" :value="showTPS" @change="toggleOption('showTPS')" />
|
||||
<Toggle title="Show TPS" :value="showTPS" @change="toggleSettingsOption('showTPS')" />
|
||||
<Toggle
|
||||
title="Hide Maxed Challenges"
|
||||
:value="hideChallenges"
|
||||
@change="toggleOption('hideChallenges')"
|
||||
@change="toggleSettingsOption('hideChallenges')"
|
||||
/>
|
||||
<Toggle
|
||||
title="Offline Production<tooltip display='Save-specific'>*</tooltip>"
|
||||
:value="offlineProd"
|
||||
@change="togglePlayerOption('offlineProd')"
|
||||
/>
|
||||
<Toggle
|
||||
title="Autosave<tooltip display='Save-specific'>*</tooltip>"
|
||||
:value="autosave"
|
||||
@change="togglePlayerOption('autosave')"
|
||||
/>
|
||||
<Toggle
|
||||
title="Pause game<tooltip display='Save-specific'>*</tooltip>"
|
||||
:value="paused"
|
||||
@change="togglePaused"
|
||||
/>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@ -41,9 +49,12 @@
|
|||
import { defineComponent } from "vue";
|
||||
import themes, { Themes } from "@/data/themes";
|
||||
import { camelToTitle } from "@/util/common";
|
||||
import { mapState } from "@/util/vue";
|
||||
import { mapPlayer, mapSettings } from "@/util/vue";
|
||||
import player from "@/game/player";
|
||||
import { MilestoneDisplay } from "@/game/enums";
|
||||
import { PlayerData } from "@/typings/player";
|
||||
import settings from "@/game/settings";
|
||||
import { Settings } from "@/typings/settings";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Options",
|
||||
|
@ -57,27 +68,31 @@ export default defineComponent({
|
|||
label: camelToTitle(theme),
|
||||
value: theme
|
||||
})),
|
||||
msDisplayOptions: ["all", "last", "configurable", "incomplete", "none"].map(option => ({
|
||||
msDisplayOptions: Object.values(MilestoneDisplay).map(option => ({
|
||||
label: camelToTitle(option),
|
||||
value: option
|
||||
}))
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["autosave", "offlineProd", "showTPS", "hideChallenges", "theme", "msDisplay"]),
|
||||
...mapSettings(["showTPS", "hideChallenges", "theme", "msDisplay"]),
|
||||
...mapPlayer(["autosave", "offlineProd"]),
|
||||
paused() {
|
||||
return player.devSpeed === 0;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleOption(option: string) {
|
||||
togglePlayerOption(option: keyof PlayerData) {
|
||||
player[option] = !player[option];
|
||||
},
|
||||
toggleSettingsOption(option: keyof Settings) {
|
||||
settings[option] = !settings[option];
|
||||
},
|
||||
setTheme(theme: Themes) {
|
||||
player.theme = theme;
|
||||
settings.theme = theme;
|
||||
},
|
||||
setMSDisplay(msDisplay: MilestoneDisplay) {
|
||||
player.msDisplay = msDisplay;
|
||||
settings.msDisplay = msDisplay;
|
||||
},
|
||||
togglePaused() {
|
||||
player.devSpeed = this.paused ? 1 : 0;
|
||||
|
@ -90,4 +105,9 @@ export default defineComponent({
|
|||
.header {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
* >>> .tooltip-container {
|
||||
display: inline;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,17 +3,19 @@
|
|||
<template v-slot:header>
|
||||
<h2>Saves Manager</h2>
|
||||
</template>
|
||||
<template v-slot:body v-sortable="{ update, handle: '.handle' }">
|
||||
<save
|
||||
v-for="(save, index) in saves"
|
||||
:key="index"
|
||||
:save="save"
|
||||
@open="openSave(save.id)"
|
||||
@export="exportSave(save.id)"
|
||||
@editSave="name => editSave(save.id, name)"
|
||||
@duplicate="duplicateSave(save.id)"
|
||||
@delete="deleteSave(save.id)"
|
||||
/>
|
||||
<template v-slot:body>
|
||||
<div v-sortable="{ update, handle: '.handle' }">
|
||||
<save
|
||||
v-for="(save, index) in saves"
|
||||
:key="index"
|
||||
:save="save"
|
||||
@open="openSave(save.id)"
|
||||
@export="exportSave(save.id)"
|
||||
@editSave="name => editSave(save.id, name)"
|
||||
@duplicate="duplicateSave(save.id)"
|
||||
@delete="deleteSave(save.id)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:footer>
|
||||
<div class="modal-footer">
|
||||
|
@ -55,8 +57,9 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import modInfo from "@/data/modInfo.json";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import state from "@/game/state";
|
||||
import { PlayerData } from "@/typings/player";
|
||||
import { getUniqueID, loadSave, newSave, save } from "@/util/save";
|
||||
import { defineComponent } from "vue";
|
||||
|
@ -86,7 +89,10 @@ export default defineComponent({
|
|||
bank
|
||||
} as {
|
||||
importingFailed: boolean;
|
||||
saves: Record<string, Partial<PlayerData>>;
|
||||
saves: Record<
|
||||
string,
|
||||
Omit<Partial<PlayerData>, "id"> & { id: string; error?: unknown }
|
||||
>;
|
||||
saveToImport: string;
|
||||
bank: Array<{ label: string; value: string }>;
|
||||
};
|
||||
|
@ -100,39 +106,36 @@ export default defineComponent({
|
|||
},
|
||||
methods: {
|
||||
loadSaveData() {
|
||||
try {
|
||||
const { saves } = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
this.saves = saves.reduce(
|
||||
(acc: Record<string, Partial<PlayerData>>, curr: string) => {
|
||||
try {
|
||||
acc[curr] = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(curr)!)))
|
||||
);
|
||||
this.saves = settings.saves.reduce(
|
||||
(
|
||||
acc: Record<
|
||||
string,
|
||||
Omit<Partial<PlayerData>, "id"> & { id: string; error?: unknown }
|
||||
>,
|
||||
curr: string
|
||||
) => {
|
||||
try {
|
||||
const save = localStorage.getItem(curr);
|
||||
if (save == null) {
|
||||
acc[curr] = { error: `Save with id "${curr}" doesn't exist`, id: curr };
|
||||
} else {
|
||||
acc[curr] = JSON.parse(decodeURIComponent(escape(atob(save))));
|
||||
acc[curr].id = curr;
|
||||
} catch (error) {
|
||||
console.warn(`Can't load save with id "${curr}"`, error);
|
||||
acc[curr] = { error, id: curr };
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
} catch (e) {
|
||||
this.saves = { [player.id]: player };
|
||||
const modData = { active: player.id, saves: [player.id] };
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Can't load save with id "${curr}"`, error);
|
||||
acc[curr] = { error, id: curr };
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
exportSave(id: string) {
|
||||
let saveToExport;
|
||||
if (player.id === id) {
|
||||
save();
|
||||
saveToExport = player.saveToExport;
|
||||
saveToExport = state.saveToExport;
|
||||
} else {
|
||||
saveToExport = btoa(unescape(encodeURIComponent(JSON.stringify(this.saves[id]))));
|
||||
}
|
||||
|
@ -157,40 +160,18 @@ export default defineComponent({
|
|||
btoa(unescape(encodeURIComponent(JSON.stringify(playerData))))
|
||||
);
|
||||
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.saves.push(playerData.id);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
settings.saves.push(playerData.id);
|
||||
this.saves[playerData.id] = playerData;
|
||||
},
|
||||
deleteSave(id: string) {
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.saves = modData.saves.filter((save: string) => save !== id);
|
||||
settings.saves = settings.saves.filter((save: string) => save !== id);
|
||||
localStorage.removeItem(id);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
delete this.saves[id];
|
||||
},
|
||||
openSave(id: string) {
|
||||
this.saves[player.id].time = player.time;
|
||||
save();
|
||||
loadSave(this.saves[id]);
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.active = id;
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
},
|
||||
newSave() {
|
||||
const playerData = newSave();
|
||||
|
@ -204,14 +185,7 @@ export default defineComponent({
|
|||
btoa(unescape(encodeURIComponent(JSON.stringify(playerData))))
|
||||
);
|
||||
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.saves.push(playerData.id);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
settings.saves.push(playerData.id);
|
||||
this.saves[playerData.id] = playerData;
|
||||
},
|
||||
editSave(id: string, newName: string) {
|
||||
|
@ -227,7 +201,6 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
importSave(text: string) {
|
||||
console.log(text);
|
||||
this.saveToImport = text;
|
||||
if (text) {
|
||||
this.$nextTick(() => {
|
||||
|
@ -247,14 +220,7 @@ export default defineComponent({
|
|||
this.saveToImport = "";
|
||||
this.importingFailed = false;
|
||||
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.saves.push(id);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
settings.saves.push(id);
|
||||
} catch (e) {
|
||||
this.importingFailed = true;
|
||||
}
|
||||
|
@ -264,14 +230,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
update(e: { newIndex: number; oldIndex: number }) {
|
||||
const modData = JSON.parse(
|
||||
decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))
|
||||
);
|
||||
modData.saves.splice(e.newIndex, 0, modData.saves.splice(e.oldIndex, 1)[0]);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
settings.saves.splice(e.newIndex, 0, settings.saves.splice(e.oldIndex, 1)[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import player from "@/game/player";
|
||||
import state from "@/game/state";
|
||||
import Decimal, { formatWhole } from "@/util/bignum";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
|
@ -13,8 +13,8 @@ export default defineComponent({
|
|||
tps() {
|
||||
return formatWhole(
|
||||
Decimal.div(
|
||||
player.lastTenTicks.length,
|
||||
player.lastTenTicks.reduce((acc, curr) => acc + curr, 0)
|
||||
state.lastTenTicks.length,
|
||||
state.lastTenTicks.reduce((acc, curr) => acc + curr, 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import themes from "@/data/themes";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import { Subtab } from "@/typings/features/subtab";
|
||||
import { InjectLayerMixin } from "@/util/vue";
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
@ -36,7 +37,7 @@ export default defineComponent({
|
|||
emits: ["selectTab"],
|
||||
computed: {
|
||||
floating(): boolean {
|
||||
return themes[player.theme].floatingTabs;
|
||||
return themes[settings.theme].floatingTabs;
|
||||
},
|
||||
style(): Array<Partial<CSSStyleDeclaration> | undefined> {
|
||||
return [
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<script lang="ts">
|
||||
import modInfo from "@/data/modInfo.json";
|
||||
import { layers } from "@/game/layers";
|
||||
import { coerceComponent, mapState } from "@/util/vue";
|
||||
import { coerceComponent, mapPlayer } from "@/util/vue";
|
||||
import { Component, defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -36,7 +36,7 @@ export default defineComponent({
|
|||
return { useHeader: modInfo.useHeader };
|
||||
},
|
||||
computed: {
|
||||
...mapState(["tabs"]),
|
||||
...mapPlayer(["tabs"]),
|
||||
components() {
|
||||
return Object.keys(layers).reduce(
|
||||
(acc: Record<string, Component | string | false>, curr) => {
|
||||
|
|
|
@ -1230,11 +1230,11 @@ export default {
|
|||
},
|
||||
effect() {
|
||||
if (!hasChallenge(this.layer, this.id)) return 0;
|
||||
if (player.layers[this.layer].challenges![this.id] == new Decimal(1))
|
||||
if (Decimal.eq(player.layers[this.layer].challenges![this.id], 1))
|
||||
return 50;
|
||||
if (player.layers[this.layer].challenges![this.id] == new Decimal(2))
|
||||
if (Decimal.eq(player.layers[this.layer].challenges![this.id], 2))
|
||||
return 60;
|
||||
if (player.layers[this.layer].challenges![this.id] == new Decimal(3))
|
||||
if (Decimal.eq(player.layers[this.layer].challenges![this.id], 3))
|
||||
return 70;
|
||||
},
|
||||
completionLimit() {
|
||||
|
|
|
@ -81,7 +81,7 @@ const main = {
|
|||
<span v-if="player.points.lt('1e1e6')"> points</span>
|
||||
</div>
|
||||
<div v-if="Decimal.gt(pointGain, 0)">
|
||||
({{ player.oompsMag != 0 ? format(player.oomps) + " OOM" + (player.oompsMag < 0 ? "^OOM" : player.oompsMag > 1 ? "^" + player.oompsMag : "") + "s" : formatSmall(pointGain) }}/sec)
|
||||
({{ state.oompsMag != 0 ? format(state.oomps) + " OOM" + (state.oompsMag < 0 ? "^OOM" : state.oompsMag > 1 ? "^" + state.oompsMag : "") + "s" : formatSmall(pointGain) }}/sec)
|
||||
</div>
|
||||
<spacer />
|
||||
<modal :show="false">
|
||||
|
|
|
@ -3,11 +3,7 @@ import modInfo from "@/data/modInfo.json";
|
|||
import Decimal, { DecimalSource } from "@/util/bignum";
|
||||
import { layers } from "./layers";
|
||||
import player from "./player";
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
function updatePopups(diff: number) {
|
||||
// TODO
|
||||
}
|
||||
import state from "./state";
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
function updateParticles(diff: number) {
|
||||
|
@ -16,21 +12,21 @@ function updateParticles(diff: number) {
|
|||
|
||||
function updateOOMPS(diff: DecimalSource) {
|
||||
if (player.points != undefined) {
|
||||
player.oompsMag = 0;
|
||||
state.oompsMag = 0;
|
||||
if (player.points.lte(new Decimal(1e100))) {
|
||||
player.lastPoints = player.points;
|
||||
state.lastPoints = player.points;
|
||||
return;
|
||||
}
|
||||
|
||||
let curr = player.points;
|
||||
let prev = (player.lastPoints as Decimal) || new Decimal(0);
|
||||
player.lastPoints = curr;
|
||||
let prev = (state.lastPoints as Decimal) || new Decimal(0);
|
||||
state.lastPoints = curr;
|
||||
if (curr.gt(prev)) {
|
||||
if (curr.gte("10^^8")) {
|
||||
curr = curr.slog(1e10);
|
||||
prev = prev.slog(1e10);
|
||||
player.oomps = curr.sub(prev).div(diff);
|
||||
player.oompsMag = -1;
|
||||
state.oomps = curr.sub(prev).div(diff);
|
||||
state.oompsMag = -1;
|
||||
} else {
|
||||
while (
|
||||
curr
|
||||
|
@ -38,13 +34,13 @@ function updateOOMPS(diff: DecimalSource) {
|
|||
.log(10)
|
||||
.div(diff)
|
||||
.gte("100") &&
|
||||
player.oompsMag <= 5 &&
|
||||
state.oompsMag <= 5 &&
|
||||
prev.gt(0)
|
||||
) {
|
||||
curr = curr.log(10);
|
||||
prev = prev.log(10);
|
||||
player.oomps = curr.sub(prev).div(diff);
|
||||
player.oompsMag++;
|
||||
state.oomps = curr.sub(prev).div(diff);
|
||||
state.oompsMag++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,11 +114,10 @@ function update() {
|
|||
const trueDiff = diff;
|
||||
|
||||
// Always update UI
|
||||
updatePopups(trueDiff);
|
||||
updateParticles(trueDiff);
|
||||
player.lastTenTicks.push(trueDiff);
|
||||
if (player.lastTenTicks.length > 10) {
|
||||
player.lastTenTicks = player.lastTenTicks.slice(1);
|
||||
state.lastTenTicks.push(trueDiff);
|
||||
if (state.lastTenTicks.length > 10) {
|
||||
state.lastTenTicks = state.lastTenTicks.slice(1);
|
||||
}
|
||||
|
||||
// Stop here if the game is paused on the win screen
|
||||
|
@ -130,7 +125,7 @@ function update() {
|
|||
return;
|
||||
}
|
||||
// Stop here if the player had a NaN value
|
||||
if (player.hasNaN) {
|
||||
if (state.hasNaN) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import clone from "lodash.clonedeep";
|
|||
import { isRef } from "vue";
|
||||
import { ProgressDisplay, Shape } from "./enums";
|
||||
import { default as playerProxy } from "./player";
|
||||
import settings from "./settings";
|
||||
|
||||
export const layers: Record<string, Readonly<Layer>> = {};
|
||||
export const hotkeys: Hotkey[] = [];
|
||||
|
@ -217,7 +218,7 @@ export function addLayer(layer: RawLayer, player?: Partial<PlayerData>): void {
|
|||
for (const id in layer.challenges.data) {
|
||||
layer.challenges.data[id].shown = function() {
|
||||
return (
|
||||
this.unlocked !== false && (playerProxy.hideChallenges === false || !this.maxed)
|
||||
this.unlocked !== false && (settings.hideChallenges === false || !this.maxed)
|
||||
);
|
||||
};
|
||||
layer.challenges.data[id].completed = function() {
|
||||
|
@ -376,7 +377,7 @@ export function addLayer(layer: RawLayer, player?: Partial<PlayerData>): void {
|
|||
if (!this.unlocked) {
|
||||
return false;
|
||||
}
|
||||
switch (playerProxy.msDisplay) {
|
||||
switch (settings.msDisplay) {
|
||||
default:
|
||||
case "all":
|
||||
return true;
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import { Themes } from "@/data/themes";
|
||||
import { PlayerData } from "@/typings/player";
|
||||
import Decimal from "@/util/bignum";
|
||||
import { isPlainObject } from "@/util/common";
|
||||
import { reactive } from "vue";
|
||||
import { ImportingStatus, MilestoneDisplay } from "./enums";
|
||||
import transientState from "./state";
|
||||
|
||||
const state = reactive<PlayerData>({
|
||||
id: "",
|
||||
points: new Decimal(0),
|
||||
oomps: new Decimal(0),
|
||||
oompsMag: 0,
|
||||
name: "",
|
||||
tabs: [],
|
||||
time: -1,
|
||||
|
@ -18,22 +15,11 @@ const state = reactive<PlayerData>({
|
|||
offlineTime: null,
|
||||
timePlayed: new Decimal(0),
|
||||
keepGoing: false,
|
||||
lastTenTicks: [],
|
||||
showTPS: true,
|
||||
msDisplay: MilestoneDisplay.All,
|
||||
hideChallenges: false,
|
||||
theme: Themes.Nordic,
|
||||
subtabs: {},
|
||||
minimized: {},
|
||||
modID: "",
|
||||
modVersion: "",
|
||||
justLoaded: false,
|
||||
hasNaN: false,
|
||||
NaNPath: [],
|
||||
NaNReceiver: null,
|
||||
importing: ImportingStatus.NotImporting,
|
||||
saveToImport: "",
|
||||
saveToExport: "",
|
||||
layers: {}
|
||||
});
|
||||
|
||||
|
@ -65,7 +51,7 @@ const playerHandler: ProxyHandler<Record<string, any>> = {
|
|||
receiver: ProxyConstructor
|
||||
): boolean {
|
||||
if (
|
||||
!state.hasNaN &&
|
||||
!transientState.hasNaN &&
|
||||
((typeof value === "number" && isNaN(value)) ||
|
||||
(value instanceof Decimal &&
|
||||
(isNaN(value.sign) || isNaN(value.layer) || isNaN(value.mag))))
|
||||
|
@ -81,9 +67,9 @@ const playerHandler: ProxyHandler<Record<string, any>> = {
|
|||
)
|
||||
) {
|
||||
state.autosave = false;
|
||||
state.hasNaN = true;
|
||||
state.NaNPath = [...target.__path, property];
|
||||
state.NaNReceiver = (receiver as unknown) as Record<string, unknown>;
|
||||
transientState.hasNaN = true;
|
||||
transientState.NaNPath = [...target.__path, property];
|
||||
transientState.NaNReceiver = (receiver as unknown) as Record<string, unknown>;
|
||||
console.error(
|
||||
`Attempted to set NaN value`,
|
||||
[...target.__path, property],
|
||||
|
|
72
src/game/settings.ts
Normal file
72
src/game/settings.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import modInfo from "@/data/modInfo.json";
|
||||
import { Themes } from "@/data/themes";
|
||||
import { Settings } from "@/typings/settings";
|
||||
import { isPlainObject } from "@/util/common";
|
||||
import { hardReset } from "@/util/save";
|
||||
import { reactive } from "vue";
|
||||
import { MilestoneDisplay } from "./enums";
|
||||
|
||||
const state = reactive<Settings>({
|
||||
active: "",
|
||||
saves: [],
|
||||
showTPS: true,
|
||||
msDisplay: MilestoneDisplay.All,
|
||||
hideChallenges: false,
|
||||
theme: Themes.Nordic
|
||||
});
|
||||
|
||||
const settingsHandler: ProxyHandler<Record<string, any>> = {
|
||||
get(target: Record<string, any>, key: string): any {
|
||||
if (key === "__state") {
|
||||
return target[key];
|
||||
}
|
||||
if (target.__state[key] == undefined) {
|
||||
return;
|
||||
}
|
||||
if (isPlainObject(target.__state[key])) {
|
||||
if (target.__state[key] !== target[key]?.__state) {
|
||||
target[key] = new Proxy({ __state: target.__state[key] }, settingsHandler);
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
|
||||
return target.__state[key];
|
||||
},
|
||||
set(target: Record<string, any>, property: string, value: any): boolean {
|
||||
target.__state[property] = value;
|
||||
localStorage.setItem(modInfo.id, btoa(unescape(encodeURIComponent(JSON.stringify(state)))));
|
||||
return true;
|
||||
},
|
||||
ownKeys(target: Record<string, any>) {
|
||||
return Reflect.ownKeys(target.__state);
|
||||
},
|
||||
has(target: Record<string, any>, key: string) {
|
||||
return Reflect.has(target.__state, key);
|
||||
}
|
||||
};
|
||||
export default window.settings = new Proxy({ __state: state }, settingsHandler) as Settings;
|
||||
|
||||
export function loadSettings(): void {
|
||||
try {
|
||||
const item: string | null = localStorage.getItem(modInfo.id);
|
||||
if (item != null && item !== "") {
|
||||
const settings = JSON.parse(decodeURIComponent(escape(atob(item))));
|
||||
if (typeof settings === "object") {
|
||||
Object.assign(state, settings);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export const hardResetSettings = (window.hardResetSettings = () => {
|
||||
Object.assign(state, {
|
||||
active: "",
|
||||
saves: [],
|
||||
showTPS: true,
|
||||
msDisplay: MilestoneDisplay.All,
|
||||
hideChallenges: false,
|
||||
theme: Themes.Nordic
|
||||
});
|
||||
hardReset();
|
||||
});
|
44
src/game/state.ts
Normal file
44
src/game/state.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { Transient } from "@/typings/transient";
|
||||
import Decimal from "@/util/bignum";
|
||||
import { isPlainObject } from "@/util/common";
|
||||
import { reactive } from "vue";
|
||||
|
||||
const state = reactive<Transient>({
|
||||
lastTenTicks: [],
|
||||
hasNaN: false,
|
||||
NaNPath: [],
|
||||
lastPoints: new Decimal(0),
|
||||
saveToExport: "",
|
||||
oomps: new Decimal(0),
|
||||
oompsMag: 0
|
||||
});
|
||||
|
||||
const stateHandler: ProxyHandler<Record<string, any>> = {
|
||||
get(target: Record<string, any>, key: string): any {
|
||||
if (key === "__state") {
|
||||
return target[key];
|
||||
}
|
||||
if (target.__state[key] == undefined) {
|
||||
return;
|
||||
}
|
||||
if (isPlainObject(target.__state[key])) {
|
||||
if (target.__state[key] !== target[key]?.__state) {
|
||||
target[key] = new Proxy({ __state: target.__state[key] }, stateHandler);
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
|
||||
return target.__state[key];
|
||||
},
|
||||
set(target: Record<string, any>, property: string, value: any): boolean {
|
||||
target.__state[property] = value;
|
||||
return true;
|
||||
},
|
||||
ownKeys(target: Record<string, any>) {
|
||||
return Reflect.ownKeys(target.__state);
|
||||
},
|
||||
has(target: Record<string, any>, key: string) {
|
||||
return Reflect.has(target.__state, key);
|
||||
}
|
||||
};
|
||||
export default window.state = new Proxy({ __state: state }, stateHandler) as Transient;
|
5
src/typings/global.d.ts
vendored
5
src/typings/global.d.ts
vendored
|
@ -1,14 +1,19 @@
|
|||
import Decimal, { DecimalSource } from "@/util/bignum";
|
||||
import { App } from "vue";
|
||||
import { PlayerData } from "./player";
|
||||
import { Settings } from "./settings";
|
||||
import { Transient } from "./transient";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
vue: App;
|
||||
save: () => void;
|
||||
hardReset: () => void;
|
||||
hardResetSettings: () => void;
|
||||
layers: Dictionary<typeof Proxy>;
|
||||
player: PlayerData;
|
||||
state: Transient;
|
||||
settings: Settings;
|
||||
Decimal: typeof Decimal;
|
||||
exponentialFormat: (
|
||||
num: DecimalSource,
|
||||
|
|
23
src/typings/player.d.ts
vendored
23
src/typings/player.d.ts
vendored
|
@ -1,21 +1,11 @@
|
|||
import { Themes } from "@/data/themes";
|
||||
import { DecimalSource } from "@/lib/break_eternity";
|
||||
import Decimal from "@/util/bignum";
|
||||
import Decimal, { DecimalSource } from "@/util/bignum";
|
||||
import { BoardData } from "./features/board";
|
||||
import { MilestoneDisplay } from "./features/milestone";
|
||||
import { State } from "./state";
|
||||
|
||||
export interface ModSaveData {
|
||||
active?: string;
|
||||
saves?: string[];
|
||||
}
|
||||
|
||||
export interface PlayerData {
|
||||
id: string;
|
||||
devSpeed?: DecimalSource;
|
||||
points: Decimal;
|
||||
oomps: Decimal;
|
||||
oompsMag: number;
|
||||
name: string;
|
||||
tabs: Array<string>;
|
||||
time: number;
|
||||
|
@ -24,11 +14,6 @@ export interface PlayerData {
|
|||
offlineTime: Decimal | null;
|
||||
timePlayed: Decimal;
|
||||
keepGoing: boolean;
|
||||
lastTenTicks: Array<number>;
|
||||
showTPS: boolean;
|
||||
msDisplay: MilestoneDisplay;
|
||||
hideChallenges: boolean;
|
||||
theme: Themes;
|
||||
subtabs: {
|
||||
[index: string]: {
|
||||
mainTabs?: string;
|
||||
|
@ -39,12 +24,6 @@ export interface PlayerData {
|
|||
modID: string;
|
||||
modVersion: string;
|
||||
justLoaded: boolean;
|
||||
hasNaN: boolean;
|
||||
NaNPath?: Array<string>;
|
||||
NaNReceiver?: Record<string, unknown> | null;
|
||||
importing: ImportingStatus;
|
||||
saveToImport: string;
|
||||
saveToExport: string;
|
||||
layers: Record<string, LayerSaveData>;
|
||||
[index: string]: unknown;
|
||||
}
|
||||
|
|
13
src/typings/settings.d.ts
vendored
Normal file
13
src/typings/settings.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Themes } from "@/data/themes";
|
||||
import { MilestoneDisplay } from "@/game/enums";
|
||||
|
||||
// This is the global save data, persists between individual saves
|
||||
export interface Settings {
|
||||
active: string;
|
||||
saves: string[];
|
||||
showTPS: boolean;
|
||||
msDisplay: MilestoneDisplay;
|
||||
hideChallenges: boolean;
|
||||
theme: Themes;
|
||||
[index: string]: unknown;
|
||||
}
|
13
src/typings/transient.d.ts
vendored
Normal file
13
src/typings/transient.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
import Decimal from "@/lib/break_eternity";
|
||||
|
||||
// Save data that doesn't persist between reloads
|
||||
export interface Transient {
|
||||
lastTenTicks: number[];
|
||||
hasNaN: bool;
|
||||
NaNPath?: string[];
|
||||
NaNReceiver?: Record<string, unknown>;
|
||||
saveToExport: string;
|
||||
lastPoints: Decimal;
|
||||
oomps: Decimal;
|
||||
oompsMag: number;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
import { fixOldSave, getInitialLayers, getStartingData } from "@/data/mod";
|
||||
import modInfo from "@/data/modInfo.json";
|
||||
import { Themes } from "@/data/themes";
|
||||
import { ImportingStatus, MilestoneDisplay } from "@/game/enums";
|
||||
import player from "@/game/player";
|
||||
import { ModSaveData, PlayerData } from "@/typings/player";
|
||||
import settings, { loadSettings } from "@/game/settings";
|
||||
import state from "@/game/state";
|
||||
import { PlayerData } from "@/typings/player";
|
||||
import Decimal from "./bignum";
|
||||
|
||||
export function getInitialStore(playerData: Partial<PlayerData> = {}): PlayerData {
|
||||
|
@ -11,8 +11,6 @@ export function getInitialStore(playerData: Partial<PlayerData> = {}): PlayerDat
|
|||
{
|
||||
id: `${modInfo.id}-0`,
|
||||
points: new Decimal(0),
|
||||
oomps: new Decimal(0),
|
||||
oompsMag: 0,
|
||||
name: "Default Save",
|
||||
tabs: modInfo.initialTabs.slice(),
|
||||
time: Date.now(),
|
||||
|
@ -21,61 +19,29 @@ export function getInitialStore(playerData: Partial<PlayerData> = {}): PlayerDat
|
|||
offlineTime: new Decimal(0),
|
||||
timePlayed: new Decimal(0),
|
||||
keepGoing: false,
|
||||
lastTenTicks: [],
|
||||
showTPS: true,
|
||||
msDisplay: MilestoneDisplay.All,
|
||||
hideChallenges: false,
|
||||
theme: Themes.Nordic,
|
||||
subtabs: {},
|
||||
minimized: {},
|
||||
modID: modInfo.id,
|
||||
modVersion: modInfo.versionNumber,
|
||||
layers: {},
|
||||
justLoaded: false,
|
||||
...getStartingData(),
|
||||
|
||||
// Values that don't get loaded/saved
|
||||
hasNaN: false,
|
||||
NaNPath: [],
|
||||
NaNReceiver: null,
|
||||
importing: ImportingStatus.NotImporting,
|
||||
saveToImport: "",
|
||||
saveToExport: ""
|
||||
...getStartingData()
|
||||
},
|
||||
playerData
|
||||
) as PlayerData;
|
||||
}
|
||||
|
||||
export function save(): void {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const {
|
||||
hasNaN,
|
||||
NaNPath,
|
||||
NaNReceiver,
|
||||
importing,
|
||||
saveToImport,
|
||||
saveToExport,
|
||||
...playerData
|
||||
} = player.__state as PlayerData;
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
player.saveToExport = btoa(unescape(encodeURIComponent(JSON.stringify(playerData))));
|
||||
|
||||
localStorage.setItem(player.id, player.saveToExport);
|
||||
state.saveToExport = btoa(unescape(encodeURIComponent(JSON.stringify(player.__state))));
|
||||
localStorage.setItem(player.id, state.saveToExport);
|
||||
}
|
||||
|
||||
export async function load(): Promise<void> {
|
||||
// Load global settings
|
||||
loadSettings();
|
||||
|
||||
try {
|
||||
let modData: string | ModSaveData | null = localStorage.getItem(modInfo.id);
|
||||
if (modData == null) {
|
||||
await loadSave(newSave());
|
||||
return;
|
||||
}
|
||||
modData = JSON.parse(decodeURIComponent(escape(atob(modData)))) as ModSaveData;
|
||||
if (modData?.active == null) {
|
||||
await loadSave(newSave());
|
||||
return;
|
||||
}
|
||||
const save = localStorage.getItem(modData.active);
|
||||
const save = localStorage.getItem(settings.active);
|
||||
if (save == null) {
|
||||
await loadSave(newSave());
|
||||
return;
|
||||
|
@ -85,7 +51,7 @@ export async function load(): Promise<void> {
|
|||
await loadSave(newSave());
|
||||
return;
|
||||
}
|
||||
playerData.id = modData.active;
|
||||
playerData.id = settings.active;
|
||||
await loadSave(playerData);
|
||||
} catch (e) {
|
||||
await loadSave(newSave());
|
||||
|
@ -97,21 +63,7 @@ export function newSave(): PlayerData {
|
|||
const playerData = getInitialStore({ id });
|
||||
localStorage.setItem(id, btoa(unescape(encodeURIComponent(JSON.stringify(playerData)))));
|
||||
|
||||
const rawModData = localStorage.getItem(modInfo.id);
|
||||
if (rawModData == null) {
|
||||
const modData = { active: id, saves: [id] };
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
} else {
|
||||
const modData = JSON.parse(decodeURIComponent(escape(atob(rawModData))));
|
||||
modData.saves.push(id);
|
||||
localStorage.setItem(
|
||||
modInfo.id,
|
||||
btoa(unescape(encodeURIComponent(JSON.stringify(modData))))
|
||||
);
|
||||
}
|
||||
settings.saves.push(id);
|
||||
|
||||
return playerData;
|
||||
}
|
||||
|
@ -150,6 +102,7 @@ export async function loadSave(playerData: Partial<PlayerData>): Promise<void> {
|
|||
}
|
||||
}
|
||||
player.justLoaded = true;
|
||||
settings.active = player.id;
|
||||
}
|
||||
|
||||
export function applyPlayerData<T extends Record<string, any>>(
|
||||
|
@ -191,7 +144,4 @@ window.onbeforeunload = () => {
|
|||
window.save = save;
|
||||
export const hardReset = (window.hardReset = async () => {
|
||||
await loadSave(newSave());
|
||||
const modData = JSON.parse(decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!))));
|
||||
modData.active = player.id;
|
||||
localStorage.setItem(modInfo.id, btoa(unescape(encodeURIComponent(JSON.stringify(modData)))));
|
||||
});
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import { hasWon, pointGain } from "@/data/mod";
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import settings from "@/game/settings";
|
||||
import state from "@/game/state";
|
||||
import { Feature, Features, GridFeatures } from "@/typings/features/feature";
|
||||
import { Layer } from "@/typings/layer";
|
||||
import { PlayerData } from "@/typings/player";
|
||||
import { Settings } from "@/typings/settings";
|
||||
import { Transient } from "@/typings/transient";
|
||||
import { App, Component, ComponentOptions, defineComponent, inject, PropType } from "vue";
|
||||
import Decimal, * as numberUtils from "./bignum";
|
||||
import {
|
||||
|
@ -34,7 +39,7 @@ export function setVue(vm: App): void {
|
|||
|
||||
// Pass in various data that the template could potentially use
|
||||
const data = function(): Record<string, unknown> {
|
||||
return { Decimal, player, layers, hasWon, pointGain, ...numberUtils };
|
||||
return { Decimal, player, state, settings, layers, hasWon, pointGain, ...numberUtils };
|
||||
};
|
||||
export function coerceComponent(
|
||||
component: string | ComponentOptions | Component,
|
||||
|
@ -95,14 +100,41 @@ export function getFiltered<T>(
|
|||
return objects;
|
||||
}
|
||||
|
||||
export function mapState(properties: Array<string> = []): Record<string, unknown> {
|
||||
return properties.reduce((acc: Record<string, unknown>, curr: string): Record<
|
||||
string,
|
||||
unknown
|
||||
> => {
|
||||
type OmitIndex<T> = {
|
||||
[K in keyof T as unknown extends Record<K, 1> ? never : K]: T[K];
|
||||
};
|
||||
|
||||
export function mapPlayer<K extends keyof OmitIndex<PlayerData>>(
|
||||
properties: K[] = []
|
||||
): {
|
||||
[P in K]: () => PlayerData[P];
|
||||
} {
|
||||
return properties.reduce((acc, curr: keyof PlayerData) => {
|
||||
acc[curr] = () => player[curr];
|
||||
return acc;
|
||||
}, {});
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
export function mapSettings<K extends keyof OmitIndex<Settings>>(
|
||||
properties: K[] = []
|
||||
): {
|
||||
[P in K]: () => Settings[P];
|
||||
} {
|
||||
return properties.reduce((acc, curr: keyof Settings) => {
|
||||
acc[curr] = () => settings[curr];
|
||||
return acc;
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
export function mapState<K extends keyof OmitIndex<Transient>>(
|
||||
properties: K[] = []
|
||||
): {
|
||||
[P in K]: () => Transient[P];
|
||||
} {
|
||||
return properties.reduce((acc, curr: keyof Transient) => {
|
||||
acc[curr] = () => state[curr];
|
||||
return acc;
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
export const InjectLayerMixin = {
|
||||
|
@ -126,9 +158,9 @@ export function FilteredFeaturesMixin<T extends Feature>(
|
|||
};
|
||||
};
|
||||
computed: {
|
||||
filtered: () => Record<string, T> | undefined;
|
||||
rows: () => number | undefined;
|
||||
cols: () => number | undefined;
|
||||
filtered: (this: { layer: string; [feature]: string[] }) => Record<string, T> | undefined;
|
||||
rows: (this: { layer: string }) => number | undefined;
|
||||
cols: (this: { layer: string }) => number | undefined;
|
||||
};
|
||||
} {
|
||||
return {
|
||||
|
@ -139,19 +171,19 @@ export function FilteredFeaturesMixin<T extends Feature>(
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
filtered(this: { layer: string; [feature]: string[] }) {
|
||||
filtered() {
|
||||
return (
|
||||
(layers[this.layer][feature] as Features<T> | undefined) &&
|
||||
getFiltered((layers[this.layer][feature] as Features<T>).data, this[feature])
|
||||
);
|
||||
},
|
||||
rows(this: { layer: string }) {
|
||||
rows() {
|
||||
return (
|
||||
(layers[this.layer][feature] as Features<T> | undefined) &&
|
||||
(layers[this.layer][feature] as Features<T> | GridFeatures<T>).rows
|
||||
);
|
||||
},
|
||||
cols(this: { layer: string }) {
|
||||
cols() {
|
||||
return (
|
||||
(layers[this.layer][feature] as Features<T> | undefined) &&
|
||||
(layers[this.layer][feature] as Features<T> | GridFeatures<T>).cols
|
||||
|
|
Loading…
Reference in a new issue