1
0
Fork 0

tested arrow corruption

This commit is contained in:
iTNTPiston 2022-06-23 10:47:00 -07:00
parent dbcb7aef8d
commit bbd1e12952
18 changed files with 697 additions and 854 deletions

View file

@ -1,19 +1,16 @@
import { Command, CommandNothing } from "core/Command"; import { Command, CommandNothing } from "core/Command";
import { Inventory } from "core/Inventory";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import "./App.css"; import "./App.css";
import { CommandItem } from "./components/CommandItem"; import { CommandItem } from "./components/CommandItem";
import { DisplayPane } from "surfaces/DisplayPane"; import { DisplayPane } from "surfaces/DisplayPane";
import { Item } from "core/Item";
import { saveAs } from "data/FileSaver"; import { saveAs } from "data/FileSaver";
import { parseCommand } from "core/Parser"; import { parseCommand } from "core/Parser";
import { ItemList } from "components/ItemList"; 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 { GameData } from "core/GameData";
const getDefaultCommands = (): Command[]=>{ const getDefaultCommands = (): Command[]=>{
const encoded = localStorage.getItem("HDS.CurrentCommandsText"); const encoded = localStorage.getItem("HDS.CurrentCommandsText");
@ -28,10 +25,9 @@ const getDefaultCommands = (): Command[]=>{
parseCommand("Reload"), parseCommand("Reload"),
parseCommand("Save"), parseCommand("Save"),
parseCommand("Reload"), parseCommand("Reload"),
] as Command[];; ] as 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); const [overlaySave, setOverlaySave] = useState<boolean>(false);
@ -120,12 +116,12 @@ export const App: React.FC = () => {
height: 40 height: 40
}}> }}>
<button onClick={()=>{ <button onClick={()=>{
setPage("#simulation") setPage("#simulation");
}}>Simulation</button> }}>Simulation</button>
<button onClick={()=>{ <button onClick={()=>{
setPage("#reference") setPage("#reference");
}}>Reference</button> }}>Reference</button>
<button>Options</button> <button disabled>Options</button>
</div> </div>
<div id="SidePane" style={{ <div id="SidePane" style={{
@ -147,31 +143,31 @@ export const App: React.FC = () => {
{ {
!!simulationStates[displayIndex].getManualSave() && !!simulationStates[displayIndex].getManualSave() &&
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setSelectedSaveName(""); setSelectedSaveName("");
}} }}
comment={false} comment={false}
isSelected={selectedSaveName===""} isSelected={selectedSaveName===""}
> >
Manual Save Manual Save
</CommandItem> </CommandItem>
} }
{ {
Object.entries(simulationStates[displayIndex].getNamedSaves()).map(([name, _gamedata])=>( Object.entries(simulationStates[displayIndex].getNamedSaves()).map(([name, _gamedata])=>
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setSelectedSaveName(name); setSelectedSaveName(name);
}} }}
comment={false} comment={false}
isSelected={selectedSaveName===name} isSelected={selectedSaveName===name}
> >
{name} {name}
</CommandItem> </CommandItem>
)) )
} }
</ol> </ol>
} }
</TitledList> </TitledList>
@ -185,55 +181,55 @@ export const App: React.FC = () => {
}}> }}>
<TitledList title="Instructions"> <TitledList title="Instructions">
<ol style={{ <ol style={{
}}> }}>
{ {
commands.map((c,i)=> commands.map((c,i)=>
<CommandItem <CommandItem
onClick={()=>{ onClick={()=>{
setDisplayIndex(i); setDisplayIndex(i);
const inputField = document.getElementById("CommandInputField"); const inputField = document.getElementById("CommandInputField");
if(inputField){ if(inputField){
inputField.focus(); inputField.focus();
} }
}} }}
onContextMenu={(x,y)=>{ onContextMenu={(x,y)=>{
setContextIndex(i); setContextIndex(i);
setContextMenuX(x); setContextMenuX(x);
setContextMenuY(y); setContextMenuY(y);
setContextMenuShowing(true); setContextMenuShowing(true);
}} }}
key={i} key={i}
isSelected={displayIndex===i} isSelected={displayIndex===i}
isContextSelected={contextIndex===i} isContextSelected={contextIndex===i}
comment={c.getDisplayString().startsWith("#")} comment={c.getDisplayString().startsWith("#")}
> >
{c.getDisplayString()} {c.getDisplayString()}
</CommandItem> </CommandItem>
) )
} }
<CommandItem onClick={()=>{ <CommandItem onClick={()=>{
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.push(new CommandNothing()); arrCopy.push(new CommandNothing());
setCommands(arrCopy); setCommands(arrCopy);
}} onContextMenu={()=>{ }} onContextMenu={()=>{
const arrCopy = [...commands]; const arrCopy = [...commands];
arrCopy.push(new CommandNothing()); arrCopy.push(new CommandNothing());
setCommands(arrCopy); setCommands(arrCopy);
}}>(new)</CommandItem> }}>(new)</CommandItem>
<CommandItem onClick={(x,y)=>{ <CommandItem onClick={(x,y)=>{
setContextIndex(-1); setContextIndex(-1);
setContextMenuX(x); setContextMenuX(x);
setContextMenuY(y); setContextMenuY(y);
setContextMenuShowing(true); setContextMenuShowing(true);
}} onContextMenu={(x,y)=>{ }} onContextMenu={(x,y)=>{
setContextIndex(-1); setContextIndex(-1);
setContextMenuX(x); setContextMenuX(x);
setContextMenuY(y); setContextMenuY(y);
setContextMenuShowing(true); setContextMenuShowing(true);
}}>(options)</CommandItem> }}>(options)</CommandItem>
</ol> </ol>
</TitledList> </TitledList>
</div> </div>
@ -249,45 +245,51 @@ export const App: React.FC = () => {
}}> }}>
{ {
page === "#simulation" && <> page === "#simulation" && <>
<div style={{ <div style={{
maxHeight: 220, maxHeight: 220,
height: "30vh", height: "30vh",
border: "1px solid black", border: "1px solid black",
boxSizing: "border-box", boxSizing: "border-box",
overflowY: "hidden", overflowY: "hidden",
color: "white", color: "white",
backgroundColor: "#262626" backgroundColor: "#262626"
} }> } }>
{
(displayIndex >= 0 && displayIndex < commands.length) ?
<TitledList title="Save Data">
{ {
selectedSaveName === "" && !!simulationStates[displayIndex].getManualSave() && displayIndex >= 0 && displayIndex < commands.length ?
<ItemList slots={(simulationStates[displayIndex].getManualSave() as GameData).getDisplayedSlots()}/> <TitledList title="Save Data">
{
(()=>{
if (selectedSaveName === ""){
const manualSave = simulationStates[displayIndex].getManualSave();
if(manualSave){
return <ItemList slots={manualSave.getDisplayedSlots()}/>;
}
}else if(selectedSaveName){
const namedSaves = simulationStates[displayIndex].getNamedSaves();
if(selectedSaveName in namedSaves){
const save = namedSaves[selectedSaveName];
return <ItemList slots={save.getDisplayedSlots()}/>;
}
}
return null;
})()
}
</TitledList>
:
<TitledList title="Select an instruction on the left to view it">
</TitledList>
} }
{
selectedSaveName !== "" && !!simulationStates[displayIndex].getNamedSaves()[selectedSaveName] &&
<ItemList slots={(simulationStates[displayIndex].getNamedSaves()[selectedSaveName] as GameData).getDisplayedSlots()}/>
}
</TitledList>
:
<TitledList title="Select an instruction on the left to view it">
</TitledList> </div>
} <div style={{
minHeight: "calc( 70vh - 40px )",
height: "calc( 100vh - 40px - 220px )",
border: "1px solid black",
</div> boxSizing: "border-box",
<div style={{ overflowY: "hidden"
minHeight: "calc( 70vh - 40px )", }}>
height: "calc( 100vh - 40px - 220px )", {displayIndex >= 0 && displayIndex < commands.length &&
border: "1px solid black",
boxSizing: "border-box",
overflowY: "hidden"
}}>
{displayIndex >= 0 && displayIndex < commands.length &&
<DisplayPane <DisplayPane
overlaySave={overlaySave} overlaySave={overlaySave}
displayIndex={displayIndex} displayIndex={displayIndex}
@ -300,45 +302,15 @@ export const App: React.FC = () => {
}} }}
/> />
} }
</div> </div>
</> </>
} }
{ {
page === "#reference" && <ReferencePage /> page === "#reference" && <ReferencePage />
} }
</div> </div>
{/* <div id="SavePane" style={{
height: "200px"
}}>
</div>
<div id="InstructionPane" style={{
}}> */}
{/* <div id="CommandList" style={{
width: "300px",
height: "calc( 60vh - 5px )",
overflowY: "auto",
border: "1px solid black",
boxSizing: "content-box"
} }>
</div> */}
{/* </div> */}
{ {
contextMenuShowing && <div style={{ contextMenuShowing && <div style={{
position: "absolute", position: "absolute",
@ -411,45 +383,6 @@ export const App: React.FC = () => {
const text = lines.join("\n"); const text = lines.join("\n");
saveAs(text, "dupe.txt"); saveAs(text, "dupe.txt");
}}>Export</CommandItem> }}>Export</CommandItem>
<CommandItem onClick={()=>{
alert(`Available Commands:
Initialize X Item1 Y Item2 Z Item3 ...
Break X Slots - add X broken slots
Save
Reload
Sort Key/Material - sort key items or material
Get/Add/Cook/Pickup X ITEM
Remove/Drop/Sell X ITEM From Slot Y
Remove/Sell/Eat MEAL From Slot X
Limitations:
Inventory corruption is not implemented yet
`);
alert(`Available Items:
Slate
Glider
SpiritOrb
SpeedFood
Lotus
SilentPrincess
Honey
Acorn
FaroshScale
FaroshClaw
FaroshHorn
HeartyBass
Beetle
Opal
Diamond
Tail
Spring
Shaft
Core
Wood
Weapon
`);
}}>Reference</CommandItem>
</> </>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -11,7 +11,7 @@ type CommandItemProps = PropsWithChildren<{
export const CommandItem: React.FC<CommandItemProps> = ({isSelected, isContextSelected, comment,children, onClick, onContextMenu}) => { export const CommandItem: React.FC<CommandItemProps> = ({isSelected, isContextSelected, comment,children, onClick, onContextMenu}) => {
if(comment){ if(comment){
return <div className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")}>{children}</div> return <div className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")}>{children}</div>;
} }
return <li return <li
className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")} className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",comment && "CommandItemComment")}

View file

@ -2,7 +2,6 @@ import clsx from "clsx";
import { DisplayableSlot } from "core/DisplayableInventory"; import { DisplayableSlot } from "core/DisplayableInventory";
import Background from "assets/Background.png"; import Background from "assets/Background.png";
type ItemSlotProps = { type ItemSlotProps = {
slot: DisplayableSlot slot: DisplayableSlot
}; };

View file

@ -1,25 +1,25 @@
import { PropsWithChildren } from "react" import { PropsWithChildren } from "react";
type TitledListProps = PropsWithChildren<{ type TitledListProps = PropsWithChildren<{
title: string title: string
}> }>
export const TitledList: React.FC<TitledListProps> = ({title, children}) => { export const TitledList: React.FC<TitledListProps> = ({title, children}) => {
return ( return (
<> <>
<h3 className="ListHeader" style={{ <h3 className="ListHeader" style={{
height: 40, height: 40,
borderBottom: "2px solid", borderBottom: "2px solid",
boxSizing: "border-box", boxSizing: "border-box",
}}> }}>
{title} {title}
</h3> </h3>
<div style={{ <div style={{
height: "calc( 100% - 40px )", height: "calc( 100% - 40px )",
overflowY: "auto"}} overflowY: "auto"}}
> >
{children} {children}
</div> </div>
</> </>
); );
} };

View file

@ -1,5 +1,5 @@
import { Inventory } from "./Inventory"; import { Inventory } from "./Inventory";
import { Item, ItemStack, itemToArrowType } from "./Item"; import { Item, ItemStack } from "./Item";
import { SimulationState } from "./SimulationState"; import { SimulationState } from "./SimulationState";
export interface Command { export interface Command {
@ -70,7 +70,6 @@ export class CommandReload implements Command {
} }
} }
export class CommandUse implements Command { export class CommandUse implements Command {
private name: string; private name: string;
constructor(name: string){ constructor(name: string){
@ -215,7 +214,7 @@ const joinItemStackString = (initial: string, stacks: ItemStack[]): string => {
parts.push(item); parts.push(item);
}); });
return parts.join(" "); return parts.join(" ");
} };
export class CommandDaP implements Command { export class CommandDaP implements Command {
private count: number; private count: number;
@ -273,7 +272,7 @@ export class CommandUnequip implements Command {
} }
export class CommandShootArrow implements Command { export class CommandShootArrow implements Command {
private count: number private count: number;
constructor(count: number){ constructor(count: number){
this.count = count; this.count = count;
} }
@ -286,39 +285,28 @@ export class CommandShootArrow implements Command {
} }
} }
export class CommandCloseGame implements Command {
public execute(state: SimulationState): void {
state.closeGame();
}
public getDisplayString(): string {
return "Close Game";
}
}
// export class CommandEquipArrow implements Command { export class CommandSync implements Command {
// private item: Item; private actionString: string;
// private slot: number; constructor(actionString: string){
// private noSlot: boolean; this.actionString = actionString;
// constructor(item: Item, slot: number, noSlot: boolean){ }
// this.item = item;
// this.slot = slot;
// this.noSlot = noSlot;
// }
// public execute(inv: Inventory): void {
// inv.equipEquipmentOrArrow(this.item, this.slot);
// }
// public getDisplayString(): string {
// const slotString = this.noSlot ? "" : ` In Slot ${this.slot+1}`;
// return `Equip ${itemToArrowType(this.item)} Arrow${slotString}`;
// }
// }
public execute(state: SimulationState): void {
state.syncGameDataWithPouch();
}
public getDisplayString(): string {
return this.actionString;
// export class CommandCloseGame implements Command { }
// public execute(inv: Inventory): void { }
// inv.closeGame();
// }
// public getDisplayString(): string {
// return "Close Game";
// }
// }
export class CommandComment implements Command { export class CommandComment implements Command {
private name: string; private name: string;
@ -333,38 +321,38 @@ export class CommandComment implements Command {
} }
} }
// export class CommandSortKey implements Command { export class CommandSortKey implements Command {
// static Op = 0x5; static Op = 0x5;
// // public fromBuffer(_buf: Buffer): number { // public fromBuffer(_buf: Buffer): number {
// // return 0; // return 0;
// // } // }
// // public toBuffer(): Buffer { // public toBuffer(): Buffer {
// // const buf: Buffer = Buffer.alloc(1); // const buf: Buffer = Buffer.alloc(1);
// // buf.writeInt8(CommandSortKey.Op); // buf.writeInt8(CommandSortKey.Op);
// // return buf; // return buf;
// // } // }
// public execute(inv: Inventory): void { public execute(_state: SimulationState): void {
// inv.sortKey(); // wip
// } }
// public getDisplayString(): string { public getDisplayString(): string {
// return "Sort Key"; return "Sort Key";
// } }
// } }
// export class CommandSortMaterial implements Command { export class CommandSortMaterial implements Command {
// static Op = 0x6; static Op = 0x6;
// // public fromBuffer(_buf: Buffer): number { // public fromBuffer(_buf: Buffer): number {
// // return 0; // return 0;
// // } // }
// // public toBuffer(): Buffer { // public toBuffer(): Buffer {
// // const buf: Buffer = Buffer.alloc(1); // const buf: Buffer = Buffer.alloc(1);
// // buf.writeInt8(CommandSortMaterial.Op); // buf.writeInt8(CommandSortMaterial.Op);
// // return buf; // return buf;
// // } // }
// public execute(inv: Inventory): void { public execute(_state: SimulationState): void {
// inv.sortMaterial(); // wip
// } }
// public getDisplayString(): string { public getDisplayString(): string {
// return "Sort Material"; return "Sort Material";
// } }
// } }

