diff --git a/data.mv.db b/data.mv.db index 852d8bc..f6c3032 100644 Binary files a/data.mv.db and b/data.mv.db differ diff --git a/maps/551e1afc-9cda-4d9f-8817-bfd831fc0a75.dat b/maps/551e1afc-9cda-4d9f-8817-bfd831fc0a75.dat index 9047a07..1aea8a0 100644 Binary files a/maps/551e1afc-9cda-4d9f-8817-bfd831fc0a75.dat and b/maps/551e1afc-9cda-4d9f-8817-bfd831fc0a75.dat differ diff --git a/src/main/java/com/bartlomiejpluta/demo/ai/WeaponBasedAI.java b/src/main/java/com/bartlomiejpluta/demo/ai/WeaponBasedAI.java index 7989fa2..430a60a 100644 --- a/src/main/java/com/bartlomiejpluta/demo/ai/WeaponBasedAI.java +++ b/src/main/java/com/bartlomiejpluta/demo/ai/WeaponBasedAI.java @@ -40,8 +40,7 @@ public class WeaponBasedAI implements AI { @Override public void nextActivity(ObjectLayer layer, float dt) { var lastAttacker = enemy.getLastAttacker(); - if (lastAttacker != null && lastAttacker instanceof Creature) { - var attacker = (Creature) lastAttacker; + if (lastAttacker instanceof Creature attacker) { if (attacker.isAlive()) { runawayAI.setDanger(attacker); meleeAI.setTarget(attacker); @@ -61,7 +60,7 @@ public class WeaponBasedAI implements AI { return; } - if (rangedWeapon == null || enemy.manhattanDistance(target) == 1) { + if (rangedWeapon == null || enemy.manhattanDistance(target) == 1 || enemy.getAmmunition() == null) { enemy.setWeapon(meleeWeapon); meleeAI.nextActivity(layer, dt); return; diff --git a/src/main/java/com/bartlomiejpluta/demo/entity/Creature.java b/src/main/java/com/bartlomiejpluta/demo/entity/Creature.java index ce903ad..da50e8c 100644 --- a/src/main/java/com/bartlomiejpluta/demo/entity/Creature.java +++ b/src/main/java/com/bartlomiejpluta/demo/entity/Creature.java @@ -2,6 +2,8 @@ package com.bartlomiejpluta.demo.entity; import com.bartlomiejpluta.base.api.character.Character; import com.bartlomiejpluta.demo.world.item.Item; +import com.bartlomiejpluta.demo.world.weapon.Ammunition; +import com.bartlomiejpluta.demo.world.weapon.RangedWeapon; import com.bartlomiejpluta.demo.world.weapon.Weapon; import lombok.Getter; import lombok.NonNull; @@ -30,6 +32,10 @@ public abstract class Creature extends NamedCharacter { @Setter private Weapon weapon; + @Getter + @Setter + private Ammunition ammunition; + @Getter private NamedCharacter lastAttacker; @@ -44,6 +50,14 @@ public abstract class Creature extends NamedCharacter { if (attackCooldown >= weapon.getCooldown()) { if (weapon.attack(this)) { + if(weapon instanceof RangedWeapon) { + ammunition.decrease(); + + if(ammunition.getCount() == 0) { + ammunition = null; + } + } + attackCooldown = 0; } } @@ -62,6 +76,11 @@ public abstract class Creature extends NamedCharacter { public void useEquipmentItem(Item item) { if (item instanceof Weapon weapon) { setWeapon(weapon); + return; + } + + if (item instanceof Ammunition ammunition) { + setAmmunition(ammunition); } } diff --git a/src/main/java/com/bartlomiejpluta/demo/entity/Player.java b/src/main/java/com/bartlomiejpluta/demo/entity/Player.java index 48a54c9..677ae29 100644 --- a/src/main/java/com/bartlomiejpluta/demo/entity/Player.java +++ b/src/main/java/com/bartlomiejpluta/demo/entity/Player.java @@ -2,6 +2,7 @@ package com.bartlomiejpluta.demo.entity; import com.bartlomiejpluta.base.api.character.Character; import com.bartlomiejpluta.demo.world.item.Item; +import com.bartlomiejpluta.demo.world.weapon.Ammunition; import com.bartlomiejpluta.demo.world.weapon.Weapon; import lombok.NonNull; import org.joml.Vector2i; @@ -63,9 +64,49 @@ public class Player extends Creature { item.setCoordinates(getCoordinates()); getLayer().addEntity(item); - if(item == getWeapon()) { + if (item == getWeapon()) { setWeapon(null); } + + if (item == getAmmunition()) { + setAmmunition(null); + } + } + + @Override + public void setWeapon(Weapon weapon) { + var currentWeapon = getWeapon(); + + if (weapon != null) { + removeItemFromEquipment(weapon); + } + + if (currentWeapon != null) { + pushItemToEquipment(currentWeapon); + } + + super.setWeapon(weapon); + } + + @Override + public void setAmmunition(Ammunition ammunition) { + var currentAmmo = getAmmunition(); + + if (currentAmmo != null && currentAmmo.getId().equals(ammunition.getId())) { + currentAmmo.increase(ammunition.getCount()); + removeItemFromEquipment(ammunition); + return; + } + + if (ammunition != null) { + removeItemFromEquipment(ammunition); + } + + if (currentAmmo != null) { + pushItemToEquipment(currentAmmo); + } + + super.setAmmunition(ammunition); } @Override diff --git a/src/main/java/com/bartlomiejpluta/demo/gui/EquipmentWindow.java b/src/main/java/com/bartlomiejpluta/demo/gui/EquipmentWindow.java index 2494126..4cf49f9 100644 --- a/src/main/java/com/bartlomiejpluta/demo/gui/EquipmentWindow.java +++ b/src/main/java/com/bartlomiejpluta/demo/gui/EquipmentWindow.java @@ -8,9 +8,9 @@ import com.bartlomiejpluta.base.lib.gui.VOptionChoice; import com.bartlomiejpluta.demo.entity.Player; import com.bartlomiejpluta.demo.runner.DemoRunner; import com.bartlomiejpluta.demo.world.item.Item; +import com.bartlomiejpluta.demo.world.item.Useable; import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon; import com.bartlomiejpluta.demo.world.weapon.RangedWeapon; -import com.bartlomiejpluta.demo.world.weapon.Weapon; import java.util.Map; import java.util.function.Consumer; @@ -31,6 +31,12 @@ public class EquipmentWindow extends DecoratedWindow { @Ref("eq") private VGridOptionChoice eqGrid; + @Ref("weapon") + private ItemIconView weapon; + + @Ref("ammo") + private ItemIconView ammo; + @Ref("item-name") private Label nameLbl; @@ -55,6 +61,13 @@ public class EquipmentWindow extends DecoratedWindow { cancelBtn.setAction(manager::close); eqGrid.setOnSelect(this::updateItemDetails); + updateEquipment(); + + eqGrid.select(0, 0); + eqGrid.focus(); + } + + private void updateEquipment() { var i = 0; for (var child : eqGrid.getChildren()) { var slot = (ItemIconView) child; @@ -62,8 +75,8 @@ public class EquipmentWindow extends DecoratedWindow { slot.setAction(handleItem(slot)); } - eqGrid.select(0, 0); - eqGrid.focus(); + weapon.setItem(player.getWeapon()); + ammo.setItem(player.getAmmunition()); } private Consumer handleItem(ItemIconView slot) { @@ -74,10 +87,13 @@ public class EquipmentWindow extends DecoratedWindow { manager.open(eqItemMenuWindow); - useBtn.setAction(() -> { - player.useEquipmentItem(item); - manager.close(); - }); + if (item instanceof Useable useable) { + useBtn.setAction(() -> { + useable.use(player); + updateEquipment(); + manager.close(); + }); + } dropBtn.setAction(() -> { player.dropItemFromEquipment(item); @@ -110,8 +126,8 @@ public class EquipmentWindow extends DecoratedWindow { } private String getButtonTitle(Item item) { - if (item instanceof Weapon) { - return "Equip"; + if (item instanceof Useable useable) { + return useable.usageName(); } return "Use"; diff --git a/src/main/java/com/bartlomiejpluta/demo/gui/ItemIconView.java b/src/main/java/com/bartlomiejpluta/demo/gui/ItemIconView.java index 704584c..4868b06 100644 --- a/src/main/java/com/bartlomiejpluta/demo/gui/ItemIconView.java +++ b/src/main/java/com/bartlomiejpluta/demo/gui/ItemIconView.java @@ -102,7 +102,7 @@ public class ItemIconView extends IconView { gui.beginPath(); gui.setFontFace(fonts.roboto_regular.uid); gui.setFontSize(17); - gui.putText(x + 15, y + 5, String.valueOf(stack.count())); + gui.putText(x + 15, y + 5, String.valueOf(stack.getCount())); gui.setFillColor(textColor); gui.fill(); gui.closePath(); diff --git a/src/main/java/com/bartlomiejpluta/demo/world/item/ItemStack.java b/src/main/java/com/bartlomiejpluta/demo/world/item/ItemStack.java index fa8ec6e..c46c340 100644 --- a/src/main/java/com/bartlomiejpluta/demo/world/item/ItemStack.java +++ b/src/main/java/com/bartlomiejpluta/demo/world/item/ItemStack.java @@ -1,5 +1,15 @@ package com.bartlomiejpluta.demo.world.item; public interface ItemStack extends Item { - int count(); + int getCount(); + + void setCount(int count); + + void decrease(); + + void increase(); + + void increase(int count); + + void decrease(int count); } diff --git a/src/main/java/com/bartlomiejpluta/demo/world/item/Useable.java b/src/main/java/com/bartlomiejpluta/demo/world/item/Useable.java new file mode 100644 index 0000000..58fe9d6 --- /dev/null +++ b/src/main/java/com/bartlomiejpluta/demo/world/item/Useable.java @@ -0,0 +1,11 @@ +package com.bartlomiejpluta.demo.world.item; + +import com.bartlomiejpluta.demo.entity.Creature; + +public interface Useable { + void use(Creature creature); + + default String usageName() { + return "Use"; + } +} diff --git a/src/main/java/com/bartlomiejpluta/demo/world/weapon/Ammunition.java b/src/main/java/com/bartlomiejpluta/demo/world/weapon/Ammunition.java index 171cc1f..25af6dc 100644 --- a/src/main/java/com/bartlomiejpluta/demo/world/weapon/Ammunition.java +++ b/src/main/java/com/bartlomiejpluta/demo/world/weapon/Ammunition.java @@ -3,33 +3,76 @@ package com.bartlomiejpluta.demo.world.weapon; import com.bartlomiejpluta.base.api.context.ContextHolder; import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.lib.icon.IconDelegate; +import com.bartlomiejpluta.demo.entity.Creature; import com.bartlomiejpluta.demo.world.item.ItemStack; +import com.bartlomiejpluta.demo.world.item.Useable; import lombok.Getter; import lombok.NonNull; +import lombok.Setter; +import lombok.ToString; -public class Ammunition extends IconDelegate implements ItemStack { +@ToString +public class Ammunition extends IconDelegate implements ItemStack, Useable { + + @Getter + private final String id; + + @Getter + @Setter private int count; @Getter private final String name; + @Getter + private final String appliesTo; + public Ammunition(@NonNull String id, int count) { this(DB.dao.ammunition.find(id), count); } public Ammunition(@NonNull DB.model.AmmunitionModel template, int count) { super(createIcon(template)); + this.id = template.getId(); this.name = template.getName(); this.count = count; - } - - @Override - public int count() { - return count; + this.appliesTo = template.getAppliesTo(); } private static Icon createIcon(DB.model.AmmunitionModel template) { var icons = template.getIcon().split(","); return ContextHolder.INSTANCE.getContext().createIcon(A.iconsets.get(icons[0]).uid, Integer.parseInt(icons[1]), Integer.parseInt(icons[2])); } + + @Override + public void decrease() { + if (count > 0) { + --count; + } + } + + @Override + public void increase() { + ++count; + } + + @Override + public void increase(int count) { + this.count += count; + } + + @Override + public void decrease(int count) { + this.count = Math.max(0, count); + } + + @Override + public void use(Creature creature) { + creature.setAmmunition(this); + } + + @Override + public String usageName() { + return "Equip"; + } } diff --git a/src/main/java/com/bartlomiejpluta/demo/world/weapon/MeleeWeapon.java b/src/main/java/com/bartlomiejpluta/demo/world/weapon/MeleeWeapon.java index 1617a22..228e9ac 100644 --- a/src/main/java/com/bartlomiejpluta/demo/world/weapon/MeleeWeapon.java +++ b/src/main/java/com/bartlomiejpluta/demo/world/weapon/MeleeWeapon.java @@ -59,6 +59,16 @@ public class MeleeWeapon extends IconDelegate implements Weapon { return false; } + @Override + public void use(Creature creature) { + creature.setWeapon(this); + } + + @Override + public String usageName() { + return "Equip"; + } + private static Icon createIcon(DB.model.MeleeWeaponModel template) { var icons = template.getIcon().split(","); return ContextHolder.INSTANCE.getContext().createIcon(A.iconsets.get(icons[0]).uid, Integer.parseInt(icons[1]), Integer.parseInt(icons[2])); diff --git a/src/main/java/com/bartlomiejpluta/demo/world/weapon/RangedWeapon.java b/src/main/java/com/bartlomiejpluta/demo/world/weapon/RangedWeapon.java index 8708b1e..41bd460 100644 --- a/src/main/java/com/bartlomiejpluta/demo/world/weapon/RangedWeapon.java +++ b/src/main/java/com/bartlomiejpluta/demo/world/weapon/RangedWeapon.java @@ -28,6 +28,9 @@ public class RangedWeapon extends IconDelegate implements Weapon { @Getter private final String name; + @Getter + private final String type; + @Getter private final DiceRoller dmgRoller; @@ -46,6 +49,7 @@ public class RangedWeapon extends IconDelegate implements Weapon { this.context = ContextHolder.INSTANCE.getContext(); this.name = template.getName(); + this.type = template.getType(); this.dmgRoller = DiceRoller.of(template.getDamage()); this.rangeRoller = DiceRoller.of(template.getRange()); this.cooldown = template.getCooldown(); @@ -75,12 +79,28 @@ public class RangedWeapon extends IconDelegate implements Weapon { @Override public boolean attack(Creature attacker) { + var ammunition = attacker.getAmmunition(); + + if(ammunition == null || !ammunition.getAppliesTo().equals(type)) { + return false; + } + var direction = attacker.getFaceDirection(); context.playSound(sound); animation.range(rangeRoller.roll()).direction(direction).rotation(direction.xAngle - 180).run(context, attacker.getLayer(), attacker); return true; } + @Override + public void use(Creature creature) { + creature.setWeapon(this); + } + + @Override + public String usageName() { + return "Equip"; + } + private static Icon createIcon(DB.model.RangedWeaponModel template) { var icons = template.getIcon().split(","); return ContextHolder.INSTANCE.getContext().createIcon(A.iconsets.get(icons[0]).uid, Integer.parseInt(icons[1]), Integer.parseInt(icons[2])); diff --git a/src/main/java/com/bartlomiejpluta/demo/world/weapon/Weapon.java b/src/main/java/com/bartlomiejpluta/demo/world/weapon/Weapon.java index 7975bd4..a8a1fbf 100644 --- a/src/main/java/com/bartlomiejpluta/demo/world/weapon/Weapon.java +++ b/src/main/java/com/bartlomiejpluta/demo/world/weapon/Weapon.java @@ -2,8 +2,9 @@ package com.bartlomiejpluta.demo.world.weapon; import com.bartlomiejpluta.demo.entity.Creature; import com.bartlomiejpluta.demo.world.item.Item; +import com.bartlomiejpluta.demo.world.item.Useable; -public interface Weapon extends Item { +public interface Weapon extends Item, Useable { int getCooldown(); diff --git a/widgets/c473a91a-ff25-4e71-9bec-b35e48102aeb.xml b/widgets/c473a91a-ff25-4e71-9bec-b35e48102aeb.xml index 14998aa..b620b1c 100644 --- a/widgets/c473a91a-ff25-4e71-9bec-b35e48102aeb.xml +++ b/widgets/c473a91a-ff25-4e71-9bec-b35e48102aeb.xml @@ -21,6 +21,11 @@ + + + + +