From 28432f056abc9d7168a25d7a2af0f08d7b235922 Mon Sep 17 00:00:00 2001
From: Chris Kearney <chris@kearneymail.com>
Date: Sun, 7 Aug 2016 23:27:21 -0700
Subject: [PATCH] npc kill tally

---
 .../comandante/creeper/ConfigureCommands.java |  7 +++-
 .../creeper/command/KillTallyCommand.java     | 40 +++++++++++++++++++
 .../managers/NewUserRegistrationManager.java  |  3 +-
 .../java/com/comandante/creeper/npc/Npc.java  |  1 +
 .../com/comandante/creeper/player/Player.java | 20 ++++++++--
 .../creeper/player/PlayerMetadata.java        | 29 +++++++++++++-
 .../creeper/player/NpcTestHarness.java        |  2 +-
 7 files changed, 92 insertions(+), 10 deletions(-)
 create mode 100644 src/main/java/com/comandante/creeper/command/KillTallyCommand.java

diff --git a/src/main/java/com/comandante/creeper/ConfigureCommands.java b/src/main/java/com/comandante/creeper/ConfigureCommands.java
index 480300f4..10961f8c 100755
--- a/src/main/java/com/comandante/creeper/ConfigureCommands.java
+++ b/src/main/java/com/comandante/creeper/ConfigureCommands.java
@@ -5,8 +5,10 @@ import com.comandante.creeper.command.UnknownCommand;
 import com.comandante.creeper.command.admin.*;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.merchant.bank.commands.*;
-import com.comandante.creeper.merchant.bank.commands.DoneCommand;
-import com.comandante.creeper.merchant.lockers.*;
+import com.comandante.creeper.merchant.lockers.GetCommand;
+import com.comandante.creeper.merchant.lockers.LockerCommandRegistry;
+import com.comandante.creeper.merchant.lockers.PutCommand;
+import com.comandante.creeper.merchant.lockers.QueryCommand;
 import com.comandante.creeper.server.CreeperCommandRegistry;
 
 public class ConfigureCommands {
@@ -88,5 +90,6 @@ public class ConfigureCommands {
         creeperCommandRegistry.addCommand(new SetCommand(gameManager));
         creeperCommandRegistry.addCommand(new DelCommand(gameManager));
         creeperCommandRegistry.addCommand(new OpCommand(gameManager));
+        creeperCommandRegistry.addCommand(new KillTallyCommand(gameManager));
     }
 }
diff --git a/src/main/java/com/comandante/creeper/command/KillTallyCommand.java b/src/main/java/com/comandante/creeper/command/KillTallyCommand.java
new file mode 100644
index 00000000..9e8aa883
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/command/KillTallyCommand.java
@@ -0,0 +1,40 @@
+package com.comandante.creeper.command;
+
+import com.comandante.creeper.managers.GameManager;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+import org.nocrala.tools.texttablefmt.BorderStyle;
+import org.nocrala.tools.texttablefmt.ShownBorders;
+import org.nocrala.tools.texttablefmt.Table;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class KillTallyCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("killtally", "kt", "tally");
+    final static String description = "View your kill tally.";
+    final static String correctUsage = "tally";
+
+    public KillTallyCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description, correctUsage);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        this.execCommand(ctx, e, () -> {
+            Table table = new Table(2, BorderStyle.CLASSIC_COMPATIBLE, ShownBorders.HEADER_ONLY);
+            table.setColumnWidth(0, 22, 30);
+            table.setColumnWidth(1, 10, 20);
+            table.addCell("Npc");
+            table.addCell("# Killed");
+            Map<String, Long> npcKillLog = player.getNpcKillLog();
+            npcKillLog.forEach((s, aLong) -> {
+                table.addCell(s);
+                table.addCell(String.valueOf(aLong));
+            });
+            write(table.render());
+        });
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/managers/NewUserRegistrationManager.java b/src/main/java/com/comandante/creeper/managers/NewUserRegistrationManager.java
index 6185df31..ed068573 100644
--- a/src/main/java/com/comandante/creeper/managers/NewUserRegistrationManager.java
+++ b/src/main/java/com/comandante/creeper/managers/NewUserRegistrationManager.java
@@ -8,6 +8,7 @@ import com.comandante.creeper.player.PlayerRole;
 import com.comandante.creeper.player.PlayerStats;
 import com.comandante.creeper.server.CreeperSession;
 import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.jboss.netty.channel.MessageEvent;
 
@@ -63,7 +64,7 @@ public class NewUserRegistrationManager {
             return;
         }
         session.setPassword(Optional.of(password));
-        PlayerMetadata playerMetadata = new PlayerMetadata(session.getUsername().get(), session.getPassword().get(), Main.createPlayerId(session.getUsername().get()), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0]);
+        PlayerMetadata playerMetadata = new PlayerMetadata(session.getUsername().get(), session.getPassword().get(), Main.createPlayerId(session.getUsername().get()), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0], Maps.newHashMap());
         playerManager.savePlayerMetadata(playerMetadata);
         e.getChannel().write("User created.\r\n");
         session.setState(CreeperSession.State.newUserRegCompleted);
diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java
index 658b4664..d3d9f9d3 100644
--- a/src/main/java/com/comandante/creeper/npc/Npc.java
+++ b/src/main/java/com/comandante/creeper/npc/Npc.java
@@ -244,6 +244,7 @@ public class Npc extends CreeperEntity {
 
             long xpEarned = (long) (getNpcXp(playerLevel, npcLevel) * playerDamagePercentValue);
             p.addExperience(xpEarned);
+            p.addNpcKillLog(getName());
             gameManager.getChannelUtils().write(p.getPlayerId(), getBattleReport(xpEarned) + "\r\n", true);
         }
     }
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index 29e88507..504166ab 100755
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -19,13 +19,11 @@ import com.comandante.creeper.stat.StatsHelper;
 import com.comandante.creeper.world.Room;
 import com.google.common.base.Optional;
 import com.google.common.collect.*;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 import org.jboss.netty.channel.Channel;