View file

@ -1,4 +1,4 @@
import { Item, ItemStack, itemToItemData, ItemType } from "./Item" import { ItemStack, itemToItemData, ItemType } from "./Item";
export type DisplayableSlot = { export type DisplayableSlot = {
image: string, image: string,
@ -13,12 +13,13 @@ export interface DisplayableInventory {
} }
export const itemStackToDisplayableSlot = ({item, count, equipped}: ItemStack, isBrokenSlot: boolean): DisplayableSlot => { export const itemStackToDisplayableSlot = ({item, count, equipped}: ItemStack, isBrokenSlot: boolean): DisplayableSlot => {
const data = itemToItemData(item); const data = itemToItemData(item);
return { return {
image: data.image, image: data.image,
displayCount: data.stackable && (data.type === ItemType.Arrow || count > 0), // for unstackable items (meal/key items) display count if count > 1, even if it's unstackable
count, displayCount: data.stackable ? data.type === ItemType.Arrow || count > 0 : count > 1,
isEquipped: equipped, count,
isBrokenSlot isEquipped: equipped,
} isBrokenSlot
} };
};

View file

@ -1,5 +1,4 @@
import { DisplayableInventory, DisplayableSlot, itemStackToDisplayableSlot } from "./DisplayableInventory"; import { DisplayableInventory, DisplayableSlot, itemStackToDisplayableSlot } from "./DisplayableInventory";
import { Item, itemToItemData } from "./Item";
import { Slots } from "./Slots"; import { Slots } from "./Slots";
import { VisibleInventory } from "./VisibleInventory"; import { VisibleInventory } from "./VisibleInventory";
@ -8,28 +7,28 @@ import { VisibleInventory } from "./VisibleInventory";
*/ */
export class GameData implements DisplayableInventory { export class GameData implements DisplayableInventory {
private slots: Slots = new Slots([]); private slots: Slots = new Slots([]);
constructor(slots: Slots){ constructor(slots: Slots){
this.slots = slots; this.slots = slots;
} }
public deepClone(): GameData { public deepClone(): GameData {
return new GameData(this.slots.deepClone()); return new GameData(this.slots.deepClone());
} }
public syncWith(pouch: VisibleInventory) { public syncWith(pouch: VisibleInventory) {
this.slots = pouch.getSlots().deepClone(); this.slots = pouch.getSlots().deepClone();
} }
public updateDurability(durability: number, slot: number){ public updateDurability(durability: number, slot: number){
this.slots.corrupt(durability, slot); this.slots.corrupt(durability, slot);
} }
public addAllToPouchOnReload(pouch: VisibleInventory) { public addAllToPouchOnReload(pouch: VisibleInventory) {
this.slots.getSlotsRef().forEach(stack=>pouch.addWhenReload(stack.item, stack.count, stack.equipped)); this.slots.getSlotsRef().forEach(stack=>pouch.addWhenReload(stack.item, stack.count, stack.equipped));
} }
public getDisplayedSlots(): DisplayableSlot[] { public getDisplayedSlots(): DisplayableSlot[] {
return this.slots.getSlotsRef().map(stack=>itemStackToDisplayableSlot(stack, false)); return this.slots.getSlotsRef().map(stack=>itemStackToDisplayableSlot(stack, false));
} }
} }

View file

@ -1,5 +1,5 @@
import { Item, ItemStack, itemToItemData, ItemType, ItemTypes } from "./Item"; // import { Item, ItemStack, itemToItemData, ItemType, ItemTypes } from "./Item";
import { Slots } from "./Slots"; // import { Slots } from "./Slots";
export class Inventory { export class Inventory {
// private slots: Slots = new Slots([]); // private slots: Slots = new Slots([]);

View file

@ -76,6 +76,7 @@ export enum Item {
Fairy = "Fairy", Fairy = "Fairy",
MasterSword = "MasterSword", MasterSword = "MasterSword",
ZoraArmor = "ZoraArmor",
} }
type ItemData = { type ItemData = {
@ -167,7 +168,7 @@ register(0x50, Item.Weapon, ItemType.Weapon, {
}); });
register(0, Item.MasterSword, ItemType.Weapon, { register(0, Item.MasterSword, ItemType.Weapon, {
stackable: false, stackable: false,
}) });
register(0x60, Item.Bow, ItemType.Bow, { register(0x60, Item.Bow, ItemType.Bow, {
image: Images.ForestDwellerBow, image: Images.ForestDwellerBow,
@ -184,6 +185,10 @@ register(0x80, Item.Shield, ItemType.Shield, {
stackable: false stackable: false
}); });
register(9, Item.ZoraArmor, ItemType.Armor, {
stackable: false
});
//export const idToItemData = (id: number): ItemData => IdToData[id]; //export const idToItemData = (id: number): ItemData => IdToData[id];
export const itemToItemData = (item: Item): ItemData => ItemToData[item] as ItemData; export const itemToItemData = (item: Item): ItemData => ItemToData[item] as ItemData;
export const itemToArrowType = (item: Item): string => { export const itemToArrowType = (item: Item): string => {
@ -193,3 +198,5 @@ export const itemToArrowType = (item: Item): string => {
} }
return ""; return "";
}; };
export const getAllItems = (): string[] => Object.keys(ItemToData);

View file

@ -4,6 +4,7 @@ import {
CommandAddMultiple, CommandAddMultiple,
CommandAddWithoutCount, CommandAddWithoutCount,
CommandBreakSlots, CommandBreakSlots,
CommandCloseGame,
CommandComment, CommandComment,
CommandDaP, CommandDaP,
CommandEquip, CommandEquip,
@ -16,6 +17,9 @@ import {
CommandSave, CommandSave,
CommandSaveAs, CommandSaveAs,
CommandShootArrow, CommandShootArrow,
CommandSortKey,
CommandSortMaterial,
CommandSync,
CommandUnequip, CommandUnequip,
CommandUse CommandUse
} from "./Command"; } from "./Command";
@ -54,7 +58,7 @@ export const parseCommand = (cmdString: string): Command | undefined => {
if(tokens.length===2 && tokens[0] === "Reload"){ if(tokens.length===2 && tokens[0] === "Reload"){
return new CommandReload(tokens[1]); return new CommandReload(tokens[1]);
} }
// break // break
if (tokens.length > 2 && tokens[0] === "Break" && tokens[2]=== "Slots" ){ if (tokens.length > 2 && tokens[0] === "Break" && tokens[2]=== "Slots" ){
const slots = parseInt(tokens[1]); const slots = parseInt(tokens[1]);
if(Number.isInteger(slots)){ if(Number.isInteger(slots)){
@ -176,50 +180,29 @@ export const parseCommand = (cmdString: string): Command | undefined => {
return undefined; return undefined;
} }
// if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){ if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){
// return new CommandSortKey(); return new CommandSortKey();
// } }
// if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Material"){ if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Material"){
// return new CommandSortMaterial(); return new CommandSortMaterial();
// } }
// if(tokens.length===2 && tokens[0] === "Close" && tokens[1] === "Game"){ if(tokens.length===2 && tokens[0] === "Close" && tokens[1] === "Game"){
// return new CommandCloseGame(); return new CommandCloseGame();
// } }
if(tokens.length===2 && tokens[0] === "Sync" && tokens[1] === "GameData"){
// return undefined; return new CommandSync("Sync GameData");
// } }
// // remove material
// // Equip Arrow
// if (tokens.length === 6 && tokens[0] === "Equip" && tokens[2] === "Arrow" && tokens[3] === "In" && tokens[4] ==="Slot" ){
// const item = tokens[1]+"Arrow";
// const slot = parseInt(tokens[5]);
// if( Number.isInteger(slot) && item in Item){
// return new CommandEquipArrow(Item[item as keyof typeof Item], slot-1, false);
// }
// return undefined;
// }
// if (tokens.length === 3 && tokens[0] === "Equip" && tokens[2] === "Arrow" ){
// const item = tokens[1]+"Arrow";
// if(item in Item){
// return new CommandEquipArrow(Item[item as keyof typeof Item], 0, true);
// }
// return undefined;
// }
return undefined; return undefined;
}; };
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";
} };
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";
} };
const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => { const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => {
if((tokens.length-from)%2 !== 0){ if((tokens.length-from)%2 !== 0){
@ -242,4 +225,4 @@ const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefine
} }
} }
return stacks; return stacks;
} };

