1
0
Fork 0

shoot arrow WIP

This commit is contained in:
iTNTPiston 2022-06-23 07:32:45 -07:00
parent 8567bec9f9
commit dbcb7aef8d
9 changed files with 731 additions and 500 deletions

View file

@ -116,5 +116,10 @@ p.Example {
h3.Reference {
margin-top: 30px;
margin-bottom: 0
margin-bottom: 0;
}
h3.Reference2 {
margin-top: 0;
margin-bottom: 0;
}

View file

@ -29,12 +29,7 @@ export class CommandInitialize implements Command {
state.initialize(this.stacks);
}
public getDisplayString(): string {
const parts = ["Initialize"];
this.stacks.forEach(({item, count})=>{
parts.push(""+count);
parts.push(item);
});
return parts.join(" ");
return joinItemStackString("Initialize", this.stacks);
}
}
@ -104,7 +99,239 @@ export class CommandBreakSlots implements Command {
}
}
export class CommandAdd implements Command {
private verb: string;
private count: number;
private item: Item;
constructor(verb: string, count: number, item: Item){
this.verb = verb;
this.count = count;
this.item = item;
}
public execute(state: SimulationState): void {
state.obtain(this.item, this.count);
}
public getDisplayString(): string {
return `${this.verb} ${this.count} ${this.item}`;
}
}
export class CommandAddWithoutCount implements Command {
private verb: string;
private item: Item;
constructor(verb: string, item: Item){
this.verb = verb;
this.item = item;
}
public execute(state: SimulationState): void {
state.obtain(this.item, 1);
}
public getDisplayString(): string {
return `${this.verb} ${this.item}`;
}
}
export class CommandAddMultiple implements Command {
private verb: string;
private stacks: ItemStack[];
constructor(verb: string, stacks: ItemStack[]){
this.verb = verb;
this.stacks = stacks;
}
public execute(state: SimulationState): void {
this.stacks.forEach(({item, count})=>state.obtain(item,count));
}
public getDisplayString(): string {
return joinItemStackString(this.verb, this.stacks);
}
}
export class CommandRemove implements Command {
private verb: string;
private count: number;
private item: Item;
private slot: number;
private noSlot: boolean;
constructor(verb: string, count: number, item: Item, slot: number, noSlot: boolean){
this.verb = verb;
this.count = count;
this.item = item;
this.slot = slot;
this.noSlot = noSlot;
}
public execute(state: SimulationState): void {
state.remove(this.item, this.count, this.slot);
}
public getDisplayString(): string {
const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`;
return `${this.verb} ${this.count} ${this.item}${slotString}`;
}
}
export class CommandRemoveWithoutCount implements Command {
private verb: string;
private item: Item;
private slot: number;
private noSlot: boolean;
constructor(verb: string, item: Item, slot: number, noSlot: boolean){
this.verb = verb;
this.item = item;
this.slot = slot;
this.noSlot = noSlot;
}
public execute(state: SimulationState): void {
state.remove(this.item, 1, this.slot);
}
public getDisplayString(): string {
const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`;
return `${this.verb} ${this.item}${slotString}`;
}
}
export class CommandRemoveMultiple implements Command {
private verb: string;
private stacks: ItemStack[];
constructor(verb: string, stacks: ItemStack[]){
this.verb = verb;
this.stacks = stacks;
}
public execute(state: SimulationState): void {
this.stacks.forEach(({item, count})=>state.remove(item,count,0));
}
public getDisplayString(): string {
return joinItemStackString(this.verb, this.stacks);
}
}
const joinItemStackString = (initial: string, stacks: ItemStack[]): string => {
const parts: string[] = [initial];
stacks.forEach(({item, count})=>{
parts.push(""+count);
parts.push(item);
});
return parts.join(" ");
}
export class CommandDaP implements Command {
private count: number;
private item: Item;
constructor(count: number, item: Item,){
this.count = count;
this.item = item;
}
public execute(state: SimulationState): void {
state.remove(this.item, this.count, 0);
state.obtain(this.item, this.count);
}
public getDisplayString(): string {
return `D&P ${this.count} ${this.item}`;
}
}
export class CommandEquip implements Command {
private item: Item;
private slot: number;
private noSlot: boolean;
constructor(item: Item, slot: number, noSlot: boolean){
this.item = item;
this.slot = slot;
this.noSlot = noSlot;
}
public execute(state: SimulationState): void {
state.equip(this.item, this.slot);
}
public getDisplayString(): string {
const slotString = this.noSlot ? "" : ` In Slot ${this.slot+1}`;
return `Equip ${this.item}${slotString}`;
}
}
export class CommandUnequip implements Command {
private item: Item;
private slot: number;
private noSlot: boolean;
constructor(item: Item, slot: number, noSlot: boolean){
this.item = item;
this.slot = slot;
this.noSlot = noSlot;
}
public execute(state: SimulationState): void {
state.unequip(this.item, this.slot);
}
public getDisplayString(): string {
const slotString = this.noSlot ? "" : ` In Slot ${this.slot+1}`;
return `Unequip ${this.item}${slotString}`;
}
}
export class CommandShootArrow implements Command {
private count: number
constructor(count: number){
this.count = count;
}
public execute(state: SimulationState): void {
state.shootArrow(this.count);
}
public getDisplayString(): string {
return `Shoot ${this.count} Arrow`;
}
}
// export class CommandEquipArrow implements Command {
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// 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}`;
// }
// }
// export class CommandCloseGame implements Command {
// public execute(inv: Inventory): void {
// inv.closeGame();
// }
// public getDisplayString(): string {
// return "Close Game";
// }
// }
export class CommandComment implements Command {
private name: string;
constructor(name: string){
this.name = name;
}
public execute(_state: SimulationState): void {
// nothing
}
public getDisplayString(): string {
return `# ${this.name}`;
}
}
// export class CommandSortKey implements Command {
// static Op = 0x5;
@ -141,182 +368,3 @@ export class CommandBreakSlots implements Command {
// return "Sort Material";
// }
// }
// const Verbs = ["?", "Remove", "Drop", "Sell", "Eat", "Cook", "Get", "Add", "Pickup"];
// const VerbToId = {
// "Remove" : 1,
// "Drop": 2,
// "Sell": 3,
// "Eat": 4,
// "Cook": 5,
// "Get": 6,
// "Add": 7,
// "Pickup": 8
// };
// export class CommandRemoveMaterial implements Command {
// static Op = 0x7;
// private verb: number;
// private count: number;
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// constructor(verb: string, count: number, item: Item, slot: number, noSlot: boolean){
// this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
// this.count = count;
// this.item = item;
// this.slot = slot;
// this.noSlot = noSlot;
// }
// public execute(inv: Inventory): void {
// inv.remove(this.item, this.count, this.slot);
// }
// public getDisplayString(): string {
// const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`;
// return `${Verbs[this.verb]} ${this.count} ${this.item}${slotString}`;
// }
// }
// export class CommandRemoveUnstackableMaterial implements Command {
// static Op = 0x8;
// private verb: number;
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// constructor(verb: string,item: Item, slot: number, noSlot: boolean){
// this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
// this.item = item;
// this.slot = slot;
// this.noSlot = noSlot;
// }
// public execute(inv: Inventory): void {
// inv.remove(this.item, 1, this.slot);
// }
// public getDisplayString(): string {
// const slotString = this.noSlot ? "" : ` From Slot ${this.slot+1}`;
// return `${Verbs[this.verb]} ${this.item}${slotString}`;
// }
// }
// export class CommandAddMaterial implements Command {
// static Op = 0x9;
// private verb: number;
// private count: number;
// private item: Item;
// constructor(verb: string, count: number, item: Item){
// this.verb = VerbToId[verb as keyof typeof VerbToId] || 0;
// this.count = count;
// this.item = item;
// }
// // public fromBuffer(buf: Buffer): number {
// // let read = 0;
// // const id = buf.readInt8(read);
// // read+=1;
// // this.item = idToItemData(id).item;
// // this.count = buf.readInt16LE(read);
// // read+=2;
// // this.verb = buf.readInt8(read);
// // read++;
// // return read;
// // }
// // public toBuffer(): Buffer {
// // const buf: Buffer = Buffer.alloc(1+1+2+1);
// // let write = 0;
// // buf.writeInt8(CommandAddMaterial.Op);
// // write++;
// // buf.writeInt8(itemToItemData(this.item).id, write);
// // write++;
// // buf.writeInt16LE(this.count, write);
// // write+=2;
// // buf.writeInt8(this.verb, write);
// // return buf;
// // }
// public execute(inv: Inventory): void {
// inv.add(this.item, this.count);
// }
// public getDisplayString(): string {
// return `${Verbs[this.verb]} ${this.count} ${this.item}`;
// }
// }
// export class CommandEquipArrow implements Command {
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// 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}`;
// }
// }
// export class CommandEquip implements Command {
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// 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 ${this.item}${slotString}`;
// }
// }
// export class CommandUnequip implements Command {
// private item: Item;
// private slot: number;
// private noSlot: boolean;
// constructor(item: Item, slot: number, noSlot: boolean){
// this.item = item;
// this.slot = slot;
// this.noSlot = noSlot;
// }
// public execute(inv: Inventory): void {
// inv.unequipEquipment(this.item, this.slot);
// }
// public getDisplayString(): string {
// const slotString = this.noSlot ? "" : ` In Slot ${this.slot+1}`;
// return `Unequip ${this.item}${slotString}`;
// }
// }
// export class CommandCloseGame implements Command {
// public execute(inv: Inventory): void {
// inv.closeGame();
// }
// public getDisplayString(): string {
// return "Close Game";
// }
// }
export class CommandComment implements Command {
private name: string;
constructor(name: string){
this.name = name;
}
public execute(_state: SimulationState): void {
// nothing
}
public getDisplayString(): string {
return `# ${this.name}`;
}
}

View file

@ -1,4 +1,5 @@
import { DisplayableInventory, DisplayableSlot, itemStackToDisplayableSlot } from "./DisplayableInventory";
import { Item, itemToItemData } from "./Item";
import { Slots } from "./Slots";
import { VisibleInventory } from "./VisibleInventory";
@ -20,6 +21,10 @@ export class GameData implements DisplayableInventory {
this.slots = pouch.getSlots().deepClone();
}
public updateDurability(durability: number, slot: number){
this.slots.corrupt(durability, slot);
}
public addAllToPouchOnReload(pouch: VisibleInventory) {
this.slots.getSlotsRef().forEach(stack=>pouch.addWhenReload(stack.item, stack.count, stack.equipped));
}

View file

@ -1,12 +1,22 @@
import {
Command,
CommandAdd,
CommandAddMultiple,
CommandAddWithoutCount,
CommandBreakSlots,
CommandComment,
CommandDaP,
CommandEquip,
CommandInitialize,
CommandNothing,
CommandReload,
CommandRemove,
CommandRemoveMultiple,
CommandRemoveWithoutCount,
CommandSave,
CommandSaveAs,
CommandShootArrow,
CommandUnequip,
CommandUse
} from "./Command";
import { Item, ItemStack } from "./Item";
@ -21,23 +31,9 @@ export const parseCommand = (cmdString: string): Command | undefined => {
return new CommandNothing();
}
// intialize
if(tokens.length>1 && tokens[0] === "Initialize" && tokens.length%2 === 1){
const stacks: ItemStack[] = [];
for(let i=1;i<tokens.length;i+=2){
const count = parseInt(tokens[i]);
if(!Number.isInteger(count)){
return undefined;
}
const item = tokens[i+1];
if (item in Item){
stacks.push({
item: Item[item as keyof typeof Item], count, equipped:false
});
}else{
return undefined;
}
}
return new CommandInitialize(stacks);
if(tokens.length>1 && tokens[0] === "Initialize"){
const stacks = parseItemStacks(tokens, 1);
return stacks ? new CommandInitialize(stacks) : undefined;
}
// Save/Reload
if(tokens.length===1 && tokens[0] === "Save"){
@ -65,6 +61,121 @@ export const parseCommand = (cmdString: string): Command | undefined => {
return new CommandBreakSlots(slots);
}
}
// add material
if (tokens.length === 3 && isAddVerb(tokens[0])){
const count = parseInt(tokens[1]);
const item = tokens[2];
if(Number.isInteger(count) && item in Item){
return new CommandAdd(tokens[0], count, Item[item as keyof typeof Item]);
}
return undefined;
}
if (tokens.length === 2 && isAddVerb(tokens[0])){
const item = tokens[1];
if(item in Item){
return new CommandAddWithoutCount(tokens[0], Item[item as keyof typeof Item]);
}
return undefined;
}
if(tokens.length>2 && isAddVerb(tokens[0])){
const stacks = parseItemStacks(tokens, 1);
return stacks ? new CommandAddMultiple(tokens[0], stacks) : undefined;
}
// remove X item From Slot Y
if (tokens.length === 6 && isRemoveVerb(tokens[0]) && tokens[3] === "From" && tokens[4] ==="Slot" ){
const count = parseInt(tokens[1]);
const item = tokens[2];
const slot = parseInt(tokens[5]);
if(Number.isInteger(count) && Number.isInteger(slot) && item in Item){
return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], slot-1, false);
}
return undefined;
}
// remove X item
if (tokens.length === 3 && isRemoveVerb(tokens[0]) ){
const count = parseInt(tokens[1]);
const item = tokens[2];
if(Number.isInteger(count) && item in Item){
return new CommandRemove(tokens[0], count, Item[item as keyof typeof Item], 0, true);
}
return undefined;
}
// remove item From Slot Y
if (tokens.length === 5 && isRemoveVerb(tokens[0]) && tokens[2] === "From" && tokens[3] ==="Slot" ){
const item = tokens[1];
const slot = parseInt(tokens[4]);
if(Number.isInteger(slot) && item in Item){
return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], slot-1, false);
}
return undefined;
}
// remove item
if (tokens.length === 2 && isRemoveVerb(tokens[0]) ){
const item = tokens[1];
if(item in Item){
return new CommandRemoveWithoutCount(tokens[0], Item[item as keyof typeof Item], 0, true);
}
return undefined;
}
// remove multiple
if(tokens.length>2 && isRemoveVerb(tokens[0])){
const stacks = parseItemStacks(tokens, 1);
return stacks ? new CommandRemoveMultiple(tokens[0], stacks) : undefined;
}
//Shortcut for drop and pick up
if (tokens.length === 3 && tokens[0] === "D&P" ){
const count = parseInt(tokens[1]);
const item = tokens[2];
if(Number.isInteger(count) && item in Item){
return new CommandDaP(count, Item[item as keyof typeof Item]);
}
return undefined;
}
// Equip item In Slot X
if (tokens.length === 5 && tokens[0] === "Equip" && tokens[2] === "In" && tokens[3] ==="Slot" ){
const item = tokens[1];
const slot = parseInt(tokens[4]);
if( Number.isInteger(slot) && item in Item){
return new CommandEquip(Item[item as keyof typeof Item], slot-1, false);
}
return undefined;
}
// Equip item
if (tokens.length === 2 && tokens[0] === "Equip"){
const item = tokens[1];
if( item in Item){
return new CommandEquip(Item[item as keyof typeof Item], 0, true);
}
return undefined;
}
// Unequip item in slot X
if (tokens.length === 5 && tokens[0] === "Unequip" && tokens[2] === "In" && tokens[3] ==="Slot" ){
const item = tokens[1];
const slot = parseInt(tokens[4]);
if( Number.isInteger(slot) && item in Item){
return new CommandUnequip(Item[item as keyof typeof Item], slot-1, false);
}
return undefined;
}
// Unequip item
if (tokens.length === 2 && tokens[0] === "Unequip"){
const item = tokens[1];
if( item in Item){
return new CommandUnequip(Item[item as keyof typeof Item], -1, true);
}
return undefined;
}
// Shoot X Arrow
if (tokens.length === 3 && tokens[0] === "Shoot" && tokens[2] === "Arrow"){
const count = parseInt(tokens[1]);
if( Number.isInteger(count) ){
return new CommandShootArrow(count);
}
return undefined;
}
// if(tokens.length===2 && tokens[0] === "Sort" && tokens[1] === "Key"){
// return new CommandSortKey();
// }
@ -78,80 +189,10 @@ export const parseCommand = (cmdString: string): Command | undefined => {
// return undefined;
// }
// // remove material
// if (tokens.length === 6 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Drop"|| tokens[0] === "Eat") && tokens[3] === "From" && tokens[4] ==="Slot" ){
// const count = parseInt(tokens[1]);
// const item = tokens[2];
// const slot = parseInt(tokens[5]);
// if(Number.isInteger(count) && Number.isInteger(slot) && item in Item){
// return new CommandRemoveMaterial(tokens[0], count, Item[item as keyof typeof Item], slot-1, false);
// }
// return undefined;
// }
// if (tokens.length === 3 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Drop"|| tokens[0] === "Eat")){
// const count = parseInt(tokens[1]);
// const item = tokens[2];
// if(Number.isInteger(count) && item in Item){
// return new CommandRemoveMaterial(tokens[0], count, Item[item as keyof typeof Item], 0, true);
// }
// return undefined;
// }
// // remove 1 material
// if (tokens.length === 5 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Eat") && tokens[2] === "From" && tokens[3] ==="Slot" ){
// const item = tokens[1];
// const slot = parseInt(tokens[4]);
// if(Number.isInteger(slot) && item in Item){
// return new CommandRemoveUnstackableMaterial(tokens[0], Item[item as keyof typeof Item], slot-1, false);
// }
// return undefined;
// }
// if (tokens.length === 2 && (tokens[0] === "Remove" || tokens[0] === "Sell" || tokens[0] === "Eat")){
// const item = tokens[1];
// if(item in Item){
// return new CommandRemoveUnstackableMaterial(tokens[0], Item[item as keyof typeof Item], 0, true);
// }
// return undefined;
// }
// // add material
// if (tokens.length === 3 && (tokens[0] === "Get" || tokens[0] === "Cook" || tokens[0] === "Add" || tokens[0] === "Pickup")){
// const count = parseInt(tokens[1]);
// const item = tokens[2];
// if(Number.isInteger(count) && item in Item){
// return new CommandAddMaterial(tokens[0], count, Item[item as keyof typeof Item]);
// }
// return undefined;
// }
// // Equip Equipment
// if (tokens.length === 5 && tokens[0] === "Equip" && tokens[2] === "In" && tokens[3] ==="Slot" ){
// const item = tokens[1];
// const slot = parseInt(tokens[4]);
// if( Number.isInteger(slot) && item in Item){
// return new CommandEquip(Item[item as keyof typeof Item], slot-1, false);
// }
// return undefined;
// }
// if (tokens.length === 2 && tokens[0] === "Equip"){
// const item = tokens[1];
// if( item in Item){
// return new CommandEquip(Item[item as keyof typeof Item], 0, true);
// }
// return undefined;
// }
// // Unequip Equipment
// if (tokens.length === 5 && tokens[0] === "Unequip" && tokens[2] === "In" && tokens[3] ==="Slot" ){
// const item = tokens[1];
// const slot = parseInt(tokens[4]);
// if( Number.isInteger(slot) && item in Item){
// return new CommandUnequip(Item[item as keyof typeof Item], slot-1, false);
// }
// return undefined;
// }
// if (tokens.length === 2 && tokens[0] === "Unequip"){
// const item = tokens[1];
// if( item in Item){
// return new CommandUnequip(Item[item as keyof typeof Item], -1, true);
// }
// return undefined;
// }
// // Equip Arrow
// if (tokens.length === 6 && tokens[0] === "Equip" && tokens[2] === "Arrow" && tokens[3] === "In" && tokens[4] ==="Slot" ){
// const item = tokens[1]+"Arrow";
@ -171,3 +212,34 @@ export const parseCommand = (cmdString: string): Command | undefined => {
return undefined;
};
const isAddVerb = (token: string): boolean => {
return token === "Get" || token === "Cook" || token === "Add" || token === "Pickup"
}
const isRemoveVerb = (token: string): boolean => {
return token === "Remove" || token === "Sell" || token === "Eat" || token === "Drop"
}
const parseItemStacks = (tokens: string[], from: number): ItemStack[] | undefined => {
if((tokens.length-from)%2 !== 0){
return undefined;
}
const stacks: ItemStack[] = [];
for(let i=from;i<tokens.length;i+=2){
const count = parseInt(tokens[i]);
if(!Number.isInteger(count)){
return undefined;
}
const item = tokens[i+1];
if (item in Item){
stacks.push({
item: Item[item as keyof typeof Item], count, equipped:false
});
}else{
return undefined;
}
}
return stacks;
}

View file

@ -1,6 +1,6 @@
import { DisplayableInventory } from "./DisplayableInventory";
import { GameData } from "./GameData";
import { ItemStack } from "./Item";
import { Item, ItemStack } from "./Item";
import { Slots } from "./Slots";
import { VisibleInventory } from "./VisibleInventory";
@ -21,6 +21,7 @@ export class SimulationState {
private namedSaves: {[name: string]: GameData} = {};
private pouch: VisibleInventory;
private nextReloadName?: string;
private isOnEventide: boolean = false;
constructor(gameData: GameData, manualSave: GameData | null, namedSaves: {[name: string]: GameData}, pouch: VisibleInventory){
this.gameData = gameData;
@ -34,12 +35,16 @@ export class SimulationState {
for(const name in this.namedSaves){
copyNamedSaves[name] = this.namedSaves[name].deepClone();
}
return new SimulationState(
const newState = new SimulationState(
this.gameData.deepClone(),
this.manualSave ? this.manualSave.deepClone() : null,
copyNamedSaves,
this.pouch.deepClone()
);
newState.nextReloadName = this.nextReloadName;
newState.isOnEventide = this.isOnEventide;
return newState;
}
public initialize(stacks: ItemStack[]) {
@ -79,6 +84,7 @@ export class SimulationState {
this.gameData = data.deepClone();
this.pouch.clearForReload();
this.gameData.addAllToPouchOnReload(this.pouch);
this.pouch.updateEquipmentDurability(this.gameData);
}
public useSaveForNextReload(name: string){
@ -89,6 +95,37 @@ export class SimulationState {
this.pouch.modifyCount(-n);
}
public obtain(item: Item, count: number) {
this.pouch.addInGame(item, count);
this.syncGameDataWithPouch();
}
public remove(item: Item, count: number, slot: number) {
this.pouch.remove(item, count, slot);
this.syncGameDataWithPouch();
}
public equip(item: Item, slot: number) {
this.pouch.equip(item, slot);
this.syncGameDataWithPouch();
}
public unequip(item: Item, slot: number){
this.pouch.unequip(item, slot);
this.syncGameDataWithPouch();
}
public shootArrow(count: number){
this.pouch.shootArrow(count, this.gameData);
// does not sync
}
public syncGameDataWithPouch() {
if(!this.isOnEventide){
this.gameData.syncWith(this.pouch);
}
}
public get displayableGameData(): DisplayableInventory {
return this.gameData;
}
@ -116,21 +153,13 @@ export class SimulationState {
}
// Save - save to hard save slot
// Save As <name> - save to a auto save slot
// Reload - reload hard save
// Reload <name> - reload a named auto save
// Use <name> - no effect, but next Reload reloads the named auto save
// Break X Slots
// Sort Key (In Tab X)
// Sort Material (In Tab X)
// Get/Add/Cook/Pickup X <item>, X can be omitted and default to 1
// Get/Add/Cook/Pickup X <item> Y <item2> ...
// Remove/Drop/Sell/Eat X <item> From Slot Y, X can be omitted and default to 1
// Remove/Drop/Sell/Eat X <item1> Y <item2> ...
// D&P X <item>, drop and pick up (to sort)
// Equip <item> (In Slot X)
// Unequip <item> (In Slot X), without slot, it unequipps the first equipped
// Shoot X Arrow, x can be ommited and default to 1
// Close Game
// Close Inventory, same as Resync GameData
// 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 Material (In Tab X) - need more research on which tab is sorted

View file

@ -61,7 +61,7 @@ export class Slots {
public addStackDirectly(stack: ItemStack): number {
const data = itemToItemData(stack.item);
if(data.stackable){
this.internalSlots.push(stack);
this.internalSlots.push({...stack});
return 1;
}
for(let i=0;i<stack.count;i++){
@ -70,7 +70,7 @@ export class Slots {
return stack.count;
}
public addSlot(stack: ItemStack, mCount: number | null) {
this.internalSlots.push(stack);
this.internalSlots.push({...stack});
this.sortItemType(mCount);
}
// public addStackCopy(stack: ItemStack) {
@ -85,27 +85,33 @@ export class Slots {
// const end = this.internalSlots.splice(-count, count);
// return new Slots(end);
// }
// public remove(item: Item, count: number, slot: number) {
// let s = 0;
// for(let i = 0; i<this.internalSlots.length && count > 0;i++){
// if(this.internalSlots[i].item === item){
// if(s<slot){
// s++;
// }else{
// if(this.internalSlots[i].count<count){
// count-=this.internalSlots[i].count;
// this.internalSlots[i].count=0;
// remove item(s) start from slot
// return number of slots removed
public remove(item: Item, count: number, slot: number): number {
const oldLength = this.internalSlots.length;
let s = 0;
for(let i = 0; i<this.internalSlots.length && count > 0;i++){
if(this.internalSlots[i].item === item){
if(s<slot){
s++;
}else{
if(this.internalSlots[i].count<count){
count-=this.internalSlots[i].count;
this.internalSlots[i].count=0;
// }else{
// this.internalSlots[i].count-=count;
// break;
// }
}else{
this.internalSlots[i].count-=count;
break;
}
// }
// }
// }
// this.internalSlots = this.internalSlots.filter(({count})=>count>0);
// }
}
}
}
this.internalSlots = this.internalSlots.filter(({count})=>count>0);
return oldLength-this.internalSlots.length;
}
// Add something to inventory in game
// returns number of slots added
@ -153,140 +159,140 @@ export class Slots {
// Checks finish, do add new slot
if(data.stackable){
if(data.type===ItemType.Arrow){
// if currently equipped arrow == 0. new arrows are equiped
// TODO: botw needs more testing on how arrows are handled in various cases
const shouldEquipNew = this.internalSlots.filter(s=>{
const sData = itemToItemData(s.item);
return sData.type === data.type && s.equipped && s.count > 0;
}).length === 0;
this.addSlot({item,count,equipped:shouldEquipNew}, mCount+1);
if(reloading){
this.addSlot({item,count,equipped:equippedDuringReload}, mCount+1);
}else{
this.addSlot({item,count,equipped:false}, mCount+1);
if(data.type===ItemType.Arrow){
// if currently equipped arrow == 0. new arrows are equiped
// TODO: botw needs more testing on how arrows are handled in various cases
const shouldEquipNew = this.internalSlots.filter(s=>{
const sData = itemToItemData(s.item);
return sData.type === data.type && s.equipped && s.count > 0;
}).length === 0;
this.addSlot({item,count,equipped:shouldEquipNew}, mCount+1);
}else{
this.addSlot({item,count,equipped:false}, mCount+1);
}
}
return 1;
}
if(data.type===ItemType.Weapon || data.type===ItemType.Bow || data.type===ItemType.Shield){
//Check equip
const shouldEquipNew = !reloading && 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);
if(reloading){
for(let i=0;i<count;i++){
this.addSlot({item,count:1,equipped: equippedDuringReload}, mCount+i+1);
}
}else{
for(let i=0;i<count;i++){
this.addSlot({item,count:1,equipped: false}, mCount+i+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{
for(let i=0;i<count;i++){
this.addSlot({item,count:1,equipped: false}, mCount+i+1);
}
}
}
return count;
}
// return how many slots are added
// public add(item: Item, count: number, equipped: boolean, isReloading: boolean, mCount: number): number {
// let added = false;
// const data = itemToItemData(item);
// if(data.stackable){
// for(let i = 0; i<this.internalSlots.length;i++){
// if(this.internalSlots[i].item === item){
// if(isReloading){
// if(mCount > 0 && this.internalSlots[i].count + count > 999){
// return 0; // Skip, do not add new stack at all
// }
// // Otherwise push the entire new stack
// this.internalSlots.push({item, count, equipped});
// }else{
// this.internalSlots[i].count = Math.min(999, this.internalSlots[i].count+count);
// added = true;
// }
// break;
// }
// }
// }
// if(!added){
// const after = this.removeFromEnd(this.getAfterType(data.type).length);
// if(data.stackable){
// if(data.type===ItemType.Arrow){
// // if currently equipped arrow == 0. new arrows are equiped
// const shouldEquipNew = this.internalSlots.filter(s=>{
// const sData = itemToItemData(s.item);
// return sData.type === data.type && s.equipped && s.count > 0;
// }).length === 0;
// this.addStack({item,count,equipped:shouldEquipNew});
// }else{
// this.addStack({item,count,equipped:false});
// }
// }else{
// 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.addStack({item,count:1,equipped: shouldEquipNew});
// for(let i=1;i<count;i++){
// this.addStack({item,count:1,equipped: false});
// }
// }else{
// for(let i=0;i<count;i++){
// this.addStack({item,count:1,equipped: false});
// }
// }
// }
// this is for both equipments and arrows
public equip(item: Item, slot: number) {
let s = 0;
// unequip same type in first tab
const type = itemToItemData(item).type;
let i=0;
while(i<this.internalSlots.length && itemToItemData(this.internalSlots[i].item).type < type){
i++;
}
for(;i<this.internalSlots.length && itemToItemData(this.internalSlots[i].item).type === type;i++){
this.internalSlots[i].equipped = false;
}
// now search for the one the player selects and equip it
for(let i = 0; i<this.internalSlots.length;i++){
if(this.internalSlots[i].item === item){
if (s===slot){
this.internalSlots[i].equipped=true;
break;
}
s++;
}
}
}
public unequip(item:Item, slot: number) {
let s = 0;
const type = itemToItemData(item).type;
if (type===ItemType.Arrow){
return; // cannot unequip arrow
}
for(let i = 0; i<this.internalSlots.length;i++){
if(this.internalSlots[i].item === item){
if(slot < 0){
if(this.internalSlots[i].equipped){
this.internalSlots[i].equipped=false;
break;
}
}else{
if(s<slot){
s++;
}else{
this.internalSlots[i].equipped=false;
break;
}
}
}
}
}
// this.addSlotsToEnd(after);
// }
// }
public corrupt(durability: number, slot: number) {
if(slot < 0 || slot >= this.internalSlots.length){
return;
}
const thisData = itemToItemData(this.internalSlots[slot].item);
if(thisData.stackable){
this.internalSlots[slot].count = durability;
}
}
// // this is for both equipments and arrows
// public equip(item: Item, slot: number) {
// let s = 0;
// const type = itemToItemData(item).type;
// const filtered = this.internalSlots.filter(s=>itemToItemData(s.item).type === type);
// for(let i = 0; i<filtered.length;i++){
// filtered[i].equipped=false;
// if(filtered[i].item === item){
// if (s===slot){
// filtered[i].equipped=true;
// }
// s++;
// }
// }
// }
// public unequip(item:Item, slot: number) {
// let s = 0;
// const type = itemToItemData(item).type;
// if (type===ItemType.Arrow){
// return; // cannot unequip arrow
// }
// for(let i = 0; i<this.internalSlots.length;i++){
// if(this.internalSlots[i].item === item){
// if(slot < 0){
// if(this.internalSlots[i].equipped){
// this.internalSlots[i].equipped=false;
// break;
// }
// }else{
// if(s<slot){
// s++;
// }else{
// this.internalSlots[i].equipped=false;
// break;
// }
// }
// }
// }
// }
// shoot count arrows. return the slot that was updated, or -1
public shootArrow(count: number): number {
// first find equipped arrow, search entire inventory
let i=0;
for(;i<this.internalSlots.length;i++){
if(this.internalSlots[i].equipped){
const data = itemToItemData(this.internalSlots[i].item);
if(data.type === ItemType.Arrow){
break;
}
}
}
if(i>=this.internalSlots.length){
//can't find equipped arrow
return -1;
}
const equippedArrow = this.internalSlots[i].item;
// now find the first slot of that arrow and update
for(let j=0;j<this.internalSlots.length;j++){
if(this.internalSlots[j].item === equippedArrow){
this.internalSlots[j].count = Math.max(0, this.internalSlots[j].count-count);
return j;
}
}
//for some reason cannot find that arrow now?
return -1;
}
// // Difference between shoot and remove:
// // 1. can only be from first (leftmost) slot
// // 2. empty slots not removed

View file

@ -1,5 +1,6 @@
import { DisplayableInventory, DisplayableSlot, itemStackToDisplayableSlot } from "./DisplayableInventory";
import { Item, ItemStack } from "./Item";
import { GameData } from "./GameData";
import { Item, ItemStack, itemToItemData, ItemType } from "./Item";
import { Slots } from "./Slots";
/*
@ -35,7 +36,23 @@ export class VisibleInventory implements DisplayableInventory{
this.count+=slotsAdded;
}
//public addInGame
public addInGame(item: Item, count: number) {
const slotsAdded = this.slots.add(item, count, false, false, this.count);
this.count+=slotsAdded;
}
public remove(item: Item, count: number, slot: number) {
const slotsRemoved = this.slots.remove(item, count, slot);
this.count-=slotsRemoved;
}
public equip(item: Item, slot: number) {
this.slots.equip(item, slot);
}
public unequip(item: Item, slot: number) {
this.slots.unequip(item, slot);
}
// Only clears first this.count
public clearForReload() {
@ -45,6 +62,38 @@ export class VisibleInventory implements DisplayableInventory{
}
}
public updateEquipmentDurability(gameData: GameData) {
// find first weapon/bow/shield. this one searches entire inventory
let foundWeapon = false;
let foundBow = false;
let foundShield = false;
this.slots.getSlotsRef().forEach(({item, equipped}, i)=>{
if(equipped){
const type = itemToItemData(item).type;
if(type === ItemType.Weapon && !foundWeapon){
gameData.updateDurability(999, i);
foundWeapon = true;
}
if(type === ItemType.Bow && !foundBow){
gameData.updateDurability(999, i);
foundBow = true;
}
if(type === ItemType.Shield && !foundShield){
gameData.updateDurability(999, i);
foundShield = true;
}
}
})
}
public shootArrow(count: number, gameData: GameData) {
const updatedSlot = this.slots.shootArrow(count);
if(updatedSlot>=0){
const durability = this.slots.getSlotsRef()[updatedSlot].count;
gameData.updateDurability(durability, updatedSlot);
}
}
public getCount(): number {
return this.count;
}

View file

@ -1,66 +0,0 @@
export {};
// import { Command, CommandAddMaterial, CommandBreakSlots, CommandInitialize, CommandNothing, CommandReload, CommandRemoveMaterial, CommandRemoveUnstackableMaterial, CommandSave, CommandSortKey, CommandSortMaterial } from "./Command";
// import { Item } from "./Item";
// const Buffer = require("buffer/").Buffer; /* eslint-disable-line @typescript-eslint/no-var-requires*/
// export const serializeCommands = (commands: Command[]): string => {
// const sizeBuf: Buffer = Buffer.alloc(4);
// sizeBuf.writeInt32LE(commands.length);
// const commandBuffers = commands.map(c=>c.toBuffer());
// const allBufs = Buffer.concat([sizeBuf, ...commandBuffers]);
// return allBufs.toString("base64");
// };
// export const deserialzeCommands = (base64str: string): Command[] => {
// const buf: Buffer = Buffer.from(base64str, "base64");
// const size = buf.readInt32LE();
// let off = 4;
// const commands: Command[] = [];
// for(let i=0;i<size;i++){
// const op = buf.readUInt8(off);
// off++;
// let command: Command | undefined = undefined;
// switch(op){
// case CommandNothing.Op:
// command = new CommandNothing();
// break;
// case CommandInitialize.Op:
// command = new CommandInitialize([]);
// break;
// case CommandBreakSlots.Op:
// command = new CommandBreakSlots(0);
// break;
// case CommandSave.Op:
// command = new CommandSave();
// break;
// case CommandReload.Op:
// command = new CommandReload();
// break;
// case CommandSortKey.Op:
// command = new CommandSortKey();
// break;
// case CommandSortMaterial.Op:
// command = new CommandSortMaterial();
// break;
// case CommandRemoveMaterial.Op:
// command = new CommandRemoveMaterial("",0,Item.Slate,0);
// break;
// case CommandRemoveUnstackableMaterial.Op:
// command = new CommandRemoveUnstackableMaterial("", Item.Slate, 0);
// break;
// case CommandAddMaterial.Op:
// command = new CommandAddMaterial("",0,Item.Slate);
// break;
// }
// if(command){
// off += command.fromBuffer(buf.slice(off));
// commands.push(command);
// }else{
// console.error("invalid opcode: "+op);
// }
// }
// return commands;
// };

View file

@ -78,8 +78,91 @@ export const ReferencePage: React.FC = React.memo(()=>{
</p>
<p className="Reference Example">Example: Break 4 Slots</p>
<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 item1 Y item2 Z item3 ...</h3>
<h4 className="Reference">Simulate obtaining items in game</h4>
<p className="Reference">
Add the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS
</p>
<p className="Reference">
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).
</p>
<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.
</p>
<p className="Reference">
Note that you must not enter plural forms for the item name.
</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 3: Pickup 10 Apple 5 Diamond 1 Slate 5 MasterSword</p>
<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 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>
<h4 className="Reference">Simulate removing items in game</h4>
<p className="Reference">
Remove the item(s) to visible inventory. Sync with Game Data unless you are on Eventide or inside TOTS
</p>
<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.
If X &gt; total number of items in inventory, all of them will be removed.
</p>
<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).
</p>
<p className="Reference">
Note that you must not enter plural forms for the item name.
</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 3: Sell 10 Apple 5 Diamond</p>
<p className="Reference Example">Example 4: Sell 5 Apple From Slot 3</p>
<h3 className="Reference">D&amp;P X item</h3>
<h4 className="Reference">Shortcut for drop and pick up, for sorting inventory</h4>
<p className="Reference">
This command drops X item from the first slot, then pick them up
</p>
<p className="Reference Example">Example: D&amp;P 5 Diamond</p>
<h3 className="Reference">Equip item</h3>
<h3 className="Reference2">Equip item In Slot X</h3>
<h4 className="Reference">Simulates equipping something</h4>
<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.
</p>
<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.
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
</p>
<p className="Reference Example">Example 1: Equip Weapon</p>
<p className="Reference Example">Example 2: Equip Weapon In Slot 3</p>
<h3 className="Reference">Unequip item</h3>
<h3 className="Reference2">Unequip item In Slot X</h3>
<h4 className="Reference">Simulates unequipping something</h4>
<p className="Reference">
When unequipping an item, only the selected item is unequipped.
</p>
<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.
Note that you can use this command to unequip something that is already unequipped, which is useless.
You cannot unequip arrows.
</p>
<p className="Reference Example">Example 1: Unequip Shield</p>
<p className="Reference Example">Example 2: Unequip Shield In Slot 5</p>
</div>
</TitledList>
</div>
)