1
0
Fork 0

options refactoring

This commit is contained in:
iTNTPiston 2022-06-24 14:58:33 -07:00
parent 155bc5be84
commit 7174332bf1
9 changed files with 360 additions and 375 deletions

View file

@ -24,6 +24,10 @@ h1 {
font-size: 10pt; font-size: 10pt;
} }
.CommandItemInvalid {
color: red;
}
.CommandItem { .CommandItem {
padding: 2px 2px 2px 10px; padding: 2px 2px 2px 10px;
cursor: pointer; cursor: pointer;
@ -110,7 +114,7 @@ p.Reference {
padding-left: 20px; padding-left: 20px;
} }
p.Example { .Example {
color:#eeee00; color:#eeee00;
} }
@ -123,3 +127,65 @@ h3.Reference2 {
margin-top: 0; margin-top: 0;
margin-bottom: 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;
}

View file

@ -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 React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import "./App.css"; import "./App.css";
@ -11,16 +11,18 @@ import { ItemList } from "components/ItemList";
import { TitledList } from "components/TitledList"; import { TitledList } from "components/TitledList";
import { createSimulationState, SimulationState } from "core/SimulationState"; import { createSimulationState, SimulationState } from "core/SimulationState";
import { ReferencePage } from "surfaces/ReferencePage"; import { ReferencePage } from "surfaces/ReferencePage";
import { OptionPage } from "surfaces/OptionPage";
const getDefaultCommands = (): Command[]=>{ const getDefaultCommands = (): Command[]=>{
const encoded = localStorage.getItem("HDS.CurrentCommandsText"); const encoded = localStorage.getItem("HDS.CurrentCommandsText");
if(encoded){ if(encoded){
const lines = encoded.split("\n"); const lines = encoded.split("\n");
return lines.map(l=>parseCommand(l)).filter(c=>c) as Command[]; return lines.map(parseCommand);
} }
return [ return [
parseCommand("Get 5 Diamond 1 Slate 1 Glider 4 SpiritOrb"), parseCommand("Get 5 Diamond 1 Slate 1 Glider 4 SpiritOrb"),
parseCommand("Save"), parseCommand("Save"),
parseCommand("# Magically break 4 slots"),
parseCommand("Break 4 Slots"), parseCommand("Break 4 Slots"),
parseCommand("Reload"), parseCommand("Reload"),
parseCommand("Save"), parseCommand("Save"),
@ -30,16 +32,16 @@ const getDefaultCommands = (): Command[]=>{
export const App: React.FC = () => { export const App: React.FC = () => {
const [page, setPageInState] = useState<string>("#simulation"); const [page, setPageInState] = useState<string>("#simulation");
const [overlaySave, setOverlaySave] = useState<boolean>(false); // Option States
const [interlaceInventory, setInterlaceInventory] = useState<boolean>(false);
const [commands, setCommands] = useState<Command[]>(getDefaultCommands()); const [commands, setCommands] = useState<Command[]>(getDefaultCommands());
const [selectedSaveName, setSelectedSaveName] = useState<string>(""); const [selectedSaveName, setSelectedSaveName] = useState<string>("");
const [displayIndex, setDisplayIndex] = useState<number>(0); const [displayIndex, setDisplayIndex] = useState<number>(0);
const [contextMenuX, setContextMenuX] = useState<number>(0); const [contextMenuX, setContextMenuX] = useState<number>(0);
const [contextMenuY, setContextMenuY] = useState<number>(0); const [contextMenuY, setContextMenuY] = useState<number>(0);
const [contextMenuShowing, setContextMenuShowing] = useState<boolean>(false);
const [contextIndex, setContextIndex] = useState<number>(-1); const [contextIndex, setContextIndex] = useState<number>(-1);
const uploadRef = useRef<HTMLInputElement>(null);
const contextMenuRef = useRef<HTMLDivElement>(null); const contextMenuRef = useRef<HTMLDivElement>(null);
// compute props // compute props
const simulationStates = useMemo(()=>{ const simulationStates = useMemo(()=>{
@ -51,6 +53,9 @@ export const App: React.FC = () => {
}); });
return simulationStates; return simulationStates;
}, [commands]); }, [commands]);
const commandText = useMemo(()=>{
return commands.map(c=>c.getDisplayString()).join("\n");
}, [commands]);
const setPage = useCallback((hash: string)=>{ const setPage = useCallback((hash: string)=>{
window.location.hash = hash; window.location.hash = hash;
@ -66,7 +71,7 @@ export const App: React.FC = () => {
if(e.code==="ArrowDown"){ if(e.code==="ArrowDown"){
if(displayIndex===commands.length-1){ if(displayIndex===commands.length-1){
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.push(new CommandNothing()); arrCopy.push(new CommandNop(""));
setCommands(arrCopy); setCommands(arrCopy);
setDisplayIndex(arrCopy.length-1); setDisplayIndex(arrCopy.length-1);
}else{ }else{
@ -88,40 +93,32 @@ export const App: React.FC = () => {
}, [commands]); }, [commands]);
useEffect(()=>{ useEffect(()=>{
if(contextMenuRef.current && contextMenuShowing){ if(contextIndex < 0 || contextIndex >= commands.length){
setContextIndex(-1);
}else if(contextMenuRef.current){
const rect = contextMenuRef.current.getBoundingClientRect(); const rect = contextMenuRef.current.getBoundingClientRect();
if (rect.bottom > window.innerHeight){ if (rect.bottom > window.innerHeight){
setContextMenuY(contextMenuY-rect.height); setContextMenuY(contextMenuY-rect.height);
} }
} }
}, [contextMenuRef, contextMenuShowing]); }, [contextMenuRef, contextIndex, commands]);
return ( return (
<div className='Calamity'> <div className='Calamity'>
<input ref={uploadRef} id="Upload" type="File" hidden onChange={(e)=>{
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);
});
}
}}/>
<div id="NavBar" style={{ <div id="NavBar" style={{
backgroundColor: "#262626",
height: 40 height: 40
}}> }}>
<button onClick={()=>{ <button className="MainButton" onClick={()=>{
setPage("#simulation"); setPage("#simulation");
}}>Simulation</button> }}>Simulation</button>
<button onClick={()=>{ <button className="MainButton" onClick={()=>{
setPage("#reference"); setPage("#reference");
}}>Reference</button> }}>Reference</button>
<button disabled>Options</button> <button className="MainButton" onClick={()=>{
setPage("#options");
}}>Options</button>
</div> </div>
<div id="SidePane" style={{ <div id="SidePane" style={{
@ -145,8 +142,9 @@ export const App: React.FC = () => {
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setSelectedSaveName(""); setSelectedSaveName("");
setPage("#simulation");
}} }}
comment={false} useListItem
isSelected={selectedSaveName===""} isSelected={selectedSaveName===""}
> >
@ -159,9 +157,10 @@ export const App: React.FC = () => {
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setSelectedSaveName(name); setSelectedSaveName(name);
setPage("#simulation");
}} }}
comment={false}
isSelected={selectedSaveName===name} isSelected={selectedSaveName===name}
useListItem
> >
{name} {name}
</CommandItem> </CommandItem>
@ -188,6 +187,7 @@ export const App: React.FC = () => {
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setDisplayIndex(i); setDisplayIndex(i);
setPage("#simulation");
const inputField = document.getElementById("CommandInputField"); const inputField = document.getElementById("CommandInputField");
if(inputField){ if(inputField){
inputField.focus(); inputField.focus();
@ -197,12 +197,13 @@ export const App: React.FC = () => {
setContextIndex(i); setContextIndex(i);
setContextMenuX(x); setContextMenuX(x);
setContextMenuY(y); setContextMenuY(y);
setContextMenuShowing(true);
}} }}
key={i} key={i}
isSelected={displayIndex===i} isSelected={displayIndex===i}
isContextSelected={contextIndex===i} isContextSelected={contextIndex===i}
comment={c.getDisplayString().startsWith("#")} isComment={c.getDisplayString().startsWith("#")}
useListItem={!c.getDisplayString().startsWith("#")}
isInvalid={!c.isValid()}
> >
{c.getDisplayString()} {c.getDisplayString()}
</CommandItem> </CommandItem>
@ -210,24 +211,14 @@ export const App: React.FC = () => {
} }
<CommandItem onClick={()=>{ <CommandItem onClick={()=>{
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.push(new CommandNothing()); arrCopy.push(new CommandNop(""));
setCommands(arrCopy); setCommands(arrCopy);
}} onContextMenu={()=>{ }} onContextMenu={()=>{
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.push(new CommandNothing()); arrCopy.push(new CommandNop(""));
setCommands(arrCopy); setCommands(arrCopy);
}}>(new)</CommandItem> }}>(new)</CommandItem>
<CommandItem onClick={(x,y)=>{
setContextIndex(-1);
setContextMenuX(x);
setContextMenuY(y);
setContextMenuShowing(true);
}} onContextMenu={(x,y)=>{
setContextIndex(-1);
setContextMenuX(x);
setContextMenuY(y);
setContextMenuShowing(true);
}}>(options)</CommandItem>
</ol> </ol>
</TitledList> </TitledList>
@ -248,8 +239,6 @@ export const App: React.FC = () => {
<div style={{ <div style={{
maxHeight: 220, maxHeight: 220,
height: "30vh", height: "30vh",
border: "1px solid black",
boxSizing: "border-box",
overflowY: "hidden", overflowY: "hidden",
color: "white", color: "white",
backgroundColor: "#262626" backgroundColor: "#262626"
@ -291,7 +280,7 @@ export const App: React.FC = () => {
}}> }}>
{displayIndex >= 0 && displayIndex < commands.length && {displayIndex >= 0 && displayIndex < commands.length &&
<DisplayPane <DisplayPane
overlaySave={overlaySave} overlaySave={interlaceInventory}
displayIndex={displayIndex} displayIndex={displayIndex}
command={commands[displayIndex].getDisplayString()} command={commands[displayIndex].getDisplayString()}
simulationState={simulationStates[displayIndex]} simulationState={simulationStates[displayIndex]}
@ -309,20 +298,32 @@ export const App: React.FC = () => {
{ {
page === "#reference" && <ReferencePage /> page === "#reference" && <ReferencePage />
} }
{
page === "#options" &&
<OptionPage
interlaceInventory={interlaceInventory}
setInterlaceInventory={setInterlaceInventory}
commandText={commandText}
setCommandText={(value)=>{
if(value !== commandText){
const commands = value.split("\n").map(parseCommand)
setCommands(commands);
}
}}
/>
}
</div> </div>
{ {
contextMenuShowing && <div style={{ contextIndex >= 0 && contextIndex < commands.length && <div style={{
position: "absolute", position: "absolute",
top: 0, top: 0,
left: 0, left: 0,
width: "100vw", width: "100vw",
height: "100vh", height: "100vh",
}} onClick={()=>{ }} onClick={()=>{
setContextMenuShowing(false);
setContextIndex(-1); setContextIndex(-1);
}} onContextMenu={(e)=>{ }} onContextMenu={(e)=>{
setContextMenuShowing(false);
setContextIndex(-1); setContextIndex(-1);
e.preventDefault(); e.preventDefault();
}}> }}>
@ -339,12 +340,11 @@ export const App: React.FC = () => {
listStyleType: "none", listStyleType: "none",
paddingInlineStart: 0 paddingInlineStart: 0
}}> }}>
{contextIndex >= 0 ? <>
<CommandItem onClick={()=>{ <CommandItem onClick={()=>{
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.splice(contextIndex, 0, new CommandNothing()); arrCopy.splice(contextIndex, 0, new CommandNop(""));
setCommands(arrCopy); setCommands(arrCopy);
setContextMenuShowing(false);
setContextIndex(-1); setContextIndex(-1);
}}>Insert Above</CommandItem> }}>Insert Above</CommandItem>
<CommandItem onClick={()=>{ <CommandItem onClick={()=>{
@ -354,7 +354,6 @@ export const App: React.FC = () => {
arrCopy[contextIndex] = arrCopy[contextIndex-1]; arrCopy[contextIndex] = arrCopy[contextIndex-1];
arrCopy[contextIndex-1] = temp; arrCopy[contextIndex-1] = temp;
setCommands(arrCopy); setCommands(arrCopy);
setContextMenuShowing(false);
setContextIndex(-1); setContextIndex(-1);
} }
@ -365,28 +364,9 @@ export const App: React.FC = () => {
if(displayIndex >= commands.length){ if(displayIndex >= commands.length){
setDisplayIndex(commands.length-1); setDisplayIndex(commands.length-1);
} }
setContextMenuShowing(false);
setContextIndex(-1); setContextIndex(-1);
} }
}}>Delete</CommandItem></> : }}>Delete</CommandItem>
<>
<CommandItem onClick={()=>{
setOverlaySave(!overlaySave);
}}>Toggle Save Overlay</CommandItem>
<CommandItem onClick={()=>{
if(uploadRef.current){
uploadRef.current.click();
}
}}>Import</CommandItem>
<CommandItem onClick={()=>{
const lines = commands.map(c=>c.getDisplayString());
const text = lines.join("\n");
saveAs(text, "dupe.txt");
}}>Export</CommandItem>
</>
}
</ul> </ul>
</div> </div>

View file

@ -1,30 +1,55 @@
import clsx from "clsx"; import clsx from "clsx";
import { PropsWithChildren } from "react"; import React, { PropsWithChildren, useCallback } from "react";
type CommandItemProps = PropsWithChildren<{ type CommandItemProps = PropsWithChildren<{
useListItem?: boolean,
isSelected?: boolean, isSelected?: boolean,
comment?:boolean, isComment?: boolean,
isInvalid?: boolean,
isContextSelected?: boolean, isContextSelected?: boolean,
onClick: (x: number, y: number)=>void, onClick: (x: number, y: number)=>void,
onContextMenu?: (x: number, y: number)=>void onContextMenu?: (x: number, y: number)=>void
}>; }>;
export const CommandItem: React.FC<CommandItemProps> = ({isSelected, isContextSelected, comment,children, onClick, onContextMenu}) => { export const CommandItem: React.FC<CommandItemProps> = ({
if(comment){ useListItem,
return <div className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")}>{children}</div>; isSelected,
} isContextSelected,
return <li isComment,
className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")} isInvalid,
onClick={(e)=>{ onClick,
onClick(e.clientX, e.clientY); onContextMenu,
}} children
onContextMenu={(e)=>{ }) => {
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){ if(onContextMenu){
onContextMenu(e.clientX,e.clientY); onContextMenu(e.clientX,e.clientY);
e.preventDefault(); e.preventDefault();
} }
}, [onContextMenu]);
}} if(!useListItem){
>{children}&nbsp;</li>; return (
<div className={className} onClick={clickHandler} onContextMenu={contextMenuHandler}>
{children}&nbsp;
</div>
);
}
return (
<li className={className} onClick={clickHandler} onContextMenu={contextMenuHandler}>
{children}&nbsp;
</li>
);
}; };

View file

@ -1,27 +1,29 @@
import { Inventory } from "./Inventory";
import { Item, ItemStack } from "./Item"; import { Item, ItemStack } from "./Item";
import { SimulationState } from "./SimulationState"; import { SimulationState } from "./SimulationState";
export interface Command { export interface Command {
isValid(): boolean,
execute(state: SimulationState): void, execute(state: SimulationState): void,
getDisplayString(): string, getDisplayString(): string,
} }
export class CommandNothing implements Command { class CommandImpl implements Command{
isValid(): boolean {
execute(_state: Inventory): void { return true;
}
execute(_state: SimulationState): void {
// nothing // nothing
} }
getDisplayString(): string { getDisplayString(): string {
return ""; throw new Error("Method not implemented.");
}
} }
} export class CommandInitialize extends CommandImpl {
export class CommandInitialize implements Command {
private stacks: ItemStack[]; private stacks: ItemStack[];
constructor(stacks: ItemStack[]){ constructor(stacks: ItemStack[]){
super();
this.stacks = stacks; 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 { public execute(state: SimulationState): void {
state.save(); state.save();
@ -44,9 +46,10 @@ export class CommandSave implements Command {
} }
} }
export class CommandSaveAs implements Command { export class CommandSaveAs extends CommandImpl {
private name: string; private name: string;
constructor(name: string){ constructor(name: string){
super();
this.name = name; this.name = name;
} }
public execute(state: SimulationState): void { 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; private name?: string;
constructor(name?: string){ constructor(name?: string){
super();
this.name = name; this.name = name;
} }
public execute(state: SimulationState): void { 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; private name: string;
constructor(name: string){ constructor(name: string){
super();
this.name = name; this.name = name;
} }
public execute(state: SimulationState): void { public execute(state: SimulationState): void {
@ -81,12 +86,16 @@ export class CommandUse implements Command {
public getDisplayString(): string { public getDisplayString(): string {
return `Use ${this.name}`; 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; private numToBreak: number;
constructor(numToBreak: number){ constructor(numToBreak: number){
super();
this.numToBreak = numToBreak; 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 verb: string;
private count: number; private count: number;
private item: Item; private item: Item;
constructor(verb: string, count: number, item: Item){ constructor(verb: string, count: number, item: Item){
super();
this.verb = verb; this.verb = verb;
this.count = count; this.count = count;
this.item = item; 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 verb: string;
private item: Item; private item: Item;
constructor(verb: string, item: Item){ constructor(verb: string, item: Item){
super();
this.verb = verb; this.verb = verb;
this.item = item; 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 verb: string;
private stacks: ItemStack[]; private stacks: ItemStack[];
constructor(verb: string, stacks: ItemStack[]){ constructor(verb: string, stacks: ItemStack[]){
super();
this.verb = verb; this.verb = verb;
this.stacks = stacks; 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 verb: string;
private count: number; private count: number;
private item: Item; private item: Item;
private slot: number; private slot: number;
private noSlot: boolean; private noSlot: boolean;
constructor(verb: string, count: number, item: Item, slot: number, noSlot: boolean){ constructor(verb: string, count: number, item: Item, slot: number, noSlot: boolean){
super();
this.verb = verb; this.verb = verb;
this.count = count; this.count = count;
this.item = item; 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 verb: string;
private item: Item; private item: Item;
private slot: number; private slot: number;
private noSlot: boolean; private noSlot: boolean;
constructor(verb: string, item: Item, slot: number, noSlot: boolean){ constructor(verb: string, item: Item, slot: number, noSlot: boolean){
super();
this.verb = verb; this.verb = verb;
this.item = item; this.item = item;
this.slot = slot; 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 verb: string;
private stacks: ItemStack[]; private stacks: ItemStack[];
constructor(verb: string, stacks: ItemStack[]){ constructor(verb: string, stacks: ItemStack[]){
super();
this.verb = verb; this.verb = verb;
this.stacks = stacks; this.stacks = stacks;
} }
@ -216,11 +231,12 @@ const joinItemStackString = (initial: string, stacks: ItemStack[]): string => {
return parts.join(" "); return parts.join(" ");
}; };
export class CommandDaP implements Command { export class CommandDaP extends CommandImpl {
private count: number; private count: number;
private item: Item; private item: Item;
constructor(count: number, item: Item,){ constructor(count: number, item: Item){
super();
this.count = count; this.count = count;
this.item = item; 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 item: Item;
private slot: number; private slot: number;
private noSlot: boolean; private noSlot: boolean;
constructor(item: Item, slot: number, noSlot: boolean){ constructor(item: Item, slot: number, noSlot: boolean){
super();
this.item = item; this.item = item;
this.slot = slot; this.slot = slot;
this.noSlot = noSlot; 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 item: Item;
private slot: number; private slot: number;
private noSlot: boolean; private noSlot: boolean;
constructor(item: Item, slot: number, noSlot: boolean){ constructor(item: Item, slot: number, noSlot: boolean){
super();
this.item = item; this.item = item;
this.slot = slot; this.slot = slot;
this.noSlot = noSlot; 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; private count: number;
constructor(count: number){ constructor(count: number){
super();
this.count = count; 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 { public execute(state: SimulationState): void {
state.closeGame(); state.closeGame();
} }
@ -294,9 +313,10 @@ export class CommandCloseGame implements Command {
} }
} }
export class CommandSync implements Command { export class CommandSync extends CommandImpl {
private actionString: string; private actionString: string;
constructor(actionString: string){ constructor(actionString: string){
super();
this.actionString = actionString; this.actionString = actionString;
} }
@ -308,20 +328,24 @@ export class CommandSync implements Command {
} }
} }
export class CommandComment implements Command { export class CommandNop extends CommandImpl {
private name: string; private text: string;
constructor(name: string){ constructor(text: string){
this.name = name; super();
this.text = text;
}
public isValid(): boolean {
return false;
} }
public execute(_state: SimulationState): void { public execute(_state: SimulationState): void {
// nothing // nothing
} }
public getDisplayString(): string { public getDisplayString(): string {
return `# ${this.name}`; return this.text;
} }
} }
export class CommandSortKey implements Command { export class CommandSortKey extends CommandImpl {
static Op = 0x5; static Op = 0x5;
// public fromBuffer(_buf: Buffer): number { // public fromBuffer(_buf: Buffer): number {
// return 0; // return 0;
@ -339,7 +363,7 @@ export class CommandSortKey implements Command {
} }
} }
export class CommandSortMaterial implements Command { export class CommandSortMaterial extends CommandImpl {
static Op = 0x6; static Op = 0x6;
// public fromBuffer(_buf: Buffer): number { // public fromBuffer(_buf: Buffer): number {
// return 0; // return 0;

View file

@ -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<this.savedSlots.length){
// // We ignore the case where durability transfer happens from equipment to equipment
// if(itemToItemData(this.savedSlots.get(s).item).stackable){
// this.savedSlots.get(s).count = 999;
// }
// }
// });
// }
// public reload() {
// // get things to dupe
// const dupeMap: {[k in ItemType]: Slots} = {
// [ItemType.Weapon]: new Slots([]),
// [ItemType.Bow]: new Slots([]),
// [ItemType.Arrow]: new Slots([]),
// [ItemType.Shield]: new Slots([]),
// [ItemType.Material]: new Slots([]),
// [ItemType.Meal]: new Slots([]),
// [ItemType.Key]: new Slots([])
// };
// for(let i=Math.max(0, this.slots.length-this.numBroken);i<this.slots.length;i++){
// const stack = this.slots.get(i);
// const itemData = itemToItemData(stack.item);
// dupeMap[itemData.type].addStackCopy(stack);
// }
// // apply dupe
// //console.log(dupeMap);
// this.slots = new Slots([]);
// // const dupeType = (type: ItemType) => {
// // }
// 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;
// }
}

View file

@ -5,11 +5,10 @@ import {
CommandAddWithoutCount, CommandAddWithoutCount,
CommandBreakSlots, CommandBreakSlots,
CommandCloseGame, CommandCloseGame,
CommandComment,
CommandDaP, CommandDaP,
CommandEquip, CommandEquip,
CommandInitialize, CommandInitialize,
CommandNothing, CommandNop,
CommandReload, CommandReload,
CommandRemove, CommandRemove,
CommandRemoveMultiple, CommandRemoveMultiple,
@ -25,25 +24,24 @@ import {
} from "./Command"; } from "./Command";
import { Item, ItemStack } from "./Item"; 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); const tokens = cmdString.split(" ").filter(i=>i);
if(tokens.length===0){ if(tokens.length===0){
return new CommandNothing(); return new CommandNop("");
} }
// intialize // intialize
if(tokens.length>1 && tokens[0] === "Initialize"){ if(tokens.length>1 && tokens[0] === "Initialize"){
const stacks = parseItemStacks(tokens, 1); const stacks = parseItemStacks(tokens, 1);
return stacks ? new CommandInitialize(stacks) : undefined; if(stacks){
return new CommandInitialize(stacks);
}
} }
// Save/Reload // Save/Reload
if(tokens.length===1 && tokens[0] === "Save"){ if(tokens.length===1 && tokens[0] === "Save"){
return new CommandSave(); return new CommandSave();
} }
// // Multi Save // Multi Save
if (tokens.length === 3 && tokens[0] === "Save" && tokens[1] === "As"){ if (tokens.length === 3 && tokens[0] === "Save" && tokens[1] === "As"){
const name = tokens[2]; const name = tokens[2];
return new CommandSaveAs(name); return new CommandSaveAs(name);
@ -73,18 +71,18 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if(Number.isInteger(count) && item in Item){ if(Number.isInteger(count) && item in Item){
return new CommandAdd(tokens[0], count, Item[item as keyof typeof Item]); return new CommandAdd(tokens[0], count, Item[item as keyof typeof Item]);
} }
return undefined;
} }
if (tokens.length === 2 && isAddVerb(tokens[0])){ if (tokens.length === 2 && isAddVerb(tokens[0])){
const item = tokens[1]; const item = tokens[1];
if(item in Item){ if(item in Item){
return new CommandAddWithoutCount(tokens[0], Item[item as keyof typeof Item]); return new CommandAddWithoutCount(tokens[0], Item[item as keyof typeof Item]);
} }
return undefined;
} }
if(tokens.length>2 && isAddVerb(tokens[0])){ if(tokens.length>2 && isAddVerb(tokens[0])){
const stacks = parseItemStacks(tokens, 1); 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 // remove X item From Slot Y
if (tokens.length === 6 && isRemoveVerb(tokens[0]) && tokens[3] === "From" && tokens[4] ==="Slot" ){ 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){ 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 new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], slot-1, false);
} }
return undefined;
} }
// remove X item // remove X item
if (tokens.length === 3 && isRemoveVerb(tokens[0]) ){ 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){ if(Number.isInteger(count) && item in Item){
return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], 0, true); return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], 0, true);
} }
return undefined;
} }
// remove item From Slot Y // remove item From Slot Y
if (tokens.length === 5 && isRemoveVerb(tokens[0]) && tokens[2] === "From" && tokens[3] ==="Slot" ){ 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){ if(Number.isInteger(slot) && item in Item){
return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], slot-1, false); return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], slot-1, false);
} }
return undefined;
} }
// remove item // remove item
if (tokens.length === 2 && isRemoveVerb(tokens[0]) ){ if (tokens.length === 2 && isRemoveVerb(tokens[0]) ){
@ -120,12 +115,13 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if(item in Item){ if(item in Item){
return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], 0, true); return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], 0, true);
} }
return undefined;
} }
// remove multiple // remove multiple
if(tokens.length>2 && isRemoveVerb(tokens[0])){ if(tokens.length>2 && isRemoveVerb(tokens[0])){
const stacks = parseItemStacks(tokens, 1); 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 //Shortcut for drop and pick up
if (tokens.length === 3 && tokens[0] === "D&P" ){ 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){ if(Number.isInteger(count) && item in Item){
return new CommandDaP(count, Item[item as keyof typeof Item]); return new CommandDaP(count, Item[item as keyof typeof Item]);
} }
return undefined;
} }
// Equip item In Slot X // Equip item In Slot X
@ -144,7 +139,6 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if( Number.isInteger(slot) && item in Item){ if( Number.isInteger(slot) && item in Item){
return new CommandEquip(Item[item as keyof typeof Item], slot-1, false); return new CommandEquip(Item[item as keyof typeof Item], slot-1, false);
} }
return undefined;
} }
// Equip item // Equip item
if (tokens.length === 2 && tokens[0] === "Equip"){ if (tokens.length === 2 && tokens[0] === "Equip"){
@ -152,7 +146,6 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if( item in Item){ if( item in Item){
return new CommandEquip(Item[item as keyof typeof Item], 0, true); return new CommandEquip(Item[item as keyof typeof Item], 0, true);
} }
return undefined;
} }
// Unequip item in slot X // Unequip item in slot X
if (tokens.length === 5 && tokens[0] === "Unequip" && tokens[2] === "In" && tokens[3] ==="Slot" ){ 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){ if( Number.isInteger(slot) && item in Item){
return new CommandUnequip(Item[item as keyof typeof Item], slot-1, false); return new CommandUnequip(Item[item as keyof typeof Item], slot-1, false);
} }
return undefined;
} }
// Unequip item // Unequip item
if (tokens.length === 2 && tokens[0] === "Unequip"){ if (tokens.length === 2 && tokens[0] === "Unequip"){
@ -169,7 +161,6 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if( item in Item){ if( item in Item){
return new CommandUnequip(Item[item as keyof typeof Item], -1, true); return new CommandUnequip(Item[item as keyof typeof Item], -1, true);
} }
return undefined;
} }
// Shoot X Arrow // Shoot X Arrow
if (tokens.length === 3 && tokens[0] === "Shoot" && tokens[2] === "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) ){ if( Number.isInteger(count) ){
return new CommandShootArrow(count); return new CommandShootArrow(count);
} }
return undefined;
} }
if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){ 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 new CommandSync("Sync GameData");
} }
return undefined; return new CommandNop(cmdString);
}; };
const isAddVerb = (token: string): boolean => { 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 => { 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 => { const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => {

View file

@ -53,6 +53,7 @@ export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,dis
outline: "none", outline: "none",
}}value={commandString} }}value={commandString}
placeholder="Type command here..." placeholder="Type command here..."
spellCheck={false}
onChange={(e)=>{ onChange={(e)=>{
const cmdString = e.target.value; const cmdString = e.target.value;
setCommandString(cmdString); setCommandString(cmdString);

107
src/surfaces/OptionPage.tsx Normal file
View file

@ -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<OptionPageProps> = ({
interlaceInventory,
setInterlaceInventory,
commandText,
setCommandText
}) => {
const [currentText, setCurrentText] = useState<string>(commandText);
const [fileName, setFileName] = useState<string>("");
const uploadRef = useRef<HTMLInputElement>(null);
return (
<div className="OtherPage">
<input ref={uploadRef} id="Upload" type="File" hidden onChange={(e)=>{
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);
});
}
}}/>
<TitledList title="Options">
<div className="OtherPageContent">
<h3 className="Reference">
Interlace Inventory with GameData
<button className="MainButton" onClick={()=>{
setInterlaceInventory(!interlaceInventory);
}}>
{interlaceInventory ? "ON" : "OFF"}
</button>
</h3>
<h4 className="Reference">
Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced.
</h4>
<h3 className="Reference">Import / Export</h3>
<h4 className="Reference">
You can also directly copy, paste, or edit the commands here
</h4>
<p className="Reference">
<button className="MainButton" onClick={()=>{
if(uploadRef.current){
uploadRef.current.click();
}
}}>
Import
</button>
<button className="MainButton" onClick={()=>{
saveAs(currentText, fileName+".txt" || "dupe.txt");
}}>
Export
</button>
<input
className="MainInput"
spellCheck={false}
value={fileName}
onChange={(e)=>{
setFileName(e.target.value);
}}
placeholder="File name"
/>
<textarea
className="MainInput"
spellCheck={false}
value={currentText}
onChange={(e)=>{
setCurrentText(e.target.value);
}}
/>
{
currentText !== commandText &&
<>
<button className="MainButton" onClick={()=>{
setCommandText(currentText);
}}>
Save
</button>
<span className="Example">Don't forget to save changes</span>
</>
}
</p>
</div>
</TitledList>
</div>
)
}

View file

@ -5,12 +5,12 @@ import React from "react";
export const ReferencePage: React.FC = React.memo(()=>{ export const ReferencePage: React.FC = React.memo(()=>{
return ( return (
<div style={{height: "100%", width: "100%", color: "white"}}> <div className="OtherPage">
<TitledList title="Reference"> <TitledList title="Reference">
<div style={{padding: 10}}> <div className="OtherPageContent">
<h2>Items</h2> <h2>Items</h2>
{ {
getAllItems().map(item=><h4 className="Reference">{item}</h4>) getAllItems().map((item, i)=><h4 key={i} className="Reference">{item}</h4>)
} }
<h2>Commands</h2> <h2>Commands</h2>
<h3 className="Reference">Initialize X item1 Y item2 Z item3 ...</h3> <h3 className="Reference">Initialize X item1 Y item2 Z item3 ...</h3>
@ -81,9 +81,9 @@ export const ReferencePage: React.FC = React.memo(()=>{
<p className="Reference Example">Example: Break 4 Slots</p> <p className="Reference Example">Example: Break 4 Slots</p>
<h3 className="Reference">Get/Add/Cook/Pickup item</h3> <h3 className="Reference">Get/Add/Cook/Pickup/Buy item</h3>
<h3 className="Reference2">Get/Add/Cook/Pickup X item</h3> <h3 className="Reference2">Get/Add/Cook/Pickup/Buy X item</h3>
<h3 className="Reference2">Get/Add/Cook/Pickup X item1 Y item2 Z item3 ...</h3> <h3 className="Reference2">Get/Add/Cook/Pickup/Buy X item1 Y item2 Z item3 ...</h3>
<h4 className="Reference">Simulate obtaining items in game</h4> <h4 className="Reference">Simulate obtaining items in game</h4>
<p className="Reference"> <p className="Reference">
Add the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS Add the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS
@ -103,11 +103,11 @@ export const ReferencePage: React.FC = React.memo(()=>{
<p className="Reference Example">Example 2: Get 10 Apple</p> <p className="Reference Example">Example 2: Get 10 Apple</p>
<p className="Reference Example">Example 3: Pickup 10 Apple 5 Diamond 1 Slate 5 MasterSword</p> <p className="Reference Example">Example 3: Pickup 10 Apple 5 Diamond 1 Slate 5 MasterSword</p>
<h3 className="Reference">Remove/Sell/Eat/Drop item</h3> <h3 className="Reference">With/Remove/Sell/Eat/Drop item</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop X item</h3> <h3 className="Reference2">With/Remove/Sell/Eat/Drop X item</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop item From Slot Y</h3> <h3 className="Reference2">With/Remove/Sell/Eat/Drop item From Slot Y</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop X item From Slot Y</h3> <h3 className="Reference2">With/Remove/Sell/Eat/Drop X item From Slot Y</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop X item1 Y item2 Z item3 ...</h3> <h3 className="Reference2">With/Remove/Sell/Eat/Drop X item1 Y item2 Z item3 ...</h3>
<h4 className="Reference">Simulate removing items in game</h4> <h4 className="Reference">Simulate removing items in game</h4>
<p className="Reference"> <p className="Reference">
Remove the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS Remove the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS
@ -170,6 +170,13 @@ export const ReferencePage: React.FC = React.memo(()=>{
</p> </p>
<p className="Reference Example">Example: Close Game</p> <p className="Reference Example">Example: Close Game</p>
<h3 className="Reference">Sync GameData</h3>
<h4 className="Reference">Copy Visible Inventory to Game Data</h4>
<p className="Reference">
Usually done in game by opening and closing inventory.
</p>
<p className="Reference Example">Example: Sync GameData</p>
<h3 className="Reference">Sort Key/Material</h3> <h3 className="Reference">Sort Key/Material</h3>
<h4 className="Reference">Simulates press Y to sort tab</h4> <h4 className="Reference">Simulates press Y to sort tab</h4>
<p className="Reference Example"> <p className="Reference Example">