Settings update

This commit is contained in:
ducdat0507 2022-12-13 19:53:15 +07:00
parent f193d0f4b3
commit 3bdf33a4b6
13 changed files with 155 additions and 37 deletions

View file

@ -6,7 +6,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"git.ignoreLimitWarning": true, "git.ignoreLimitWarning": true,
"[typescriptreact]": { "[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"typescript.tsdk": "node_modules/typescript/lib" "typescript.tsdk": "node_modules/typescript/lib"
} }

View file

@ -1,17 +1,26 @@
<template> <template>
<Modal v-model="isOpen"> <Modal v-model="isOpen">
<template v-slot:header> <template v-slot:header>
<h2>Options</h2> <h2>Settings</h2>
<div class="option-tabs">
<button :class="{selected: isTab('behaviour')}" @click="setTab('behaviour')">Behaviour</button>
<button :class="{selected: isTab('appearance')}" @click="setTab('appearance')">Appearance</button>
</div>
</template> </template>
<template v-slot:body> <template v-slot:body>
<Select title="Theme" :options="themes" v-model="theme" /> <div v-if="isTab('behaviour')">
<component :is="settingFieldsComponent" />
<Toggle title="Show TPS" v-model="showTPS" />
<hr />
<Toggle :title="autosaveTitle" v-model="autosave" /> <Toggle :title="autosaveTitle" v-model="autosave" />
<FeedbackButton v-if="!autosave" class="button save-button" @click="save()">Manually save</FeedbackButton>
<Toggle v-if="projInfo.enablePausing" :title="isPausedTitle" v-model="isPaused" /> <Toggle v-if="projInfo.enablePausing" :title="isPausedTitle" v-model="isPaused" />
<Toggle :title="autoPauseTitle" v-model="autoPause" />
</div>
<div v-if="isTab('appearance')">
<Select :title="themeTitle" :options="themes" v-model="theme" />
<component :is="settingFieldsComponent" />
<Toggle :title="showTPSTitle" v-model="showTPS" />
<Toggle :title="progressMethodTitle" v-model="usingLog" /> <Toggle :title="progressMethodTitle" v-model="usingLog" />
<Toggle :title="alignModifierUnitsTitle" v-model="alignUnits" /> <Toggle :title="alignModifierUnitsTitle" v-model="alignUnits" />
</div>
</template> </template>
</Modal> </Modal>
</template> </template>
@ -25,19 +34,36 @@ import Tooltip from "features/tooltips/Tooltip.vue";
import player from "game/player"; import player from "game/player";
import settings, { settingFields } from "game/settings"; import settings, { settingFields } from "game/settings";
import { camelToTitle } from "util/common"; import { camelToTitle } from "util/common";
import { save } from "util/save";
import { coerceComponent, render } from "util/vue"; import { coerceComponent, render } from "util/vue";
import { computed, ref, toRefs } from "vue"; import { computed, ref, toRefs } from "vue";
import Select from "./fields/Select.vue"; import Select from "./fields/Select.vue";
import Toggle from "./fields/Toggle.vue"; import Toggle from "./fields/Toggle.vue";
import FeedbackButton from "./fields/FeedbackButton.vue";
const isOpen = ref(false); const isOpen = ref(false);
const currentTab = ref("behaviour");
defineExpose({ defineExpose({
isTab,
setTab,
save() {
save();
},
open() { open() {
isOpen.value = true; isOpen.value = true;
} }
}); });
function isTab (tab: string): boolean {
return tab == currentTab.value;
}
function setTab (tab: string) {
currentTab.value = tab;
}
const themes = Object.keys(rawThemes).map(theme => ({ const themes = Object.keys(rawThemes).map(theme => ({
label: camelToTitle(theme), label: camelToTitle(theme),
value: theme value: theme
@ -47,8 +73,10 @@ const settingFieldsComponent = computed(() => {
return coerceComponent(jsx(() => <>{settingFields.map(render)}</>)); return coerceComponent(jsx(() => <>{settingFields.map(render)}</>));
}); });
const { showTPS, theme } = toRefs(settings); const { showTPS, theme, usingLog, alignUnits } = toRefs(settings);
const { autosave, usingLog, alignUnits } = toRefs(player);
const { autosave, autoPause } = toRefs(player);
const isPaused = computed({ const isPaused = computed({
get() { get() {
return player.devSpeed === 0; return player.devSpeed === 0;
@ -58,32 +86,85 @@ const isPaused = computed({
} }
}); });
const autosaveTitle = jsx(() => ( const autosaveTitle = jsx(() => (
<span> <span class="option-title">
Autosave<Tooltip display="Save-specific">*</Tooltip> Autosave<Tooltip display="Save-specific">*</Tooltip>
<desc>Automatically save the game every second or when the game is closed.</desc>
</span> </span>
)); ));
const isPausedTitle = jsx(() => ( const isPausedTitle = jsx(() => (
<span> <span class="option-title">
Pause game<Tooltip display="Save-specific">*</Tooltip> Pause game<Tooltip display="Save-specific">*</Tooltip>
<desc>Stop everything from moving.</desc>
</span>
));
const autoPauseTitle = jsx(() => (
<span class="option-title">
Auto-pause<Tooltip display="Save-specific">*</Tooltip>
<desc>Automatically pause the game when a day is completed. It is best to keep this on to avoid over-grinding.</desc>
</span>
));
const themeTitle = jsx(() => (
<span class="option-title">
Theme
<desc>How the game looks.</desc>
</span>
));
const showTPSTitle = jsx(() => (
<span class="option-title">
Show TPS
<desc>Show TPS meter at the bottom-left corner of the page.</desc>
</span> </span>
)); ));
const progressMethodTitle = jsx(() => ( const progressMethodTitle = jsx(() => (
<span> <span class="option-title">
Logarithmic progress bars<Tooltip display="Save-specific">*</Tooltip> Logarithmic progress bars
<desc>Whether progress bars should be normalized for exponential growth.</desc>
</span> </span>
)); ));
const alignModifierUnitsTitle = jsx(() => ( const alignModifierUnitsTitle = jsx(() => (
<span> <span class="option-title">
Align modifier units<Tooltip display="Save-specific">*</Tooltip> Align modifier units
<desc>Align numbers to the beginning of the unit in modifier view.</desc>
</span> </span>
)); ));
</script> </script>
<style scoped> <style>
.option-tabs {
border-bottom: 2px solid var(--outline);
}
*:deep() .tooltip-container { .option-tabs button {
background-color: transparent;
color: var(--foreground);
margin-bottom: -2px;
font-size: 14px;
cursor: pointer;
padding: 5px 20px;
border: none;
border-bottom: 2px solid var(--foreground);
}
.option-tabs button:not(.selected) {
border-bottom-color: transparent;
}
.option-title .tooltip-container {
display: inline; display: inline;
margin-left: 5px; margin-left: 5px;
} }
.option-title desc {
display: block;
opacity: 0.6;
font-size: small;
width: 300px;
margin-left: 0;
}
.save-button {
text-align: right;
}
</style> </style>

View file

@ -8,10 +8,13 @@
} }
.modifier-amount { .modifier-amount {
flex-basis: 100px;
flex-shrink: 0; flex-shrink: 0;
text-align: right; text-align: right;
} }
:not(:first-of-type, :last-of-type) > .modifier-amount::after {
content: var(--unit);
opacity: 0;
}
.modifier-description { .modifier-description {
flex-grow: 1; flex-grow: 1;

View file

@ -87,6 +87,10 @@ function onUpdate(value: SelectOption) {
background-color: var(--bought); background-color: var(--bought);
} }
.vue-input input {
font-size: inherit;
}
.vue-input input::placeholder { .vue-input input::placeholder {
color: var(--link); color: var(--link);
} }

View file

@ -44,14 +44,16 @@ input {
span { span {
width: 100%; width: 100%;
padding-right: 41px;
position: relative; position: relative;
} }
/* track */ /* track */
input + span::before { input + span::before {
content: ""; content: "";
float: right; position: absolute;
margin: 5px 0 5px 10px; top: calc(50% - 7px);
right: 0px;
border-radius: 7px; border-radius: 7px;
width: 36px; width: 36px;
height: 14px; height: 14px;
@ -66,7 +68,7 @@ input + span::before {
input + span::after { input + span::after {
content: ""; content: "";
position: absolute; position: absolute;
top: 2px; top: calc(50% - 10px);
right: 16px; right: 16px;
border-radius: 50%; border-radius: 50%;
width: 20px; width: 20px;

View file

@ -20,6 +20,7 @@ import type { Modifier } from "game/modifiers";
import type { Persistent } from "game/persistence"; import type { Persistent } from "game/persistence";
import { DefaultValue, persistent } from "game/persistence"; import { DefaultValue, persistent } from "game/persistence";
import player from "game/player"; import player from "game/player";
import settings from "game/settings";
import type { DecimalSource } from "util/bignum"; import type { DecimalSource } from "util/bignum";
import Decimal, { format } from "util/bignum"; import Decimal, { format } from "util/bignum";
import { formatWhole } from "util/break_eternity"; import { formatWhole } from "util/break_eternity";
@ -333,7 +334,7 @@ export function createCollapsibleModifierSections(
return ( return (
<> <>
{hasPreviousSection ? <br /> : null} {hasPreviousSection ? <br /> : null}
<div> <div style={{"--unit": settings.alignUnits && s.unit ? "'" + s.unit + "'" : ""}}>
{header} {header}
<br /> <br />
{modifiers} {modifiers}
@ -424,7 +425,7 @@ export function setUpDailyProgressTracker(options: {
if (main.day.value !== options.day) return 1; if (main.day.value !== options.day) return 1;
let progress = Decimal.add(total.value, 1); let progress = Decimal.add(total.value, 1);
let requirement = options.goal; let requirement = options.goal;
if (options.usingLog?.value ?? player.usingLog) { if (options.usingLog?.value ?? settings.usingLog) {
progress = progress.log10(); progress = progress.log10();
requirement = Decimal.log10(requirement); requirement = Decimal.log10(requirement);
} }

View file

@ -1164,7 +1164,7 @@ const layer = createLayer(id, () => {
<h3>Build a Classroom</h3> <h3>Build a Classroom</h3>
<div> <div>
Hopefully it makes the school a bit less boring. Multiplies elves' XP gain by{" "} Hopefully it makes the school a bit less boring. Multiplies elves' XP gain by{" "}
<Sqrt>Classrooms + 1</Sqrt>. (Classrooms + 1)<sup>0.9</sup>.
</div> </div>
<div> <div>
You have {formatWhole(classrooms.amount.value)} classrooms, which are currently You have {formatWhole(classrooms.amount.value)} classrooms, which are currently

View file

@ -146,7 +146,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
loreScene.value = -1; loreScene.value = -1;
loreTitle.value = unref(layers[layer ?? "trees"]?.name ?? ""); loreTitle.value = unref(layers[layer ?? "trees"]?.name ?? "");
loreBody.value = story; loreBody.value = story;
player.devSpeed = null; if (player.autoPause) player.devSpeed = null;
showLoreModal.value = true; showLoreModal.value = true;
}, 1000); }, 1000);
} }
@ -370,7 +370,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
showLoreModal.value = true; showLoreModal.value = true;
day.value++; day.value++;
main.minimized.value = false; main.minimized.value = false;
player.devSpeed = 0; if (player.autoPause) player.devSpeed = 0;
} }
return { return {

View file

@ -299,7 +299,12 @@ globalBus.on("loadSettings", settings => {
registerSettingField( registerSettingField(
jsx(() => ( jsx(() => (
<Toggle <Toggle
title="Hide Maxed Challenges" title={jsx(() => (
<span class="option-title">
Hide maxed challenges
<desc>Hide challenges that have been fully completed.</desc>
</span>
))}
onUpdate:modelValue={value => (settings.hideChallenges = value)} onUpdate:modelValue={value => (settings.hideChallenges = value)}
modelValue={settings.hideChallenges} modelValue={settings.hideChallenges}
/> />

View file

@ -204,7 +204,12 @@ const msDisplayOptions = Object.values(MilestoneDisplay).map(option => ({
registerSettingField( registerSettingField(
jsx(() => ( jsx(() => (
<Select <Select
title="Show Milestones" title={jsx(() => (
<span class="option-title">
Show milestones
<desc>Select which milestones to display based on criterias.</desc>
</span>
))}
options={msDisplayOptions} options={msDisplayOptions}
onUpdate:modelValue={value => (settings.msDisplay = value as MilestoneDisplay)} onUpdate:modelValue={value => (settings.msDisplay = value as MilestoneDisplay)}
modelValue={settings.msDisplay} modelValue={settings.msDisplay}

View file

@ -1,6 +1,7 @@
import "components/common/modifiers.css"; import "components/common/modifiers.css";
import type { CoercableComponent } from "features/feature"; import type { CoercableComponent } from "features/feature";
import { jsx } from "features/feature"; import { jsx } from "features/feature";
import settings from "game/settings";
import type { DecimalSource } from "util/bignum"; import type { DecimalSource } from "util/bignum";
import Decimal, { format } from "util/bignum"; import Decimal, { format } from "util/bignum";
import type { WithRequired } from "util/common"; import type { WithRequired } from "util/common";
@ -9,6 +10,7 @@ import { convertComputable } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { renderJSX } from "util/vue"; import { renderJSX } from "util/vue";
import { computed, unref } from "vue"; import { computed, unref } from "vue";
import player from "./player";
/** /**
* An object that can be used to apply or unapply some modification to a number. * An object that can be used to apply or unapply some modification to a number.
@ -272,7 +274,7 @@ export function createModifierSection(
baseText: CoercableComponent = "Base" baseText: CoercableComponent = "Base"
) { ) {
return ( return (
<div> <div style={{"--unit": settings.alignUnits ? "'" + unit + "'" : ""}}>
<h3> <h3>
{title} {title}
{subtitle ? <span class="subtitle"> ({subtitle})</span> : null} {subtitle ? <span class="subtitle"> ({subtitle})</span> : null}

View file

@ -34,8 +34,9 @@ export interface PlayerData {
modVersion: string; modVersion: string;
/** A dictionary of layer save data. */ /** A dictionary of layer save data. */
layers: Record<string, LayerData<unknown>>; layers: Record<string, LayerData<unknown>>;
/** Whether to use log for progress toward finishing the day, or use linear. */
usingLog: boolean; /** Should the game be paused when the player complete a day? */
autoPause: boolean;
} }
/** The proxied player that is used to track NaN values. */ /** The proxied player that is used to track NaN values. */
@ -68,7 +69,8 @@ const state = reactive<PlayerData>({
modID: "", modID: "",
modVersion: "", modVersion: "",
layers: {}, layers: {},
usingLog: false
autoPause: true,
}); });
/** Convert a player save data object into a JSON string. Unwraps refs. */ /** Convert a player save data object into a JSON string. Unwraps refs. */

View file

@ -18,6 +18,13 @@ export interface Settings {
theme: Themes; theme: Themes;
/** Whether or not to cap the project at 20 ticks per second. */ /** Whether or not to cap the project at 20 ticks per second. */
unthrottled: boolean; unthrottled: boolean;
/** Game-specific settings */
/** Whether to use log for progress toward finishing the day, or use linear. */
usingLog: boolean;
/** Whether to align modifiers to the unit. */
alignUnits: boolean;
} }
const state = reactive<Partial<Settings>>({ const state = reactive<Partial<Settings>>({
@ -25,7 +32,10 @@ const state = reactive<Partial<Settings>>({
saves: [], saves: [],
showTPS: true, showTPS: true,
theme: Themes.Nordic, theme: Themes.Nordic,
unthrottled: false unthrottled: false,
usingLog: false,
alignUnits: false,
}); });
watch( watch(
@ -57,7 +67,10 @@ export const hardResetSettings = (window.hardResetSettings = () => {
active: "", active: "",
saves: [], saves: [],
showTPS: true, showTPS: true,
theme: Themes.Nordic theme: Themes.Nordic,
usingLog: false,
alignUnits: false,
}; };
globalBus.emit("loadSettings", settings); globalBus.emit("loadSettings", settings);
Object.assign(state, settings); Object.assign(state, settings);