From 425505f468f5dcfed38bde9babfd77fc3a0a5e15 Mon Sep 17 00:00:00 2001
From: Chris Kearney <chris@kearneymail.com>
Date: Sun, 21 May 2017 08:35:29 -0700
Subject: [PATCH] extending active fight structure to work with player on
 player combat

---
 .../command/commands/FightKillCommand.java    |   2 +-
 .../java/com/comandante/creeper/npc/Npc.java  |   2 +-
 .../creeper/player/ActiveFight.java           |  60 ++++++
 .../com/comandante/creeper/player/Player.java | 172 ++++++++----------
 .../creeper/storage/FilebasedJsonStorage.java |  17 +-
 5 files changed, 149 insertions(+), 104 deletions(-)
 create mode 100644 src/main/java/com/comandante/creeper/player/ActiveFight.java

diff --git a/src/main/java/com/comandante/creeper/command/commands/FightKillCommand.java b/src/main/java/com/comandante/creeper/command/commands/FightKillCommand.java
index 5f53d5c5..3bdc017d 100644
--- a/src/main/java/com/comandante/creeper/command/commands/FightKillCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/FightKillCommand.java
@@ -48,7 +48,7 @@ public class FightKillCommand extends Command {
                 if (npcEntity.getValidTriggers().contains(target)) {
                     if (player.addActiveFight(npcEntity)) {
                         writeToRoom(player.getPlayerName() + " has attacked a " + npcEntity.getColorName());
-                        player.addActiveFight(npcEntity);
+                       // player.addActiveFight(npcEntity);
                         return;
                     } else {
                         return;
diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java
index b9e958e2..6d5cb0e3 100644
--- a/src/main/java/com/comandante/creeper/npc/Npc.java
+++ b/src/main/java/com/comandante/creeper/npc/Npc.java
@@ -144,7 +144,7 @@ public class Npc extends CreeperEntity {
                         processNpcStatChange(npcStatsChange);
                     }
                     if (!isActiveCooldown(CoolDownType.NPC_FIGHT) && !isActiveCooldown(CoolDownType.NPC_ROAM) && currentRoom != null) {
-                        if (getRandPercent(.01)) {
+                        if (getRandPercent(.001)) {
                             gameManager.getNpcMover().roam(getEntityId());
                         }
                     }
diff --git a/src/main/java/com/comandante/creeper/player/ActiveFight.java b/src/main/java/com/comandante/creeper/player/ActiveFight.java
new file mode 100644
index 00000000..42d6c2b8
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/player/ActiveFight.java
@@ -0,0 +1,60 @@
+package com.comandante.creeper.player;
+
+import java.util.Optional;
+
+public class ActiveFight {
+    private final String npcId;
+    private final String playerId;
+    private boolean isPrimary;
+
+    public static Builder builder() { return new Builder();}
+
+    private ActiveFight(String npcId, String playerId, boolean isPrimary) {
+        this.npcId = npcId;
+        this.playerId = playerId;
+        this.isPrimary = isPrimary;
+    }
+
+    public Optional<String> getNpcId() {
+        return Optional.ofNullable(npcId);
+    }
+
+    public Optional<String> getPlayerId() {
+        return Optional.ofNullable(playerId);
+    }
+
+    public boolean isPrimary() {
+        return isPrimary;
+    }
+
+    public void setIsPrimary(boolean isPrimary) {
+        this.isPrimary = isPrimary;
+    }
+
+    public static class Builder {
+
+        private String npcId;
+        private String playerId;
+        private boolean isPrimary;
+
+        public Builder npcId(String npcId) {
+            this.npcId = npcId;
+            return this;
+        }
+
+        public Builder playerId(String playerId) {
+            this.playerId = playerId;
+            return this;
+        }
+
+        public Builder isPrimary(boolean isPrimary) {
+            this.isPrimary = isPrimary;
+            return this;
+        }
+
+        public ActiveFight create() {
+            return new ActiveFight(npcId, playerId, isPrimary);
+        }
+
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index ac16c928..92b24a66 100644
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -104,15 +104,21 @@ public class Player extends CreeperEntity {
     }
 
     private void processFightRounds() {
+
         DamageProcessor playerDamageProcesor = getPlayerClass().getDamageProcessor();
         Set<Map.Entry<Long, ActiveFight>> entries = activeFights.entrySet();
         for (Map.Entry<Long, ActiveFight> next : entries) {
-            addCoolDown(new CoolDown(CoolDownType.NPC_FIGHT));
-            Npc npc = gameManager.getEntityManager().getNpcEntity(next.getValue().npcId);
-            if (npc == null) {
-                continue;
+            Optional<String> npcIdOptional = next.getValue().getNpcId();
+            if (npcIdOptional.isPresent()) {
+                // If the NPC has died- bail out.
+                String npcId = npcIdOptional.get();
+                addCoolDown(new CoolDown(CoolDownType.NPC_FIGHT));
+                Npc npc = gameManager.getEntityManager().getNpcEntity(npcId);
+                if (npc == null) {
+                    continue;
+                }
+                doFightRound(playerDamageProcesor, npc.getDamageProcessor(), next.getValue());
             }
-            doFightRound(playerDamageProcesor, npc.getDamageProcessor(), next.getValue());
         }
     }
 
@@ -1251,7 +1257,10 @@ public class Player extends CreeperEntity {
             if (gameManager.getEntityManager().getNpcEntity(npc.getEntityId()) != null) {
                 if (!doesActiveFightExist(npc)) {
                     addCoolDown(new CoolDown(CoolDownType.NPC_FIGHT));
-                    ActiveFight activeFight = new ActiveFight(npc.getEntityId(), false);
+                    ActiveFight activeFight = ActiveFight.builder()
+                            .npcId(npc.getEntityId())
+                            .isPrimary(false)
+                            .create();
                     activeFights.put(System.nanoTime(), activeFight);
                     return true;
                 }
@@ -1267,7 +1276,8 @@ public class Player extends CreeperEntity {
             }
             for (Map.Entry<Long, ActiveFight> entry : activeFights.entrySet()) {
                 ActiveFight fight = entry.getValue();
-                if (fight.getNpcId().equals(npc.getEntityId())) {
+                Optional<String> npcIdOptional = fight.getNpcId();
+                if (npcIdOptional.isPresent() && npcIdOptional.get().equals(npc.getEntityId())) {
                     return true;
                 }
             }
@@ -1281,7 +1291,7 @@ public class Player extends CreeperEntity {
             while (iterator.hasNext()) {
                 Map.Entry<Long, ActiveFight> next = iterator.next();
                 if (next.getValue().getNpcId().equals(npc.getEntityId())) {
-                    if (next.getValue().isPrimary) {
+                    if (next.getValue().isPrimary()) {
                     }
                     iterator.remove();
                 }
@@ -1292,13 +1302,8 @@ public class Player extends CreeperEntity {
     public boolean isActiveFights() {
         synchronized (interner.intern(playerId)) {
             if (activeFights.size() > 0) {
-                Iterator<Map.Entry<Long, ActiveFight>> iterator = activeFights.entrySet().iterator();
-                while (iterator.hasNext()) {
-                    Map.Entry<Long, ActiveFight> next = iterator.next();
-                    if (gameManager.getEntityManager().getNpcEntity(next.getValue().getNpcId()) == null) {
-                        iterator.remove();
-                    }
-                }
+                // Remove any fights with dead NPCs that no longer exist in Entity Manager.
+                activeFights.entrySet().removeIf(next -> next.getValue().getNpcId().isPresent() && gameManager.getEntityManager().getNpcEntity(next.getValue().getNpcId().get()) == null);
             }
         }
         return activeFights.size() > 0;
@@ -1308,7 +1313,8 @@ public class Player extends CreeperEntity {
         synchronized (interner.intern(playerId)) {
             for (Map.Entry<Long, ActiveFight> entry : activeFights.entrySet()) {
                 ActiveFight fight = entry.getValue();
-                if (fight.getNpcId().equals(npc.getEntityId()) && fight.isPrimary) {
+                Optional<String> npcIdOptional = fight.getNpcId();
+                if (npcIdOptional.isPresent() && fight.getNpcId().get().equals(npc.getEntityId()) && fight.isPrimary()) {
                     return true;
                 }
             }
@@ -1316,21 +1322,21 @@ public class Player extends CreeperEntity {
         }
     }
 
-    public String getPrimaryActiveFight() {
+    public Optional<ActiveFight> getPrimaryActiveFight() {
         synchronized (interner.intern(playerId)) {
             for (Map.Entry<Long, ActiveFight> entry : activeFights.entrySet()) {
                 ActiveFight fight = entry.getValue();
-                if (fight.isPrimary) {
-                    return fight.getNpcId();
+                if (fight.isPrimary()) {
+                    return Optional.of(fight);
                 }
             }
-            return null;
+            return Optional.empty();
         }
     }
 
     public void activateNextPrimaryActiveFight() {
         synchronized (interner.intern(playerId)) {
-            if (getPrimaryActiveFight() == null) {
+            if (!getPrimaryActiveFight().isPresent()) {
                 if (activeFights.size() > 0) {
                     activeFights.get(activeFights.firstKey()).setIsPrimary(true);
                 }
@@ -1340,70 +1346,70 @@ public class Player extends CreeperEntity {
 
     private void doFightRound(DamageProcessor playerDamageProcessor, DamageProcessor npcDamageProcessor, ActiveFight activeFight) {
         removeActiveAlertStatus();
-        Npc npc = gameManager.getEntityManager().getNpcEntity(activeFight.getNpcId());
-        if (npc == null) {
-            return;
-        }
-        NpcStatsChangeBuilder npcStatsChangeBuilder = new NpcStatsChangeBuilder().setPlayer(this);
-        if (this.isValidPrimaryActiveFight(npc)) {
-            long damageToVictim = 0;
-            long chanceToHit = playerDamageProcessor.getChanceToHit(this, npc);
-            if (randInt(0, 100) < chanceToHit) {
-                damageToVictim = playerDamageProcessor.getAttackAmount(this, npc);
-            }
-            if (damageToVictim > 0) {
-                if (randInt(0, 100) > (100 - playerDamageProcessor.getCriticalChance(this, npc))) {
-                    long criticalDamage = damageToVictim * 3;
-                    final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + Color.YELLOW + "The " + npc.getColorName() + " was caught off guard by the attack! " + "+" + NumberFormat.getNumberInstance(Locale.US).format(criticalDamage) + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE" + Color.RESET + " done to " + npc.getColorName();
-                    npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-(criticalDamage)).createStats());
-                    npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
-                } else {
-                    final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + Color.YELLOW + "+" + NumberFormat.getNumberInstance(Locale.US).format(damageToVictim) + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE" + Color.RESET + " done to " + npc.getColorName();
-                    npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-damageToVictim).createStats());
-                    npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
-                }
-            } else {
-                final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + "You MISS " + npc.getName() + "!";
-                npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-damageToVictim).createStats());
-                npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
+
+        // IF FIGHTING NPC
+        Optional<String> npcIdOptional = activeFight.getNpcId();
+        if (npcIdOptional.isPresent()) {
+            String npcId = npcIdOptional.get();
+            Npc npc = gameManager.getEntityManager().getNpcEntity(npcId);
+            if (npc == null) {
+                return;
+            }
+
+            NpcStatsChangeBuilder npcStatsChangeBuilder = new NpcStatsChangeBuilder().setPlayer(this);
+            if (this.isValidPrimaryActiveFight(npc)) {
+                calculatePlayerDamageToNpc(playerDamageProcessor, npc, npcStatsChangeBuilder);
+            }
+
+            if (this.doesActiveFightExist(npc)) {
+                calculateNpcDamageToPlayer(npcDamageProcessor, npc, npcStatsChangeBuilder);
             }
         }
-        if (this.doesActiveFightExist(npc)) {
-            int chanceToHitBack = npcDamageProcessor.getChanceToHit(this, npc);
-            long damageBack = npcDamageProcessor.getAttackAmount(this, npc);
-            if (randInt(0, 100) < chanceToHitBack) {
-                final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + npc.buildAttackMessage(this.getPlayerName()) + " -" + NumberFormat.getNumberInstance(Locale.US).format(damageBack) + Color.RESET;
-                npcStatsChangeBuilder.setPlayerStatsChange(new StatsBuilder().setCurrentHealth(-damageBack).createStats());
-                npcStatsChangeBuilder.setPlayerDamageStrings(Collections.singletonList(fightMsg));
 
+        // IF FIGHTING PLAYER?
+    }
+
+    private void calculatePlayerDamageToNpc(DamageProcessor playerDamageProcessor, Npc npc, NpcStatsChangeBuilder npcStatsChangeBuilder) {
+        long damageToVictim = 0;
+        long chanceToHit = playerDamageProcessor.getChanceToHit(this, npc);
+        if (randInt(0, 100) < chanceToHit) {
+            damageToVictim = playerDamageProcessor.getAttackAmount(this, npc);
+        }
+        if (damageToVictim > 0) {
+            if (randInt(0, 100) > (100 - playerDamageProcessor.getCriticalChance(this, npc))) {
+                long criticalDamage = damageToVictim * 3;
+                final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + Color.YELLOW + "The " + npc.getColorName() + " was caught off guard by the attack! " + "+" + NumberFormat.getNumberInstance(Locale.US).format(criticalDamage) + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE" + Color.RESET + " done to " + npc.getColorName();
+                npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-(criticalDamage)).createStats());
+                npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
             } else {
-                final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + npc.getColorName() + Color.BOLD_ON + Color.CYAN + " MISSES" + Color.RESET + " you!";
-                npcStatsChangeBuilder.setPlayerStatsChange(new StatsBuilder().setCurrentHealth(0).createStats());
-                npcStatsChangeBuilder.setPlayerDamageStrings(Collections.singletonList(fightMsg));
+                final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + Color.YELLOW + "+" + NumberFormat.getNumberInstance(Locale.US).format(damageToVictim) + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE" + Color.RESET + " done to " + npc.getColorName();
+                npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-damageToVictim).createStats());
+                npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
             }
-            npc.addNpcDamage(npcStatsChangeBuilder.createNpcStatsChange());
+        } else {
+            final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + "You MISS " + npc.getName() + "!";
+            npcStatsChangeBuilder.setStats(new StatsBuilder().setCurrentHealth(-damageToVictim).createStats());
+            npcStatsChangeBuilder.setDamageStrings(Collections.singletonList(fightMsg));
         }
     }
 
-    private int getChanceToHit(Stats challenger, Stats victim) {
-        return (int) ((challenger.getStrength() + challenger.getMeleSkill()) * 5 - victim.getAgile() * 5);
-    }
+    private void calculateNpcDamageToPlayer(DamageProcessor npcDamageProcessor, Npc npc, NpcStatsChangeBuilder npcStatsChangeBuilder) {
+        int chanceToHitBack = npcDamageProcessor.getChanceToHit(this, npc);
+        long damageBack = npcDamageProcessor.getAttackAmount(this, npc);
+        if (randInt(0, 100) < chanceToHitBack) {
+            final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + npc.buildAttackMessage(this.getPlayerName()) + " -" + NumberFormat.getNumberInstance(Locale.US).format(damageBack) + Color.RESET;
+            npcStatsChangeBuilder.setPlayerStatsChange(new StatsBuilder().setCurrentHealth(-damageBack).createStats());
+            npcStatsChangeBuilder.setPlayerDamageStrings(Collections.singletonList(fightMsg));
 
-    private long getAttackAmt(Stats challenger, Stats victim) {
-        long rolls = 0;
-        long totDamage = 0;
-        while (rolls <= challenger.getNumberOfWeaponRolls()) {
-            rolls++;
-            totDamage = totDamage + randInt((int) challenger.getWeaponRatingMin(), (int) challenger.getWeaponRatingMax());
-        }
-        long i = challenger.getStrength() + totDamage - victim.getArmorRating();
-        if (i < 0) {
-            return 0;
         } else {
-            return i;
+            final String fightMsg = Color.BOLD_ON + Color.RED + "[attack] " + Color.RESET + npc.getColorName() + Color.BOLD_ON + Color.CYAN + " MISSES" + Color.RESET + " you!";
+            npcStatsChangeBuilder.setPlayerStatsChange(new StatsBuilder().setCurrentHealth(0).createStats());
+            npcStatsChangeBuilder.setPlayerDamageStrings(Collections.singletonList(fightMsg));
         }
+        npc.addNpcDamage(npcStatsChangeBuilder.createNpcStatsChange());
     }
 
+
     public SortedMap<Long, ActiveFight> getActiveFights() {
         return activeFights;
     }
@@ -1416,28 +1422,6 @@ public class Player extends CreeperEntity {
         return interner;
     }
 
-    class ActiveFight {
-        private final String npcId;
-        private boolean isPrimary;
-
-        public ActiveFight(String npcId, boolean isPrimary) {
-            this.npcId = npcId;
-            this.isPrimary = isPrimary;
-        }
-
-        public String getNpcId() {
-            return npcId;
-        }
-
-        public boolean isPrimary() {
-            return isPrimary;
-        }
-
-        public void setIsPrimary(boolean isPrimary) {
-            this.isPrimary = isPrimary;
-        }
-
-    }
 
     public boolean toggleChat() {
         synchronized (interner.intern(playerId)) {
diff --git a/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java b/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java
index 887f258f..798adf8b 100644
--- a/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java
+++ b/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java
@@ -2,6 +2,7 @@ package com.comandante.creeper.storage;
 
 import com.comandante.creeper.Main;
 import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
 import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
 
@@ -23,20 +24,17 @@ public class FilebasedJsonStorage {
     }
 
     public <E> List<E> readAllMetadatas(String storageDirectory, boolean recursive, E a) {
-        List<String> jsonStrings = getAllJsonStrings(storageDirectory, recursive);
-        List<Object> list = jsonStrings.stream()
+        return getAllJsonStrings(storageDirectory, recursive).stream()
                 .map(s -> {
                     try {
-                        return gson.fromJson(s, a.getClass());
-                    } catch (Exception e) {
+                        return (E) gson.fromJson(s, a.getClass());
+                    } catch (JsonSyntaxException e) {
                         log.error("Unable to read NpcMetaData from Json!", e);
                     }
                     return null;
                 })
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
-
-        return (List<E>) list;
     }
 
     public void saveMetadata(String name, String storageDirectory, Object metadata) throws IOException {
@@ -46,8 +44,11 @@ public class FilebasedJsonStorage {
     }
 
     private List<String> getAllJsonStrings(String storageDirectory, boolean recursive) {
-        new File(storageDirectory).mkdirs();
-        Iterator<File> iterator = FileUtils.iterateFiles(new File(storageDirectory), new String[]{"json"}, recursive);
+        boolean mkdirs = new File(storageDirectory).mkdirs();
+        if (mkdirs) {
+            log.info("Created directory: " + storageDirectory);
+        }
+        Iterator iterator = FileUtils.iterateFiles(new File(storageDirectory), new String[]{"json"}, recursive);
         return toListOfJsonStrings(iterator);
     }
 
-- 
GitLab