inventory #14

Merged
erns6604 merged 11 commits from inventory into main 2025-10-29 14:21:29 +01:00
13 changed files with 185 additions and 36 deletions

View File

@ -1,27 +1,74 @@
package Inventory; package Inventory;
import Item.Item; import Item.Item;
import Item.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class Inventory { public class Inventory {
List<Item> items; private final List<ItemStack> items;
private final int maxWeight;
public Inventory() { public Inventory() {
items = new ArrayList<>(); items = new ArrayList<>();
maxWeight = 100;
} }
public List<Item> getItems() { public Inventory(int weightLimit) {
items = new ArrayList<>();
this.maxWeight = weightLimit;
}
public List<ItemStack> getItems() {
return Collections.unmodifiableList(items); return Collections.unmodifiableList(items);
} }
public void addItem(Item item) { public void addItem(ItemStack stack) {
items.add(item); if (stack.getWeight() + getCurrentWeight() > maxWeight) {
if(stack.isSingleItem()) return;
trySubstack(stack);
return;
}
items.add(stack);
} }
public boolean containsItem(String item) { private void trySubstack(ItemStack stack) {
return items.contains(item); int stackSize = getMaxStackSize(stack);
if (stackSize == 0) return;
items.add(new ItemStack(stack.getItem(), stackSize));
}
private int getMaxStackSize(ItemStack stack) {
int weight = stack.getItem().getWeight();
int maxSize = (maxWeight - getCurrentWeight()) / weight;
return Math.min(maxSize, stack.getQuantity());
}
public int getCurrentWeight() {
int currentWeight = 0;
for (ItemStack item : items) {
currentWeight += item.getItem().getWeight();
}
return currentWeight;
}
private int calculateStackWeight(ItemStack stack) {
return stack.getItem().getWeight() * stack.getQuantity();
}
public boolean containsItem(Item item) {
for (ItemStack stack : items) {
if (stack.item().equals(item)) {
return true;
}
}
return false;
}
public int getMaxWeight() {
return maxWeight;
} }
} }

View File

@ -1,6 +1,6 @@
package Item; package Item;
public record BasicItem(String id, String name) implements Item { public record BasicItem(String id, String name, int weight) implements Item {
@Override @Override
public String getId() { public String getId() {
return id; return id;
@ -10,4 +10,8 @@ public record BasicItem(String id, String name) implements Item {
public String getName() { public String getName() {
return name; return name;
} }
@Override
public int getWeight() {
return weight;
}
} }

View File

@ -24,6 +24,11 @@ public class Equipment implements Item {
return name; return name;
} }
@Override
public int getWeight() {
return 0;
}
public EquipmentType getEquipmentType() { public EquipmentType getEquipmentType() {
return equipmentType; return equipmentType;
} }

View File

@ -3,4 +3,5 @@ package Item;
public interface Item { public interface Item {
String getId(); String getId();
String getName(); String getName();
int getWeight();
} }

View File

@ -0,0 +1,26 @@
package Item;
import Inventory.Inventory;
public record ItemStack(Item item, int quantity) {
public ItemStack {
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity must be greater than zero.");
}
}
public Item getItem() {
return item;
}
public int getQuantity() {
return quantity;
}
public boolean isSingleItem() {
return quantity == 1;
}
public int getWeight() {
return item.getWeight() * quantity;
}
}

View File

@ -1,6 +1,7 @@
package Job; package Job;
import Inventory.HasInventory; import Inventory.HasInventory;
import Item.ItemStack;
import Terrain.Biome; import Terrain.Biome;
@ -18,6 +19,6 @@ public class Miner extends Job {
public void dig(Biome biome) { public void dig(Biome biome) {
var item = biome.getLootTable().roll(); var item = biome.getLootTable().roll();
actor.getInventory().addItem(item); actor.getInventory().addItem(new ItemStack(item, 1));
} }
} }

View File

@ -2,7 +2,6 @@ package Shared;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
public class LootTable<T> { public class LootTable<T> {
private RandomProvider random; private RandomProvider random;
@ -18,6 +17,8 @@ public class LootTable<T> {
this.entries.addAll(entries); this.entries.addAll(entries);
} }
public void setRandomProvider(RandomProvider random) { public void setRandomProvider(RandomProvider random) {
this.random = random; this.random = random;
} }
@ -43,4 +44,7 @@ public class LootTable<T> {
return null; return null;
} }
public List<LootEntry<T>> getEntries() {
return entries;
}
} }

View File