View file

@ -5,160 +5,161 @@ import { Slots } from "./Slots";
import { VisibleInventory } from "./VisibleInventory"; import { VisibleInventory } from "./VisibleInventory";
export const createSimulationState = (): SimulationState => { export const createSimulationState = (): SimulationState => {
return new SimulationState( return new SimulationState(
new GameData(new Slots([])), new GameData(new Slots([])),
null, null,
{}, {},
new VisibleInventory(new Slots([]), 0) new VisibleInventory(new Slots([]), 0)
); );
} };
/* /*
* The state of simulation, including game data, visible inventory, and all save slots * The state of simulation, including game data, visible inventory, and all save slots
*/ */
export class SimulationState { export class SimulationState {
private gameData: GameData; private gameData: GameData;
private manualSave: GameData | null; private manualSave: GameData | null;
private namedSaves: {[name: string]: GameData} = {}; private namedSaves: {[name: string]: GameData} = {};
private pouch: VisibleInventory; private pouch: VisibleInventory;
private nextReloadName?: string; private nextReloadName?: string;
private isOnEventide: boolean = false; private isOnEventide = false;
constructor(gameData: GameData, manualSave: GameData | null, namedSaves: {[name: string]: GameData}, pouch: VisibleInventory){ constructor(gameData: GameData, manualSave: GameData | null, namedSaves: {[name: string]: GameData}, pouch: VisibleInventory){
this.gameData = gameData; this.gameData = gameData;
this.manualSave = manualSave; this.manualSave = manualSave;
this.namedSaves = namedSaves; this.namedSaves = namedSaves;
this.pouch = pouch; this.pouch = pouch;
} }
public deepClone(): SimulationState { public deepClone(): SimulationState {
const copyNamedSaves: {[name: string]: GameData} = {}; const copyNamedSaves: {[name: string]: GameData} = {};
for(const name in this.namedSaves){ for(const name in this.namedSaves){
copyNamedSaves[name] = this.namedSaves[name].deepClone(); copyNamedSaves[name] = this.namedSaves[name].deepClone();
} }
const newState = new SimulationState( const newState = new SimulationState(
this.gameData.deepClone(), this.gameData.deepClone(),
this.manualSave ? this.manualSave.deepClone() : null, this.manualSave ? this.manualSave.deepClone() : null,
copyNamedSaves, copyNamedSaves,
this.pouch.deepClone() this.pouch.deepClone()
); );
newState.nextReloadName = this.nextReloadName; newState.nextReloadName = this.nextReloadName;
newState.isOnEventide = this.isOnEventide; newState.isOnEventide = this.isOnEventide;
return newState; return newState;
} }
public initialize(stacks: ItemStack[]) { public initialize(stacks: ItemStack[]) {
this.pouch = new VisibleInventory(new Slots([]), 0); this.pouch = new VisibleInventory(new Slots([]), 0);
stacks.forEach((stack)=>this.pouch.addDirectly(stack)); stacks.forEach((stack)=>this.pouch.addDirectly(stack));
this.gameData.syncWith(this.pouch); this.gameData.syncWith(this.pouch);
} }
public save(name?: string) { public save(name?: string) {
if(name){ if(name){
this.namedSaves[name] = this.gameData.deepClone(); this.namedSaves[name] = this.gameData.deepClone();
}else{ }else{
this.manualSave = this.gameData.deepClone(); this.manualSave = this.gameData.deepClone();
} }
} }
public reload(name?: string) { public reload(name?: string) {
if(name){ if(name){
if(name in this.namedSaves){ if(name in this.namedSaves){
this.reloadFrom(this.namedSaves[name]); this.reloadFrom(this.namedSaves[name]);
} }
}else{ }else{
if(this.nextReloadName){ if(this.nextReloadName){
if(this.nextReloadName in this.namedSaves){ if(this.nextReloadName in this.namedSaves){
this.reloadFrom(this.namedSaves[this.nextReloadName]); this.reloadFrom(this.namedSaves[this.nextReloadName]);
} }
}else{ }else{
const save = this.manualSave; const save = this.manualSave;
if(save){ if(save){
this.reloadFrom(save); this.reloadFrom(save);
} }
} }
} }
} }
private reloadFrom(data: GameData) { private reloadFrom(data: GameData) {
this.gameData = data.deepClone(); this.gameData = data.deepClone();
this.pouch.clearForReload(); this.pouch.clearForReload();
this.gameData.addAllToPouchOnReload(this.pouch); this.gameData.addAllToPouchOnReload(this.pouch);
this.pouch.updateEquipmentDurability(this.gameData); this.pouch.updateEquipmentDurability(this.gameData);
} }
public useSaveForNextReload(name: string){ public useSaveForNextReload(name: string){
this.nextReloadName = name; this.nextReloadName = name;
} }
public breakSlots(n: number) { public breakSlots(n: number) {
this.pouch.modifyCount(-n); this.pouch.modifyCount(-n);
} }
public obtain(item: Item, count: number) { public obtain(item: Item, count: number) {
this.pouch.addInGame(item, count); this.pouch.addInGame(item, count);
this.syncGameDataWithPouch(); this.syncGameDataWithPouch();
} }
public remove(item: Item, count: number, slot: number) { public remove(item: Item, count: number, slot: number) {
this.pouch.remove(item, count, slot); this.pouch.remove(item, count, slot);
this.syncGameDataWithPouch(); this.syncGameDataWithPouch();
} }
public equip(item: Item, slot: number) { public equip(item: Item, slot: number) {
this.pouch.equip(item, slot); this.pouch.equip(item, slot);
this.syncGameDataWithPouch(); this.syncGameDataWithPouch();
} }
public unequip(item: Item, slot: number){ public unequip(item: Item, slot: number){
this.pouch.unequip(item, slot); this.pouch.unequip(item, slot);
this.syncGameDataWithPouch(); this.syncGameDataWithPouch();
} }
public shootArrow(count: number){ public shootArrow(count: number){
this.pouch.shootArrow(count, this.gameData); this.pouch.shootArrow(count, this.gameData);
// does not sync // does not sync
} }
public syncGameDataWithPouch() { public closeGame() {
if(!this.isOnEventide){ this.pouch = new VisibleInventory(new Slots([]), 0);
this.gameData.syncWith(this.pouch); this.gameData = new GameData(new Slots([]));
} this.isOnEventide = false;
} }
public get displayableGameData(): DisplayableInventory { public syncGameDataWithPouch() {
return this.gameData; if(!this.isOnEventide){
} this.gameData.syncWith(this.pouch);
}
}
public get displayablePouch(): DisplayableInventory { public get displayableGameData(): DisplayableInventory {
return this.pouch; return this.gameData;
} }
public get inventoryMCount(): number { public get displayablePouch(): DisplayableInventory {
return this.pouch.getCount(); return this.pouch;
} }
public getManualSave(): GameData | null { public get inventoryMCount(): number {
return this.manualSave; return this.pouch.getCount();
} }
public getNamedSaves(): {[name: string]: GameData} { public getManualSave(): GameData | null {
return this.namedSaves; return this.manualSave;
} }
// public get displayableGameData(): DisplayableInventory { public getNamedSaves(): {[name: string]: GameData} {
// return this.gameData; return this.namedSaves;
// } }
// public get displayableGameData(): DisplayableInventory {
// return this.gameData;
// }
} }
// Shoot X Arrow, x can be ommited and default to 1 // Shoot X Arrow, x can be ommited and default to 1
// Close Game
// Close Inventory, same as Resync GameData // Close Inventory, same as Resync GameData
// Enter Eventide / Leave Eventide // Enter Eventide / Leave Eventide
// Sort Key (In Tab X) - need more research on which tab is sorted. (might not be possible to select which tab to sort) // Sort Key (In Tab X) - need more research on which tab is sorted. (might not be possible to select which tab to sort)

