diff --git a/src/main/java/com/comandante/creeper/command/LookCommand.java b/src/main/java/com/comandante/creeper/command/LookCommand.java index 1a0062af9db8813e0b547cb4cce9b6b0448e7177..6c09973648ca77236ca7705c3b1d709698d52ac8 100644 --- a/src/main/java/com/comandante/creeper/command/LookCommand.java +++ b/src/main/java/com/comandante/creeper/command/LookCommand.java @@ -3,6 +3,7 @@ package com.comandante.creeper.command; import com.comandante.creeper.managers.GameManager; import com.comandante.creeper.npc.Npc; +import com.comandante.creeper.player.Levels; import com.comandante.creeper.player.Player; import com.google.common.base.Joiner; import org.jboss.netty.channel.ChannelHandlerContext; @@ -53,7 +54,7 @@ public class LookCommand extends Command { for (String npcId : npcIds) { Npc currentNpc = gameManager.getEntityManager().getNpcEntity(npcId); if (currentNpc.getValidTriggers().contains(target)) { - write(gameManager.getLookString(currentNpc) + "\r\n"); + write(gameManager.getLookString(currentNpc, Levels.getLevel(gameManager.getStatsModifierFactory().getStatsModifier(player).getExperience())) + "\r\n"); } } } finally { diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java index 215f741d70c0e6410a7e49ef65a1f532551798ae..ce01d8f30c48ae78f1533c73a1d5cd8e0d7d5ca2 100755 --- a/src/main/java/com/comandante/creeper/managers/GameManager.java +++ b/src/main/java/com/comandante/creeper/managers/GameManager.java @@ -410,10 +410,11 @@ public class GameManager { } } - public String getLookString(Npc npc) { + public String getLookString(Npc npc, long playerLevel) { StringBuilder sb = new StringBuilder(); // passing an empty createState because of the "difference calculation" sb.append(Color.MAGENTA + "-+=[ " + Color.RESET).append(npc.getColorName()).append(Color.MAGENTA + " ]=+- " + Color.RESET).append("\r\n"); + sb.append("Level ").append(Levels.getLevel(npc.getStats().getExperience())).append(" ").append(npc.getLevelColor((int) playerLevel).getColor()).append("\r\n"); sb.append(Color.MAGENTA + "Stats--------------------------------" + Color.RESET).append("\r\n"); sb.append(buildLookString(npc.getColorName(), npc.getStats(), new StatsBuilder().createStats())).append("\r\n"); if (npc.getEffects() != null && npc.getEffects().size() > 0) { @@ -616,13 +617,13 @@ public class GameManager { long amount = damageEntry.getValue(); double pct = (double) amount / totalDamageDone; if (pct >= .90) { - damagePcts.put(playerId, npc.getPctOFExperience(1, Levels.getLevel(playerMetadata.getStats().getExperience()))); + damagePcts.put(playerId, (double) 1); } else if (pct >= 0.25) { - damagePcts.put(playerId, npc.getPctOFExperience(.8, Levels.getLevel(playerMetadata.getStats().getExperience()))); + damagePcts.put(playerId, .8); } else if (pct >= 0.10) { - damagePcts.put(playerId, npc.getPctOFExperience(.5, Levels.getLevel(playerMetadata.getStats().getExperience()))); + damagePcts.put(playerId, .5); } else { - damagePcts.put(playerId, npc.getPctOFExperience(.25, Levels.getLevel(playerMetadata.getStats().getExperience()))); + damagePcts.put(playerId, .25); } } return damagePcts; diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java index 98ff0ac2bfc36fc656b5ed1cc6778b4a5c394ce1..1e8a1821122e6ab32cb78db78eb009fa63cdce29 100644 --- a/src/main/java/com/comandante/creeper/npc/Npc.java +++ b/src/main/java/com/comandante/creeper/npc/Npc.java @@ -9,6 +9,7 @@ import com.comandante.creeper.managers.GameManager; import com.comandante.creeper.managers.SentryManager; import com.comandante.creeper.player.CoolDown; import com.comandante.creeper.player.CoolDownType; +import com.comandante.creeper.player.Levels; import com.comandante.creeper.player.Player; import com.comandante.creeper.server.Color; import com.comandante.creeper.spawner.SpawnRule; @@ -79,6 +80,8 @@ public class Npc extends CreeperEntity { try { if (isAlive.get()) { if (effectsTickBucket == 5) { + + // START Process NPC Effects for (Effect effect : effects) { if (effect.getEffectApplications() >= effect.getMaxEffectApplications()) { Optional<Room> npcCurrentRoom = gameManager.getRoomManager().getNpcCurrentRoom(this); @@ -96,10 +99,13 @@ public class Npc extends CreeperEntity { gameManager.getEntityManager().saveEffect(effect); } } + // END Process Npc Effects + effectsTickBucket = 0; } else { effectsTickBucket++; } + List<NpcStatsChange> npcStatsChangeList = Lists.newArrayList(); npcStatsChanges.drainTo(npcStatsChangeList); for (NpcStatsChange npcStatsChange : npcStatsChangeList) { @@ -200,7 +206,7 @@ public class Npc extends CreeperEntity { public Optional<SpawnRule> getSpawnRuleByArea(Area area) { Set<SpawnRule> spawnRules = getSpawnRules(); - for (SpawnRule spawnRule: spawnRules) { + for (SpawnRule spawnRule : spawnRules) { if (spawnRule.getArea().equals(area)) { return Optional.of(spawnRule); } @@ -254,7 +260,7 @@ public class Npc extends CreeperEntity { if (!isActiveCooldown(CoolDownType.NPC_FIGHT)) { addCoolDown(new CoolDown(CoolDownType.NPC_FIGHT)); } else { - for (CoolDown coolDown: coolDowns) { + for (CoolDown coolDown : coolDowns) { if (coolDown.getCoolDownType().equals(CoolDownType.NPC_FIGHT)) { coolDown.setNumberOfTicks(coolDown.getOriginalNumberOfTicks()); } @@ -321,7 +327,6 @@ public class Npc extends CreeperEntity { } } catch (Exception e) { SentryManager.logSentry(this.getClass(), e, "Problem processing NPC Stat Change!"); - } } @@ -362,12 +367,12 @@ public class Npc extends CreeperEntity { private void killNpc(Player player) { isAlive.set(false); - Map<String, Double> xpProcessed; + Map<String, Double> damagePercents; Item corpse = new Item(getName() + " corpse", "a bloody corpse.", Arrays.asList("corpse", "c"), "a corpse lies on the ground.", UUID.randomUUID().toString(), Item.CORPSE_ID_RESERVED, 0, false, 120, Rarity.BASIC, 0, getLoot()); if (!player.isActive(CoolDownType.DEATH)) { gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), getDieMessage()); } - xpProcessed = gameManager.processExperience(this, getCurrentRoom()); + damagePercents = gameManager.processExperience(this, getCurrentRoom()); gameManager.getEntityManager().saveItem(corpse); Integer roomId = gameManager.getRoomManager().getNpcCurrentRoom(this).get().getRoomId(); Room room = gameManager.getRoomManager().getRoom(roomId); @@ -376,15 +381,140 @@ public class Npc extends CreeperEntity { getCurrentRoom().removePresentNpc(getEntityId()); gameManager.getEntityManager().deleteNpcEntity(getEntityId()); player.removeActiveFight(this); - for (Map.Entry<String, Double> playerDamageExperience : xpProcessed.entrySet()) { - Player p = gameManager.getPlayerManager().getPlayer(playerDamageExperience.getKey()); + for (Map.Entry<String, Double> playerDamagePercent : damagePercents.entrySet()) { + Player p = gameManager.getPlayerManager().getPlayer(playerDamagePercent.getKey()); if (p == null) { continue; } - long xpEarned = (long) Math.round(playerDamageExperience.getValue()); + Double playerDamagePercentValue = playerDamagePercent.getValue(); + + int playerLevel = (int) Levels.getLevel(gameManager.getStatsModifierFactory().getStatsModifier(player).getExperience()); + int npcLevel = (int) Levels.getLevel(this.getStats().getExperience()); + + long xpEarned = (long) (getNpcXp(playerLevel, npcLevel) * playerDamagePercentValue); p.addExperience(xpEarned); gameManager.getChannelUtils().write(p.getPlayerId(), getBattleReport(xpEarned) + "\r\n", true); } } + public static enum NpcLevelColor { + + RED(Color.RED + "Red"), + ORANGE(Color.CYAN + "Cyan"), + YELLOW(Color.YELLOW + "Yellow"), + GREEN(Color.GREEN + "Green"), + WHITE(Color.WHITE + "White"); + + private final String color; + + NpcLevelColor(String color) { + this.color = color; + } + + public String getColor() { + return "(" + Color.BOLD_ON + color + Color.RESET + ")"; + } + } + + public NpcLevelColor getLevelColor(int playerLevel) { + int npcLevel = (int) Levels.getLevel(this.getStats().getExperience()); + + if (playerLevel + 5 <= npcLevel) { + return NpcLevelColor.RED; + } else { + switch (npcLevel - playerLevel) { + case 4: + case 3: + return NpcLevelColor.ORANGE; + case 2: + case 1: + case 0: + case -1: + case -3: + return NpcLevelColor.YELLOW; + default: + if (playerLevel <= 5) { + return NpcLevelColor.GREEN; + } else { + if (playerLevel <= 50) { + if (npcLevel <= (playerLevel - 5 - Math.floor(playerLevel / 10))) { + return NpcLevelColor.WHITE; + } else { + return NpcLevelColor.GREEN; + } + } else { + // Player is over level 50 + if (npcLevel <= (playerLevel - 1 - Math.floor(playerLevel / 5))) { + return NpcLevelColor.WHITE; + } else { + return NpcLevelColor.GREEN; + } + } + } + } + } + } + + private int getNpcXp(int playerLevel, int npcLevel) { + if (npcLevel >= playerLevel) { + double temp = ((playerLevel * 5) + 45) * (1 + (0.05 * (npcLevel - playerLevel))); + double tempCap = ((playerLevel * 5) + 45) * 1.2; + if (temp > tempCap) { + return (int) Math.floor(tempCap); + } else { + return (int) Math.floor(temp); + } + } else { + if (getLevelColor(playerLevel).equals(NpcLevelColor.WHITE)) { + return 0; + } else { + return (int) (Math.floor((playerLevel * 5) + 45) * (1 - (playerLevel - npcLevel) / getZD(playerLevel))); + } + } + } + + private int getZD(int lvl) { + if (lvl <= 7) { + return 5; + } + if (lvl <= 9) { + return 6; + } + if (lvl <= 11) { + return 7; + } + if (lvl <= 15) { + return 8; + } + if (lvl <= 19) { + return 9; + } + if (lvl <= 29) { + return 11; + } + if (lvl <= 39) { + return 12; + } + if (lvl <= 49) { + return 13; + } + if (lvl <= 59) { + return 14; + } + if (lvl <= 69) { + return 15; + } + if (lvl <= 79) { + return 16; + } + if (lvl <= 89) { + return 17; + } + if (lvl <= 99) { + return 18; + } else { + return 19; + } + } + } diff --git a/src/main/java/com/comandante/creeper/player/Levels.java b/src/main/java/com/comandante/creeper/player/Levels.java index 123a27ebc3be3692f481d82eb4a3dbd531d90695..6eb9ca510aa63b96063b78b3283f7cbbc011e5c4 100644 --- a/src/main/java/com/comandante/creeper/player/Levels.java +++ b/src/main/java/com/comandante/creeper/player/Levels.java @@ -5,7 +5,7 @@ import static java.lang.StrictMath.sqrt; public class Levels { - private static double CONSTANT_MODIFIER = 0.005; + private static double CONSTANT_MODIFIER = 0.02; public static long getLevel(long experience) { double v = CONSTANT_MODIFIER * sqrt(experience); diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java index 4ed831d1e9de4311b904a64eeecd51f953a2f955..a3ded4048fddac62355cbdb929982a320504198b 100755 --- a/src/main/java/com/comandante/creeper/player/Player.java +++ b/src/main/java/com/comandante/creeper/player/Player.java @@ -2,6 +2,7 @@ package com.comandante.creeper.player; import com.codahale.metrics.Meter; +import com.comandante.creeper.Items.ForageManager; import com.comandante.creeper.Items.Item; import com.comandante.creeper.Items.ItemType; import com.comandante.creeper.Main; @@ -740,7 +741,7 @@ public class Player extends CreeperEntity { Stats diffStats = StatsHelper.getDifference(modifiedStats, origStats); sb.append(Color.MAGENTA + "-+=[ " + Color.RESET).append(playerName).append(Color.MAGENTA + " ]=+- " + Color.RESET).append("\r\n"); sb.append("Level ").append(Levels.getLevel(origStats.getExperience())).append("\r\n"); - sb.append("Foraging Level ").append(gameManager.getForageManager().getLevel(modifiedStats.getForaging())).append("\r\n"); + sb.append("Foraging Level ").append(ForageManager.getLevel(modifiedStats.getForaging())).append("\r\n"); sb.append(Color.MAGENTA + "Equip--------------------------------" + Color.RESET).append("\r\n"); sb.append(buildEquipmentString()).append("\r\n"); sb.append(Color.MAGENTA + "Stats--------------------------------" + Color.RESET).append("\r\n"); diff --git a/src/test/com/comandante/creeper/player/LevelsTest.java b/src/test/com/comandante/creeper/player/LevelsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dad461bc3c6d49157aace404fc3ae552c8967676 --- /dev/null +++ b/src/test/com/comandante/creeper/player/LevelsTest.java @@ -0,0 +1,30 @@ +package com.comandante.creeper.player; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class LevelsTest { + + @Test + public void testLevels() throws Exception { + for (int i = 0; i < 100; i++) { + long xp = Levels.getXp(i); + long level = Levels.getLevel(xp); + Assert.assertEquals(level, i); + System.out.println("Level: " + i + " | XP: " + xp); + } + } + + @Test + public void printHowMuchXpIsNecessaryToLevelUp() throws Exception { + for (int i = 0; i < 100; i++) { + long xp = Levels.getXp(i); + long level = Levels.getLevel(xp); + long xpNext = Levels.getXp(i + 1); + long l = xpNext - xp; + System.out.println("Level " + i + " to " + (i + 1) + " takes " + l + " xp."); + } + } +} \ No newline at end of file diff --git a/world/npcs/treeberserker.json b/world/npcs/treeberserker.json index fb4ff4f6494fc2722c337a23ec7313360289f498..099e28c6b13ee757057892989a33cdbee93544ea 100755 --- a/world/npcs/treeberserker.json +++ b/world/npcs/treeberserker.json @@ -16,7 +16,7 @@ "armorRating": 8, "currentHealth": 200, "currentMana": 100, - "experience": 150, + "experience": 22600, "maxHealth": 150, "maxMana": 100, "meleSkill": 6,