@ -10,27 +10,27 @@ import java.util.List;
public enum Biome { public enum Biome {
GRASSLAND("Grassland", new LootTable<>(new ArrayList<>(List.of( GRASSLAND("Grassland", new LootTable<>(new ArrayList<>(List.of(
new LootEntry<>(new BasicItem("mud", "Mud"), 10), new LootEntry<>(new BasicItem("mud", "Mud", 10), 10),
new LootEntry<>(new BasicItem("earth_root", "Earth Root"), 50), new LootEntry<>(new BasicItem("earth_root", "Earth Root", 5), 50),
new LootEntry<>(new BasicItem("crystal_core", "Crystal core"), 180) new LootEntry<>(new BasicItem("crystal_core", "Crystal core", 20), 180)
)) { )) {
})), })),
MOUNTAIN("Mountain", new LootTable<>(new ArrayList<>(List.of( MOUNTAIN("Mountain", new LootTable<>(new ArrayList<>(List.of(
new LootEntry<>(new BasicItem("rock", "Rock"), 10), new LootEntry<>(new BasicItem("rock", "Rock", 50), 10),
new LootEntry<>(new BasicItem("iron", "Iron"), 50), new LootEntry<>(new BasicItem("iron", "Iron", 80), 50),
new LootEntry<>(new BasicItem("diamond", "Diamond"), 180) new LootEntry<>(new BasicItem("diamond", "Diamond", 8), 180)
)) { )) {
})), })),
COAST("Coast", new LootTable<>(new ArrayList<>(List.of( COAST("Coast", new LootTable<>(new ArrayList<>(List.of(
new LootEntry<>(new BasicItem("sand", "Sand"), 10), new LootEntry<>(new BasicItem("sand", "Sand", 1), 10),
new LootEntry<>(new BasicItem("shell", "Shell"), 50), new LootEntry<>(new BasicItem("shell", "Shell", 4), 50),
new LootEntry<>(new BasicItem("sandfish", "Sandfish"), 180) new LootEntry<>(new BasicItem("sandfish", "Sandfish", 11), 180)
)) { )) {
})), })),
FOREST("Forest", new LootTable<>(new ArrayList<>(List.of( FOREST("Forest", new LootTable<>(new ArrayList<>(List.of(
new LootEntry<>(new BasicItem("moss", "Moss"), 10), new LootEntry<>(new BasicItem("moss", "Moss", 7 ), 10),
new LootEntry<>(new BasicItem("fairy_rock", "Fairy rock"), 50), new LootEntry<>(new BasicItem("fairy_rock", "Fairy rock", 89), 50),
new LootEntry<>(new BasicItem("unicorn_horn", "Unicorn horn"), 230) new LootEntry<>(new BasicItem("unicorn_horn", "Unicorn horn", 18), 230)
)) { )) {
})); }));

View File

@ -29,7 +29,7 @@ public class EquipmentTest {
@Test @Test
void setTypeOnCreation() { void setTypeOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals("helmet", e.getEquipmentType().getName(), "Equipment type should have been set"); assertEquals("Body Armour", e.getEquipmentType().getName(), "Equipment type should have been set");
} }
@Test @Test
@ -41,19 +41,19 @@ public class EquipmentTest {
@Test @Test
void setMaxHpModOnCreation() { void setMaxHpModOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals(1, e.getEquipmentType().getModifiers().getMaxHpMod(), "Equipment max hp modifier should have been set"); assertEquals(4, e.getEquipmentType().getModifiers().getMaxHpMod(), "Equipment max hp modifier should have been set");
} }
@Test @Test
void setMaxMpModOnCreation() { void setMaxMpModOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals(1, e.getEquipmentType().getModifiers().getMaxMpMod(), "Equipment max mp modifier should have been set"); assertEquals(8, e.getEquipmentType().getModifiers().getMaxMpMod(), "Equipment max mp modifier should have been set");
} }
@Test @Test
void setStrModOnCreation() { void setStrModOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals(1, e.getEquipmentType().getModifiers().getStrMod(), "Equipment strength modifier should have been set"); assertEquals(7, e.getEquipmentType().getModifiers().getStrMod(), "Equipment strength modifier should have been set");
} }
@Test @Test
@ -65,12 +65,12 @@ public class EquipmentTest {
@Test @Test
void setDefModOnCreation() { void setDefModOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals(1, e.getEquipmentType().getModifiers().getDefMod(), "Equipment defence modifier should have been set"); assertEquals(4, e.getEquipmentType().getModifiers().getDefMod(), "Equipment defence modifier should have been set");
} }
@Test @Test
void setMagicDefModOnCreation() { void setMagicDefModOnCreation() {
var e = defaultBodyArmour(); var e = defaultBodyArmour();
assertEquals(1, e.getEquipmentType().getModifiers().getMagicDefMod(), "Equipment magic defence modifier should have been set"); assertEquals(16, e.getEquipmentType().getModifiers().getMagicDefMod(), "Equipment magic defence modifier should have been set");
} }
} }

View File

