From 7174332bf1c4bab02591275c57144543d4d805d3 Mon Sep 17 00:00:00 2001 From: iTNTPiston Date: Fri, 24 Jun 2022 14:58:33 -0700 Subject: [PATCH] options refactoring --- src/App.css | 68 ++++++++++- src/App.tsx | 124 ++++++++----------- src/components/CommandItem.tsx | 61 +++++++--- src/core/Command.ts | 88 +++++++++----- src/core/Inventory.ts | 215 --------------------------------- src/core/Parser.ts | 42 +++---- src/surfaces/DisplayPane.tsx | 1 + src/surfaces/OptionPage.tsx | 107 ++++++++++++++++ src/surfaces/ReferencePage.tsx | 29 +++-- 9 files changed, 360 insertions(+), 375 deletions(-) delete mode 100644 src/core/Inventory.ts create mode 100644 src/surfaces/OptionPage.tsx diff --git a/src/App.css b/src/App.css index 2f1a372..c2bfa7e 100644 --- a/src/App.css +++ b/src/App.css @@ -24,6 +24,10 @@ h1 { font-size: 10pt; } +.CommandItemInvalid { + color: red; +} + .CommandItem { padding: 2px 2px 2px 10px; cursor: pointer; @@ -110,7 +114,7 @@ p.Reference { padding-left: 20px; } -p.Example { +.Example { color:#eeee00; } @@ -123,3 +127,65 @@ h3.Reference2 { margin-top: 0; margin-bottom: 0; } + +button.MainButton { + font-family: CalamitySans; + font-weight: bold; + display: inline-block; + padding: 5px; + width: 100px; + margin: 5px; + background-color: #00000099; + color: #ffffff; + border-radius: 0; + border: 2px solid #888888; +} + +button.MainButton:hover { + border-color: #eeeeee; + box-shadow: 0 0 5px #eeeeee; +} + +button.MainButton:active { + background-color: #888888; +} + +.FullWidth { + width: 100% !important; +} + +div.OtherPage { + height: 100%; + width: 100%; + color: #ffffff; +} + +div.OtherPageContent{ + padding: 10px; +} + +.MainInput { + display: block; + width: 100%; + background-color: #00000099; + color: #ffffff; + border-radius: 0; + border: 2px solid #888888; + margin-bottom: 5px; +} + +input.MainInput { + font-size: 14pt; + font-family: CalamitySans; +} + +textarea { + resize: none; + height: 300px; +} + +.MainInput:focus-visible { + outline: none; + border-color: #eeeeee; + box-shadow: 0 0 5px #eeeeee; +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 69618a5..65d3467 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { Command, CommandNothing } from "core/Command"; +import { Command, CommandNop } from "core/Command"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import "./App.css"; @@ -11,16 +11,18 @@ import { ItemList } from "components/ItemList"; import { TitledList } from "components/TitledList"; import { createSimulationState, SimulationState } from "core/SimulationState"; import { ReferencePage } from "surfaces/ReferencePage"; +import { OptionPage } from "surfaces/OptionPage"; const getDefaultCommands = (): Command[]=>{ const encoded = localStorage.getItem("HDS.CurrentCommandsText"); if(encoded){ const lines = encoded.split("\n"); - return lines.map(l=>parseCommand(l)).filter(c=>c) as Command[]; + return lines.map(parseCommand); } return [ parseCommand("Get 5 Diamond 1 Slate 1 Glider 4 SpiritOrb"), parseCommand("Save"), + parseCommand("# Magically break 4 slots"), parseCommand("Break 4 Slots"), parseCommand("Reload"), parseCommand("Save"), @@ -30,16 +32,16 @@ const getDefaultCommands = (): Command[]=>{ export const App: React.FC = () => { const [page, setPageInState] = useState("#simulation"); - const [overlaySave, setOverlaySave] = useState(false); + // Option States + const [interlaceInventory, setInterlaceInventory] = useState(false); + const [commands, setCommands] = useState(getDefaultCommands()); const [selectedSaveName, setSelectedSaveName] = useState(""); const [displayIndex, setDisplayIndex] = useState(0); const [contextMenuX, setContextMenuX] = useState(0); const [contextMenuY, setContextMenuY] = useState(0); - const [contextMenuShowing, setContextMenuShowing] = useState(false); const [contextIndex, setContextIndex] = useState(-1); - const uploadRef = useRef(null); const contextMenuRef = useRef(null); // compute props const simulationStates = useMemo(()=>{ @@ -51,6 +53,9 @@ export const App: React.FC = () => { }); return simulationStates; }, [commands]); + const commandText = useMemo(()=>{ + return commands.map(c=>c.getDisplayString()).join("\n"); + }, [commands]); const setPage = useCallback((hash: string)=>{ window.location.hash = hash; @@ -66,7 +71,7 @@ export const App: React.FC = () => { if(e.code==="ArrowDown"){ if(displayIndex===commands.length-1){ const arrCopy = [...commands]; - arrCopy.push(new CommandNothing()); + arrCopy.push(new CommandNop("")); setCommands(arrCopy); setDisplayIndex(arrCopy.length-1); }else{ @@ -88,40 +93,32 @@ export const App: React.FC = () => { }, [commands]); useEffect(()=>{ - if(contextMenuRef.current && contextMenuShowing){ + if(contextIndex < 0 || contextIndex >= commands.length){ + setContextIndex(-1); + }else if(contextMenuRef.current){ const rect = contextMenuRef.current.getBoundingClientRect(); if (rect.bottom > window.innerHeight){ setContextMenuY(contextMenuY-rect.height); } } - }, [contextMenuRef, contextMenuShowing]); + }, [contextMenuRef, contextIndex, commands]); return (
- { - const files = e.target.files; - if(files?.length && files[0]){ - const file = files[0]; - file.text().then(text=>{ - const lines = text.split("\n"); - const parsedCommands: Command[] = lines.map(l=>parseCommand(l)).filter(c=>c) as Command[]; - setDisplayIndex(0); - setContextIndex(-1); - setContextMenuShowing(false); - setCommands(parsedCommands); - }); - } - }}/> +
{ { setSelectedSaveName(""); + setPage("#simulation"); }} - comment={false} + useListItem isSelected={selectedSaveName===""} > @@ -159,9 +157,10 @@ export const App: React.FC = () => { { setSelectedSaveName(name); + setPage("#simulation"); }} - comment={false} isSelected={selectedSaveName===name} + useListItem > {name} @@ -188,6 +187,7 @@ export const App: React.FC = () => { { setDisplayIndex(i); + setPage("#simulation"); const inputField = document.getElementById("CommandInputField"); if(inputField){ inputField.focus(); @@ -197,12 +197,13 @@ export const App: React.FC = () => { setContextIndex(i); setContextMenuX(x); setContextMenuY(y); - setContextMenuShowing(true); }} key={i} isSelected={displayIndex===i} isContextSelected={contextIndex===i} - comment={c.getDisplayString().startsWith("#")} + isComment={c.getDisplayString().startsWith("#")} + useListItem={!c.getDisplayString().startsWith("#")} + isInvalid={!c.isValid()} > {c.getDisplayString()} @@ -210,24 +211,14 @@ export const App: React.FC = () => { } { const arrCopy = [...commands]; - arrCopy.push(new CommandNothing()); + arrCopy.push(new CommandNop("")); setCommands(arrCopy); }} onContextMenu={()=>{ const arrCopy = [...commands]; - arrCopy.push(new CommandNothing()); + arrCopy.push(new CommandNop("")); setCommands(arrCopy); }}>(new) - { - setContextIndex(-1); - setContextMenuX(x); - setContextMenuY(y); - setContextMenuShowing(true); - }} onContextMenu={(x,y)=>{ - setContextIndex(-1); - setContextMenuX(x); - setContextMenuY(y); - setContextMenuShowing(true); - }}>(options) + @@ -248,8 +239,6 @@ export const App: React.FC = () => {
{ }}> {displayIndex >= 0 && displayIndex < commands.length && { { page === "#reference" && } + { + page === "#options" && + { + if(value !== commandText){ + const commands = value.split("\n").map(parseCommand) + setCommands(commands); + } + }} + /> + }
{ - contextMenuShowing &&
= 0 && contextIndex < commands.length &&
{ - setContextMenuShowing(false); setContextIndex(-1); }} onContextMenu={(e)=>{ - setContextMenuShowing(false); setContextIndex(-1); e.preventDefault(); }}> @@ -339,12 +340,11 @@ export const App: React.FC = () => { listStyleType: "none", paddingInlineStart: 0 }}> - {contextIndex >= 0 ? <> + { const arrCopy = [...commands]; - arrCopy.splice(contextIndex, 0, new CommandNothing()); + arrCopy.splice(contextIndex, 0, new CommandNop("")); setCommands(arrCopy); - setContextMenuShowing(false); setContextIndex(-1); }}>Insert Above { @@ -354,7 +354,6 @@ export const App: React.FC = () => { arrCopy[contextIndex] = arrCopy[contextIndex-1]; arrCopy[contextIndex-1] = temp; setCommands(arrCopy); - setContextMenuShowing(false); setContextIndex(-1); } @@ -365,28 +364,9 @@ export const App: React.FC = () => { if(displayIndex >= commands.length){ setDisplayIndex(commands.length-1); } - setContextMenuShowing(false); setContextIndex(-1); } - }}>Delete : - <> - { - setOverlaySave(!overlaySave); - }}>Toggle Save Overlay - { - if(uploadRef.current){ - uploadRef.current.click(); - } - }}>Import - { - const lines = commands.map(c=>c.getDisplayString()); - const text = lines.join("\n"); - saveAs(text, "dupe.txt"); - }}>Export - - - - } + }}>Delete
diff --git a/src/components/CommandItem.tsx b/src/components/CommandItem.tsx index 6c29e07..dc7366e 100644 --- a/src/components/CommandItem.tsx +++ b/src/components/CommandItem.tsx @@ -1,30 +1,55 @@ import clsx from "clsx"; -import { PropsWithChildren } from "react"; +import React, { PropsWithChildren, useCallback } from "react"; type CommandItemProps = PropsWithChildren<{ + useListItem?: boolean, isSelected?: boolean, - comment?:boolean, + isComment?: boolean, + isInvalid?: boolean, isContextSelected?: boolean, onClick: (x: number, y: number)=>void, onContextMenu?: (x: number, y: number)=>void }>; -export const CommandItem: React.FC = ({isSelected, isContextSelected, comment,children, onClick, onContextMenu}) => { - if(comment){ - return
{children}
; +export const CommandItem: React.FC = ({ + useListItem, + isSelected, + isContextSelected, + isComment, + isInvalid, + onClick, + onContextMenu, + children +}) => { + const className = clsx( + "CommandItem", + isSelected && "CommandItemSelected", + isContextSelected && "CommandItemContextSelected", + isComment && "CommandItemComment", + isInvalid && !isComment && "CommandItemInvalid", + ); + + const clickHandler = useCallback((e: React.MouseEvent)=>{ + onClick(e.clientX, e.clientY) + }, [onClick]); + const contextMenuHandler = useCallback((e: React.MouseEvent)=>{ + if(onContextMenu){ + onContextMenu(e.clientX,e.clientY); + e.preventDefault(); + } + }, [onContextMenu]); + + if(!useListItem){ + return ( +
+ {children}  +
+ ); } - return
  • { - onClick(e.clientX, e.clientY); - }} - onContextMenu={(e)=>{ - if(onContextMenu){ - onContextMenu(e.clientX,e.clientY); - e.preventDefault(); - } - - }} - >{children} 
  • ; + return ( +
  • + {children}  +
  • + ); }; diff --git a/src/core/Command.ts b/src/core/Command.ts index 7ad4c18..a9ba2db 100644 --- a/src/core/Command.ts +++ b/src/core/Command.ts @@ -1,27 +1,29 @@ -import { Inventory } from "./Inventory"; import { Item, ItemStack } from "./Item"; import { SimulationState } from "./SimulationState"; export interface Command { + isValid(): boolean, execute(state: SimulationState): void, getDisplayString(): string, } -export class CommandNothing implements Command { - - execute(_state: Inventory): void { +class CommandImpl implements Command{ + isValid(): boolean { + return true; + } + execute(_state: SimulationState): void { // nothing } getDisplayString(): string { - return ""; + throw new Error("Method not implemented."); } - } -export class CommandInitialize implements Command { +export class CommandInitialize extends CommandImpl { private stacks: ItemStack[]; constructor(stacks: ItemStack[]){ + super(); this.stacks = stacks; } @@ -34,7 +36,7 @@ export class CommandInitialize implements Command { } -export class CommandSave implements Command { +export class CommandSave extends CommandImpl { public execute(state: SimulationState): void { state.save(); @@ -44,9 +46,10 @@ export class CommandSave implements Command { } } -export class CommandSaveAs implements Command { +export class CommandSaveAs extends CommandImpl { private name: string; constructor(name: string){ + super(); this.name = name; } public execute(state: SimulationState): void { @@ -57,9 +60,10 @@ export class CommandSaveAs implements Command { } } -export class CommandReload implements Command { +export class CommandReload extends CommandImpl { private name?: string; constructor(name?: string){ + super(); this.name = name; } public execute(state: SimulationState): void { @@ -70,9 +74,10 @@ export class CommandReload implements Command { } } -export class CommandUse implements Command { +export class CommandUse extends CommandImpl{ private name: string; constructor(name: string){ + super(); this.name = name; } public execute(state: SimulationState): void { @@ -81,12 +86,16 @@ export class CommandUse implements Command { public getDisplayString(): string { return `Use ${this.name}`; } + public isValid(): boolean { + return false; // this command is deprecated + } } -export class CommandBreakSlots implements Command { +export class CommandBreakSlots extends CommandImpl { private numToBreak: number; constructor(numToBreak: number){ + super(); this.numToBreak = numToBreak; } @@ -98,11 +107,12 @@ export class CommandBreakSlots implements Command { } } -export class CommandAdd implements Command { +export class CommandAdd extends CommandImpl { private verb: string; private count: number; private item: Item; constructor(verb: string, count: number, item: Item){ + super(); this.verb = verb; this.count = count; this.item = item; @@ -116,10 +126,11 @@ export class CommandAdd implements Command { } } -export class CommandAddWithoutCount implements Command { +export class CommandAddWithoutCount extends CommandImpl { private verb: string; private item: Item; constructor(verb: string, item: Item){ + super(); this.verb = verb; this.item = item; } @@ -132,10 +143,11 @@ export class CommandAddWithoutCount implements Command { } } -export class CommandAddMultiple implements Command { +export class CommandAddMultiple extends CommandImpl { private verb: string; private stacks: ItemStack[]; constructor(verb: string, stacks: ItemStack[]){ + super(); this.verb = verb; this.stacks = stacks; } @@ -149,13 +161,14 @@ export class CommandAddMultiple implements Command { } } -export class CommandRemove implements Command { +export class CommandRemove extends CommandImpl { private verb: string; private count: number; private item: Item; private slot: number; private noSlot: boolean; constructor(verb: string, count: number, item: Item, slot: number, noSlot: boolean){ + super(); this.verb = verb; this.count = count; this.item = item; @@ -171,12 +184,13 @@ export class CommandRemove implements Command { } } -export class CommandRemoveWithoutCount implements Command { +export class CommandRemoveWithoutCount extends CommandImpl { private verb: string; private item: Item; private slot: number; private noSlot: boolean; constructor(verb: string, item: Item, slot: number, noSlot: boolean){ + super(); this.verb = verb; this.item = item; this.slot = slot; @@ -191,10 +205,11 @@ export class CommandRemoveWithoutCount implements Command { } } -export class CommandRemoveMultiple implements Command { +export class CommandRemoveMultiple extends CommandImpl { private verb: string; private stacks: ItemStack[]; constructor(verb: string, stacks: ItemStack[]){ + super(); this.verb = verb; this.stacks = stacks; } @@ -216,11 +231,12 @@ const joinItemStackString = (initial: string, stacks: ItemStack[]): string => { return parts.join(" "); }; -export class CommandDaP implements Command { +export class CommandDaP extends CommandImpl { private count: number; private item: Item; - constructor(count: number, item: Item,){ + constructor(count: number, item: Item){ + super(); this.count = count; this.item = item; } @@ -233,11 +249,12 @@ export class CommandDaP implements Command { } } -export class CommandEquip implements Command { +export class CommandEquip extends CommandImpl { private item: Item; private slot: number; private noSlot: boolean; constructor(item: Item, slot: number, noSlot: boolean){ + super(); this.item = item; this.slot = slot; this.noSlot = noSlot; @@ -252,11 +269,12 @@ export class CommandEquip implements Command { } } -export class CommandUnequip implements Command { +export class CommandUnequip extends CommandImpl { private item: Item; private slot: number; private noSlot: boolean; constructor(item: Item, slot: number, noSlot: boolean){ + super(); this.item = item; this.slot = slot; this.noSlot = noSlot; @@ -271,9 +289,10 @@ export class CommandUnequip implements Command { } } -export class CommandShootArrow implements Command { +export class CommandShootArrow extends CommandImpl { private count: number; constructor(count: number){ + super(); this.count = count; } @@ -285,7 +304,7 @@ export class CommandShootArrow implements Command { } } -export class CommandCloseGame implements Command { +export class CommandCloseGame extends CommandImpl { public execute(state: SimulationState): void { state.closeGame(); } @@ -294,9 +313,10 @@ export class CommandCloseGame implements Command { } } -export class CommandSync implements Command { +export class CommandSync extends CommandImpl { private actionString: string; constructor(actionString: string){ + super(); this.actionString = actionString; } @@ -308,20 +328,24 @@ export class CommandSync implements Command { } } -export class CommandComment implements Command { - private name: string; - constructor(name: string){ - this.name = name; +export class CommandNop extends CommandImpl { + private text: string; + constructor(text: string){ + super(); + this.text = text; + } + public isValid(): boolean { + return false; } public execute(_state: SimulationState): void { // nothing } public getDisplayString(): string { - return `# ${this.name}`; + return this.text; } } -export class CommandSortKey implements Command { +export class CommandSortKey extends CommandImpl { static Op = 0x5; // public fromBuffer(_buf: Buffer): number { // return 0; @@ -339,7 +363,7 @@ export class CommandSortKey implements Command { } } -export class CommandSortMaterial implements Command { +export class CommandSortMaterial extends CommandImpl { static Op = 0x6; // public fromBuffer(_buf: Buffer): number { // return 0; diff --git a/src/core/Inventory.ts b/src/core/Inventory.ts deleted file mode 100644 index 4bc5e26..0000000 --- a/src/core/Inventory.ts +++ /dev/null @@ -1,215 +0,0 @@ -// import { Item, ItemStack, itemToItemData, ItemType, ItemTypes } from "./Item"; -// import { Slots } from "./Slots"; - -export class Inventory { - // private slots: Slots = new Slots([]); - // private savedSlots: Slots = new Slots([]); - // private namedSlots: {[name: string]: Slots} = {}; - // private numBroken = 0; - // private isInitialSort = false; - // private isAltered = true; - // private inaccurate = false; - // private turnedInOrbs = 0; - // public deepClone(): Inventory { - // const other = new Inventory(); - // other.slots = this.slots.deepClone(); - // other.savedSlots = this.savedSlots.deepClone(); - // other.numBroken = this.numBroken; - // other.isInitialSort = this.isInitialSort; - // other.isAltered = this.isAltered; - // other.inaccurate = this.inaccurate; - // other.turnedInOrbs = this.turnedInOrbs; - // other.namedSlots = {}; - // for(const name in this.namedSlots){ - // other.namedSlots[name] = this.namedSlots[name].deepClone(); - // } - // return other; - // } - - // public getSlots(): Slots { - // return this.slots; - // } - - // public getSavedSlots(): Slots { - // return this.savedSlots; - // } - - // public getNumBroken(): number { - // return this.numBroken; - // } - - // public isInaccurate(): boolean { - // return this.inaccurate; - // } - - // public getTurnedInOrbs(): number { - // return this.turnedInOrbs; - // } - - // public rawInit(stacks: ItemStack[]) { - // this.slots = new Slots(stacks); - // } - - // public init(stacks: ItemStack[]) { - // this.slots = new Slots([]); - // stacks.forEach(s=>{ - // this.slots.add(s.item, s.count); - // }); - // this.numBroken = 0; - // this.isInitialSort = false; - // this.isAltered = true; - // this.inaccurate = false; - // } - - // public closeGame() { - // this.numBroken = 0; - // this.isInitialSort = false; - // this.isAltered = true; - // this.inaccurate = false; - // this.slots = new Slots([]); - // } - - // public addBrokenSlots(num: number) { - // this.numBroken+=num; - // } - - // public setTag(name: string){ - // this.namedSlots[name] = this.savedSlots.deepClone(); - // } - - // public applyTag(name: string){ - // if(name in this.namedSlots){ - // this.savedSlots = this.namedSlots[name].deepClone(); - // }else{ - // this.savedSlots = new Slots([]); - // } - // } - - // public save() { - // if(this.isAltered){ - // this.savedSlots = this.slots.deepClone(); - // } - // // Inventory Corruption - // // get durability transfer slots - // const durabilityTransferSlots: number[] = []; - // const equippedWeapon = this.slots.getFirstEquippedSlotIndex(ItemType.Weapon); - // if(equippedWeapon>=0){ - // durabilityTransferSlots.push(equippedWeapon); - // } - // const equippedBow = this.slots.getFirstEquippedSlotIndex(ItemType.Bow); - // if(equippedBow>=0){ - // durabilityTransferSlots.push(equippedBow); - // } - // const equippedShield = this.slots.getFirstEquippedSlotIndex(ItemType.Shield); - // if(equippedShield>=0){ - // durabilityTransferSlots.push(equippedShield); - // } - // durabilityTransferSlots.forEach(s=>{ - // if(s { - - // // } - // ItemTypes.forEach(type=>{ - // this.slots.addSlotsToEnd(dupeMap[type]); - // this.slots.addSlotsToEnd(this.savedSlots.getByType(type).deepClone()); - // }); - - // this.slots.sortArrows(); - // this.isInitialSort = true; - // this.isAltered = false; - // } - - // public sortKey() { - // const nonKeyItems = this.slots.getBeforeType(ItemType.Key); - // const keyItems = this.slots.getByType(ItemType.Key); - // keyItems.sort(); - // nonKeyItems.addSlotsToEnd(keyItems); - // this.slots = nonKeyItems; - // this.isAltered=true; - // this.isInitialSort=false; - // } - - // public sortMaterial() { - // const beforeMaterial = this.slots.getBeforeType(ItemType.Material); - // const afterMaterial = this.slots.getAfterType(ItemType.Material); - // const materials = this.slots.getByType(ItemType.Material); - // if(this.isInitialSort){ - // // the materials in broken slots are not sorted - // const brokenSlots = Math.max(0, this.numBroken - afterMaterial.length); - // const noSortPart = materials.removeFromEnd(brokenSlots); - // materials.sort(); - // beforeMaterial.addSlotsToEnd(materials); - // beforeMaterial.addSlotsToEnd(noSortPart); - // beforeMaterial.addSlotsToEnd(afterMaterial); - // }else{ - // materials.sort(); - // beforeMaterial.addSlotsToEnd(materials); - // beforeMaterial.addSlotsToEnd(afterMaterial); - // } - - // this.slots = beforeMaterial; - // this.isInitialSort = false; - // this.isAltered=true; - // } - - // public remove(item: Item, count: number, slot: number) { - // this.slots.remove(item, count, slot); - // if(item===Item.SpiritOrb){ - // this.turnedInOrbs+=count; - // } - // this.isAltered=true; - // } - - // public add(item: Item, count: number) { - // this.slots.add(item, count); - // if(itemToItemData(item).type===ItemType.Arrow){ - // this.slots.sortArrows(); - // } - // this.isAltered=true; - // } - - // public equipEquipmentOrArrow(item: Item, slot: number) { - // this.slots.equip(item, slot); - // this.isAltered=true; - // } - - // public unequipEquipment(item: Item, slot: number){ - // this.slots.unequip(item, slot); - // this.isAltered=true; - // } - - // public shootArrow(item: Item, count: number){ - // this.slots.shoot(item, count); - // this.isAltered=true; - // } - -} diff --git a/src/core/Parser.ts b/src/core/Parser.ts index 12003de..f546b2b 100644 --- a/src/core/Parser.ts +++ b/src/core/Parser.ts @@ -5,11 +5,10 @@ import { CommandAddWithoutCount, CommandBreakSlots, CommandCloseGame, - CommandComment, CommandDaP, CommandEquip, CommandInitialize, - CommandNothing, + CommandNop, CommandReload, CommandRemove, CommandRemoveMultiple, @@ -25,25 +24,24 @@ import { } from "./Command"; import { Item, ItemStack } from "./Item"; -export const parseCommand = (cmdString: string): Command | undefined => { +export const parseCommand = (cmdString: string): Command => { - if(cmdString.startsWith("# ")){ - return new CommandComment(cmdString.substring(2)); - } const tokens = cmdString.split(" ").filter(i=>i); if(tokens.length===0){ - return new CommandNothing(); + return new CommandNop(""); } // intialize if(tokens.length>1 && tokens[0] === "Initialize"){ const stacks = parseItemStacks(tokens, 1); - return stacks ? new CommandInitialize(stacks) : undefined; + if(stacks){ + return new CommandInitialize(stacks); + } } // Save/Reload if(tokens.length===1 && tokens[0] === "Save"){ return new CommandSave(); } - // // Multi Save + // Multi Save if (tokens.length === 3 && tokens[0] === "Save" && tokens[1] === "As"){ const name = tokens[2]; return new CommandSaveAs(name); @@ -73,18 +71,18 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(Number.isInteger(count) && item in Item){ return new CommandAdd(tokens[0], count, Item[item as keyof typeof Item]); } - return undefined; } if (tokens.length === 2 && isAddVerb(tokens[0])){ const item = tokens[1]; if(item in Item){ return new CommandAddWithoutCount(tokens[0], Item[item as keyof typeof Item]); } - return undefined; } if(tokens.length>2 && isAddVerb(tokens[0])){ const stacks = parseItemStacks(tokens, 1); - return stacks ? new CommandAddMultiple(tokens[0], stacks) : undefined; + if(stacks){ + return new CommandAddMultiple(tokens[0], stacks); + } } // remove X item From Slot Y if (tokens.length === 6 && isRemoveVerb(tokens[0]) && tokens[3] === "From" && tokens[4] ==="Slot" ){ @@ -94,7 +92,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(Number.isInteger(count) && Number.isInteger(slot) && item in Item){ return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], slot-1, false); } - return undefined; } // remove X item if (tokens.length === 3 && isRemoveVerb(tokens[0]) ){ @@ -103,7 +100,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(Number.isInteger(count) && item in Item){ return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], 0, true); } - return undefined; } // remove item From Slot Y if (tokens.length === 5 && isRemoveVerb(tokens[0]) && tokens[2] === "From" && tokens[3] ==="Slot" ){ @@ -112,7 +108,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(Number.isInteger(slot) && item in Item){ return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], slot-1, false); } - return undefined; } // remove item if (tokens.length === 2 && isRemoveVerb(tokens[0]) ){ @@ -120,12 +115,13 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(item in Item){ return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], 0, true); } - return undefined; } // remove multiple if(tokens.length>2 && isRemoveVerb(tokens[0])){ const stacks = parseItemStacks(tokens, 1); - return stacks ? new CommandRemoveMultiple(tokens[0], stacks) : undefined; + if(stacks){ + return new CommandRemoveMultiple(tokens[0], stacks); + } } //Shortcut for drop and pick up if (tokens.length === 3 && tokens[0] === "D&P" ){ @@ -134,7 +130,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if(Number.isInteger(count) && item in Item){ return new CommandDaP(count, Item[item as keyof typeof Item]); } - return undefined; } // Equip item In Slot X @@ -144,7 +139,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if( Number.isInteger(slot) && item in Item){ return new CommandEquip(Item[item as keyof typeof Item], slot-1, false); } - return undefined; } // Equip item if (tokens.length === 2 && tokens[0] === "Equip"){ @@ -152,7 +146,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if( item in Item){ return new CommandEquip(Item[item as keyof typeof Item], 0, true); } - return undefined; } // Unequip item in slot X if (tokens.length === 5 && tokens[0] === "Unequip" && tokens[2] === "In" && tokens[3] ==="Slot" ){ @@ -161,7 +154,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if( Number.isInteger(slot) && item in Item){ return new CommandUnequip(Item[item as keyof typeof Item], slot-1, false); } - return undefined; } // Unequip item if (tokens.length === 2 && tokens[0] === "Unequip"){ @@ -169,7 +161,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if( item in Item){ return new CommandUnequip(Item[item as keyof typeof Item], -1, true); } - return undefined; } // Shoot X Arrow if (tokens.length === 3 && tokens[0] === "Shoot" && tokens[2] === "Arrow"){ @@ -177,7 +168,6 @@ export const parseCommand = (cmdString: string): Command | undefined => { if( Number.isInteger(count) ){ return new CommandShootArrow(count); } - return undefined; } if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){ @@ -193,15 +183,15 @@ export const parseCommand = (cmdString: string): Command | undefined => { return new CommandSync("Sync GameData"); } - return undefined; + return new CommandNop(cmdString); }; const isAddVerb = (token: string): boolean => { - return token === "Get" || token === "Cook" || token === "Add" || token === "Pickup"; + return token === "Get" || token === "Cook" || token === "Add" || token === "Pickup" || token === "Buy"; }; const isRemoveVerb = (token: string): boolean => { - return token === "Remove" || token === "Sell" || token === "Eat" || token === "Drop"; + return token === "Remove" || token === "Sell" || token === "Eat" || token === "Drop" || token === "With"; }; const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => { diff --git a/src/surfaces/DisplayPane.tsx b/src/surfaces/DisplayPane.tsx index a4d43f8..dd77df7 100644 --- a/src/surfaces/DisplayPane.tsx +++ b/src/surfaces/DisplayPane.tsx @@ -53,6 +53,7 @@ export const DisplayPane: React.FC = ({command,editCommand,dis outline: "none", }}value={commandString} placeholder="Type command here..." + spellCheck={false} onChange={(e)=>{ const cmdString = e.target.value; setCommandString(cmdString); diff --git a/src/surfaces/OptionPage.tsx b/src/surfaces/OptionPage.tsx new file mode 100644 index 0000000..fdccd61 --- /dev/null +++ b/src/surfaces/OptionPage.tsx @@ -0,0 +1,107 @@ +import { TitledList } from "components/TitledList" +import { parseCommand } from "core/Parser"; +import { saveAs } from "data/FileSaver"; +import { useRef, useState } from "react"; + +type OptionPageProps = { + interlaceInventory: boolean, + setInterlaceInventory: (value: boolean)=>void, + commandText: string, + setCommandText: (value: string)=>void, +} + +export const OptionPage: React.FC = ({ + interlaceInventory, + setInterlaceInventory, + commandText, + setCommandText +}) => { + const [currentText, setCurrentText] = useState(commandText); + const [fileName, setFileName] = useState(""); + const uploadRef = useRef(null); + + return ( +
    + + { + const files = e.target.files; + if(files?.length && files[0]){ + const file = files[0]; + const fileName = file.name.endsWith(".txt") ? file.name.substring(0, file.name.length-4) : file.name; + setFileName(fileName); + file.text().then(text=>{ + setCurrentText(text); + setCommandText(text); + }); + } + }}/> + + +
    + +

    + Interlace Inventory with GameData + +

    +

    + Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced. +

    + +

    Import / Export

    +

    + You can also directly copy, paste, or edit the commands here +

    +

    + + + { + setFileName(e.target.value); + }} + placeholder="File name" + /> +