-import org.nocrala.tools.texttablefmt.*;
+import org.nocrala.tools.texttablefmt.BorderStyle;
+import org.nocrala.tools.texttablefmt.ShownBorders;
 import org.nocrala.tools.texttablefmt.Table;
 
 import java.text.NumberFormat;
@@ -364,6 +362,14 @@ public class Player extends CreeperEntity {
         }
     }
 
+    public void addNpcKillLog(String npcName) {
+        synchronized (interner.intern(playerId)) {
+            PlayerMetadata playerMetadata = getPlayerMetadata();
+            playerMetadata.addNpcKill(npcName);
+            savePlayerMetadata(playerMetadata);
+        }
+    }
+
     public void transferItemFromLocker(String entityId) {
         synchronized (interner.intern(playerId)) {
             if (gameManager.acquireItem(this, entityId)) {
@@ -485,6 +491,12 @@ public class Player extends CreeperEntity {
         this.currentRoom = currentRoom;
     }
 
+    public Map<String, Long> getNpcKillLog() {
+        ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder();
+        getPlayerMetadata().getNpcKillLog().forEach((key, value) -> builder.put(key, value));
+        return builder.build();
+    }
+
     public void movePlayer(PlayerMovement playerMovement) {
         synchronized (interner.intern(playerId)) {
             Room sourceRoom = gameManager.getRoomManager().getRoom(playerMovement.getSourceRoomId());
diff --git a/src/main/java/com/comandante/creeper/player/PlayerMetadata.java b/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
index 8ed7a3b1..6dc03565 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
@@ -25,8 +25,9 @@ public class PlayerMetadata implements Serializable {
     private boolean isMarkedForDelete;
     private Map<String, String> playerSettings;
     private String[] learnedSpells;
+    private Map<String, Long> npcKillLog;
 
-    public PlayerMetadata(String playerName, String password, String playerId, Stats stats, int gold, Set<PlayerRole> playerRoleSet, String[] playerEquipment, int goldInBank, String[] learnedSpells) {
+    public PlayerMetadata(String playerName, String password, String playerId, Stats stats, int gold, Set<PlayerRole> playerRoleSet, String[] playerEquipment, int goldInBank, String[] learnedSpells, Map<String, Long> npcKillLog) {
         this.playerName = playerName;
         this.password = password;
         this.playerId = playerId;
@@ -36,6 +37,7 @@ public class PlayerMetadata implements Serializable {
         this.playerEquipment = playerEquipment;
         this.goldInBank = goldInBank;
         this.learnedSpells = learnedSpells;
+        this.npcKillLog = npcKillLog;
     }
 
     public PlayerMetadata(PlayerMetadata playerMetadata) {
@@ -61,12 +63,15 @@ public class PlayerMetadata implements Serializable {
             this.effects = Lists.newArrayList(playerMetadata.getEffects());
         }
         if (playerMetadata.playerSettings != null) {
-            this.playerSettings = new HashMap<String, String>(playerMetadata.getPlayerSettings());
+            this.playerSettings = new HashMap<>(playerMetadata.getPlayerSettings());
         }
         if (playerMetadata.learnedSpells != null) {
             this.learnedSpells = Arrays.copyOf(playerMetadata.learnedSpells, playerMetadata.learnedSpells.length);
         }
         this.isMarkedForDelete = new Boolean(playerMetadata.isMarkedForDelete);
+        if (playerMetadata.npcKillLog != null) {
+            this.npcKillLog = new HashMap<>(playerMetadata.getNpcKillLog());
+        }
     }
 
     public List<String> getInventory() {
@@ -97,6 +102,19 @@ public class PlayerMetadata implements Serializable {
         lockerInventory.add(newEntityId);
     }
 
+    protected void addNpcKill(String npcName) {
+        if (this.npcKillLog == null) {
+            npcKillLog = Maps.newHashMap();
+        }
+        if (npcKillLog.containsKey(npcName)) {
+            Long aLong = npcKillLog.get(npcName);
+            Long newLong = aLong + 1;
+            npcKillLog.put(npcName, newLong);
+        } else {
+            npcKillLog.put(npcName, 1L);
+        }
+    }
+
 
     protected void removeLockerEntityId(String newEntityId) {
         lockerInventory.remove(newEntityId);
@@ -191,6 +209,13 @@ public class PlayerMetadata implements Serializable {
         return learnedSpells;
     }
 
+    public Map<String, Long> getNpcKillLog() {
+        if (this.npcKillLog == null) {
+            npcKillLog = Maps.newHashMap();
+        }
+        return npcKillLog;
+    }
+
     protected void setGold(long amt) {
         this.gold = amt;
     }
diff --git a/src/test/com/comandante/creeper/player/NpcTestHarness.java b/src/test/com/comandante/creeper/player/NpcTestHarness.java
index 1b8e3389..1c45807f 100644
--- a/src/test/com/comandante/creeper/player/NpcTestHarness.java
+++ b/src/test/com/comandante/creeper/player/NpcTestHarness.java
@@ -191,7 +191,7 @@ public class NpcTestHarness {
     }
 
     private void createUser(String username, String password) {
-        PlayerMetadata playerMetadata = new PlayerMetadata(username, password, Main.createPlayerId(username), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0]);
+        PlayerMetadata playerMetadata = new PlayerMetadata(username, password, Main.createPlayerId(username), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0], Maps.newHashMap());
         gameManager.getPlayerManager().savePlayerMetadata(playerMetadata);
     }
 
-- 
GitLab