@ -1,5 +1,6 @@
import Inventory.Inventory; import Inventory.Inventory;
import Item.BasicItem; import Item.BasicItem;
import Item.ItemStack;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
@ -9,9 +10,54 @@ public class InventoryTest {
@Test @Test
void can_add_item_to_inventory() { void can_add_item_to_inventory() {
var inventory = new Inventory(); var inventory = new Inventory();
inventory.addItem(new BasicItem("iron_sword", "Iron Sword")); var item = new BasicItem("iron_sword", "Iron Sword", 5);
inventory.addItem(new ItemStack(item, 1));
assertThat(inventory.getItems(), hasItem( assertThat(inventory.getItems(), hasItem(
hasProperty("item",
hasProperty("id", equalTo("iron_sword")) hasProperty("id", equalTo("iron_sword"))
)
));
}
@Test
void can_add_quantity_to_inventory() {
var inventory = new Inventory();
var item = new BasicItem("iron_sword", "Iron Sword", 5);
var stack = new ItemStack(item, 5);
inventory.addItem(stack);
assertThat(inventory.getItems(), hasItem(
allOf(
hasProperty("item",
hasProperty("id", equalTo("iron_sword"))),
hasProperty("quantity", equalTo(5))
)
)); ));
} }
@Test
void item_can_not_be_added_if_above_weight_limit() {
var inventory = new Inventory(5);
var item = new BasicItem("iron_sword", "Iron Sword", 10);
var stack = new ItemStack(item, 1);
inventory.addItem(stack);
assertThat(inventory.getItems().size(), is(0));
}
@Test
void stack_can_be_added_up_to_capacity() {
var inventory = new Inventory(5);
var item = new BasicItem("sand_grain", "Sand Grain", 1);
var stack = new ItemStack(item, 8);
inventory.addItem(stack);
assertThat(inventory.getItems(), hasItem(allOf(
hasProperty("item", (
hasProperty("id", equalTo("sand_grain"))
)),
hasProperty("quantity", equalTo(5)))
));
}
} }

View File

@ -2,10 +2,8 @@ import Shared.LootTable;
import Shared.RandomProvider; import Shared.RandomProvider;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Random;
import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -19,6 +17,12 @@ public class LootTableTest {
return lootTable; return lootTable;
} }
@Test
void instantiates_as_empty() {
LootTable<String> lootTable = new LootTable<>();
assertThat(lootTable.getEntries().size(), is(0));
}
@Test @Test
void returns_an_item_was_added() { void returns_an_item_was_added() {
LootTable<String> loot = defaultLootTable(); LootTable<String> loot = defaultLootTable();
@ -33,7 +37,10 @@ public class LootTableTest {
LootTable<String> loot = new LootTable<>(mockRandomProvider); LootTable<String> loot = new LootTable<>(mockRandomProvider);
loot.addEntry("Stone", 90); loot.addEntry("Stone", 90);
loot.addEntry("Iron", 10); loot.addEntry("Iron", 10);
String result = loot.roll(); String result = loot.roll();
assertThat(result, equalTo("Iron")); assertThat(result, equalTo("Iron"));
} }
} }

View File

@ -7,7 +7,9 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MinerTest { public class MinerTest {
private Player defaultPlayer() {return new Player("John"); } private Player defaultPlayer() {return new Player("John"); }
@ -41,21 +43,27 @@ public class MinerTest {
} }
@Test @Test
void dig_in_coast_use_coast_loot() { void dig_in_coast_use_coast_loot() {
RandomProvider random = bound -> 9; RandomProvider random = mock(RandomProvider.class);
when(random.nextInt(anyInt())).thenReturn(9);
var job = new Miner(defaultPlayer()); var job = new Miner(defaultPlayer());
Biome.COAST.getLootTable().setRandomProvider(random); Biome.COAST.getLootTable().setRandomProvider(random);
job.dig(Biome.COAST); job.dig(Biome.COAST);
assertThat(job.getActor().getInventory().getItems(), hasItem( assertThat(job.getActor().getInventory().getItems(), hasItem(
hasProperty("id", equalTo("sand")))); hasProperty("item", hasProperty("id", equalTo("sand")))));
} }
@Test @Test
void dig_in_mountain_use_mountain_loot() { void dig_in_mountain_use_mountain_loot() {
RandomProvider random = bound -> 15; RandomProvider random = mock(RandomProvider.class);
when(random.nextInt(anyInt())).thenReturn(15);
var job = new Miner(defaultPlayer()); var job = new Miner(defaultPlayer());
Biome.MOUNTAIN.getLootTable().setRandomProvider(random); Biome.MOUNTAIN.getLootTable().setRandomProvider(random);
job.dig(Biome.MOUNTAIN); job.dig(Biome.MOUNTAIN);
assertThat(job.getActor().getInventory().getItems(), hasItem( hasProperty("id", equalTo("iron")))); assertThat(job.getActor().getInventory().getItems(), hasItem(
hasProperty("item",
hasProperty("id", equalTo("iron")))
)
);
} }
} }

View File

@ -78,7 +78,7 @@ class PlayerTest {
p.learnJob(new Miner(p)); p.learnJob(new Miner(p));
var mockAction = mock(DigAction.class); var mockAction = mock(DigAction.class);
p.performAction(mockAction); p.performAction(mockAction);
verify(mockAction, times(1)).execute(any()); verify(mockAction, times(1)).execute(p);
} }
@Test @Test