add import/export
This commit is contained in:
parent
7d7e11bdb1
commit
3a92f0fc1d
22 changed files with 1185 additions and 983 deletions
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "/static/css/main.7948f1f9.css",
|
"main.css": "/static/css/main.7948f1f9.css",
|
||||||
"main.js": "/static/js/main.22757a4a.js",
|
"main.js": "/static/js/main.6564ce4b.js",
|
||||||
"static/js/787.ada1a5f8.chunk.js": "/static/js/787.ada1a5f8.chunk.js",
|
"static/js/787.ada1a5f8.chunk.js": "/static/js/787.ada1a5f8.chunk.js",
|
||||||
"static/media/Calamity-Regular.otf": "/static/media/Calamity-Regular.cbeefc650e6ac39335b6.otf",
|
"static/media/Calamity-Regular.otf": "/static/media/Calamity-Regular.cbeefc650e6ac39335b6.otf",
|
||||||
"index.html": "/index.html",
|
"index.html": "/index.html",
|
||||||
"main.7948f1f9.css.map": "/static/css/main.7948f1f9.css.map",
|
"main.7948f1f9.css.map": "/static/css/main.7948f1f9.css.map",
|
||||||
"main.22757a4a.js.map": "/static/js/main.22757a4a.js.map",
|
"main.6564ce4b.js.map": "/static/js/main.6564ce4b.js.map",
|
||||||
"787.ada1a5f8.chunk.js.map": "/static/js/787.ada1a5f8.chunk.js.map"
|
"787.ada1a5f8.chunk.js.map": "/static/js/787.ada1a5f8.chunk.js.map"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.7948f1f9.css",
|
"static/css/main.7948f1f9.css",
|
||||||
"static/js/main.22757a4a.js"
|
"static/js/main.6564ce4b.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="for Breath of the Wild"/><meta property="og:site_name" content="itntpiston.app"/><meta property="og:title" content="Hundo Duplication Simulator"><meta property="og:type" content="website"><meta property="og:url" content="https://dupl.itntpiston.app/#/"><meta property="og:description" content="for Breath of the Wild"><link rel="manifest" href="/manifest.json"/><title>Hundo Duplication Simulator</title><script defer="defer" src="/static/js/main.22757a4a.js"></script><link href="/static/css/main.7948f1f9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="for Breath of the Wild"/><meta property="og:site_name" content="itntpiston.app"/><meta property="og:title" content="Hundo Duplication Simulator"><meta property="og:type" content="website"><meta property="og:url" content="https://dupl.itntpiston.app/#/"><meta property="og:description" content="for Breath of the Wild"><link rel="manifest" href="/manifest.json"/><title>Hundo Duplication Simulator</title><script defer="defer" src="/static/js/main.6564ce4b.js"></script><link href="/static/css/main.7948f1f9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
1
docs/static/js/main.22757a4a.js.map
vendored
1
docs/static/js/main.22757a4a.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
docs/static/js/main.6564ce4b.js.map
vendored
Normal file
1
docs/static/js/main.6564ce4b.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
383
src/App.tsx
383
src/App.tsx
|
@ -1,193 +1,212 @@
|
||||||
import { Command, CommandBreakSlots, CommandInitialize, CommandNothing, CommandReload, CommandSave, CommandSortKey } from 'core/Command';
|
import { Command, CommandBreakSlots, CommandInitialize, CommandNothing, CommandReload, CommandSave, CommandSortKey } from "core/Command";
|
||||||
import { Inventory } from 'core/Inventory';
|
import { Inventory } from "core/Inventory";
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
import './App.css';
|
import "./App.css";
|
||||||
import { CommandItem } from './components/CommandItem';
|
import { CommandItem } from "./components/CommandItem";
|
||||||
import { ItemStack as ISC } from './components/ItemStack';
|
|
||||||
|
|
||||||
import { ItemStack, ItemType } from 'core/ItemStack';
|
import { DisplayPane } from "surfaces/DisplayPane";
|
||||||
import { DisplayPane } from 'surfaces/DisplayPane';
|
import { Item } from "core/Item";
|
||||||
import { Item } from 'core/Item';
|
import { deserialzeCommands, serializeCommands } from "core/serialize";
|
||||||
import { deserialzeCommands, serializeCommands } from 'core/serialize';
|
import { saveAs } from "data/FileSaver";
|
||||||
|
import { parseCommand } from "core/Parser";
|
||||||
const Buffer = require("buffer/").Buffer;
|
|
||||||
|
|
||||||
const getDefaultCommands = (): Command[]=>{
|
const getDefaultCommands = (): Command[]=>{
|
||||||
const encoded = localStorage.getItem("HDS.CurrentCommands");
|
const encoded = localStorage.getItem("HDS.CurrentCommands");
|
||||||
if(encoded){
|
if(encoded){
|
||||||
return deserialzeCommands(encoded);
|
return deserialzeCommands(encoded);
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
new CommandInitialize([
|
new CommandInitialize([
|
||||||
{
|
{
|
||||||
item: Item.Diamond,
|
item: Item.Diamond,
|
||||||
count: 5,
|
count: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: Item.Slate,
|
item: Item.Slate,
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: Item.Glider,
|
item: Item.Glider,
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
item: Item.SpiritOrb,
|
item: Item.SpiritOrb,
|
||||||
count: 4,
|
count: 4,
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
new CommandBreakSlots(4),
|
new CommandBreakSlots(4),
|
||||||
new CommandReload(),
|
new CommandReload(),
|
||||||
new CommandSortKey(),
|
new CommandSortKey(),
|
||||||
new CommandSave(),
|
new CommandSave(),
|
||||||
new CommandReload()
|
new CommandReload()
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
export const App: React.FC = () => {
|
export const App: React.FC = () => {
|
||||||
const [commands, setCommands] = useState<Command[]>(getDefaultCommands());
|
const [commands, setCommands] = useState<Command[]>(getDefaultCommands());
|
||||||
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 [contextMenuShowing, setContextMenuShowing] = useState<boolean>(false);
|
||||||
const [contextIndex, setContextIndex] = useState<number>(-1);
|
const [contextIndex, setContextIndex] = useState<number>(-1);
|
||||||
// compute props
|
// compute props
|
||||||
const inventories = useMemo(()=>{
|
const inventories = useMemo(()=>{
|
||||||
const inventories: Inventory[] = [];
|
const inventories: Inventory[] = [];
|
||||||
const inv = new Inventory();
|
const inv = new Inventory();
|
||||||
commands.forEach(c=>{
|
commands.forEach(c=>{
|
||||||
c.execute(inv);
|
c.execute(inv);
|
||||||
inventories.push(inv.clone());
|
inventories.push(inv.clone());
|
||||||
});
|
});
|
||||||
return inventories;
|
return inventories;
|
||||||
}, [commands]);
|
}, [commands]);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
window.onkeydown=(e)=>{
|
window.onkeydown=(e)=>{
|
||||||
if(e.code==="ArrowDown"){
|
if(e.code==="ArrowDown"){
|
||||||
setDisplayIndex(Math.min(commands.length-1, displayIndex+1));
|
setDisplayIndex(Math.min(commands.length-1, displayIndex+1));
|
||||||
}else if(e.code==="ArrowUp"){
|
}else if(e.code==="ArrowUp"){
|
||||||
setDisplayIndex(Math.max(0, displayIndex-1));
|
setDisplayIndex(Math.max(0, displayIndex-1));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}, [commands, displayIndex]);
|
}, [commands, displayIndex]);
|
||||||
|
|
||||||
useEffect(()=>{
|
|
||||||
const encoded = serializeCommands(commands);
|
|
||||||
localStorage.setItem("HDS.CurrentCommands", encoded);
|
|
||||||
}, [commands]);
|
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
const encoded = serializeCommands(commands);
|
||||||
|
localStorage.setItem("HDS.CurrentCommands", encoded);
|
||||||
|
}, [commands]);
|
||||||
|
|
||||||
|
const uploadRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='Calamity'
|
<div className='Calamity'
|
||||||
>
|
>
|
||||||
|
<input ref={uploadRef} id="Upload" type="File" hidden onChange={(e)=>{
|
||||||
<div id="CommandList" style={{
|
const files = e.target.files;
|
||||||
width: "300px",
|
if(files?.length && files[0]){
|
||||||
height: "calc( 100vh - 5px )",
|
const file = files[0];
|
||||||
overflowY: "auto",
|
file.text().then(text=>{
|
||||||
|
const lines = text.split("\n");
|
||||||
float: "left",
|
const parsedCommands: Command[] = lines.map(l=>parseCommand(l)).filter(c=>c) as Command[];
|
||||||
border: "1px solid black",
|
setDisplayIndex(0);
|
||||||
boxSizing: "content-box"
|
setContextIndex(-1);
|
||||||
} }>
|
setContextMenuShowing(false);
|
||||||
<ul style={{
|
setCommands(parsedCommands);
|
||||||
listStyleType: "none",
|
});
|
||||||
paddingInlineStart: 0
|
}
|
||||||
}}>
|
}}/>
|
||||||
{
|
<div id="CommandList" style={{
|
||||||
commands.map((c,i)=>(
|
width: "300px",
|
||||||
<CommandItem
|
height: "calc( 100vh - 5px )",
|
||||||
onClick={()=>setDisplayIndex(i)}
|
overflowY: "auto",
|
||||||
onContextMenu={(x,y)=>{
|
|
||||||
setContextIndex(i)
|
float: "left",
|
||||||
setContextMenuX(x);
|
border: "1px solid black",
|
||||||
setContextMenuY(y);
|
boxSizing: "content-box"
|
||||||
setContextMenuShowing(true);
|
} }>
|
||||||
}}
|
<ul style={{
|
||||||
key={i}
|
listStyleType: "none",
|
||||||
isSelected={displayIndex===i}
|
paddingInlineStart: 0
|
||||||
isContextSelected={contextIndex===i}
|
}}>
|
||||||
error={inventories[i].isInaccurate()}
|
{
|
||||||
>
|
commands.map((c,i)=>
|
||||||
{c.getDisplayString()}
|
<CommandItem
|
||||||
</CommandItem>
|
onClick={()=>setDisplayIndex(i)}
|
||||||
))
|
onContextMenu={(x,y)=>{
|
||||||
}
|
setContextIndex(i);
|
||||||
<CommandItem onClick={()=>{
|
setContextMenuX(x);
|
||||||
const arrCopy = [...commands];
|
setContextMenuY(y);
|
||||||
arrCopy.push(new CommandNothing());
|
setContextMenuShowing(true);
|
||||||
setCommands(arrCopy);
|
}}
|
||||||
}}>(new)</CommandItem>
|
key={i}
|
||||||
|
isSelected={displayIndex===i}
|
||||||
</ul>
|
isContextSelected={contextIndex===i}
|
||||||
</div>
|
error={inventories[i].isInaccurate()}
|
||||||
{displayIndex >= 0 && displayIndex < commands.length &&
|
>
|
||||||
<DisplayPane
|
{c.getDisplayString()}
|
||||||
displayIndex={displayIndex}
|
</CommandItem>
|
||||||
command={commands[displayIndex].getDisplayString()}
|
)
|
||||||
stacks={inventories[displayIndex].getSlots()}
|
}
|
||||||
numBroken={inventories[displayIndex].getNumBroken()}
|
<CommandItem onClick={()=>{
|
||||||
editCommand={(c)=>{
|
const arrCopy = [...commands];
|
||||||
const arrCopy = [...commands];
|
arrCopy.push(new CommandNothing());
|
||||||
arrCopy[displayIndex] = c;
|
setCommands(arrCopy);
|
||||||
setCommands(arrCopy);
|
}}>(new)</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>
|
||||||
|
</div>
|
||||||
|
{displayIndex >= 0 && displayIndex < commands.length &&
|
||||||
|
<DisplayPane
|
||||||
|
displayIndex={displayIndex}
|
||||||
|
command={commands[displayIndex].getDisplayString()}
|
||||||
|
stacks={inventories[displayIndex].getSlots()}
|
||||||
|
numBroken={inventories[displayIndex].getNumBroken()}
|
||||||
|
editCommand={(c)=>{
|
||||||
|
const arrCopy = [...commands];
|
||||||
|
arrCopy[displayIndex] = c;
|
||||||
|
setCommands(arrCopy);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
}
|
contextMenuShowing && <div style={{
|
||||||
|
position: "absolute",
|
||||||
{
|
top: 0,
|
||||||
contextMenuShowing && <div style={{
|
left: 0,
|
||||||
position: "absolute",
|
width: "100vw",
|
||||||
top: 0,
|
height: "100vh",
|
||||||
left: 0,
|
}} onClick={()=>{
|
||||||
width: "100vw",
|
setContextMenuShowing(false);
|
||||||
height: "100vh",
|
setContextIndex(-1);
|
||||||
}} onClick={()=>{
|
}} onContextMenu={(e)=>{
|
||||||
setContextMenuShowing(false);
|
setContextMenuShowing(false);
|
||||||
setContextIndex(-1);
|
setContextIndex(-1);
|
||||||
}} onContextMenu={(e)=>{
|
e.preventDefault();
|
||||||
setContextMenuShowing(false);
|
}}>
|
||||||
setContextIndex(-1);
|
<div style={{
|
||||||
e.preventDefault();
|
position: "absolute",
|
||||||
}}>
|
top: contextMenuY,
|
||||||
<div style={{
|
left: contextMenuX,
|
||||||
position: "absolute",
|
width: "200px",
|
||||||
top: contextMenuY,
|
backgroundColor: "white",
|
||||||
left: contextMenuX,
|
border: "1px solid black"
|
||||||
width: "200px",
|
}}>
|
||||||
backgroundColor: "white",
|
<ul style={{
|
||||||
border: "1px solid black"
|
margin: 0,
|
||||||
}}>
|
listStyleType: "none",
|
||||||
<ul style={{
|
paddingInlineStart: 0
|
||||||
margin: 0,
|
}}>
|
||||||
listStyleType: "none",
|
<CommandItem onClick={()=>{
|
||||||
paddingInlineStart: 0
|
const arrCopy = [...commands];
|
||||||
}}>
|
arrCopy.splice(contextIndex, 0, new CommandNothing());
|
||||||
<CommandItem onClick={()=>{
|
setCommands(arrCopy);
|
||||||
const arrCopy = [...commands];
|
setContextMenuShowing(false);
|
||||||
arrCopy.splice(contextIndex, 0, new CommandNothing());
|
setContextIndex(-1);
|
||||||
setCommands(arrCopy);
|
}}>Insert Above</CommandItem>
|
||||||
setContextMenuShowing(false);
|
<CommandItem error onClick={()=>{
|
||||||
setContextIndex(-1);
|
if(confirm("Delete?")){
|
||||||
}}>Insert Above</CommandItem>
|
setCommands(commands.filter((_,i)=>i!==contextIndex));
|
||||||
<CommandItem error onClick={()=>{
|
if(displayIndex >= commands.length){
|
||||||
if(confirm("Delete?")){
|
setDisplayIndex(commands.length-1);
|
||||||
setCommands(commands.filter((_,i)=>i!==contextIndex));
|
}
|
||||||
if(displayIndex >= commands.length){
|
setContextMenuShowing(false);
|
||||||
setDisplayIndex(commands.length-1);
|
setContextIndex(-1);
|
||||||
}
|
}
|
||||||
setContextMenuShowing(false);
|
}}>Delete</CommandItem>
|
||||||
setContextIndex(-1);
|
</ul>
|
||||||
}
|
</div>
|
||||||
}}>Delete</CommandItem>
|
</div>
|
||||||
</ul>
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
}
|
};
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,17 +10,16 @@ type CommandItemProps = PropsWithChildren<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const CommandItem: React.FC<CommandItemProps> = ({isSelected, isContextSelected,error, children, onClick, onContextMenu}) => {
|
export const CommandItem: React.FC<CommandItemProps> = ({isSelected, isContextSelected,error, children, onClick, onContextMenu}) => {
|
||||||
return <li
|
return <li
|
||||||
className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",error && "CommandItemError")}
|
className={clsx("CommandItem", isSelected && "CommandItemSelected", isContextSelected&& "CommandItemContextSelected",error && "CommandItemError")}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onContextMenu={(e)=>{
|
onContextMenu={(e)=>{
|
||||||
if(onContextMenu){
|
if(onContextMenu){
|
||||||
console.log(e);
|
onContextMenu(e.clientX,e.clientY);
|
||||||
onContextMenu(e.clientX,e.clientY);
|
e.preventDefault();
|
||||||
e.preventDefault();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>{children} </li>
|
>{children} </li>;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ export type ItemListProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ItemList: React.FC<ItemListProps> = ({items, numBroken}) => {
|
export const ItemList: React.FC<ItemListProps> = ({items, numBroken}) => {
|
||||||
return <>
|
return <>
|
||||||
{
|
{
|
||||||
items.map(({name, count}, i)=>{
|
items.map(({name, count}, i)=>{
|
||||||
const broken = i+numBroken >= items.length;
|
const broken = i+numBroken >= items.length;
|
||||||
return <ItemStack key={i} name={name} count={count} isBroken={broken}/>
|
return <ItemStack key={i} name={name} count={count} isBroken={broken}/>;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</>;
|
</>;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,5 +5,5 @@ type ItemStackProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ItemStack: React.FC<ItemStackProps> = ({name, count, isBroken})=>{
|
export const ItemStack: React.FC<ItemStackProps> = ({name, count, isBroken})=>{
|
||||||
return <span>[{name} x{count}]{isBroken && " (broken)"} <br/></span>
|
return <span>[{name} x{count}]{isBroken && " (broken)"} <br/></span>;
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,341 +1,337 @@
|
||||||
import { Inventory } from "./Inventory";
|
import { Inventory } from "./Inventory";
|
||||||
import { Item, ItemIds } from "./Item";
|
import { Item, ItemIds } from "./Item";
|
||||||
import { ItemStack, ItemType } from "./ItemStack";
|
import { ItemStack } from "./ItemStack";
|
||||||
|
|
||||||
const Buffer = require("buffer/").Buffer;
|
const Buffer = require("buffer/").Buffer; /* eslint-disable-line @typescript-eslint/no-var-requires*/
|
||||||
|
|
||||||
export interface Command {
|
export interface Command {
|
||||||
execute(inv: Inventory): void,
|
execute(inv: Inventory): void,
|
||||||
getDisplayString(): string,
|
getDisplayString(): string,
|
||||||
fromBuffer(buf: Buffer): number,
|
fromBuffer(buf: Buffer): number,
|
||||||
toBuffer(): Buffer,
|
toBuffer(): Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandNothing implements Command {
|
export class CommandNothing implements Command {
|
||||||
static Op = 0x0;
|
static Op = 0x0;
|
||||||
constructor(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fromBuffer(buf: Buffer): number {
|
fromBuffer(_buf: Buffer): number {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
toBuffer(): Buffer {
|
toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(1);
|
const buf: Buffer = Buffer.alloc(1);
|
||||||
buf.writeInt8(CommandNothing.Op);
|
buf.writeInt8(CommandNothing.Op);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(inv: Inventory): void {
|
execute(_inv: Inventory): void {
|
||||||
|
// nothing
|
||||||
}
|
}
|
||||||
getDisplayString(): string {
|
getDisplayString(): string {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandInitialize implements Command {
|
export class CommandInitialize implements Command {
|
||||||
static Op = 0x1;
|
static Op = 0x1;
|
||||||
private stacks: ItemStack[]
|
private stacks: ItemStack[];
|
||||||
constructor(stacks: ItemStack[]){
|
constructor(stacks: ItemStack[]){
|
||||||
this.stacks = stacks;
|
this.stacks = stacks;
|
||||||
}
|
}
|
||||||
public fromBuffer(buf: Buffer): number {
|
public fromBuffer(buf: Buffer): number {
|
||||||
let read = 0;
|
let read = 0;
|
||||||
const size = buf.readUInt16LE();
|
const size = buf.readUInt16LE();
|
||||||
read+=2;
|
read+=2;
|
||||||
const stacks: ItemStack[] = [];
|
const stacks: ItemStack[] = [];
|
||||||
for(let i=0;i<size;i++){
|
for(let i=0;i<size;i++){
|
||||||
const count = buf.readInt16LE(read);
|
const count = buf.readInt16LE(read);
|
||||||
read+=2;
|
read+=2;
|
||||||
const id = buf.readInt8(read);
|
const id = buf.readInt8(read);
|
||||||
read++;
|
read++;
|
||||||
for(const item in ItemIds){
|
for(const item in ItemIds){
|
||||||
if(ItemIds[item as Item] === id){
|
if(ItemIds[item as Item] === id){
|
||||||
stacks.push({item: item as Item, count});
|
stacks.push({item: item as Item, count});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.stacks = stacks;
|
this.stacks = stacks;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
public toBuffer(): Buffer {
|
public toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(3*this.stacks.length+3);
|
const buf: Buffer = Buffer.alloc(3*this.stacks.length+3);
|
||||||
let write = 0;
|
let write = 0;
|
||||||
buf.writeInt8(CommandInitialize.Op);
|
buf.writeInt8(CommandInitialize.Op);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt16LE(this.stacks.length, write);
|
buf.writeInt16LE(this.stacks.length, write);
|
||||||
write+=2;
|
write+=2;
|
||||||
this.stacks.forEach(({item,count})=>{
|
this.stacks.forEach(({item,count})=>{
|
||||||
console.log(count);
|
buf.writeInt16LE(count&0xffff, write);
|
||||||
buf.writeInt16LE(count&0xffff, write);
|
write+=2;
|
||||||
write+=2;
|
buf.writeInt8(ItemIds[item], write);
|
||||||
buf.writeInt8(ItemIds[item], write);
|
write++;
|
||||||
write++;
|
});
|
||||||
});
|
return buf;
|
||||||
return buf;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.init(this.stacks);
|
inv.init(this.stacks);
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
const parts = ["Initialize"];
|
const parts = ["Initialize"];
|
||||||
this.stacks.forEach(({item, count})=>{
|
this.stacks.forEach(({item, count})=>{
|
||||||
parts.push(""+count);
|
parts.push(""+count);
|
||||||
parts.push(item);
|
parts.push(item);
|
||||||
})
|
});
|
||||||
return parts.join(" ");
|
return parts.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandBreakSlots implements Command {
|
export class CommandBreakSlots implements Command {
|
||||||
static Op = 0x2;
|
static Op = 0x2;
|
||||||
private numToBreak: number;
|
private numToBreak: number;
|
||||||
constructor(numToBreak: number){
|
constructor(numToBreak: number){
|
||||||
this.numToBreak = numToBreak;
|
this.numToBreak = numToBreak;
|
||||||
}
|
}
|
||||||
public fromBuffer(buf: Buffer): number {
|
public fromBuffer(buf: Buffer): number {
|
||||||
this.numToBreak = buf.readInt16LE();
|
this.numToBreak = buf.readInt16LE();
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
public toBuffer(): Buffer {
|
public toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(3);
|
const buf: Buffer = Buffer.alloc(3);
|
||||||
buf.writeUInt8(CommandBreakSlots.Op);
|
buf.writeUInt8(CommandBreakSlots.Op);
|
||||||
buf.writeInt16LE(this.numToBreak, 1);
|
buf.writeInt16LE(this.numToBreak, 1);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.addBrokenSlots(this.numToBreak);
|
inv.addBrokenSlots(this.numToBreak);
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return `Break ${this.numToBreak} Slots`;
|
return `Break ${this.numToBreak} Slots`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandSave implements Command {
|
export class CommandSave implements Command {
|
||||||
static Op = 0x3;
|
static Op = 0x3;
|
||||||
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(CommandSave.Op);
|
buf.writeInt8(CommandSave.Op);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.save();
|
inv.save();
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return "Save";
|
return "Save";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandReload implements Command {
|
export class CommandReload implements Command {
|
||||||
static Op = 0x4;
|
static Op = 0x4;
|
||||||
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(CommandReload.Op);
|
buf.writeInt8(CommandReload.Op);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.reload();
|
inv.reload();
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return "Reload";
|
return "Reload";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(inv: Inventory): void {
|
||||||
inv.sortKey();
|
inv.sortKey();
|
||||||
}
|
}
|
||||||
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(inv: Inventory): void {
|
||||||
inv.sortMaterial();
|
inv.sortMaterial();
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return "Sort Material";
|
return "Sort Material";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Verbs = ["?", "Remove", "Drop", "Sell", "Eat", "Cook", "Get", "Add", "Pickup"];
|
const Verbs = ["?", "Remove", "Drop", "Sell", "Eat", "Cook", "Get", "Add", "Pickup"];
|
||||||
const VerbToId = {
|
const VerbToId = {
|
||||||
"Remove" : 1,
|
"Remove" : 1,
|
||||||
"Drop": 2,
|
"Drop": 2,
|
||||||
"Sell": 3,
|
"Sell": 3,
|
||||||
"Eat": 4,
|
"Eat": 4,
|
||||||
"Cook": 5,
|
"Cook": 5,
|
||||||
"Get": 6,
|
"Get": 6,
|
||||||
"Add": 7,
|
"Add": 7,
|
||||||
"Pickup": 8
|
"Pickup": 8
|
||||||
}
|
};
|
||||||
|
|
||||||
export class CommandRemoveMaterial implements Command {
|
export class CommandRemoveMaterial implements Command {
|
||||||
static Op = 0x7;
|
static Op = 0x7;
|
||||||
private verb: number;
|
private verb: number;
|
||||||
private count: number;
|
private count: number;
|
||||||
private item: Item;
|
private item: Item;
|
||||||
private slot: number;
|
private slot: number;
|
||||||
constructor(verb: string, count: number, item: Item, slot: number){
|
constructor(verb: string, count: number, item: Item, slot: number){
|
||||||
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
|
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
}
|
}
|
||||||
public fromBuffer(buf: Buffer): number {
|
public fromBuffer(buf: Buffer): number {
|
||||||
let read = 0;
|
let read = 0;
|
||||||
this.count = buf.readInt16LE(read);
|
this.count = buf.readInt16LE(read);
|
||||||
read+=2;
|
read+=2;
|
||||||
const id = buf.readInt8(read);
|
const id = buf.readInt8(read);
|
||||||
read+=1;
|
read+=1;
|
||||||
for(const item in ItemIds){
|
for(const item in ItemIds){
|
||||||
if(ItemIds[item as Item] === id){
|
if(ItemIds[item as Item] === id){
|
||||||
this.item = item as Item;
|
this.item = item as Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.slot = buf.readInt16LE(read);
|
this.slot = buf.readInt16LE(read);
|
||||||
read+=2;
|
read+=2;
|
||||||
this.verb = buf.readInt8(read);
|
this.verb = buf.readInt8(read);
|
||||||
read++;
|
read++;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
public toBuffer(): Buffer {
|
public toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(1+2+1+2+1);
|
const buf: Buffer = Buffer.alloc(1+2+1+2+1);
|
||||||
let write = 0;
|
let write = 0;
|
||||||
buf.writeInt8(CommandRemoveMaterial.Op);
|
buf.writeInt8(CommandRemoveMaterial.Op);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt16LE(this.count, write);
|
buf.writeInt16LE(this.count, write);
|
||||||
write+=2;
|
write+=2;
|
||||||
buf.writeInt8(ItemIds[this.item], write);
|
buf.writeInt8(ItemIds[this.item], write);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt16LE(this.slot, write);
|
buf.writeInt16LE(this.slot, write);
|
||||||
write+=2;
|
write+=2;
|
||||||
buf.writeInt8(this.verb, write);
|
buf.writeInt8(this.verb, write);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.remove(this.item, this.count, this.slot);
|
inv.remove(this.item, this.count, this.slot);
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return `${Verbs[this.verb]} ${this.count} ${this.item} From Slot ${this.slot+1}`;
|
return `${Verbs[this.verb]} ${this.count} ${this.item} From Slot ${this.slot+1}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandRemoveUnstackableMaterial implements Command {
|
export class CommandRemoveUnstackableMaterial implements Command {
|
||||||
static Op = 0x8;
|
static Op = 0x8;
|
||||||
private verb: number;
|
private verb: number;
|
||||||
private item: Item;
|
private item: Item;
|
||||||
private slot: number;
|
private slot: number;
|
||||||
constructor(verb: string,item: Item, slot: number){
|
constructor(verb: string,item: Item, slot: number){
|
||||||
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;;
|
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
}
|
}
|
||||||
public fromBuffer(buf: Buffer): number {
|
public fromBuffer(buf: Buffer): number {
|
||||||
let read = 0;
|
let read = 0;
|
||||||
const id = buf.readInt8(read);
|
const id = buf.readInt8(read);
|
||||||
read+=1;
|
read+=1;
|
||||||
for(const item in ItemIds){
|
for(const item in ItemIds){
|
||||||
if(ItemIds[item as Item] === id){
|
if(ItemIds[item as Item] === id){
|
||||||
this.item = item as Item;
|
this.item = item as Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.slot = buf.readInt16LE(read);
|
this.slot = buf.readInt16LE(read);
|
||||||
read+=2;
|
read+=2;
|
||||||
this.verb = buf.readInt8(read);
|
this.verb = buf.readInt8(read);
|
||||||
read++;
|
read++;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
public toBuffer(): Buffer {
|
public toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(1+1+2+1);
|
const buf: Buffer = Buffer.alloc(1+1+2+1);
|
||||||
let write = 0;
|
let write = 0;
|
||||||
buf.writeInt8(CommandRemoveUnstackableMaterial.Op);
|
buf.writeInt8(CommandRemoveUnstackableMaterial.Op);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt8(ItemIds[this.item], write);
|
buf.writeInt8(ItemIds[this.item], write);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt16LE(this.slot, write);
|
buf.writeInt16LE(this.slot, write);
|
||||||
write+=2;
|
write+=2;
|
||||||
buf.writeInt8(this.verb, write);
|
buf.writeInt8(this.verb, write);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.remove(this.item, 1, this.slot);
|
inv.remove(this.item, 1, this.slot);
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return `${Verbs[this.verb]} ${this.item} From Slot ${this.slot+1}`;
|
return `${Verbs[this.verb]} ${this.item} From Slot ${this.slot+1}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandAddMaterial implements Command {
|
export class CommandAddMaterial implements Command {
|
||||||
static Op = 0x9;
|
static Op = 0x9;
|
||||||
private verb: number;
|
private verb: number;
|
||||||
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){
|
||||||
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
|
this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
public fromBuffer(buf: Buffer): number {
|
public fromBuffer(buf: Buffer): number {
|
||||||
let read = 0;
|
let read = 0;
|
||||||
const id = buf.readInt8(read);
|
const id = buf.readInt8(read);
|
||||||
read+=1;
|
read+=1;
|
||||||
for(const item in ItemIds){
|
for(const item in ItemIds){
|
||||||
if(ItemIds[item as Item] === id){
|
if(ItemIds[item as Item] === id){
|
||||||
this.item = item as Item;
|
this.item = item as Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.count = buf.readInt16LE(read);
|
this.count = buf.readInt16LE(read);
|
||||||
read+=2;
|
read+=2;
|
||||||
this.verb = buf.readInt8(read);
|
this.verb = buf.readInt8(read);
|
||||||
read++;
|
read++;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
public toBuffer(): Buffer {
|
public toBuffer(): Buffer {
|
||||||
const buf: Buffer = Buffer.alloc(1+1+2+1);
|
const buf: Buffer = Buffer.alloc(1+1+2+1);
|
||||||
let write = 0;
|
let write = 0;
|
||||||
buf.writeInt8(CommandAddMaterial.Op);
|
buf.writeInt8(CommandAddMaterial.Op);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt8(ItemIds[this.item], write);
|
buf.writeInt8(ItemIds[this.item], write);
|
||||||
write++;
|
write++;
|
||||||
buf.writeInt16LE(this.count, write);
|
buf.writeInt16LE(this.count, write);
|
||||||
write+=2;
|
write+=2;
|
||||||
buf.writeInt8(this.verb, write);
|
buf.writeInt8(this.verb, write);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
public execute(inv: Inventory): void {
|
public execute(inv: Inventory): void {
|
||||||
inv.add(this.item, this.count);
|
inv.add(this.item, this.count);
|
||||||
}
|
}
|
||||||
public getDisplayString(): string {
|
public getDisplayString(): string {
|
||||||
return `${Verbs[this.verb]} ${this.count} ${this.item}`;
|
return `${Verbs[this.verb]} ${this.count} ${this.item}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,171 +2,176 @@ import { itemToType, getKeyItemSortOrder, shouldIgnoreOnReload, getMaterialSortO
|
||||||
import { ItemStack, ItemType } from "./ItemStack";
|
import { ItemStack, ItemType } from "./ItemStack";
|
||||||
|
|
||||||
export class Inventory {
|
export class Inventory {
|
||||||
private slots: ItemStack[] = [];
|
private slots: ItemStack[] = [];
|
||||||
private savedSlots: ItemStack[] = [];
|
private savedSlots: ItemStack[] = [];
|
||||||
private numBroken: number = 0;
|
private numBroken = 0;
|
||||||
private isInitialSort: boolean = false;
|
private isInitialSort = false;
|
||||||
private isAltered: boolean = true;
|
private isAltered = true;
|
||||||
private isSaveAltered: boolean = true;
|
private isSaveAltered = true;
|
||||||
private inaccurate: boolean = false;
|
private inaccurate = false;
|
||||||
public clone(): Inventory {
|
public clone(): Inventory {
|
||||||
const other = new Inventory();
|
const other = new Inventory();
|
||||||
other.slots = [...this.slots.map(stack=>({...stack}))];
|
other.slots = [...this.slots.map(stack=>({...stack}))];
|
||||||
other.savedSlots = [...this.savedSlots.map(stack=>({...stack}))];
|
other.savedSlots = [...this.savedSlots.map(stack=>({...stack}))];
|
||||||
other.numBroken = this.numBroken;
|
other.numBroken = this.numBroken;
|
||||||
other.isInitialSort = this.isInitialSort;
|
other.isInitialSort = this.isInitialSort;
|
||||||
other.isAltered = this.isAltered;
|
other.isAltered = this.isAltered;
|
||||||
other.isSaveAltered = this.isSaveAltered;
|
other.isSaveAltered = this.isSaveAltered;
|
||||||
other.inaccurate = this.inaccurate;
|
other.inaccurate = this.inaccurate;
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSlots(): ItemStack[] {
|
public getSlots(): ItemStack[] {
|
||||||
return this.slots;
|
return this.slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNumBroken(): number {
|
public getNumBroken(): number {
|
||||||
return this.numBroken;
|
return this.numBroken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isInaccurate(): boolean {
|
public isInaccurate(): boolean {
|
||||||
return this.inaccurate;
|
return this.inaccurate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(stacks: ItemStack[]) {
|
public init(stacks: ItemStack[]) {
|
||||||
this.savedSlots = [...stacks.map((stack)=>({...stack}))];
|
this.savedSlots = [...stacks.map((stack)=>({...stack}))];
|
||||||
this.slots = [...stacks.map((stack)=>({...stack}))];
|
this.slots = [...stacks.map((stack)=>({...stack}))];
|
||||||
}
|
this.numBroken = 0;
|
||||||
|
this.isInitialSort = false;
|
||||||
|
this.isAltered = true;
|
||||||
|
this.isSaveAltered = true;
|
||||||
|
this.inaccurate = false;
|
||||||
|
}
|
||||||
|
|
||||||
public addBrokenSlots(num: number) {
|
public addBrokenSlots(num: number) {
|
||||||
this.numBroken+=num;
|
this.numBroken+=num;
|
||||||
}
|
}
|
||||||
|
|
||||||
public save() {
|
public save() {
|
||||||
this.isSaveAltered = this.isAltered;
|
this.isSaveAltered = this.isAltered;
|
||||||
this.savedSlots = [...this.slots];
|
this.savedSlots = [...this.slots];
|
||||||
}
|
}
|
||||||
|
|
||||||
public reload() {
|
public reload() {
|
||||||
if(!this.isSaveAltered){
|
if(!this.isSaveAltered){
|
||||||
this.inaccurate = true;
|
this.inaccurate = true;
|
||||||
}
|
}
|
||||||
// get things to dupe
|
// get things to dupe
|
||||||
const dupeMap: {[k in ItemType]: ItemStack[]} = {
|
const dupeMap: {[k in ItemType]: ItemStack[]} = {
|
||||||
[ItemType.Material]: [],
|
[ItemType.Material]: [],
|
||||||
[ItemType.Meal]: [],
|
[ItemType.Meal]: [],
|
||||||
[ItemType.Key]: []
|
[ItemType.Key]: []
|
||||||
}
|
};
|
||||||
for(let i=Math.max(0, this.slots.length-this.numBroken);i<this.slots.length;i++){
|
for(let i=Math.max(0, this.slots.length-this.numBroken);i<this.slots.length;i++){
|
||||||
const stack = this.slots[i];
|
const stack = this.slots[i];
|
||||||
if(!shouldIgnoreOnReload(stack.item)){
|
if(!shouldIgnoreOnReload(stack.item)){
|
||||||
dupeMap[itemToType(stack.item)].push(stack);
|
dupeMap[itemToType(stack.item)].push(stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get materials, food, and key items
|
// get materials, food, and key items
|
||||||
const materials = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
const materials = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
||||||
const meals = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Meal);
|
const meals = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Meal);
|
||||||
const keyItems = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
const keyItems = this.savedSlots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
||||||
// apply dupe
|
// apply dupe
|
||||||
this.slots = [];
|
this.slots = [];
|
||||||
// duped materials go to the left
|
// duped materials go to the left
|
||||||
this.slots.push(...dupeMap[ItemType.Material].map(stack=>({...stack})));
|
this.slots.push(...dupeMap[ItemType.Material].map(stack=>({...stack})));
|
||||||
this.slots.push(...materials.map(stack=>({...stack})));
|
this.slots.push(...materials.map(stack=>({...stack})));
|
||||||
this.slots.push(...dupeMap[ItemType.Meal].map(stack=>({...stack})));
|
this.slots.push(...dupeMap[ItemType.Meal].map(stack=>({...stack})));
|
||||||
this.slots.push(...meals.map(stack=>({...stack})));
|
this.slots.push(...meals.map(stack=>({...stack})));
|
||||||
// key items to the right
|
// key items to the right
|
||||||
this.slots.push(...keyItems.map(stack=>({...stack})));
|
this.slots.push(...keyItems.map(stack=>({...stack})));
|
||||||
this.slots.push(...dupeMap[ItemType.Key].map(stack=>({...stack})));
|
this.slots.push(...dupeMap[ItemType.Key].map(stack=>({...stack})));
|
||||||
|
|
||||||
this.isInitialSort = true;
|
this.isInitialSort = true;
|
||||||
this.isAltered = false;
|
this.isAltered = false;
|
||||||
this.isSaveAltered = false;
|
this.isSaveAltered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sortKey() {
|
public sortKey() {
|
||||||
const nonKeyItems = this.slots.filter(stack=>itemToType(stack.item)!==ItemType.Key);
|
const nonKeyItems = this.slots.filter(stack=>itemToType(stack.item)!==ItemType.Key);
|
||||||
const keyItems = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
const keyItems = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
||||||
keyItems.sort((a,b)=>{
|
keyItems.sort((a,b)=>{
|
||||||
return getKeyItemSortOrder(a.item) - getKeyItemSortOrder(b.item);
|
return getKeyItemSortOrder(a.item) - getKeyItemSortOrder(b.item);
|
||||||
});
|
});
|
||||||
this.slots = [...nonKeyItems, ...keyItems];
|
this.slots = [...nonKeyItems, ...keyItems];
|
||||||
this.isAltered=true;
|
this.isAltered=true;
|
||||||
this.isInitialSort=false;
|
this.isInitialSort=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sortMaterial() {
|
public sortMaterial() {
|
||||||
const nonMaterial = this.slots.filter(stack=>itemToType(stack.item)!==ItemType.Material);
|
const nonMaterial = this.slots.filter(stack=>itemToType(stack.item)!==ItemType.Material);
|
||||||
const materials = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
const materials = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
||||||
if(this.isInitialSort){
|
if(this.isInitialSort){
|
||||||
// the materials in broken slots are not sorted
|
// the materials in broken slots are not sorted
|
||||||
const brokenSlots = Math.max(0, this.numBroken - nonMaterial.length);
|
const brokenSlots = Math.max(0, this.numBroken - nonMaterial.length);
|
||||||
const sortPart = materials.splice(0, materials.length-brokenSlots);
|
const sortPart = materials.splice(0, materials.length-brokenSlots);
|
||||||
sortPart.sort((a,b)=>{
|
sortPart.sort((a,b)=>{
|
||||||
return getMaterialSortOrder(a.item) - getMaterialSortOrder(b.item);
|
return getMaterialSortOrder(a.item) - getMaterialSortOrder(b.item);
|
||||||
});
|
});
|
||||||
this.slots = [...sortPart, ...materials, ...nonMaterial];
|
this.slots = [...sortPart, ...materials, ...nonMaterial];
|
||||||
this.isInitialSort = false;
|
this.isInitialSort = false;
|
||||||
}else{
|
}else{
|
||||||
materials.sort((a,b)=>{
|
materials.sort((a,b)=>{
|
||||||
return getMaterialSortOrder(a.item) - getMaterialSortOrder(b.item);
|
return getMaterialSortOrder(a.item) - getMaterialSortOrder(b.item);
|
||||||
});
|
});
|
||||||
this.slots = [...materials, ...nonMaterial];
|
this.slots = [...materials, ...nonMaterial];
|
||||||
}
|
}
|
||||||
this.isAltered=true;
|
this.isAltered=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(item: Item, count: number, slot: number) {
|
public remove(item: Item, count: number, slot: number) {
|
||||||
let s = 0;
|
let s = 0;
|
||||||
for(let i = 0; i<this.slots.length;i++){
|
for(let i = 0; i<this.slots.length;i++){
|
||||||
if(this.slots[i].item === item){
|
if(this.slots[i].item === item){
|
||||||
if(s<slot){
|
if(s<slot){
|
||||||
s++;
|
s++;
|
||||||
}else{
|
}else{
|
||||||
this.slots[i].count-=count;
|
this.slots[i].count-=count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.slots = this.slots.filter(({count})=>count>0);
|
this.slots = this.slots.filter(({count})=>count>0);
|
||||||
this.isAltered=true;
|
this.isAltered=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(item: Item, count: number) {
|
public add(item: Item, count: number) {
|
||||||
let added = false;
|
let added = false;
|
||||||
if(isStackable(item)){
|
if(isStackable(item)){
|
||||||
for(let i = 0; i<this.slots.length;i++){
|
for(let i = 0; i<this.slots.length;i++){
|
||||||
if(this.slots[i].item === item){
|
if(this.slots[i].item === item){
|
||||||
this.slots[i].count+=count;
|
this.slots[i].count+=count;
|
||||||
added = true;
|
added = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!added){
|
if(!added){
|
||||||
// add to the correct type
|
// add to the correct type
|
||||||
switch(itemToType(item)){
|
switch(itemToType(item)){
|
||||||
case ItemType.Material: {
|
case ItemType.Material: {
|
||||||
const materials = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
const materials = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Material);
|
||||||
this.slots.splice(materials.length, 0, {
|
this.slots.splice(materials.length, 0, {
|
||||||
item, count
|
item, count
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ItemType.Meal: {
|
case ItemType.Meal: {
|
||||||
const keyItems = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
const keyItems = this.slots.filter(stack=>itemToType(stack.item)===ItemType.Key);
|
||||||
this.slots.splice(-keyItems.length, 0, {
|
this.slots.splice(-keyItems.length, 0, {
|
||||||
item, count
|
item, count
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ItemType.Key: {
|
case ItemType.Key: {
|
||||||
this.slots.push({
|
this.slots.push({
|
||||||
item, count
|
item, count
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.isAltered=true;
|
this.isAltered=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
131
src/core/Item.ts
131
src/core/Item.ts
|
@ -4,7 +4,6 @@ export enum Item {
|
||||||
Slate = "Slate",
|
Slate = "Slate",
|
||||||
Glider = "Glider",
|
Glider = "Glider",
|
||||||
SpiritOrb = "SpiritOrb",
|
SpiritOrb = "SpiritOrb",
|
||||||
|
|
||||||
|
|
||||||
Lotus = "Lotus",
|
Lotus = "Lotus",
|
||||||
SilentPrincess = "SilentPrincess",
|
SilentPrincess = "SilentPrincess",
|
||||||
|
@ -27,86 +26,86 @@ export enum Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ItemIds = {
|
export const ItemIds = {
|
||||||
/* Do not change the ID once created. Otherwise you would break existing codes */
|
/* Do not change the ID once created. Otherwise you would break existing codes */
|
||||||
[Item.Slate]: 0x00,
|
[Item.Slate]: 0x00,
|
||||||
[Item.Glider]: 0x01,
|
[Item.Glider]: 0x01,
|
||||||
[Item.SpiritOrb]: 0x02,
|
[Item.SpiritOrb]: 0x02,
|
||||||
|
|
||||||
[Item.Diamond]: 0x10,
|
[Item.Diamond]: 0x10,
|
||||||
[Item.Lotus]: 0x11,
|
[Item.Lotus]: 0x11,
|
||||||
[Item.SilentPrincess]: 0x12,
|
[Item.SilentPrincess]: 0x12,
|
||||||
[Item.Honey]: 0x13,
|
[Item.Honey]: 0x13,
|
||||||
[Item.Acorn]: 0x14,
|
[Item.Acorn]: 0x14,
|
||||||
[Item.FaroshScale]: 0x15,
|
[Item.FaroshScale]: 0x15,
|
||||||
[Item.FaroshClaw]: 0x16,
|
[Item.FaroshClaw]: 0x16,
|
||||||
[Item.FaroshHorn]: 0x17,
|
[Item.FaroshHorn]: 0x17,
|
||||||
[Item.HeartyBass]: 0x18,
|
[Item.HeartyBass]: 0x18,
|
||||||
[Item.Beetle]: 0x19,
|
[Item.Beetle]: 0x19,
|
||||||
[Item.Opal]: 0x1a,
|
[Item.Opal]: 0x1a,
|
||||||
[Item.Tail]: 0x1b,
|
[Item.Tail]: 0x1b,
|
||||||
[Item.Spring]: 0x1c,
|
[Item.Spring]: 0x1c,
|
||||||
[Item.Shaft]: 0x1d,
|
[Item.Shaft]: 0x1d,
|
||||||
[Item.Core]: 0x1e,
|
[Item.Core]: 0x1e,
|
||||||
[Item.Wood]: 0x1f,
|
[Item.Wood]: 0x1f,
|
||||||
|
|
||||||
[Item.SpeedFood]: 0x40,
|
[Item.SpeedFood]: 0x40,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const itemToType = (item: Item): ItemType => {
|
export const itemToType = (item: Item): ItemType => {
|
||||||
if (item === Item.Slate || item === Item.Glider || item === Item.SpiritOrb){
|
if (item === Item.Slate || item === Item.Glider || item === Item.SpiritOrb){
|
||||||
return ItemType.Key;
|
return ItemType.Key;
|
||||||
}
|
}
|
||||||
if (item === Item.SpeedFood) {
|
if (item === Item.SpeedFood) {
|
||||||
return ItemType.Meal;
|
return ItemType.Meal;
|
||||||
}
|
}
|
||||||
return ItemType.Material;
|
return ItemType.Material;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const shouldIgnoreOnReload = (item: Item): boolean => {
|
export const shouldIgnoreOnReload = (item: Item): boolean => {
|
||||||
return item === Item.Slate || item === Item.Glider;
|
return item === Item.Slate || item === Item.Glider;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const isStackable = (item: Item): boolean => {
|
export const isStackable = (item: Item): boolean => {
|
||||||
return item !==Item.Slate && item !== Item.Glider && item !== Item.SpeedFood;
|
return item !==Item.Slate && item !== Item.Glider && item !== Item.SpeedFood;
|
||||||
}
|
};
|
||||||
|
|
||||||
const KeyItemSortOrderMap = (()=>{
|
const KeyItemSortOrderMap = (()=>{
|
||||||
const map: {[k in Item]?: number} = {};
|
const map: {[k in Item]?: number} = {};
|
||||||
[
|
[
|
||||||
Item.Slate,
|
Item.Slate,
|
||||||
Item.Glider,
|
Item.Glider,
|
||||||
Item.SpiritOrb
|
Item.SpiritOrb
|
||||||
].forEach((item, i)=>map[item] = i);
|
].forEach((item, i)=>map[item] = i);
|
||||||
return map;
|
return map;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
export const getKeyItemSortOrder = (item: Item): number => {
|
export const getKeyItemSortOrder = (item: Item): number => {
|
||||||
return KeyItemSortOrderMap[item] || -1;
|
return KeyItemSortOrderMap[item] || -1;
|
||||||
}
|
};
|
||||||
|
|
||||||
const MaterialSortOrderMap = (()=>{
|
const MaterialSortOrderMap = (()=>{
|
||||||
const map: {[k in Item]?: number} = {};
|
const map: {[k in Item]?: number} = {};
|
||||||
[
|
[
|
||||||
Item.Lotus,
|
Item.Lotus,
|
||||||
Item.SilentPrincess,
|
Item.SilentPrincess,
|
||||||
Item.Honey,
|
Item.Honey,
|
||||||
Item.Acorn,
|
Item.Acorn,
|
||||||
Item.FaroshScale,
|
Item.FaroshScale,
|
||||||
Item.FaroshClaw,
|
Item.FaroshClaw,
|
||||||
Item.FaroshHorn,
|
Item.FaroshHorn,
|
||||||
Item.HeartyBass,
|
Item.HeartyBass,
|
||||||
Item.Beetle,
|
Item.Beetle,
|
||||||
Item.Opal,
|
Item.Opal,
|
||||||
Item.Diamond,
|
Item.Diamond,
|
||||||
Item.Tail,
|
Item.Tail,
|
||||||
Item.Spring,
|
Item.Spring,
|
||||||
Item.Shaft,
|
Item.Shaft,
|
||||||
Item.Core,
|
Item.Core,
|
||||||
Item.Wood,
|
Item.Wood,
|
||||||
].forEach((item, i)=>map[item] = i);
|
].forEach((item, i)=>map[item] = i);
|
||||||
return map;
|
return map;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
export const getMaterialSortOrder = (item: Item): number => {
|
export const getMaterialSortOrder = (item: Item): number => {
|
||||||
return MaterialSortOrderMap[item] || -1;
|
return MaterialSortOrderMap[item] || -1;
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,79 +3,79 @@ import { Item } from "./Item";
|
||||||
import { ItemStack } from "./ItemStack";
|
import { ItemStack } from "./ItemStack";
|
||||||
|
|
||||||
export const parseCommand = (cmdString: string): Command | undefined => {
|
export const parseCommand = (cmdString: string): Command | undefined => {
|
||||||
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 CommandNothing();
|
||||||
}
|
}
|
||||||
// intialize
|
// intialize
|
||||||
if(tokens.length>1 && tokens[0] === "Initialize" && tokens.length%2 === 1){
|
if(tokens.length>1 && tokens[0] === "Initialize" && tokens.length%2 === 1){
|
||||||
const stacks: ItemStack[] = [];
|
const stacks: ItemStack[] = [];
|
||||||
for(let i=1;i<tokens.length;i+=2){
|
for(let i=1;i<tokens.length;i+=2){
|
||||||
const count = parseInt(tokens[i]);
|
const count = parseInt(tokens[i]);
|
||||||
if(!Number.isInteger(count)){
|
if(!Number.isInteger(count)){
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const item = tokens[i+1];
|
const item = tokens[i+1];
|
||||||
if (item in Item){
|
if (item in Item){
|
||||||
stacks.push({
|
stacks.push({
|
||||||
item: Item[item as keyof typeof Item], count
|
item: Item[item as keyof typeof Item], count
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new CommandInitialize(stacks);
|
return new CommandInitialize(stacks);
|
||||||
}
|
}
|
||||||
// no var
|
// no var
|
||||||
if(tokens.length===1 && tokens[0] === "Save"){
|
if(tokens.length===1 && tokens[0] === "Save"){
|
||||||
return new CommandSave();
|
return new CommandSave();
|
||||||
}
|
}
|
||||||
if(tokens.length===1 && tokens[0] === "Reload"){
|
if(tokens.length===1 && tokens[0] === "Reload"){
|
||||||
return new CommandReload();
|
return new CommandReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
// 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)){
|
||||||
return new CommandBreakSlots(slots);
|
return new CommandBreakSlots(slots);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// remove material
|
// remove material
|
||||||
if (tokens.length === 6 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Drop") && tokens[3] === "From" && tokens[4] ==="Slot" ){
|
if (tokens.length === 6 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Drop") && tokens[3] === "From" && tokens[4] ==="Slot" ){
|
||||||
const count = parseInt(tokens[1]);
|
const count = parseInt(tokens[1]);
|
||||||
const item = tokens[2];
|
const item = tokens[2];
|
||||||
const slot = parseInt(tokens[5]);
|
const slot = parseInt(tokens[5]);
|
||||||
if(Number.isInteger(count) && Number.isInteger(slot) && item in Item){
|
if(Number.isInteger(count) && Number.isInteger(slot) && item in Item){
|
||||||
return new CommandRemoveMaterial(tokens[0], count, Item[item as keyof typeof Item], slot-1);
|
return new CommandRemoveMaterial(tokens[0], count, Item[item as keyof typeof Item], slot-1);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// remove 1 material
|
// remove 1 material
|
||||||
if (tokens.length === 5 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Eat") && tokens[2] === "From" && tokens[3] ==="Slot" ){
|
if (tokens.length === 5 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Eat") && tokens[2] === "From" && tokens[3] ==="Slot" ){
|
||||||
const item = tokens[1];
|
const item = tokens[1];
|
||||||
const slot = parseInt(tokens[4]);
|
const slot = parseInt(tokens[4]);
|
||||||
if(Number.isInteger(slot) && item in Item){
|
if(Number.isInteger(slot) && item in Item){
|
||||||
return new CommandRemoveUnstackableMaterial(tokens[0], Item[item as keyof typeof Item], slot-1);
|
return new CommandRemoveUnstackableMaterial(tokens[0], Item[item as keyof typeof Item], slot-1);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// add material
|
// add material
|
||||||
if (tokens.length === 3 && (tokens[0] === "Get" || tokens[0] === "Cook" || tokens[0] === "Add" || tokens[0] === "Pickup")){
|
if (tokens.length === 3 && (tokens[0] === "Get" || tokens[0] === "Cook" || tokens[0] === "Add" || tokens[0] === "Pickup")){
|
||||||
const count = parseInt(tokens[1]);
|
const count = parseInt(tokens[1]);
|
||||||
const item = tokens[2];
|
const item = tokens[2];
|
||||||
if(Number.isInteger(count) && item in Item){
|
if(Number.isInteger(count) && item in Item){
|
||||||
return new CommandAddMaterial(tokens[0], count, Item[item as keyof typeof Item]);
|
return new CommandAddMaterial(tokens[0], count, Item[item as keyof typeof Item]);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,65 +1,65 @@
|
||||||
import { Command, CommandAddMaterial, CommandBreakSlots, CommandInitialize, CommandNothing, CommandReload, CommandRemoveMaterial, CommandRemoveUnstackableMaterial, CommandSave, CommandSortKey, CommandSortMaterial } from "./Command";
|
import { Command, CommandAddMaterial, CommandBreakSlots, CommandInitialize, CommandNothing, CommandReload, CommandRemoveMaterial, CommandRemoveUnstackableMaterial, CommandSave, CommandSortKey, CommandSortMaterial } from "./Command";
|
||||||
import { Item } from "./Item";
|
import { Item } from "./Item";
|
||||||
|
|
||||||
const Buffer = require("buffer/").Buffer;
|
const Buffer = require("buffer/").Buffer; /* eslint-disable-line @typescript-eslint/no-var-requires*/
|
||||||
|
|
||||||
export const serializeCommands = (commands: Command[]): string => {
|
export const serializeCommands = (commands: Command[]): string => {
|
||||||
const sizeBuf: Buffer = Buffer.alloc(4);
|
const sizeBuf: Buffer = Buffer.alloc(4);
|
||||||
sizeBuf.writeInt32LE(commands.length);
|
sizeBuf.writeInt32LE(commands.length);
|
||||||
|
|
||||||
const commandBuffers = commands.map(c=>c.toBuffer());
|
const commandBuffers = commands.map(c=>c.toBuffer());
|
||||||
const allBufs = Buffer.concat([sizeBuf, ...commandBuffers]);
|
const allBufs = Buffer.concat([sizeBuf, ...commandBuffers]);
|
||||||
console.log(allBufs);
|
|
||||||
return allBufs.toString("base64");
|
return allBufs.toString("base64");
|
||||||
}
|
};
|
||||||
|
|
||||||
export const deserialzeCommands = (base64str: string): Command[] => {
|
export const deserialzeCommands = (base64str: string): Command[] => {
|
||||||
const buf: Buffer = Buffer.from(base64str, "base64");
|
const buf: Buffer = Buffer.from(base64str, "base64");
|
||||||
const size = buf.readInt32LE();
|
const size = buf.readInt32LE();
|
||||||
let off = 4;
|
let off = 4;
|
||||||
const commands: Command[] = [];
|
const commands: Command[] = [];
|
||||||
for(let i=0;i<size;i++){
|
for(let i=0;i<size;i++){
|
||||||
const op = buf.readUInt8(off);
|
const op = buf.readUInt8(off);
|
||||||
off++;
|
off++;
|
||||||
let command: Command | undefined = undefined;
|
let command: Command | undefined = undefined;
|
||||||
switch(op){
|
switch(op){
|
||||||
case CommandNothing.Op:
|
case CommandNothing.Op:
|
||||||
command = new CommandNothing();
|
command = new CommandNothing();
|
||||||
break;
|
break;
|
||||||
case CommandInitialize.Op:
|
case CommandInitialize.Op:
|
||||||
command = new CommandInitialize([]);
|
command = new CommandInitialize([]);
|
||||||
break;
|
break;
|
||||||
case CommandBreakSlots.Op:
|
case CommandBreakSlots.Op:
|
||||||
command = new CommandBreakSlots(0);
|
command = new CommandBreakSlots(0);
|
||||||
break;
|
break;
|
||||||
case CommandSave.Op:
|
case CommandSave.Op:
|
||||||
command = new CommandSave();
|
command = new CommandSave();
|
||||||
break;
|
break;
|
||||||
case CommandReload.Op:
|
case CommandReload.Op:
|
||||||
command = new CommandReload();
|
command = new CommandReload();
|
||||||
break;
|
break;
|
||||||
case CommandSortKey.Op:
|
case CommandSortKey.Op:
|
||||||
command = new CommandSortKey();
|
command = new CommandSortKey();
|
||||||
break;
|
break;
|
||||||
case CommandSortMaterial.Op:
|
case CommandSortMaterial.Op:
|
||||||
command = new CommandSortMaterial();
|
command = new CommandSortMaterial();
|
||||||
break;
|
break;
|
||||||
case CommandRemoveMaterial.Op:
|
case CommandRemoveMaterial.Op:
|
||||||
command = new CommandRemoveMaterial("",0,Item.Slate,0);
|
command = new CommandRemoveMaterial("",0,Item.Slate,0);
|
||||||
break;
|
break;
|
||||||
case CommandRemoveUnstackableMaterial.Op:
|
case CommandRemoveUnstackableMaterial.Op:
|
||||||
command = new CommandRemoveUnstackableMaterial("", Item.Slate, 0);
|
command = new CommandRemoveUnstackableMaterial("", Item.Slate, 0);
|
||||||
break;
|
break;
|
||||||
case CommandAddMaterial.Op:
|
case CommandAddMaterial.Op:
|
||||||
command = new CommandAddMaterial("",0,Item.Slate);
|
command = new CommandAddMaterial("",0,Item.Slate);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(command){
|
if(command){
|
||||||
off += command.fromBuffer(buf.slice(off));
|
off += command.fromBuffer(buf.slice(off));
|
||||||
commands.push(command);
|
commands.push(command);
|
||||||
}else{
|
}else{
|
||||||
console.error("invalid opcode: "+op);
|
console.error("invalid opcode: "+op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return commands;
|
return commands;
|
||||||
}
|
};
|
||||||
|
|
168
src/data/FileSaver/FileSaver.js
Normal file
168
src/data/FileSaver/FileSaver.js
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/* eslint no-empty:0 */
|
||||||
|
/*
|
||||||
|
* FileSaver.js
|
||||||
|
* A saveAs() FileSaver implementation.
|
||||||
|
*
|
||||||
|
* By Eli Grey, http://eligrey.com
|
||||||
|
*
|
||||||
|
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
|
||||||
|
* source : http://purl.eligrey.com/github/FileSaver.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The one and only way of getting global scope in all environments
|
||||||
|
// https://stackoverflow.com/q/3277182/1008999
|
||||||
|
var _global = typeof window === "object" && window.window === window
|
||||||
|
? window : typeof window.self === "object" && window.self.self === window.self
|
||||||
|
? window.self : typeof window.global === "object" && window.global.global === window.global
|
||||||
|
? window.global
|
||||||
|
: this;
|
||||||
|
|
||||||
|
function bom (blob, opts) {
|
||||||
|
if (typeof opts === "undefined") {opts = { autoBom: false };}
|
||||||
|
else if (typeof opts !== "object") {
|
||||||
|
console.error("Deprecated: Expected third argument to be a object");
|
||||||
|
opts = { autoBom: !opts };
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||||
|
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||||
|
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||||
|
return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type });
|
||||||
|
}
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
function download (url, name, opts) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", url);
|
||||||
|
xhr.responseType = "blob";
|
||||||
|
xhr.onload = function () {
|
||||||
|
saveAs(xhr.response, name, opts);
|
||||||
|
};
|
||||||
|
xhr.onerror = function () {
|
||||||
|
console.error("could not download file");
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function corsEnabled (url) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
// use sync to avoid popup blocker
|
||||||
|
xhr.open("HEAD", url, false);
|
||||||
|
try {
|
||||||
|
xhr.send();
|
||||||
|
} catch (e) {}
|
||||||
|
return xhr.status >= 200 && xhr.status <= 299;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `a.click()` doesn't work for all browsers (#465)
|
||||||
|
function click (node) {
|
||||||
|
try {
|
||||||
|
node.dispatchEvent(new MouseEvent("click"));
|
||||||
|
} catch (e) {
|
||||||
|
var evt = document.createEvent("MouseEvents");
|
||||||
|
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 80,
|
||||||
|
20, false, false, false, false, 0, null);
|
||||||
|
node.dispatchEvent(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect WebView inside a native macOS app by ruling out all browsers
|
||||||
|
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
|
||||||
|
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
|
||||||
|
var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
|
||||||
|
|
||||||
|
var saveAs = _global.saveAs || (
|
||||||
|
// probably in some web worker
|
||||||
|
typeof window !== "object" || window !== _global
|
||||||
|
? function saveAs () { /* noop */ }
|
||||||
|
|
||||||
|
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
|
||||||
|
: "download" in HTMLAnchorElement.prototype && !isMacOSWebView
|
||||||
|
? function saveAs (blob, name, opts) {
|
||||||
|
var URL = _global.URL || _global.webkitURL;
|
||||||
|
var a = document.createElement("a");
|
||||||
|
name = name || blob.name || "download";
|
||||||
|
|
||||||
|
a.download = name;
|
||||||
|
a.rel = "noopener"; // tabnabbing
|
||||||
|
|
||||||
|
// TODO: detect chrome extensions & packaged apps
|
||||||
|
// a.target = '_blank'
|
||||||
|
|
||||||
|
if (typeof blob === "string") {
|
||||||
|
// Support regular links
|
||||||
|
a.href = blob;
|
||||||
|
if (a.origin !== window.location.origin) {
|
||||||
|
corsEnabled(a.href)
|
||||||
|
? download(blob, name, opts)
|
||||||
|
: click(a, a.target = "_blank");
|
||||||
|
} else {
|
||||||
|
click(a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Support blobs
|
||||||
|
a.href = URL.createObjectURL(blob);
|
||||||
|
setTimeout(function () { URL.revokeObjectURL(a.href); }, 4E4); // 40s
|
||||||
|
setTimeout(function () { click(a); }, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use msSaveOrOpenBlob as a second approach
|
||||||
|
: "msSaveOrOpenBlob" in navigator
|
||||||
|
? function saveAs (blob, name, opts) {
|
||||||
|
name = name || blob.name || "download";
|
||||||
|
|
||||||
|
if (typeof blob === "string") {
|
||||||
|
if (corsEnabled(blob)) {
|
||||||
|
download(blob, name, opts);
|
||||||
|
} else {
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = blob;
|
||||||
|
a.target = "_blank";
|
||||||
|
setTimeout(function () { click(a); });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to using FileReader and a popup
|
||||||
|
: function saveAs (blob, name, opts, popup) {
|
||||||
|
// Open a popup immediately do go around popup blocker
|
||||||
|
// Mostly only available on user interaction and the fileReader is async so...
|
||||||
|
popup = popup || window.open("", "_blank");
|
||||||
|
if (popup) {
|
||||||
|
popup.document.title =
|
||||||
|
popup.document.body.innerText = "downloading...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof blob === "string") {return download(blob, name, opts);}
|
||||||
|
|
||||||
|
var force = blob.type === "application/octet-stream";
|
||||||
|
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
|
||||||
|
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
|
||||||
|
|
||||||
|
if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== "undefined") {
|
||||||
|
// Safari doesn't allow downloading of blob URLs
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onloadend = function () {
|
||||||
|
var url = reader.result;
|
||||||
|
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, "data:attachment/file;");
|
||||||
|
if (popup) {popup.location.href = url;}
|
||||||
|
else {window.location = url;}
|
||||||
|
popup = null; // reverse-tabnabbing #460
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
} else {
|
||||||
|
var URL = _global.URL || _global.webkitURL;
|
||||||
|
var url = URL.createObjectURL(blob);
|
||||||
|
if (popup) {popup.location = url;}
|
||||||
|
else {window.location.href = url;}
|
||||||
|
popup = null; // reverse-tabnabbing #460
|
||||||
|
setTimeout(function () { URL.revokeObjectURL(url); }, 4E4); // 40s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default saveAs;
|
9
src/data/FileSaver/LICENSE.md
Normal file
9
src/data/FileSaver/LICENSE.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright © 2016 Eli Grey.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
src/data/FileSaver/index.ts
Normal file
8
src/data/FileSaver/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import FileSaverFunction from "./FileSaver";
|
||||||
|
|
||||||
|
export const saveAs = (content: string, filename: string): void =>{
|
||||||
|
const blob = new Blob([content], {
|
||||||
|
type: "text/plain;charset=utf-8"
|
||||||
|
});
|
||||||
|
FileSaverFunction(blob, filename);
|
||||||
|
};
|
|
@ -1,16 +1,16 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from "react-dom/client";
|
||||||
import './index.css';
|
import "./index.css";
|
||||||
import {App} from './App';
|
import {App} from "./App";
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from "./reportWebVitals";
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById('root') as HTMLElement
|
document.getElementById("root") as HTMLElement
|
||||||
);
|
);
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { ReportHandler } from 'web-vitals';
|
import { ReportHandler } from "web-vitals";
|
||||||
|
|
||||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||||
getCLS(onPerfEntry);
|
getCLS(onPerfEntry);
|
||||||
getFID(onPerfEntry);
|
getFID(onPerfEntry);
|
||||||
getFCP(onPerfEntry);
|
getFCP(onPerfEntry);
|
||||||
getLCP(onPerfEntry);
|
getLCP(onPerfEntry);
|
||||||
getTTFB(onPerfEntry);
|
getTTFB(onPerfEntry);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default reportWebVitals;
|
export default reportWebVitals;
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
// allows you to do things like:
|
// allows you to do things like:
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
import '@testing-library/jest-dom';
|
import "@testing-library/jest-dom";
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import clsx from "clsx"
|
import clsx from "clsx";
|
||||||
import { ItemList, ItemListProps } from "components/ItemList"
|
import { ItemList, ItemListProps } from "components/ItemList";
|
||||||
import { Command } from "core/Command"
|
import { Command } from "core/Command";
|
||||||
import { itemToType } from "core/Item"
|
import { itemToType } from "core/Item";
|
||||||
import { ItemStack, ItemType } from "core/ItemStack"
|
import { ItemStack, ItemType } from "core/ItemStack";
|
||||||
import { parseCommand } from "core/Parser"
|
import { parseCommand } from "core/Parser";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react"
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
type DisplayPaneProps = {
|
type DisplayPaneProps = {
|
||||||
command: string,
|
command: string,
|
||||||
|
@ -16,72 +16,72 @@ type DisplayPaneProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const stacksToItemListProps = (stacks: ItemStack[], numBroken: number): [ItemListProps, ItemListProps, ItemListProps] => {
|
const stacksToItemListProps = (stacks: ItemStack[], numBroken: number): [ItemListProps, ItemListProps, ItemListProps] => {
|
||||||
const materials = stacks.filter(stack=>itemToType(stack.item)==ItemType.Material);
|
const materials = stacks.filter(stack=>itemToType(stack.item)==ItemType.Material);
|
||||||
const meals = stacks.filter(stack=>itemToType(stack.item)==ItemType.Meal);
|
const meals = stacks.filter(stack=>itemToType(stack.item)==ItemType.Meal);
|
||||||
const keyItems = stacks.filter(stack=>itemToType(stack.item)==ItemType.Key);
|
const keyItems = stacks.filter(stack=>itemToType(stack.item)==ItemType.Key);
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
items: stacksToNameAndCount(materials),
|
items: stacksToNameAndCount(materials),
|
||||||
numBroken: Math.max(0, numBroken - keyItems.length - meals.length )
|
numBroken: Math.max(0, numBroken - keyItems.length - meals.length )
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
items: stacksToNameAndCount(meals),
|
items: stacksToNameAndCount(meals),
|
||||||
numBroken: Math.max(0, numBroken - keyItems.length)
|
numBroken: Math.max(0, numBroken - keyItems.length)
|
||||||
},{
|
},{
|
||||||
items: stacksToNameAndCount(keyItems),
|
items: stacksToNameAndCount(keyItems),
|
||||||
numBroken
|
numBroken
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
const stacksToNameAndCount = (stacks: ItemStack[]): ItemListProps["items"] => {
|
const stacksToNameAndCount = (stacks: ItemStack[]): ItemListProps["items"] => {
|
||||||
return stacks.map(({item, count})=>({name: item, count}));
|
return stacks.map(({item, count})=>({name: item, count}));
|
||||||
}
|
};
|
||||||
|
|
||||||
export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,displayIndex, stacks, numBroken})=>{
|
export const DisplayPane: React.FC<DisplayPaneProps> = ({command,editCommand,displayIndex, stacks, numBroken})=>{
|
||||||
const [commandString, setCommandString] = useState<string>("");
|
const [commandString, setCommandString] = useState<string>("");
|
||||||
const [hasError, setHasError] = useState<boolean>(false);
|
const [hasError, setHasError] = useState<boolean>(false);
|
||||||
const [materialListProps, mealListProps, keyItemListProps] = stacksToItemListProps(stacks, numBroken);
|
const [materialListProps, mealListProps, keyItemListProps] = stacksToItemListProps(stacks, numBroken);
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(commandString!==command){
|
if(commandString!==command){
|
||||||
setCommandString(command);
|
setCommandString(command);
|
||||||
setHasError(false);
|
setHasError(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [command, displayIndex]);
|
}, [command, displayIndex]);
|
||||||
|
|
||||||
return <div id="DisplayPane" style={{
|
return <div id="DisplayPane" style={{
|
||||||
width: "calc( 100% - 300px - 5px )",
|
width: "calc( 100% - 300px - 5px )",
|
||||||
float: "right",
|
float: "right",
|
||||||
border: "1px solid black",
|
border: "1px solid black",
|
||||||
boxSizing: "content-box"
|
boxSizing: "content-box"
|
||||||
} }>
|
} }>
|
||||||
<div style={{
|
<div style={{
|
||||||
marginBottom: 2,
|
marginBottom: 2,
|
||||||
boxSizing: "content-box",
|
boxSizing: "content-box",
|
||||||
height: "50px"
|
height: "50px"
|
||||||
} }>
|
} }>
|
||||||
<input className={clsx("Calamity", hasError && "InputError")} style={{
|
<input className={clsx("Calamity", hasError && "InputError")} style={{
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
width: "80%",
|
width: "80%",
|
||||||
height: "40px",
|
height: "40px",
|
||||||
fontSize: "20pt",
|
fontSize: "20pt",
|
||||||
|
|
||||||
}}value={commandString}
|
}}value={commandString}
|
||||||
placeholder="Type command here..."
|
placeholder="Type command here..."
|
||||||
onChange={(e)=>{
|
onChange={(e)=>{
|
||||||
const cmdString = e.target.value;
|
const cmdString = e.target.value;
|
||||||
setCommandString(cmdString);
|
setCommandString(cmdString);
|
||||||
const parsedCommand = parseCommand(cmdString);
|
const parsedCommand = parseCommand(cmdString);
|
||||||
if(parsedCommand){
|
if(parsedCommand){
|
||||||
editCommand(parsedCommand);
|
editCommand(parsedCommand);
|
||||||
setHasError(false);
|
setHasError(false);
|
||||||
}else{
|
}else{
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
}
|
}
|
||||||
}}></input>
|
}}></input>
|
||||||
<button onClick={()=>{
|
<button onClick={()=>{
|
||||||
alert(`Available Commands:
|
alert(`Available Commands:
|
||||||
Initialize X Item1 Y Item2 Z Item3 ...
|
Initialize X Item1 Y Item2 Z Item3 ...
|
||||||
Break X Slots - add X broken slots
|
Break X Slots - add X broken slots
|
||||||
Save
|
Save
|
||||||
|
@ -94,38 +94,37 @@ Remove/Sell/Eat MEAL From Slot X
|
||||||
Limitations:
|
Limitations:
|
||||||
When you reload without altering inventory, things become weird. It won't be handled correctly and the commands will become red
|
When you reload without altering inventory, things become weird. It won't be handled correctly and the commands will become red
|
||||||
`);
|
`);
|
||||||
}}>Reference</button>
|
}}>Reference</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{
|
<div style={{
|
||||||
borderTop: "1px solid black",
|
borderTop: "1px solid black",
|
||||||
borderBottom: "1px solid black",
|
borderBottom: "1px solid black",
|
||||||
marginBottom: 2,
|
marginBottom: 2,
|
||||||
boxSizing: "content-box",
|
boxSizing: "content-box",
|
||||||
height: "calc( ( 99vh - 60px ) / 3)",
|
height: "calc( ( 99vh - 60px ) / 3)",
|
||||||
overflowY: "auto"
|
overflowY: "auto"
|
||||||
} }>
|
} }>
|
||||||
<ItemList {...materialListProps}/>
|
<ItemList {...materialListProps}/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
borderTop: "1px solid black",
|
borderTop: "1px solid black",
|
||||||
boxSizing: "content-box",
|
boxSizing: "content-box",
|
||||||
borderBottom: "1px solid black",
|
borderBottom: "1px solid black",
|
||||||
marginBottom: 2,
|
marginBottom: 2,
|
||||||
height: "calc( ( 99vh - 60px ) / 3)",
|
height: "calc( ( 99vh - 60px ) / 3)",
|
||||||
overflowY: "auto"
|
overflowY: "auto"
|
||||||
} }>
|
} }>
|
||||||
<ItemList {...mealListProps}/>
|
<ItemList {...mealListProps}/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
borderTop: "1px solid black",
|
borderTop: "1px solid black",
|
||||||
boxSizing: "content-box",
|
boxSizing: "content-box",
|
||||||
height: "calc( ( 99vh - 60px ) / 3)",
|
height: "calc( ( 99vh - 60px ) / 3)",
|
||||||
overflowY: "auto"
|
overflowY: "auto"
|
||||||
} }>
|
} }>
|
||||||
<ItemList {...keyItemListProps}/>
|
<ItemList {...keyItemListProps}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>;
|
||||||
}
|
};
|
||||||
|
|
Reference in a new issue