diff --git a/README.md b/README.md index c1187eae..fb0123ee 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ graph TD; - [ ] entities' animation while attacking - [ ] implement bonus gained by class - [ ] implement magic, resist, ... stats - - [ ] implements drops from enemies - [ ] armor sets diff --git a/build.gradle.kts b/build.gradle.kts index 87fbe763..1f6a4842 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ plugins { allprojects { - version = "2.5.2" + version = "2.6.1" apply(plugin = "java") apply(plugin = "java-library") diff --git a/core/src/main/java/com/gdx/game/battle/BattleHUD.java b/core/src/main/java/com/gdx/game/battle/BattleHUD.java index 85f8f24c..901a90cf 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleHUD.java +++ b/core/src/main/java/com/gdx/game/battle/BattleHUD.java @@ -56,6 +56,7 @@ public class BattleHUD implements Screen, BattleObserver, ClassObserver, Compone private Entity enemy; private BattleState battleState; private BattleConversation battleConversation; + private Array drops; private final int enemyWidth = 50; private final int enemyHeight = 50; @@ -80,6 +81,7 @@ public BattleHUD(MapManager mapManager_, Stage battleStage, BattleState battleSt json = new Json(); player = mapManager.getPlayer(); battleConversation = new BattleConversation(); + drops = new Array<>(); battleState.addObserver(this); battleConversation.addObserver(this); @@ -277,7 +279,7 @@ public void onNotify(String value, ComponentEvent event) { switch (event) { case LOAD_RESUME -> { EntityConfig config = json.fromJson(EntityConfig.class, value); - notificationUI.loadResume(config); + notificationUI.loadResume(config, drops); } case SHOW_RESUME -> { EntityConfig configShow = json.fromJson(EntityConfig.class, value); @@ -310,6 +312,12 @@ public void onNotify(String value, InventoryEvent event) { battleStatusUI.addMPValue(typeValue); } } + case DROP_ITEM_ADDED -> { + if (battleInventoryUI.doesInventoryHaveSpace()) { + battleInventoryUI.addEntityToInventory(value, value); + drops.add(value); + } + } default -> { } } diff --git a/core/src/main/java/com/gdx/game/battle/BattleInventoryUI.java b/core/src/main/java/com/gdx/game/battle/BattleInventoryUI.java index cdf16b47..8c531320 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleInventoryUI.java +++ b/core/src/main/java/com/gdx/game/battle/BattleInventoryUI.java @@ -20,11 +20,15 @@ import com.gdx.game.inventory.slot.InventorySlotTooltip; import com.gdx.game.inventory.slot.InventorySlotTooltipListener; import com.gdx.game.manager.ResourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static com.gdx.game.component.Component.MESSAGE_TOKEN; public class BattleInventoryUI extends Window implements InventorySubject { + private static final Logger LOGGER = LoggerFactory.getLogger(BattleInventoryUI.class); + public final static int NUM_SLOTS = 50; public static final String PLAYER_INVENTORY = "Player_Inventory"; @@ -269,7 +273,7 @@ public boolean doesInventoryHaveSpace() { return false; } - public void addEntityToInventory(Entity entity, String itemName) { + public void addEntityToInventory(String itemTypeID, String itemName) { Array sourceCells = inventorySlotTable.getCells(); int index = 0; @@ -280,10 +284,11 @@ public void addEntityToInventory(Entity entity, String itemName) { } int numItems = inventorySlot.getNumItems(); if (numItems == 0) { - InventoryItem inventoryItem = InventoryItemFactory.getInstance().getInventoryItem(InventoryItem.ItemTypeID.valueOf(entity.getEntityConfig().getItemTypeID())); + InventoryItem inventoryItem = InventoryItemFactory.getInstance().getInventoryItem(InventoryItem.ItemTypeID.valueOf(itemTypeID)); inventoryItem.setName(itemName); inventorySlot.add(inventoryItem); dragAndDrop.addSource(new InventorySlotSource(inventorySlot, dragAndDrop)); + LOGGER.info("Item {} was looted", itemName); break; } } diff --git a/core/src/main/java/com/gdx/game/battle/BattleObserver.java b/core/src/main/java/com/gdx/game/battle/BattleObserver.java index e6d1c676..edbf465b 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleObserver.java +++ b/core/src/main/java/com/gdx/game/battle/BattleObserver.java @@ -1,6 +1,7 @@ package com.gdx.game.battle; import com.gdx.game.entities.Entity; +import com.gdx.game.inventory.InventoryObserver.InventoryEvent; public interface BattleObserver { enum BattleEvent { @@ -20,4 +21,6 @@ enum BattleEvent { } void onNotify(final Entity enemyEntity, BattleEvent event); + + void onNotify(final String drop, InventoryEvent event); } diff --git a/core/src/main/java/com/gdx/game/battle/BattleState.java b/core/src/main/java/com/gdx/game/battle/BattleState.java index 0c433eac..30f15925 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleState.java +++ b/core/src/main/java/com/gdx/game/battle/BattleState.java @@ -1,9 +1,11 @@ package com.gdx.game.battle; import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Timer; import com.gdx.game.entities.Entity; import com.gdx.game.entities.EntityConfig; +import com.gdx.game.inventory.InventoryObserver; import com.gdx.game.profile.ProfileManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -159,7 +161,7 @@ public void run() { double criticalChance = BattleUtils.criticalChance(currentPlayerAP); int damage = MathUtils.clamp(currentPlayerAP - currentOpponentDP, 0, currentPlayerAP); - if (BattleUtils.isEntitySuccessful(criticalChance)) { + if (BattleUtils.isSuccessful(criticalChance)) { damage *= criticalMultiplier; currentOpponent.getEntityConfig().setPropertyValue(EntityConfig.EntityProperties.ENTITY_RECEIVED_CRITICAL.toString(), "true"); LOGGER.debug("Critical hit !"); @@ -178,6 +180,7 @@ public void run() { } if (currentOpponentHP == 0) { + calculateDrops(); BattleState.this.notify(currentOpponent, BattleObserver.BattleEvent.OPPONENT_DEFEATED); } @@ -186,6 +189,16 @@ public void run() { }; } + private void calculateDrops() { + Array drops = currentOpponent.getEntityConfig().getDrops(); + for (EntityConfig.Drop drop : drops) { + boolean isSuccessful = BattleUtils.isSuccessful(drop.getProbability()); + if (isSuccessful) { + BattleState.this.notify(drop.getItemTypeID(), InventoryObserver.InventoryEvent.DROP_ITEM_ADDED); + } + } + } + private Timer.Task getOpponentAttackCalculationTimer() { return new Timer.Task() { @Override @@ -194,7 +207,7 @@ public void run() { double criticalChance = BattleUtils.criticalChance(currentOpponentAP); int damage = MathUtils.clamp(currentOpponentAP - currentPlayerDP, 0, currentOpponentAP); - if (BattleUtils.isEntitySuccessful(criticalChance)) { + if (BattleUtils.isSuccessful(criticalChance)) { damage *= criticalMultiplier; player.getEntityConfig().setPropertyValue(EntityConfig.EntityProperties.ENTITY_RECEIVED_CRITICAL.toString(), "true"); LOGGER.debug("Critical hit !"); @@ -221,7 +234,7 @@ public void playerRuns() { double escapeChance = BattleUtils.escapeChance(speedRatio); - if (BattleUtils.isEntitySuccessful(escapeChance)) { + if (BattleUtils.isSuccessful(escapeChance)) { LOGGER.debug("Player flees with {}% escape chance", escapeChance * 100); notify(currentOpponent, BattleObserver.BattleEvent.PLAYER_RUNNING); } else { diff --git a/core/src/main/java/com/gdx/game/battle/BattleSubject.java b/core/src/main/java/com/gdx/game/battle/BattleSubject.java index a60d0330..3a1a5b18 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleSubject.java +++ b/core/src/main/java/com/gdx/game/battle/BattleSubject.java @@ -2,6 +2,7 @@ import com.badlogic.gdx.utils.Array; import com.gdx.game.entities.Entity; +import com.gdx.game.inventory.InventoryObserver; public class BattleSubject { private Array observers; @@ -23,4 +24,10 @@ protected void notify(final Entity entity, BattleObserver.BattleEvent event) { observer.onNotify(entity, event); } } + + protected void notify(final String drop, InventoryObserver.InventoryEvent event) { + for(BattleObserver observer: observers) { + observer.onNotify(drop, event); + } + } } diff --git a/core/src/main/java/com/gdx/game/battle/BattleUtils.java b/core/src/main/java/com/gdx/game/battle/BattleUtils.java index 94511a82..76a1f7d1 100644 --- a/core/src/main/java/com/gdx/game/battle/BattleUtils.java +++ b/core/src/main/java/com/gdx/game/battle/BattleUtils.java @@ -16,7 +16,7 @@ static double criticalChance(double atkStat) { return roundDown((94 - (15260) / (atkStat + 163)) / 100); } - static boolean isEntitySuccessful(double statChance) { + static boolean isSuccessful(double statChance) { double randomVal = MathUtils.random(100f) / 100; return statChance > randomVal; diff --git a/core/src/main/java/com/gdx/game/dialog/ConversationUI.java b/core/src/main/java/com/gdx/game/dialog/ConversationUI.java index e7bce72e..31f29b5f 100644 --- a/core/src/main/java/com/gdx/game/dialog/ConversationUI.java +++ b/core/src/main/java/com/gdx/game/dialog/ConversationUI.java @@ -9,6 +9,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Window; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.gdx.game.entities.EntityConfig; import com.gdx.game.manager.ResourceManager; @@ -109,10 +110,18 @@ public void loadConversation(EntityConfig entityConfig) { setConversationGraph(graph); } - public void loadResume(EntityConfig entityConfig) { + public void loadResume(EntityConfig entityConfig, Array drops) { String fullResumePath = entityConfig.getResumeConfigPath(); - String resume = fullResumePath.replace("", entityConfig.getEntityProperties().get(EntityConfig.EntityProperties.ENTITY_XP_REWARD.name())) + String resume = fullResumePath + .replace("", entityConfig.getEntityProperties().get(EntityConfig.EntityProperties.ENTITY_XP_REWARD.name())) .replace("", entityConfig.getEntityProperties().get(EntityConfig.EntityProperties.ENTITY_GP_REWARD.name())); + if (!drops.isEmpty()) { + String newLine = System.getProperty("line.separator"); + for (String drop : drops) { + String dropResume = "Obtained : " + drop; + resume = resume.concat(newLine).concat(dropResume); + } + } this.getTitleLabel().setText(""); clearDialog(); diff --git a/core/src/main/java/com/gdx/game/entities/EntityConfig.java b/core/src/main/java/com/gdx/game/entities/EntityConfig.java index 9e1cc6be..af9eaf6b 100644 --- a/core/src/main/java/com/gdx/game/entities/EntityConfig.java +++ b/core/src/main/java/com/gdx/game/entities/EntityConfig.java @@ -19,6 +19,7 @@ public class EntityConfig { private String currentQuestID; private String itemTypeID; private ObjectMap entityProperties; + private Array drops; public enum EntityProperties { ENTITY_HEALTH_POINTS, @@ -38,6 +39,7 @@ public enum EntityProperties { animationConfig = new Array<>(); inventory = new Array<>(); entityProperties = new ObjectMap<>(); + drops = new Array<>(); } public EntityConfig(EntityConfig config) { @@ -60,6 +62,9 @@ public EntityConfig(EntityConfig config) { entityProperties = new ObjectMap<>(); entityProperties.putAll(config.entityProperties); + + drops = new Array<>(); + drops.addAll(config.getDrops()); } public ObjectMap getEntityProperties() { @@ -178,6 +183,14 @@ public void setInventory(Array inventory) { this.inventory = inventory; } + public Array getDrops() { + return drops; + } + + public void addDrop(Drop drop) { + this.drops.add(drop); + } + public static class AnimationConfig { private float frameDuration = 1.0f; private Entity.AnimationType animationType; @@ -223,4 +236,28 @@ public void setAnimationType(Entity.AnimationType animationType) { } } + public static class Drop { + private String itemTypeID = null; + private float probability = 1.0f; + + public Drop() { + } + + public String getItemTypeID() { + return itemTypeID; + } + + public void setItemTypeID(String itemTypeID) { + this.itemTypeID = itemTypeID; + } + + public float getProbability() { + return probability; + } + + public void setProbability(float probability) { + this.probability = probability; + } + } + } diff --git a/core/src/main/java/com/gdx/game/entities/player/PlayerHUD.java b/core/src/main/java/com/gdx/game/entities/player/PlayerHUD.java index d1e2bf12..0bf07943 100644 --- a/core/src/main/java/com/gdx/game/entities/player/PlayerHUD.java +++ b/core/src/main/java/com/gdx/game/entities/player/PlayerHUD.java @@ -493,7 +493,7 @@ public void onNotify(ConversationGraph graph, ConversationCommandEvent event) { } if (inventoryUI.doesInventoryHaveSpace()) { - inventoryUI.addEntityToInventory(entity, entity.getEntityConfig().getCurrentQuestID()); + inventoryUI.addEntityToInventory(entity.getEntityConfig().getItemTypeID(), entity.getEntityConfig().getCurrentQuestID()); mapManager.clearCurrentSelectedMapEntity(); conversationUI.setVisible(false); setInputUI(conversationUI); diff --git a/core/src/main/java/com/gdx/game/inventory/InventoryObserver.java b/core/src/main/java/com/gdx/game/inventory/InventoryObserver.java index 8db210ef..d4fb07c4 100644 --- a/core/src/main/java/com/gdx/game/inventory/InventoryObserver.java +++ b/core/src/main/java/com/gdx/game/inventory/InventoryObserver.java @@ -5,6 +5,7 @@ enum InventoryEvent { UPDATED_AP, UPDATED_DP, ITEM_CONSUMED, + DROP_ITEM_ADDED, ADD_WAND_AP, REMOVE_WAND_AP, REFRESH_STATS, diff --git a/core/src/main/java/com/gdx/game/inventory/InventoryUI.java b/core/src/main/java/com/gdx/game/inventory/InventoryUI.java index e5b53b50..fa48f3d9 100644 --- a/core/src/main/java/com/gdx/game/inventory/InventoryUI.java +++ b/core/src/main/java/com/gdx/game/inventory/InventoryUI.java @@ -413,7 +413,7 @@ public boolean doesInventoryHaveSpace() { return false; } - public void addEntityToInventory(Entity entity, String itemName) { + public void addEntityToInventory(String itemTypeID, String itemName) { Array sourceCells = inventorySlotTable.getCells(); int index = 0; @@ -424,7 +424,7 @@ public void addEntityToInventory(Entity entity, String itemName) { } int numItems = inventorySlot.getNumItems(); if (numItems == 0) { - InventoryItem inventoryItem = InventoryItemFactory.getInstance().getInventoryItem(InventoryItem.ItemTypeID.valueOf(entity.getEntityConfig().getItemTypeID())); + InventoryItem inventoryItem = InventoryItemFactory.getInstance().getInventoryItem(InventoryItem.ItemTypeID.valueOf(itemTypeID)); inventoryItem.setName(itemName); inventorySlot.add(inventoryItem); dragAndDrop.addSource(new InventorySlotSource(inventorySlot, dragAndDrop)); diff --git a/core/src/main/java/com/gdx/game/screen/BattleScreen.java b/core/src/main/java/com/gdx/game/screen/BattleScreen.java index d1855375..cf1bd46b 100644 --- a/core/src/main/java/com/gdx/game/screen/BattleScreen.java +++ b/core/src/main/java/com/gdx/game/screen/BattleScreen.java @@ -15,6 +15,7 @@ import com.gdx.game.entities.Entity; import com.gdx.game.entities.player.PlayerHUD; import com.gdx.game.inventory.InventoryItemLocation; +import com.gdx.game.inventory.InventoryObserver; import com.gdx.game.inventory.InventoryUI; import com.gdx.game.manager.ResourceManager; import com.gdx.game.map.MapManager; @@ -114,6 +115,11 @@ public void onNotify(Entity entity, BattleEvent event) { } } + @Override + public void onNotify(String drop, InventoryObserver.InventoryEvent event) { + + } + @Override public void show() { Gdx.input.setInputProcessor(multiplexer); diff --git a/core/src/main/resources/scripts/enemies.json b/core/src/main/resources/scripts/enemies.json index e42eb7bc..7371524b 100644 --- a/core/src/main/resources/scripts/enemies.json +++ b/core/src/main/resources/scripts/enemies.json @@ -43,6 +43,16 @@ value: 5 } } + drops: [ + { + itemTypeID: HERB001 + probability: 0.6 + } + { + itemTypeID: FUR001 + probability: 0.4 + } + ] animationConfig: [ { frameDuration: .5 @@ -128,6 +138,16 @@ value: 5 } } + drops: [ + { + itemTypeID: HERB001 + probability: 0.6 + } + { + itemTypeID: FUR001 + probability: 0.4 + } + ] animationConfig: [ { frameDuration: .5