View file

@ -1,8 +1,6 @@
import { count } from "console";
import { stableSort } from "data/mergeSort"; import { stableSort } from "data/mergeSort";
import { Item, ItemStack, itemToItemData, ItemType } from "./Item"; import { Item, ItemStack, itemToItemData, ItemType } from "./Item";
/* /*
* This is the data model common to GameData and VisibleInventory * This is the data model common to GameData and VisibleInventory
*/ */
@ -43,21 +41,7 @@ export class Slots {
public clearFirst(count: number) { public clearFirst(count: number) {
this.internalSlots.splice(0, count); this.internalSlots.splice(0, count);
} }
// public get(i: number): ItemStack{
// return this.internalSlots[i];
// }
// public getByType(type: ItemType): Slots {
// return new Slots(this.internalSlots.filter(s=>itemToItemData(s.item).type===type));
// }
// public getBeforeType(type: ItemType): Slots {
// return new Slots(this.internalSlots.filter(s=>itemToItemData(s.item).type<type));
// }
// public getAfterType(type: ItemType): Slots {
// return new Slots(this.internalSlots.filter(s=>itemToItemData(s.item).type>type));
// }
// public addSlotsToEnd(slots: Slots) {
// slots.internalSlots.forEach(s=>this.addStack(s));
// }
public addStackDirectly(stack: ItemStack): number { public addStackDirectly(stack: ItemStack): number {
const data = itemToItemData(stack.item); const data = itemToItemData(stack.item);
if(data.stackable){ if(data.stackable){
@ -73,18 +57,6 @@ export class Slots {
this.internalSlots.push({...stack}); this.internalSlots.push({...stack});
this.sortItemType(mCount); this.sortItemType(mCount);
} }
// public addStackCopy(stack: ItemStack) {
// this.addStack({...stack});
// }
// public sort() {
// this.internalSlots.sort((a,b)=>{
// return itemToItemData(a.item).sortOrder - itemToItemData(b.item).sortOrder;
// });
// }
// public removeFromEnd(count: number): Slots {
// const end = this.internalSlots.splice(-count, count);
// return new Slots(end);
// }
// remove item(s) start from slot // remove item(s) start from slot
// return number of slots removed // return number of slots removed
@ -179,34 +151,29 @@ export class Slots {
} }
if(reloading){ if(reloading){
for(let i=0;i<count;i++){ this.addSlot({item,count,equipped: equippedDuringReload}, mCount+1);
this.addSlot({item,count:1,equipped: equippedDuringReload}, mCount+i+1); return 1;
}
if(data.type===ItemType.Weapon || data.type===ItemType.Bow || data.type===ItemType.Shield){
//Check equip
const shouldEquipNew = this.internalSlots.filter(s=>{
const sData = itemToItemData(s.item);
return sData.type === data.type && s.equipped;
}).length === 0;
this.addSlot({item,count:1,equipped: shouldEquipNew}, mCount+1);
for(let i=1;i<count;i++){
this.addSlot({item,count:1,equipped: false}, mCount+i+1);
} }
}else{ }else{
if(data.type===ItemType.Weapon || data.type===ItemType.Bow || data.type===ItemType.Shield){ for(let i=0;i<count;i++){
//Check equip this.addSlot({item,count:1,equipped: false}, mCount+i+1);
const shouldEquipNew = this.internalSlots.filter(s=>{
const sData = itemToItemData(s.item);
return sData.type === data.type && s.equipped;
}).length === 0;
this.addSlot({item,count:1,equipped: shouldEquipNew}, mCount+1);
for(let i=1;i<count;i++){
this.addSlot({item,count:1,equipped: false}, mCount+i+1);
}
}else{
for(let i=0;i<count;i++){
this.addSlot({item,count:1,equipped: false}, mCount+i+1);
}
} }
} }
return count; return count;
} }
// this is for both equipments and arrows // this is for both equipments and arrows
public equip(item: Item, slot: number) { public equip(item: Item, slot: number) {
let s = 0; let s = 0;
@ -259,8 +226,9 @@ export class Slots {
if(slot < 0 || slot >= this.internalSlots.length){ if(slot < 0 || slot >= this.internalSlots.length){
return; return;
} }
const thisData = itemToItemData(this.internalSlots[slot].item); const thisData = itemToItemData(this.internalSlots[slot].item);
if(thisData.stackable){ // Currently only supports corrupting arrows, material, meal and key items as durability values are not simulated on equipments
if(thisData.type >= ItemType.Material || thisData.stackable){
this.internalSlots[slot].count = durability; this.internalSlots[slot].count = durability;
} }
} }
@ -268,20 +236,22 @@ export class Slots {
// shoot count arrows. return the slot that was updated, or -1 // shoot count arrows. return the slot that was updated, or -1
public shootArrow(count: number): number { public shootArrow(count: number): number {
// first find equipped arrow, search entire inventory // first find equipped arrow, search entire inventory
// this is the last equipped arrow before armor
let i=0; let i=0;
let equippedArrow: Item | undefined = undefined;
for(;i<this.internalSlots.length;i++){ for(;i<this.internalSlots.length;i++){
if(this.internalSlots[i].equipped){ const data = itemToItemData(this.internalSlots[i].item);
const data = itemToItemData(this.internalSlots[i].item); if(data.type > ItemType.Shield){
if(data.type === ItemType.Arrow){ break;
break; }
} if(this.internalSlots[i].equipped && data.type === ItemType.Arrow){
equippedArrow = data.item;
} }
} }
if(i>=this.internalSlots.length){ if(i>=this.internalSlots.length){
//can't find equipped arrow //can't find equipped arrow
return -1; return -1;
} }
const equippedArrow = this.internalSlots[i].item;
// now find the first slot of that arrow and update // now find the first slot of that arrow and update
for(let j=0;j<this.internalSlots.length;j++){ for(let j=0;j<this.internalSlots.length;j++){
if(this.internalSlots[j].item === equippedArrow){ if(this.internalSlots[j].item === equippedArrow){
@ -293,34 +263,5 @@ export class Slots {
return -1; return -1;
} }
// // Difference between shoot and remove:
// // 1. can only be from first (leftmost) slot
// // 2. empty slots not removed
// public shoot(item: Item, count: number) {
// for(let i = 0; i<this.internalSlots.length;i++){
// if(this.internalSlots[i].item === item){
// this.internalSlots[i].count-=count;
// }
// }
// }
// public sortArrows() {
// const after = this.removeFromEnd(this.getAfterType(ItemType.Arrow).length);
// const arrows = this.removeFromEnd(this.getByType(ItemType.Arrow).length);
// arrows.sort();
// this.addSlotsToEnd(arrows);
// this.addSlotsToEnd(after);
// }
// public getFirstEquippedSlotIndex(type: ItemType): number {
// for(let i = 0; i<this.internalSlots.length;i++){
// if(this.internalSlots[i].equipped){
// const data = itemToItemData(this.internalSlots[i].item);
// if(data.type === type){
// return i;
// }
// }
// }
// return -1;
// }
} }

View file

@ -7,102 +7,102 @@ import { Slots } from "./Slots";
* Implementation of Visible Inventory (PauseMenuDataMgr) in botw * Implementation of Visible Inventory (PauseMenuDataMgr) in botw
*/ */
export class VisibleInventory implements DisplayableInventory{ export class VisibleInventory implements DisplayableInventory{
private slots: Slots = new Slots([]); private slots: Slots = new Slots([]);
/* Implementation of mCount in botw */ /* Implementation of mCount in botw */
private count: number = 0; private count = 0;
constructor(slots: Slots, count: number){ constructor(slots: Slots, count: number){
this.slots = slots; this.slots = slots;
this.count = count; this.count = count;
} }
public deepClone(): VisibleInventory { public deepClone(): VisibleInventory {
return new VisibleInventory(this.slots.deepClone(), this.count); return new VisibleInventory(this.slots.deepClone(), this.count);
} }
public getDisplayedSlots(): DisplayableSlot[] { public getDisplayedSlots(): DisplayableSlot[] {
return this.slots.getSlotsRef().map((stack, i)=>itemStackToDisplayableSlot(stack, i>=this.count)); return this.slots.getSlotsRef().map((stack, i)=>itemStackToDisplayableSlot(stack, i>=this.count));
} }
public getSlots(): Slots { public getSlots(): Slots {
return this.slots; return this.slots;
} }
public addDirectly(stack: ItemStack){ public addDirectly(stack: ItemStack){
this.count+=this.slots.addStackDirectly(stack); this.count+=this.slots.addStackDirectly(stack);
} }
public addWhenReload(item: Item, count: number, equippedDuringReload: boolean) { public addWhenReload(item: Item, count: number, equippedDuringReload: boolean) {
const slotsAdded = this.slots.add(item, count, equippedDuringReload, true, this.count); const slotsAdded = this.slots.add(item, count, equippedDuringReload, true, this.count);
this.count+=slotsAdded; this.count+=slotsAdded;
} }
public addInGame(item: Item, count: number) { public addInGame(item: Item, count: number) {
const slotsAdded = this.slots.add(item, count, false, false, this.count); const slotsAdded = this.slots.add(item, count, false, false, this.count);
this.count+=slotsAdded; this.count+=slotsAdded;
} }
public remove(item: Item, count: number, slot: number) { public remove(item: Item, count: number, slot: number) {
const slotsRemoved = this.slots.remove(item, count, slot); const slotsRemoved = this.slots.remove(item, count, slot);
this.count-=slotsRemoved; this.count-=slotsRemoved;
} }
public equip(item: Item, slot: number) { public equip(item: Item, slot: number) {
this.slots.equip(item, slot); this.slots.equip(item, slot);
} }
public unequip(item: Item, slot: number) { public unequip(item: Item, slot: number) {
this.slots.unequip(item, slot); this.slots.unequip(item, slot);
} }
// Only clears first this.count // Only clears first this.count
public clearForReload() { public clearForReload() {
if(this.count > 0){ if(this.count > 0){
this.slots.clearFirst(this.count); this.slots.clearFirst(this.count);
this.count = 0; this.count = 0;
} }
} }
public updateEquipmentDurability(gameData: GameData) { public updateEquipmentDurability(gameData: GameData) {
// find first weapon/bow/shield. this one searches entire inventory // find first weapon/bow/shield. this one searches entire inventory
let foundWeapon = false; let foundWeapon = false;
let foundBow = false; let foundBow = false;
let foundShield = false; let foundShield = false;
this.slots.getSlotsRef().forEach(({item, equipped}, i)=>{ this.slots.getSlotsRef().forEach(({item, equipped}, i)=>{
if(equipped){ if(equipped){
const type = itemToItemData(item).type; const type = itemToItemData(item).type;
if(type === ItemType.Weapon && !foundWeapon){ if(type === ItemType.Weapon && !foundWeapon){
gameData.updateDurability(999, i); gameData.updateDurability(999, i);
foundWeapon = true; foundWeapon = true;
} }
if(type === ItemType.Bow && !foundBow){ if(type === ItemType.Bow && !foundBow){
gameData.updateDurability(999, i); gameData.updateDurability(999, i);
foundBow = true; foundBow = true;
} }
if(type === ItemType.Shield && !foundShield){ if(type === ItemType.Shield && !foundShield){
gameData.updateDurability(999, i); gameData.updateDurability(999, i);
foundShield = true; foundShield = true;
} }
} }
}) });
} }
public shootArrow(count: number, gameData: GameData) { public shootArrow(count: number, gameData: GameData) {
const updatedSlot = this.slots.shootArrow(count); const updatedSlot = this.slots.shootArrow(count);
if(updatedSlot>=0){ if(updatedSlot>=0){
const durability = this.slots.getSlotsRef()[updatedSlot].count; const durability = this.slots.getSlotsRef()[updatedSlot].count;
gameData.updateDurability(durability, updatedSlot); gameData.updateDurability(durability, updatedSlot);
} }
} }
public getCount(): number { public getCount(): number {
return this.count; return this.count;
} }
public modifyCount(delta: number): void { public modifyCount(delta: number): void {
this.count+=delta; this.count+=delta;
} }
public resetCount(): void { public resetCount(): void {
this.count = this.slots.length; this.count = this.slots.length;
} }
} }

View file

@ -1,14 +1,14 @@
//https://medium.com/@fsufitch/is-javascript-array-sort-stable-46b90822543f //https://medium.com/@fsufitch/is-javascript-array-sort-stable-46b90822543f
export const stableSort = <T>(array: T[], cmp: (a:T, b:T) => number): void => { export const stableSort = <T>(array: T[], cmp: (a:T, b:T) => number): void => {
const stabilizedThis: [T, number][] = array.map((el, index) => [el, index]); const stabilizedThis: [T, number][] = array.map((el, index) => [el, index]);
const stableCmp = (a: [T, number], b: [T, number]) => { const stableCmp = (a: [T, number], b: [T, number]) => {
let order = cmp(a[0], b[0]); const order = cmp(a[0], b[0]);
if (order != 0) return order; if (order != 0) {return order;}
return a[1] - b[1]; return a[1] - b[1];
} };
stabilizedThis.sort(stableCmp); stabilizedThis.sort(stableCmp);
for (let i=0; i<array.length; i++) { for (let i=0; i<array.length; i++) {
array[i] = stabilizedThis[i][0]; array[i] = stabilizedThis[i][0];
} }
} };

View file

@ -1,16 +1,14 @@
import clsx from "clsx"; import clsx from "clsx";
import { ItemList, ItemListProps } from "components/ItemList";
import { DoubleItemSlot } from "components/ItemSlot"; import { DoubleItemSlot } from "components/ItemSlot";
import { TitledList } from "components/TitledList"; import { TitledList } from "components/TitledList";
import { Command } from "core/Command"; import { Command } from "core/Command";
import { ItemStack, itemToItemData } from "core/Item";
import { parseCommand } from "core/Parser"; import { parseCommand } from "core/Parser";
import { SimulationState } from "core/SimulationState"; import { SimulationState } from "core/SimulationState";
import { Slots } from "core/Slots";
import Background from "assets/Background.png"; import Background from "assets/Background.png";
import InGameBackground from "assets/InGame.png"; import InGameBackground from "assets/InGame.png";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { ItemList } from "components/ItemList";
type DisplayPaneProps = { type DisplayPaneProps = {
command: string, command: string,
@ -20,23 +18,6 @@ type DisplayPaneProps = {
editCommand: (c: Command)=>void editCommand: (c: Command)=>void
} }
// export const stacksToItemListProps = (slots: Slots, numBroken: number, isSave: boolean): ItemListProps => {
// return {
// items: stacksToItemProps(slots.getSlotsRef()),
// numBroken,
// isSave,
// };
// };
// export const stacksToItemProps = (stacks: ItemStack[]): ItemListItemProps[] => {
// return stacks.map(stackToItemProps);
// };
// export const stackToItemProps = ({item, count, equipped}: ItemStack): ItemListItemProps => {
// const data = itemToItemData(item);
// return {image: data.image, count: data.stackable ? count : 0, isEquipped:equipped};
// };
export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,displayIndex,simulationState, overlaySave})=>{ export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,displayIndex,simulationState, overlaySave})=>{
const [commandString, setCommandString] = useState<string>(""); const [commandString, setCommandString] = useState<string>("");
const [hasError, setHasError] = useState<boolean>(false); const [hasError, setHasError] = useState<boolean>(false);
@ -88,88 +69,83 @@ export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,dis
<div style={{ <div style={{
height: "calc( 100% - 40px )" height: "calc( 100% - 40px )"
}}> }}>
{overlaySave ? {overlaySave ?
<div style={{ <div style={{
borderTop: "1px solid black", borderTop: "1px solid black",
boxSizing: "border-box", boxSizing: "border-box",
height: "100%", height: "100%",
overflowY: "auto", overflowY: "auto",
background: `url(${InGameBackground})`, background: `url(${InGameBackground})`,
backgroundPosition: "center", backgroundPosition: "center",
backgroundSize: "auto 100%", backgroundSize: "auto 100%",
color: "white", color: "white",
} }> } }>
<TitledList title={`Game Data / Visible Inventory (Count=${simulationState.inventoryMCount})`}> <TitledList title={`Game Data / Visible Inventory (Count=${simulationState.inventoryMCount})`}>
{ {
(()=>{ (()=>{
const doubleSlots: JSX.Element[] = []; const doubleSlots: JSX.Element[] = [];
const gameDataSlots = simulationState.displayableGameData.getDisplayedSlots(); const gameDataSlots = simulationState.displayableGameData.getDisplayedSlots();
const inventorySlots = simulationState.displayablePouch.getDisplayedSlots(); const inventorySlots = simulationState.displayablePouch.getDisplayedSlots();
console.log(inventorySlots); for(let i=0;i<gameDataSlots.length && i<inventorySlots.length;i++){
for(let i=0;i<gameDataSlots.length && i<inventorySlots.length;i++){ doubleSlots.push(<DoubleItemSlot key={i}
doubleSlots.push(<DoubleItemSlot key={i}
first={{slot: gameDataSlots[i]}}
second={{slot: inventorySlots[i]}}
/>);
}
if(inventorySlots.length>gameDataSlots.length){
for(let i=inventorySlots.length;i<gameDataSlots.length;i++){
doubleSlots.push(<DoubleItemSlot key={i+inventorySlots.length}
first={{slot: gameDataSlots[i]}} first={{slot: gameDataSlots[i]}}
/>);
}
}else if(inventorySlots.length > gameDataSlots.length){
for(let i=gameDataSlots.length;i<inventorySlots.length;i++){
doubleSlots.push(<DoubleItemSlot key={i + gameDataSlots.length}
second={{slot: inventorySlots[i]}} second={{slot: inventorySlots[i]}}
/>); />);
} }
} if(gameDataSlots.length>inventorySlots.length){
return doubleSlots; for(let i=inventorySlots.length;i<gameDataSlots.length;i++){
})() doubleSlots.push(<DoubleItemSlot key={i+inventorySlots.length}
} first={{slot: gameDataSlots[i]}}
/>);
}
}else if(inventorySlots.length > gameDataSlots.length){
for(let i=gameDataSlots.length;i<inventorySlots.length;i++){
doubleSlots.push(<DoubleItemSlot key={i + gameDataSlots.length}
second={{slot: inventorySlots[i]}}
/>);
}
}
return doubleSlots;
})()
}
</TitledList> </TitledList>
</div>
:<>
<div style={{
borderTop: "1px solid black",
background: `url(${Background})`,
color: "white",
borderBottom: "1px solid black",
boxSizing: "border-box",
height: "50%",
overflowY: "auto"
} }>
<TitledList title="Game Data">
<ItemList slots={simulationState.displayableGameData.getDisplayedSlots()}/>
</TitledList>
</div> </div>
<div style={{
borderTop: "1px solid black", :<>
background: `url(${InGameBackground})`,
backgroundPosition: "center", <div style={{
backgroundSize: "100%", borderTop: "1px solid black",
boxSizing: "border-box", background: `url(${Background})`,
height: "50%", color: "white",
overflowY: "auto", borderBottom: "1px solid black",
color: "white" boxSizing: "border-box",
} }> height: "50%",
<TitledList title={`Visible Inventory (Count=${simulationState.inventoryMCount})`}> overflowY: "auto"
<ItemList slots={simulationState.displayablePouch.getDisplayedSlots()}/> } }>
</TitledList> <TitledList title="Game Data">
<ItemList slots={simulationState.displayableGameData.getDisplayedSlots()}/>
</TitledList>
</div>
<div style={{
borderTop: "1px solid black",
background: `url(${InGameBackground})`,
backgroundPosition: "center",
backgroundSize: "100%",
boxSizing: "border-box",
height: "50%",
overflowY: "auto",
color: "white"
} }>
<TitledList title={`Visible Inventory (Count=${simulationState.inventoryMCount})`}>
<ItemList slots={simulationState.displayablePouch.getDisplayedSlots()}/>
</TitledList>
</div> </div>
</>} </>}
</div> </div>
</div>; </div>;
}; };

View file

@ -1,169 +1,184 @@
import { ItemList } from "components/ItemList";
import { TitledList } from "components/TitledList"; import { TitledList } from "components/TitledList";
import { getAllItems } from "core/Item";
import React from "react"; import React from "react";
export const ReferencePage: React.FC = React.memo(()=>{ export const ReferencePage: React.FC = React.memo(()=>{
return (
<div style={{height: "100%", width: "100%", color: "white"}}>
return ( <TitledList title="Reference">
<div style={{height: "100%", width: "100%", color: "white"}}> <div style={{padding: 10}}>
<TitledList title="Reference"> <h2>Items</h2>
<div style={{padding: 10}}> {
<h2>Commands</h2> getAllItems().map(item=><h4 className="Reference">{item}</h4>)
<h3 className="Reference">Initialize X item1 Y item2 Z item3 ...</h3> }
<h4 className="Reference">Used for initializing inventory before simulation</h4> <h2>Commands</h2>
<p className="Reference"> <h3 className="Reference">Initialize X item1 Y item2 Z item3 ...</h3>
<h4 className="Reference">Used for initializing inventory before simulation</h4>
<p className="Reference">
Fully resets the inventory by clearing all items and set Count to 0, then forcefully write the item list to inventory. Fully resets the inventory by clearing all items and set Count to 0, then forcefully write the item list to inventory.
This would reset any broken slot you already have, and any in-game checks that happen when adding items are disabled. This would reset any broken slot you already have, and any in-game checks that happen when adding items are disabled.
For example, the items will appear in the order you specify, not in the in-game tab order For example, the items will appear in the order you specify, not in the in-game tab order
</p> </p>
<p className="Reference"> <p className="Reference">
If you specify count &gt; 1 for unstackable items like weapon or sheika slate, multiple of that item would be added. If you specify count &gt; 1 for unstackable items like weapon or sheika slate, multiple of that item would be added.
Game Data will be synced with Visible Inventory after the reset Game Data will be synced with Visible Inventory after the reset
</p> </p>
<p className="Reference"> <p className="Reference">
Note that this will not clear saves. You can use this command to initialize multiple saves Note that this will not clear saves. You can use this command to initialize multiple saves
</p> </p>
<p className="Reference Example">Example: Initialize 1 Apple 2 Axe 3 Slate 4 SpiritOrb</p> <p className="Reference Example">Example: Initialize 1 Apple 2 Axe 3 Slate 4 SpiritOrb</p>
<h3 className="Reference">Save / Save As NAME</h3> <h3 className="Reference">Save / Save As NAME</h3>
<h4 className="Reference">Simulates a hard save or auto save action</h4> <h4 className="Reference">Simulates a hard save or auto save action</h4>
<p className="Reference"> <p className="Reference">
Writes Game Data to the corresponding save slot. The auto saves are specified by NAME. Writes Game Data to the corresponding save slot. The auto saves are specified by NAME.
You can have as many auto saves as you want in the simulator. You can have as many auto saves as you want in the simulator.
</p> </p>
<p className="Reference Example">Example 1: Save</p> <p className="Reference Example">Example 1: Save</p>
<p className="Reference Example">Example 2: Save As MySave</p> <p className="Reference Example">Example 2: Save As MySave</p>
<p className="Reference"> <p className="Reference">
Example 1 will save to the manual save slot, while example 2 will save to the slot named "MySave". Example 1 will save to the manual save slot, while example 2 will save to the slot named "MySave".
There cannot be spaces in the name. If "MySave" doesn't exist, a new slot is created There cannot be spaces in the name. If "MySave" doesn't exist, a new slot is created
</p> </p>
<h3 className="Reference">Reload (NAME)</h3> <h3 className="Reference">Reload (NAME)</h3>
<h4 className="Reference">Simulates reloading a save</h4> <h4 className="Reference">Simulates reloading a save</h4>
<p className="Reference"> <p className="Reference">
First, reads Game Data from the corresponding save slot. First, reads Game Data from the corresponding save slot.
If NAME is not given, the manual save is used unless "Use" commands are used before this (see below). If NAME is not given, the manual save is used unless "Use" commands are used before this (see below).
If NAME is given, the corresponding save slot with that name is used If NAME is given, the corresponding save slot with that name is used
</p> </p>
<p className="Reference"> <p className="Reference">
After that, the first Count items in the visible inventory is removed, and Count is decreased accordingly. After that, the first Count items in the visible inventory is removed, and Count is decreased accordingly.
Then, each item slot in the Game Data is added to the inventory. Then, each item slot in the Game Data is added to the inventory.
</p> </p>
<p className="Reference Example">Example 1: Reload</p> <p className="Reference Example">Example 1: Reload</p>
<p className="Reference Example">Example 2: Reload MySave</p> <p className="Reference Example">Example 2: Reload MySave</p>
<h3 className="Reference">Use NAME</h3> <h3 className="Reference">Use NAME</h3>
<h4 className="Reference">(Deprecated) Specify which save to load on the subsequent reload</h4> <h4 className="Reference">(Deprecated) Specify which save to load on the subsequent reload</h4>
<p className="Reference Example"> <p className="Reference Example">
This command is only for backward compatibility. Use "Reload" instead This command is only for backward compatibility. Use "Reload" instead
</p> </p>
<p className="Reference"> <p className="Reference">
Specify the save named NAME to be reloaded on the next "Reload" command Specify the save named NAME to be reloaded on the next "Reload" command
</p> </p>
<p className="Reference Example">Example: Use MySave</p> <p className="Reference Example">Example: Use MySave</p>
<h3 className="Reference">Break X Slots</h3> <h3 className="Reference">Break X Slots</h3>
<h4 className="Reference">Simulate making X broken slots with hold smuggle glitch</h4> <h4 className="Reference">Simulate making X broken slots with hold smuggle glitch</h4>
<p className="Reference"> <p className="Reference">
Decrease inventory Count by X Decrease inventory Count by X
</p> </p>
<p className="Reference"> <p className="Reference">
This command does not automatically simulate the hold smuggle and sell process. This command does not automatically simulate the hold smuggle and sell process.
It just changes count (i.e. make broken slots) with magic. It just changes count (i.e. make broken slots) with magic.
</p> </p>
<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 item</h3>
<h3 className="Reference2">Get/Add/Cook/Pickup X item</h3> <h3 className="Reference2">Get/Add/Cook/Pickup X item</h3>
<h3 className="Reference2">Get/Add/Cook/Pickup X item1 Y item2 Z item3 ...</h3> <h3 className="Reference2">Get/Add/Cook/Pickup 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
</p> </p>
<p className="Reference"> <p className="Reference">
Like in game, you won't be able to obtain multiple unstackable key items, or multiple master sword in this way. Like in game, you won't be able to obtain multiple unstackable key items, or multiple master sword in this way.
If a stackable item is at 999 or more when you invoke this command, the count is set to 999 (not fully accurate since you won't be able to pick up more items in game). If a stackable item is at 999 or more when you invoke this command, the count is set to 999 (not fully accurate since you won't be able to pick up more items in game).
</p> </p>
<p className="Reference"> <p className="Reference">
If you specify a count for unstackable items, they are added in different slots as if you pick them up in game, one after another. If you specify a count for unstackable items, they are added in different slots as if you pick them up in game, one after another.
</p> </p>
<p className="Reference"> <p className="Reference">
Note that you must not enter plural forms for the item name. Note that you must not enter plural forms for the item name.
</p> </p>
<p className="Reference Example">Example 1: Add Apple</p> <p className="Reference Example">Example 1: Add Apple</p>
<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">Remove/Sell/Eat/Drop item</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop X item</h3> <h3 className="Reference2">Remove/Sell/Eat/Drop X item</h3>
<h3 className="Reference2">Remove/Sell/Eat/Drop item From Slot Y</h3> <h3 className="Reference2">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">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">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
</p> </p>
<p className="Reference"> <p className="Reference">
When number of item is not specified, it defaults to 1. Up to X items will be removed from inventory, even when they span multiple slots. When number of item is not specified, it defaults to 1. Up to X items will be removed from inventory, even when they span multiple slots.
If X &gt; total number of items in inventory, all of them will be removed. If X &gt; total number of items in inventory, all of them will be removed.
</p> </p>
<p className="Reference"> <p className="Reference">
When slot is specified, it starts removing from slot X (slot 1 is the leftmost slot with that item, slot 2 is the second leftmost slot with that item). When slot is specified, it starts removing from slot X (slot 1 is the leftmost slot with that item, slot 2 is the second leftmost slot with that item).
</p> </p>
<p className="Reference"> <p className="Reference">
Note that you must not enter plural forms for the item name. Note that you must not enter plural forms for the item name.
</p> </p>
<p className="Reference Example">Example 1: Remove Apple</p> <p className="Reference Example">Example 1: Remove Apple</p>
<p className="Reference Example">Example 2: Drop 10 Diamond</p> <p className="Reference Example">Example 2: Drop 10 Diamond</p>
<p className="Reference Example">Example 3: Sell 10 Apple 5 Diamond</p> <p className="Reference Example">Example 3: Sell 10 Apple 5 Diamond</p>
<p className="Reference Example">Example 4: Sell 5 Apple From Slot 3</p> <p className="Reference Example">Example 4: Sell 5 Apple From Slot 3</p>
<h3 className="Reference">D&amp;P X item</h3> <h3 className="Reference">D&amp;P X item</h3>
<h4 className="Reference">Shortcut for drop and pick up, for sorting inventory</h4> <h4 className="Reference">Shortcut for drop and pick up, for sorting inventory</h4>
<p className="Reference"> <p className="Reference">
This command drops X item from the first slot, then pick them up This command drops X item from the first slot, then pick them up
</p> </p>
<p className="Reference Example">Example: D&amp;P 5 Diamond</p> <p className="Reference Example">Example: D&amp;P 5 Diamond</p>
<h3 className="Reference">Equip item</h3> <h3 className="Reference">Equip item</h3>
<h3 className="Reference2">Equip item In Slot X</h3> <h3 className="Reference2">Equip item In Slot X</h3>
<h4 className="Reference">Simulates equipping something</h4> <h4 className="Reference">Simulates equipping something</h4>
<p className="Reference"> <p className="Reference">
When equipping an item, all other item of the same type in the first tab is unequipped, then the item selected is equipped. When equipping an item, all other item of the same type in the first tab is unequipped, then the item selected is equipped.
</p> </p>
<p className="Reference"> <p className="Reference">
Slot can be used if you have multiple of the same item. When slot is not specified, the leftmost item will be equipped. Slot can be used if you have multiple of the same item. When slot is not specified, the leftmost item will be equipped.
Note that you can use this command to equip something that is already equipped, which is not possible in game. Note that you can use this command to equip something that is already equipped, which is not possible in game.
You can also equip unequippable items like materials, but it is not meaningful You can also equip unequippable items like materials, but it is not meaningful
</p> </p>
<p className="Reference Example">Example 1: Equip Weapon</p> <p className="Reference Example">Example 1: Equip Weapon</p>
<p className="Reference Example">Example 2: Equip Weapon In Slot 3</p> <p className="Reference Example">Example 2: Equip Weapon In Slot 3</p>
<h3 className="Reference">Unequip item</h3> <h3 className="Reference">Unequip item</h3>
<h3 className="Reference2">Unequip item In Slot X</h3> <h3 className="Reference2">Unequip item In Slot X</h3>
<h4 className="Reference">Simulates unequipping something</h4> <h4 className="Reference">Simulates unequipping something</h4>
<p className="Reference"> <p className="Reference">
When unequipping an item, only the selected item is unequipped. When unequipping an item, only the selected item is unequipped.
</p> </p>
<p className="Reference"> <p className="Reference">
Slot can be used if you have multiple of the same item. When slot is not specified, the leftmost equipped item will be unequipped. Slot can be used if you have multiple of the same item. When slot is not specified, the leftmost equipped item will be unequipped.
Note that you can use this command to unequip something that is already unequipped, which is useless. Note that you can use this command to unequip something that is already unequipped, which is useless.
You cannot unequip arrows. You cannot unequip arrows.
</p> </p>
<p className="Reference Example">Example 1: Unequip Shield</p> <p className="Reference Example">Example 1: Unequip Shield</p>
<p className="Reference Example">Example 2: Unequip Shield In Slot 5</p> <p className="Reference Example">Example 2: Unequip Shield In Slot 5</p>
</div>
<h3 className="Reference">Close Game</h3>
<h4 className="Reference">Simulates closing the game and restarting</h4>
<p className="Reference">
When closing the game, Visible Inventory and Game Data are erased
</p>
<p className="Reference Example">Example: Close Game</p>
<h3 className="Reference">Sort Key/Material</h3>
<h4 className="Reference">Simulates press Y to sort tab</h4>
<p className="Reference Example">
This command is currently broken
</p>
</div>
</TitledList>
</TitledList> </div>
</div> );
)
}); });