299 lines
8.2 KiB
JavaScript
299 lines
8.2 KiB
JavaScript
|
|
import { expect } from "@esm-bundle/chai";
|
||
|
|
import { InventoryManager } from "../../src/managers/InventoryManager.js";
|
||
|
|
import { InventoryContainer } from "../../src/models/InventoryContainer.js";
|
||
|
|
import { Item } from "../../src/items/Item.js";
|
||
|
|
|
||
|
|
describe("Manager: InventoryManager", () => {
|
||
|
|
let manager;
|
||
|
|
let mockItemRegistry;
|
||
|
|
let mockUnit;
|
||
|
|
let runStash;
|
||
|
|
let hubStash;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
// Mock Item Registry
|
||
|
|
mockItemRegistry = {
|
||
|
|
get: (defId) => {
|
||
|
|
const items = {
|
||
|
|
"ITEM_RUSTY_BLADE": new Item({
|
||
|
|
id: "ITEM_RUSTY_BLADE",
|
||
|
|
name: "Rusty Blade",
|
||
|
|
type: "WEAPON",
|
||
|
|
stats: { attack: 3 },
|
||
|
|
requirements: {},
|
||
|
|
}),
|
||
|
|
"ITEM_SCRAP_PLATE": new Item({
|
||
|
|
id: "ITEM_SCRAP_PLATE",
|
||
|
|
name: "Scrap Plate",
|
||
|
|
type: "ARMOR",
|
||
|
|
stats: { defense: 3 },
|
||
|
|
requirements: {},
|
||
|
|
}),
|
||
|
|
"ITEM_TINKER_GUN": new Item({
|
||
|
|
id: "ITEM_TINKER_GUN",
|
||
|
|
name: "Tinker Gun",
|
||
|
|
type: "WEAPON",
|
||
|
|
stats: { attack: 5 },
|
||
|
|
requirements: { class_lock: ["CLASS_TINKER"] },
|
||
|
|
}),
|
||
|
|
"ITEM_TWO_HANDED_SWORD": new Item({
|
||
|
|
id: "ITEM_TWO_HANDED_SWORD",
|
||
|
|
name: "Greatsword",
|
||
|
|
type: "WEAPON",
|
||
|
|
stats: { attack: 10 },
|
||
|
|
requirements: {},
|
||
|
|
tags: ["TWO_HANDED"],
|
||
|
|
}),
|
||
|
|
"ITEM_SHIELD": new Item({
|
||
|
|
id: "ITEM_SHIELD",
|
||
|
|
name: "Shield",
|
||
|
|
type: "UTILITY",
|
||
|
|
stats: { defense: 2 },
|
||
|
|
requirements: {},
|
||
|
|
}),
|
||
|
|
"ITEM_HEALTH_POTION": new Item({
|
||
|
|
id: "ITEM_HEALTH_POTION",
|
||
|
|
name: "Health Potion",
|
||
|
|
type: "CONSUMABLE",
|
||
|
|
stats: {},
|
||
|
|
requirements: {},
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
return items[defId] || null;
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
// Mock Unit (Explorer)
|
||
|
|
mockUnit = {
|
||
|
|
id: "UNIT_001",
|
||
|
|
activeClassId: "CLASS_VANGUARD",
|
||
|
|
baseStats: {
|
||
|
|
health: 100,
|
||
|
|
attack: 10,
|
||
|
|
defense: 5,
|
||
|
|
magic: 0,
|
||
|
|
speed: 10,
|
||
|
|
willpower: 5,
|
||
|
|
movement: 4,
|
||
|
|
tech: 0,
|
||
|
|
},
|
||
|
|
loadout: {
|
||
|
|
mainHand: null,
|
||
|
|
offHand: null,
|
||
|
|
body: null,
|
||
|
|
accessory: null,
|
||
|
|
belt: [null, null],
|
||
|
|
},
|
||
|
|
recalculateStats: () => {
|
||
|
|
// Mock stat recalculation
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
runStash = new InventoryContainer("RUN_LOOT");
|
||
|
|
hubStash = new InventoryContainer("HUB_VAULT");
|
||
|
|
|
||
|
|
manager = new InventoryManager(mockItemRegistry, runStash, hubStash);
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("canEquip", () => {
|
||
|
|
it("should return true if unit meets requirements", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_001",
|
||
|
|
defId: "ITEM_RUSTY_BLADE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
const canEquip = manager.canEquip(mockUnit, itemInstance);
|
||
|
|
expect(canEquip).to.be.true;
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should return false if unit does not meet class requirements", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_002",
|
||
|
|
defId: "ITEM_TINKER_GUN",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
const canEquip = manager.canEquip(mockUnit, itemInstance);
|
||
|
|
expect(canEquip).to.be.false;
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should return false if item definition not found", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_003",
|
||
|
|
defId: "ITEM_NONEXISTENT",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
const canEquip = manager.canEquip(mockUnit, itemInstance);
|
||
|
|
expect(canEquip).to.be.false;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("equipItem", () => {
|
||
|
|
it("should equip item to mainHand slot", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_001",
|
||
|
|
defId: "ITEM_RUSTY_BLADE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
hubStash.addItem(itemInstance);
|
||
|
|
const result = manager.equipItem(mockUnit, itemInstance, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.deep.equal(itemInstance);
|
||
|
|
expect(hubStash.findItem("ITEM_001")).to.be.null; // Removed from stash
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should swap item if slot is occupied", () => {
|
||
|
|
const existingItem = {
|
||
|
|
uid: "ITEM_002",
|
||
|
|
defId: "ITEM_SCRAP_PLATE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
const newItem = {
|
||
|
|
uid: "ITEM_001",
|
||
|
|
defId: "ITEM_RUSTY_BLADE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
mockUnit.loadout.mainHand = existingItem;
|
||
|
|
hubStash.addItem(newItem);
|
||
|
|
|
||
|
|
const result = manager.equipItem(mockUnit, newItem, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.deep.equal(newItem);
|
||
|
|
expect(hubStash.findItem("ITEM_002")).to.deep.equal(existingItem); // Old item in stash
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should automatically unequip offHand when equipping two-handed weapon", () => {
|
||
|
|
const twoHandedItem = {
|
||
|
|
uid: "ITEM_003",
|
||
|
|
defId: "ITEM_TWO_HANDED_SWORD",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
const shieldItem = {
|
||
|
|
uid: "ITEM_004",
|
||
|
|
defId: "ITEM_SHIELD",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
mockUnit.loadout.offHand = shieldItem;
|
||
|
|
hubStash.addItem(twoHandedItem);
|
||
|
|
|
||
|
|
const result = manager.equipItem(mockUnit, twoHandedItem, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.deep.equal(twoHandedItem);
|
||
|
|
expect(mockUnit.loadout.offHand).to.be.null; // Off-hand unequipped
|
||
|
|
expect(hubStash.findItem("ITEM_004")).to.deep.equal(shieldItem); // Shield in stash
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should return false if item cannot be equipped", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_002",
|
||
|
|
defId: "ITEM_TINKER_GUN",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
hubStash.addItem(itemInstance);
|
||
|
|
const result = manager.equipItem(mockUnit, itemInstance, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.false;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.be.null;
|
||
|
|
expect(hubStash.findItem("ITEM_002")).to.exist; // Still in stash
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should equip item to belt slot", () => {
|
||
|
|
const potion = {
|
||
|
|
uid: "ITEM_005",
|
||
|
|
defId: "ITEM_HEALTH_POTION",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
hubStash.addItem(potion);
|
||
|
|
const result = manager.equipItem(mockUnit, potion, "BELT", 0);
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.belt[0]).to.deep.equal(potion);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("unequipItem", () => {
|
||
|
|
it("should unequip item from slot and move to stash", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_001",
|
||
|
|
defId: "ITEM_RUSTY_BLADE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
mockUnit.loadout.mainHand = itemInstance;
|
||
|
|
const result = manager.unequipItem(mockUnit, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.be.null;
|
||
|
|
expect(hubStash.findItem("ITEM_001")).to.deep.equal(itemInstance);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should return false if slot is empty", () => {
|
||
|
|
const result = manager.unequipItem(mockUnit, "MAIN_HAND");
|
||
|
|
expect(result).to.be.false;
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should unequip from belt slot", () => {
|
||
|
|
const potion = {
|
||
|
|
uid: "ITEM_005",
|
||
|
|
defId: "ITEM_HEALTH_POTION",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
mockUnit.loadout.belt[0] = potion;
|
||
|
|
const result = manager.unequipItem(mockUnit, "BELT", 0);
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.belt[0]).to.be.null;
|
||
|
|
expect(hubStash.findItem("ITEM_005")).to.deep.equal(potion);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("transferToStash", () => {
|
||
|
|
it("should move item from unit loadout to stash", () => {
|
||
|
|
const itemInstance = {
|
||
|
|
uid: "ITEM_001",
|
||
|
|
defId: "ITEM_RUSTY_BLADE",
|
||
|
|
isNew: false,
|
||
|
|
quantity: 1,
|
||
|
|
};
|
||
|
|
|
||
|
|
mockUnit.loadout.mainHand = itemInstance;
|
||
|
|
const result = manager.transferToStash(mockUnit, "MAIN_HAND");
|
||
|
|
|
||
|
|
expect(result).to.be.true;
|
||
|
|
expect(mockUnit.loadout.mainHand).to.be.null;
|
||
|
|
expect(hubStash.findItem("ITEM_001")).to.deep.equal(itemInstance);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should return false if slot is empty", () => {
|
||
|
|
const result = manager.transferToStash(mockUnit, "MAIN_HAND");
|
||
|
|
expect(result).to.be.false;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|