diff --git a/src/engine/Dungeons/Dungeon.java b/src/engine/Dungeons/Dungeon.java new file mode 100644 index 00000000..dc325f2f --- /dev/null +++ b/src/engine/Dungeons/Dungeon.java @@ -0,0 +1,150 @@ +package engine.Dungeons; + +import engine.Enum; +import engine.InterestManagement.WorldGrid; +import engine.gameManager.BuildingManager; +import engine.gameManager.PowersManager; +import engine.gameManager.ZoneManager; +import engine.math.Vector3fImmutable; +import engine.net.ByteBufferWriter; +import engine.objects.*; +import engine.powers.EffectsBase; +import engine.server.MBServerStatics; +import org.pmw.tinylog.Logger; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashSet; + +public class Dungeon { + + public static int NoFlyEffectID = -1733819072; + public static int NoTeleportEffectID = -1971545187; + public static int NoSummonEffectID = 2122002462; + public ArrayList participants; + public int maxPerGuild; + public Vector3fImmutable entrance; + public ArrayList dungeon_mobs; + public Long respawnTime = 0L; + + public Dungeon(Vector3fImmutable entrance, int maxCount){ + this.participants = new ArrayList<>(); + this.entrance = entrance; + this.dungeon_mobs = new ArrayList<>(); + this.maxPerGuild = maxCount; + } + public void applyDungeonEffects(PlayerCharacter player){ + EffectsBase noFly = PowersManager.getEffectByToken(NoFlyEffectID); + EffectsBase noTele = PowersManager.getEffectByToken(NoTeleportEffectID); + EffectsBase noSum = PowersManager.getEffectByToken(NoSummonEffectID); + + if(noFly != null) + player.addEffectNoTimer(noFly.getName(),noFly,40,true); + + if(noTele != null) + player.addEffectNoTimer(noTele.getName(),noTele,40,true); + + if(noSum != null) + player.addEffectNoTimer(noSum.getName(),noSum,40,true); + } + + public void removeDungeonEffects(PlayerCharacter player) { + EffectsBase noFly = PowersManager.getEffectByToken(NoFlyEffectID); + EffectsBase noTele = PowersManager.getEffectByToken(NoTeleportEffectID); + EffectsBase noSum = PowersManager.getEffectByToken(NoSummonEffectID); + for (Effect eff : player.effects.values()) { + if (noFly != null && eff.getEffectsBase().equals(noFly)) + eff.endEffect(); + + if (noTele != null && eff.getEffectsBase().equals(noTele)) + eff.endEffect(); + + if (noSum != null && eff.getEffectsBase().equals(noSum)) + eff.endEffect(); + } + } + + public static void serializeForClientMsgTeleport(ByteBufferWriter writer) { + Guild rulingGuild = Guild.getErrantGuild(); + Guild rulingNation = Guild.getErrantGuild(); + + Zone zone = ZoneManager.getZoneByUUID(994); + // Begin Serialzing soverign guild data + writer.putInt(Enum.GameObjectType.Zone.ordinal()); + writer.putInt(994); + writer.putString("Whitehorn Citadel"); + writer.putInt(rulingGuild.getObjectType().ordinal()); + writer.putInt(rulingGuild.getObjectUUID()); + + writer.putString("Whitehorn Militants"); // guild name + writer.putString("In the Citadel, We Fight!"); // motto + writer.putString(rulingGuild.getLeadershipType()); + + // Serialize guild ruler's name + // If tree is abandoned blank out the name + // to allow them a rename. + + writer.putString("Kol'roth The Destroyer");//sovreign + + writer.putInt(rulingGuild.getCharter()); + writer.putInt(0); // always 00000000 + + writer.put((byte)0); + + writer.put((byte) 1); + writer.put((byte) 1); // *** Refactor: What are these flags? + writer.put((byte) 1); + writer.put((byte) 1); + writer.put((byte) 1); + + GuildTag._serializeForDisplay(rulingGuild.getGuildTag(), writer); + GuildTag._serializeForDisplay(rulingNation.getGuildTag(), writer); + + writer.putInt(0);// TODO Implement description text + + writer.put((byte) 1); + writer.put((byte) 0); + writer.put((byte) 1); + + // Begin serializing nation guild info + + if (rulingNation.isEmptyGuild()) { + writer.putInt(rulingGuild.getObjectType().ordinal()); + writer.putInt(rulingGuild.getObjectUUID()); + } else { + writer.putInt(rulingNation.getObjectType().ordinal()); + writer.putInt(rulingNation.getObjectUUID()); + } + + + // Serialize nation name + + writer.putString("Whitehorn Militants"); //nation name + + writer.putInt(-1);//city rank, -1 puts it at top of list always + + writer.putInt(0xFFFFFFFF); + + writer.putInt(0); + + writer.putString("Kol'roth The Destroyer");//nation ruler + + writer.putLocalDateTime(LocalDateTime.now()); + + //location + Vector3fImmutable loc = Vector3fImmutable.getRandomPointOnCircle(BuildingManager.getBuilding(2827951).loc,30f); + + writer.putFloat(loc.x); + writer.putFloat(loc.y); + writer.putFloat(loc.z); + + writer.putInt(0); + + writer.put((byte) 1); + writer.put((byte) 0); + writer.putInt(0x64); + writer.put((byte) 0); + writer.put((byte) 0); + writer.put((byte) 0); + } +} diff --git a/src/engine/Dungeons/DungeonManager.java b/src/engine/Dungeons/DungeonManager.java new file mode 100644 index 00000000..65f8d2b3 --- /dev/null +++ b/src/engine/Dungeons/DungeonManager.java @@ -0,0 +1,105 @@ +package engine.Dungeons; + +import engine.Enum; +import engine.InterestManagement.WorldGrid; +import engine.gameManager.DbManager; +import engine.gameManager.ZoneManager; +import engine.math.Vector3fImmutable; +import engine.objects.*; +import engine.powers.EffectsBase; +import engine.server.MBServerStatics; + +import java.util.ArrayList; +import java.util.HashSet; + +public class DungeonManager { + public static ArrayList dungeons; + + private static final float dungeonAiRange = 64f; + private static final float maxTravel = 64f; + + public static void joinDungeon(PlayerCharacter pc, Dungeon dungeon){ + if(requestEnter(pc,dungeon)) { + dungeon.participants.add(pc); + dungeon.applyDungeonEffects(pc); + translocateToDungeon(pc, dungeon); + } + } + + public static void leaveDungeon(PlayerCharacter pc, Dungeon dungeon){ + dungeon.participants.remove(pc); + dungeon.removeDungeonEffects(pc); + translocateOutOfDungeon(pc); + } + + public static boolean requestEnter(PlayerCharacter pc, Dungeon dungeon){ + int current = 0; + Guild nation = pc.guild.getNation(); + + if(nation == null) + return false; + + for(PlayerCharacter participant : dungeon.participants){ + if(participant.guild.getNation().equals(nation)){ + current ++; + } + } + + if(current >= dungeon.maxPerGuild) + return false; + + return true; + } + + public static void translocateToDungeon(PlayerCharacter pc, Dungeon dungeon){ + pc.teleport(dungeon.entrance); + pc.setSafeMode(); + } + + public static void translocateOutOfDungeon(PlayerCharacter pc){ + pc.teleport(pc.bindLoc); + pc.setSafeMode(); + } + + public static void pulse_dungeons(){ + for(Dungeon dungeon : dungeons){ + + //early exit, if no players present don't waste resources + if(dungeon.participants.isEmpty()) + continue; + + if(dungeon.respawnTime > 0 && System.currentTimeMillis() > dungeon.respawnTime){ + respawnMobs(dungeon); + } + + //remove any players that have left + HashSet obj = WorldGrid.getObjectsInRangePartial(dungeon.entrance,4096f,MBServerStatics.MASK_PLAYER); + for(PlayerCharacter player : dungeon.participants) + if(!obj.contains(player)) + leaveDungeon(player,dungeon); + + //cycle dungeon mob AI + for(Mob mob : dungeon.dungeon_mobs) + dungeonMobAI(mob); + } + } + + public static void dungeonMobAI(Mob mob){ + + } + + public static void respawnMobs(Dungeon dungeon){ + for(Mob mob : dungeon.dungeon_mobs){ + + if(!mob.isAlive() && mob.despawned) + mob.respawn(); + + if(!mob.isAlive() && !mob.despawned){ + mob.despawn(); + mob.respawn(); + } + + } + } + +} diff --git a/src/engine/Enum.java b/src/engine/Enum.java index c464da5f..34560b52 100644 --- a/src/engine/Enum.java +++ b/src/engine/Enum.java @@ -150,7 +150,8 @@ public class Enum { NEPHFEMALE(2026, MonsterType.Nephilim, RunSpeed.STANDARD, CharacterSex.FEMALE, 1.1f), HALFGIANTFEMALE(2027, MonsterType.HalfGiant, RunSpeed.STANDARD, CharacterSex.FEMALE, 1.15f), VAMPMALE(2028, MonsterType.Vampire, RunSpeed.STANDARD, CharacterSex.MALE, 1), - VAMPFEMALE(2029, MonsterType.Vampire, RunSpeed.STANDARD, CharacterSex.FEMALE, 1); + VAMPFEMALE(2029, MonsterType.Vampire, RunSpeed.STANDARD, CharacterSex.FEMALE, 1), + SAETOR(1999,MonsterType.Minotaur, RunSpeed.MINOTAUR, CharacterSex.MALE,1); @SuppressWarnings("unchecked") private static HashMap _raceTypeByID = new HashMap<>(); @@ -170,8 +171,6 @@ public class Enum { } public static RaceType getRaceTypebyRuneID(int runeID) { - if(runeID == 1999) - return _raceTypeByID.get(2017); return _raceTypeByID.get(runeID); } diff --git a/src/engine/InterestManagement/InterestManager.java b/src/engine/InterestManagement/InterestManager.java index 854f0da9..e44da878 100644 --- a/src/engine/InterestManagement/InterestManager.java +++ b/src/engine/InterestManagement/InterestManager.java @@ -511,6 +511,18 @@ public enum InterestManager implements Runnable { if (player == null) return; + for(PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()){ + if(pc.equals(player)){ + try{ + WorldGrid.RemoveWorldObject(player); + }catch(Exception e){ + + } + } + } + + + ClientConnection origin = player.getClientConnection(); if (origin == null) diff --git a/src/engine/ZergMehcanics/MineAntiZerg.java b/src/engine/ZergMehcanics/MineAntiZerg.java new file mode 100644 index 00000000..95a378d7 --- /dev/null +++ b/src/engine/ZergMehcanics/MineAntiZerg.java @@ -0,0 +1,116 @@ +package engine.ZergMehcanics; + +import engine.InterestManagement.WorldGrid; +import engine.gameManager.BuildingManager; +import engine.gameManager.ZergManager; +import engine.objects.*; +import engine.server.MBServerStatics; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +public class MineAntiZerg { + + public static HashMap> leaveTimers = new HashMap<>(); + public static HashMap> currentPlayers = new HashMap<>(); + + public static void runMines(){ + for(Mine mine : Mine.getMines()){ + + Building tower = BuildingManager.getBuildingFromCache(mine.getBuildingID()); + + if(tower == null) + continue; + + if(!mine.isActive) + continue; + + logPlayersPresent(tower,mine); + + auditPlayersPresent(tower,mine); + + auditPlayers(mine); + } + } + + public static void logPlayersPresent(Building tower, Mine mine){ + HashSet loadedPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, MBServerStatics.CHARACTER_LOAD_RANGE * 3,MBServerStatics.MASK_PLAYER); + + ArrayList playersPresent = new ArrayList<>(); + for(AbstractWorldObject player : loadedPlayers){ + playersPresent.add((PlayerCharacter)player); + } + + currentPlayers.put(mine,playersPresent); + } + + public static void auditPlayersPresent(Building tower, Mine mine){ + HashSet loadedPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, MBServerStatics.CHARACTER_LOAD_RANGE * 3,MBServerStatics.MASK_PLAYER); + + ArrayList toRemove = new ArrayList<>(); + + for(PlayerCharacter player : currentPlayers.get(mine)){ + if(!loadedPlayers.contains(player)){ + toRemove.add(player); + } + } + + currentPlayers.get(mine).removeAll(toRemove); + + for(PlayerCharacter player : toRemove){ + if(leaveTimers.containsKey(mine)){ + leaveTimers.get(mine).put(player,System.currentTimeMillis()); + }else{ + HashMap leaveTime = new HashMap<>(); + leaveTime.put(player,System.currentTimeMillis()); + leaveTimers.put(mine,leaveTime); + } + } + + toRemove.clear(); + + for(PlayerCharacter player : leaveTimers.get(mine).keySet()){ + long timeGone = System.currentTimeMillis() - leaveTimers.get(mine).get(player); + if(timeGone > 180000L) {//3 minutes + toRemove.add(player); + player.ZergMultiplier = 1.0f; + } + } + + for(PlayerCharacter player : toRemove) { + leaveTimers.get(mine).remove(player); + } + } + + public static void auditPlayers(Mine mine){ + + HashMap> playersByNation = new HashMap<>(); + + for(PlayerCharacter player : currentPlayers.get(mine)){ + if(playersByNation.containsKey(player.guild.getNation())){ + playersByNation.get(player.guild.getNation()).add(player); + }else{ + ArrayList players = new ArrayList<>(); + players.add(player); + playersByNation.put(player.guild.getNation(),players); + } + } + + for(PlayerCharacter player : leaveTimers.get(mine).keySet()){ + if(playersByNation.containsKey(player.guild.getNation())){ + playersByNation.get(player.guild.getNation()).add(player); + }else{ + ArrayList players = new ArrayList<>(); + players.add(player); + playersByNation.put(player.guild.getNation(),players); + } + } + + for(Guild nation : playersByNation.keySet()){ + for(PlayerCharacter player : playersByNation.get(nation)){ + player.ZergMultiplier = ZergManager.getCurrentMultiplier(playersByNation.get(nation).size(), mine.capSize); + } + } + } +} diff --git a/src/engine/db/handlers/dbAccountHandler.java b/src/engine/db/handlers/dbAccountHandler.java index f34ebe60..987562eb 100644 --- a/src/engine/db/handlers/dbAccountHandler.java +++ b/src/engine/db/handlers/dbAccountHandler.java @@ -13,14 +13,13 @@ import engine.Enum; import engine.Enum.GameObjectType; import engine.gameManager.ConfigManager; import engine.gameManager.DbManager; +import engine.net.DispatchMessage; +import engine.net.client.msg.chat.ChatSystemMsg; import engine.objects.Account; import engine.objects.PlayerCharacter; import org.pmw.tinylog.Logger; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; import java.util.ArrayList; public class dbAccountHandler extends dbHandlerBase { @@ -77,18 +76,24 @@ public class dbAccountHandler extends dbHandlerBase { } } - public void SET_TRASH(String machineID) { - + public void SET_TRASH(String machineID, String type) { try (Connection connection = DbManager.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO dyn_trash(`machineID`, `count`)" - + " VALUES (?, 1) ON DUPLICATE KEY UPDATE `count` = `count` + 1;")) { + PreparedStatement preparedStatement = connection.prepareStatement( + "INSERT INTO dyn_trash(`machineID`, `count`, `type`)" + + " VALUES (?, 1, ?) ON DUPLICATE KEY UPDATE `count` = `count` + 1;")) { preparedStatement.setString(1, machineID); + preparedStatement.setString(2, type); preparedStatement.execute(); } catch (SQLException e) { Logger.error(e); } + + ChatSystemMsg chatMsg = new ChatSystemMsg(null, "Account: " + machineID + " has been kicked from game for cheating"); + chatMsg.setMessageType(10); + chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID()); + DispatchMessage.dispatchMsgToAll(chatMsg); } public ArrayList GET_TRASH_LIST() { @@ -270,4 +275,21 @@ public class dbAccountHandler extends dbHandlerBase { } } + public void TRASH_CHEATERS() { + try (Connection connection = DbManager.getConnection(); + CallableStatement callableStatement = connection.prepareCall("{CALL BanAccountsWithMachineID()}")) { + + boolean hasResultSet = callableStatement.execute(); + + if (!hasResultSet && callableStatement.getUpdateCount() > 0) { + Logger.info("TRASHED CHEATERS"); + } else { + Logger.warn("No cheaters to trash."); + } + + } catch (SQLException e) { + Logger.error("Error trashing cheaters: ", e); + } + } + } diff --git a/src/engine/devcmd/cmds/DungenonCmd.java b/src/engine/devcmd/cmds/DungenonCmd.java new file mode 100644 index 00000000..39ea68c4 --- /dev/null +++ b/src/engine/devcmd/cmds/DungenonCmd.java @@ -0,0 +1,54 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2022 +// www.magicbane.com + + +package engine.devcmd.cmds; + +import engine.Dungeons.DungeonManager; +import engine.Enum.GameObjectType; +import engine.devcmd.AbstractDevCmd; +import engine.gameManager.BuildingManager; +import engine.gameManager.ChatManager; +import engine.gameManager.DbManager; +import engine.gameManager.ZoneManager; +import engine.math.Vector3fImmutable; +import engine.objects.*; +import org.pmw.tinylog.Logger; + +/** + * @author Eighty + */ +public class DungenonCmd extends AbstractDevCmd { + + public DungenonCmd() { + super("dungeon"); + } + + @Override + protected void _doCmd(PlayerCharacter pc, String[] words, + AbstractGameObject target) { + + Zone parent = ZoneManager.findSmallestZone(pc.loc); + if(parent == null) + return; + + Vector3fImmutable loc = Vector3fImmutable.getRandomPointOnCircle(BuildingManager.getBuilding(2827951).loc,30f); + pc.teleport(loc); + } + + @Override + protected String _getHelpString() { + return "indicate mob or building followed by an id and a level"; + } + + @Override + protected String _getUsageString() { + return "'/dungeon mob 2001 10'"; + } + +} diff --git a/src/engine/devcmd/cmds/InfoCmd.java b/src/engine/devcmd/cmds/InfoCmd.java index edd10365..0f80bb00 100644 --- a/src/engine/devcmd/cmds/InfoCmd.java +++ b/src/engine/devcmd/cmds/InfoCmd.java @@ -335,15 +335,18 @@ public class InfoCmd extends AbstractDevCmd { output += "Movement State: " + targetPC.getMovementState().name(); output += newline; output += "Movement Speed: " + targetPC.getSpeed(); - + output += newline; output += "Altitude : " + targetPC.getLoc().y; - + output += newline; output += "Swimming : " + targetPC.isSwimming(); output += newline; output += "isMoving : " + targetPC.isMoving(); output += newline; - output += "Zerg Multiplier : " + targetPC.ZergMultiplier+ newline; - output += "Hidden : " + targetPC.getHidden(); + output += "Zerg Multiplier : " + targetPC.ZergMultiplier + newline; + output += "Hidden : " + targetPC.getHidden() + newline; + output += "Target Loc: " + targetPC.loc + newline; + output += "Player Loc: " + pc.loc + newline; + output += "Distance Squared: " + pc.loc.distanceSquared(targetPC.loc); break; case NPC: diff --git a/src/engine/devcmd/cmds/PrintStatsCmd.java b/src/engine/devcmd/cmds/PrintStatsCmd.java index 3ee4c596..ef49b3cf 100644 --- a/src/engine/devcmd/cmds/PrintStatsCmd.java +++ b/src/engine/devcmd/cmds/PrintStatsCmd.java @@ -11,6 +11,7 @@ package engine.devcmd.cmds; import engine.Enum; import engine.devcmd.AbstractDevCmd; +import engine.gameManager.PowersManager; import engine.objects.*; import java.util.HashMap; @@ -86,6 +87,12 @@ public class PrintStatsCmd extends AbstractDevCmd { newOut += "MAX: " + tar.combatStats.maxDamageHandTwo + newline; newOut += "RANGE: " + tar.combatStats.rangeHandTwo + newline; newOut += "ATTACK SPEED: " + tar.combatStats.attackSpeedHandTwo + newline; + newOut += "=== POWERS ===" + newline; + for(CharacterPower power : pc.getPowers().values()){ + if(power.getPower().requiresHitRoll) { + newOut += power.getPower().name + " ATR: " + Math.round(PlayerCombatStats.getSpellAtr(pc,power.getPower())) + newline; + } + } throwbackInfo(pc, newOut); } diff --git a/src/engine/gameManager/CombatManager.java b/src/engine/gameManager/CombatManager.java index 32367e01..51e95243 100644 --- a/src/engine/gameManager/CombatManager.java +++ b/src/engine/gameManager/CombatManager.java @@ -8,6 +8,7 @@ package engine.gameManager; +import engine.Enum; import engine.Enum.*; import engine.exception.MsgSendException; import engine.job.JobContainer; @@ -26,7 +27,6 @@ import engine.powers.effectmodifiers.WeaponProcEffectModifier; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; -import java.util.HashSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; @@ -304,6 +304,9 @@ public enum CombatManager { //pet to assist in attacking target if(abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)){ PlayerCharacter attacker = (PlayerCharacter)abstractCharacter; + if(attacker.combatStats == null){ + attacker.combatStats = new PlayerCombatStats(attacker); + } if(attacker.getPet() != null){ Mob pet = attacker.getPet(); if(pet.combatTarget == null && pet.assist) @@ -327,10 +330,13 @@ public enum CombatManager { else if (!tar.isActive()) return 0; - if (target.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getTimers().get("Attack" + slot) == null) + if (target.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getTimers().get("Attack" + slot) == null) { + if(((PlayerCharacter)target).combatStats == null){ + ((PlayerCharacter)target).combatStats = new PlayerCombatStats(((PlayerCharacter)target)); + } if (!((PlayerCharacter) abstractCharacter).canSee((PlayerCharacter) target)) return 0; - + } //must not be immune to all or immune to attack Resists res = tar.getResists(); @@ -463,6 +469,17 @@ public enum CombatManager { //Range check. + if(abstractCharacter.isMoving()){ + range += (abstractCharacter.getSpeed() * 0.1f); + } + + if(AbstractWorldObject.IsAbstractCharacter(target)) { + AbstractCharacter tarAc = (AbstractCharacter) target; + if(tarAc != null && tarAc.isMoving()){ + range += (tarAc.getSpeed() * 0.1f); + } + } + if (NotInRange(abstractCharacter, target, range)) { //target is in stealth and can't be seen by source @@ -555,8 +572,12 @@ public enum CombatManager { if (target == null) return; + if(ac.getObjectType().equals(GameObjectType.PlayerCharacter)){ PlayerCharacter pc = (PlayerCharacter) ac; + if( pc.combatStats == null){ + pc.combatStats = new PlayerCombatStats(pc); + } pc.combatStats.calculateATR(true); pc.combatStats.calculateATR(false); if (mainHand) { @@ -672,6 +693,9 @@ public enum CombatManager { } else { AbstractCharacter tar = (AbstractCharacter) target; if(tar.getObjectType().equals(GameObjectType.PlayerCharacter)){ + if(((PlayerCharacter)tar).combatStats == null){ + ((PlayerCharacter)tar).combatStats = new PlayerCombatStats((PlayerCharacter)tar); + } ((PlayerCharacter)tar).combatStats.calculateDefense(); defense = ((PlayerCharacter)tar).combatStats.defense; }else { @@ -730,6 +754,18 @@ public enum CombatManager { PlayerBonuses bonus = ac.getBonuses(); float attackRange = getWeaponRange(wb, bonus); + + if(ac.isMoving()){ + attackRange += (ac.getSpeed() * 0.1f); + } + + if(AbstractWorldObject.IsAbstractCharacter(target)) { + //AbstractCharacter tarAc = (AbstractCharacter) target; + if(tarAc != null && tarAc.isMoving()){ + attackRange += (tarAc.getSpeed() * 0.1f); + } + } + if(specialCaseHitRoll(dpj.getPowerToken())) { if(hitLanded) { dpj.attack(target, attackRange); @@ -751,6 +787,18 @@ public enum CombatManager { if (dpj != null && dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) { float attackRange = getWeaponRange(wb, bonuses); + + if(ac.isMoving()){ + attackRange += (ac.getSpeed() * 0.1f); + } + + if(AbstractWorldObject.IsAbstractCharacter(target)) { + //AbstractCharacter tarAc = (AbstractCharacter) target; + if(tarAc != null && tarAc.isMoving()){ + attackRange += (tarAc.getSpeed() * 0.1f); + } + } + if(specialCaseHitRoll(dpj.getPowerToken())) { if(hitLanded) { dpj.attack(target, attackRange); @@ -869,15 +917,14 @@ public enum CombatManager { for(Effect eff : weapon.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(ModType.ArmorPiercing)){ - armorPierce += mod.minMod * (mod.getRamp() * eff.getTrains()); + armorPierce += mod.getPercentMod() + (mod.getRamp() * eff.getTrains()); } } } if(armorPierce > 0){ - damage *= 1 - armorPierce; + damage *= 1 + (armorPierce * 0.01f); } } - //Resists.handleFortitude(tarAc,damageType,damage); float d = 0f; @@ -899,6 +946,8 @@ public enum CombatManager { if (tarAc.getHealth() > 0) d = tarAc.modifyHealth(-damage, ac, false); + tarAc.cancelOnTakeDamage(); + } else if (target.getObjectType().equals(GameObjectType.Building)) { if (BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { @@ -929,26 +978,7 @@ public enum CombatManager { errorTrack = 14; //handle procs - - if (weapon != null && tarAc != null && tarAc.isAlive()) { - - if(weapon.effects != null){ - for (Effect eff : weapon.effects.values()){ - for(AbstractEffectModifier mod : eff.getEffectModifiers()){ - if(mod.modType.equals(ModType.WeaponProc)){ - int procChance = ThreadLocalRandom.current().nextInt(100); - if (procChance < MBServerStatics.PROC_CHANCE) { - try { - ((WeaponProcEffectModifier) mod).applyProc(ac, target); - }catch(Exception e){ - Logger.error(eff.getName() + " Failed To Cast Proc"); - } - } - } - } - } - } - } + procChanceHandler(weapon,ac,tarAc); errorTrack = 15; @@ -957,6 +987,16 @@ public enum CombatManager { if (ac.isAlive() && tarAc != null && tarAc.isAlive()) handleDamageShields(ac, tarAc, damage); + //handle mob hate values + if(target.getObjectType().equals(GameObjectType.Mob) && ac.getObjectType().equals(GameObjectType.PlayerCharacter)){ + Mob mobTarget = (Mob)target; + if(mobTarget.hate_values.containsKey((PlayerCharacter) ac)){ + mobTarget.hate_values.put((PlayerCharacter) ac,mobTarget.hate_values.get((PlayerCharacter) ac) + damage); + }else{ + mobTarget.hate_values.put((PlayerCharacter) ac, damage); + } + } + } else { // Apply Weapon power effect if any. @@ -972,6 +1012,19 @@ public enum CombatManager { if (wp.requiresHitRoll() == false) { PlayerBonuses bonus = ac.getBonuses(); float attackRange = getWeaponRange(wb, bonus); + + if(ac.isMoving()){ + attackRange += (ac.getSpeed() * 0.1f); + } + + if(AbstractWorldObject.IsAbstractCharacter(target)) { + AbstractCharacter tarAc = (AbstractCharacter) target; + if(tarAc != null && tarAc.isMoving()){ + attackRange += (tarAc.getSpeed() * 0.1f); + } + } + + if(specialCaseHitRoll(dpj.getPowerToken())) { if(hitLanded) { dpj.attack(target, attackRange); @@ -1009,6 +1062,41 @@ public enum CombatManager { } } + private static void procChanceHandler(Item weapon, AbstractCharacter ac, AbstractCharacter tarAc) { + + //no weapon means no proc + if(weapon == null) + return; + + //caster is dead of null, no proc + if(ac == null || !ac.isAlive()) + return; + + //target is dead or null, no proc + if(tarAc == null || !tarAc.isAlive()) + return; + + //no effects on weapon, skip proc + if(weapon.effects == null || weapon.effects.isEmpty()) + return; + + for (Effect eff : weapon.effects.values()){ + for(AbstractEffectModifier mod : eff.getEffectModifiers()) { + if (mod.modType.equals(ModType.WeaponProc)) { + int procChance = ThreadLocalRandom.current().nextInt(100); + if (procChance < MBServerStatics.PROC_CHANCE) { + try { + ((WeaponProcEffectModifier) mod).applyProc(ac, tarAc); + break; + } catch (Exception e) { + Logger.error(eff.getName() + " Failed To Cast Proc"); + } + } + } + } + } + } + public static boolean canTestParry(AbstractCharacter ac, AbstractWorldObject target) { if (ac == null || target == null || !AbstractWorldObject.IsAbstractCharacter(target)) @@ -1027,6 +1115,12 @@ public enum CombatManager { Item tarMain = tarItem.getItemFromEquipped(1); Item tarOff = tarItem.getItemFromEquipped(2); + if(target.getObjectType().equals(GameObjectType.PlayerCharacter)){ + PlayerCharacter pc = (PlayerCharacter) target; + if(pc.getRaceID() == 1999 && !isRanged(acMain) && !isRanged(acOff)) + return true; + } + return !isRanged(acMain) && !isRanged(acOff) && !isRanged(tarMain) && !isRanged(tarOff); } diff --git a/src/engine/gameManager/DevCmdManager.java b/src/engine/gameManager/DevCmdManager.java index 1016bfcf..ed1cc819 100644 --- a/src/engine/gameManager/DevCmdManager.java +++ b/src/engine/gameManager/DevCmdManager.java @@ -85,6 +85,7 @@ public enum DevCmdManager { DevCmdManager.registerDevCmd(new AddBuildingCmd()); DevCmdManager.registerDevCmd(new AddNPCCmd()); DevCmdManager.registerDevCmd(new AddMobCmd()); + DevCmdManager.registerDevCmd(new DungenonCmd()); DevCmdManager.registerDevCmd(new RemoveObjectCmd()); DevCmdManager.registerDevCmd(new RotateCmd()); DevCmdManager.registerDevCmd(new FlashMsgCmd()); diff --git a/src/engine/gameManager/LootManager.java b/src/engine/gameManager/LootManager.java index 8b3ff967..0397cd2d 100644 --- a/src/engine/gameManager/LootManager.java +++ b/src/engine/gameManager/LootManager.java @@ -14,6 +14,7 @@ import engine.net.DispatchMessage; import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.chat.ChatSystemMsg; import engine.objects.*; +import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.util.ArrayList; @@ -42,6 +43,15 @@ public enum LootManager { public static final ArrayList vorg_cloth_uuids = new ArrayList<>(Arrays.asList(27600,188700,188720,189550,189560)); public static final ArrayList racial_guard_uuids = new ArrayList<>(Arrays.asList(841,951,952,1050,1052,1180,1182,1250,1252,1350,1352,1450,1452,1500,1502,1525,1527,1550,1552,1575,1577,1600,1602,1650,1652,1700,980100,980102)); + public static final ArrayList static_rune_ids = new ArrayList<>(Arrays.asList( + 250001, 250002, 250003, 250004, 250005, 250006, 250007, 250008, 250010, 250011, + 250012, 250013, 250014, 250015, 250016, 250017, 250019, 250020, 250021, 250022, + 250023, 250024, 250025, 250026, 250028, 250029, 250030, 250031, 250032, 250033, + 250034, 250035, 250037, 250038, 250039, 250040, 250041, 250042, 250043, 250044, + 250115, 250118, 250119, 250120, 250121, 250122, 252123, 252124, 252125, 252126, + 252127 + )); + // Drop Rates public static float NORMAL_DROP_RATE; @@ -258,33 +268,40 @@ public enum LootManager { } public static void SpecialCaseRuneDrop(Mob mob,ArrayList entries){ - int lootTableID = 0; - for(BootySetEntry entry : entries){ - if(entry.bootyType.equals("LOOT")){ - lootTableID = entry.genTable; - break; - } - } - - if(lootTableID == 0) - return; + //int lootTableID = 0; + //for(BootySetEntry entry : entries){ + // if(entry.bootyType.equals("LOOT")){ + // lootTableID = entry.genTable; + // break; + // } + //} + + // if(lootTableID == 0) + // return; + + //int RuneTableID = 0; + //for(GenTableEntry entry : _genTables.get(lootTableID)){ + // try { + // if (ItemBase.getItemBase(_itemTables.get(entry.itemTableID).get(0).cacheID).getType().equals(Enum.ItemType.RUNE)) { + // RuneTableID = entry.itemTableID; + // break; + // } + // }catch(Exception e){ + + // } + //} + + //if(RuneTableID == 0) + // return; + + int roll = ThreadLocalRandom.current().nextInt(static_rune_ids.size() + 1); + int itemId = static_rune_ids.get(0); + try { + itemId = static_rune_ids.get(roll); + }catch(Exception e){ - int RuneTableID = 0; - for(GenTableEntry entry : _genTables.get(lootTableID)){ - try { - if (ItemBase.getItemBase(_itemTables.get(entry.itemTableID).get(0).cacheID).getType().equals(Enum.ItemType.RUNE)) { - RuneTableID = entry.itemTableID; - break; - } - }catch(Exception e){ - - } } - - if(RuneTableID == 0) - return; - - ItemBase ib = ItemBase.getItemBase(rollRandomItem(RuneTableID)); + ItemBase ib = ItemBase.getItemBase(itemId); if(ib != null){ MobLoot toAdd = new MobLoot(mob,ib,false); mob.getCharItemManager().addItemToInventory(toAdd); @@ -460,7 +477,27 @@ public enum LootManager { if (suffixMod == null) return inItem; - if (suffixMod.action.length() > 0) { + int moveSpeedRoll = ThreadLocalRandom.current().nextInt(100); + if(inItem.getItemBase().getValidSlot() == MBServerStatics.SLOT_FEET && moveSpeedRoll < 10){ + int rankRoll = ThreadLocalRandom.current().nextInt(10); + String suffixSpeed = "SUF-148"; + switch(rankRoll) { + case 1: + case 2: + case 3: + suffixSpeed = "SUF-149"; + break; + case 4: + case 5: + case 6: + case 7: + suffixSpeed = "SUF-150"; + break; + + } + inItem.setSuffix(suffixSpeed); + inItem.addPermanentEnchantment(suffixSpeed, 0, suffixMod.level, false); + }else if (suffixMod.action.length() > 0) { inItem.setSuffix(suffixMod.action); inItem.addPermanentEnchantment(suffixMod.action, 0, suffixMod.level, false); } @@ -572,7 +609,7 @@ public enum LootManager { ItemBase itemBase = me.getItemBase(); if(isVorg) { mob.spawnTime = ThreadLocalRandom.current().nextInt(300, 2700); - dropChance = 10; + dropChance = 7.5f; itemBase = getRandomVorg(itemBase); } if (equipmentRoll > dropChance) @@ -605,6 +642,82 @@ public enum LootManager { } } + public static void newFatePeddler(PlayerCharacter playerCharacter, Item gift) { + + CharacterItemManager itemMan = playerCharacter.getCharItemManager(); + + if (itemMan == null) + return; + + //check if player owns the gift he is trying to open + + if (!itemMan.doesCharOwnThisItem(gift.getObjectUUID())) + return; + + ItemBase ib = gift.getItemBase(); + + MobLoot winnings = null; + + if (ib == null) + return; + switch (ib.getUUID()) { + case 971070: //wrapped rune + ItemBase runeBase = null; + int roll = ThreadLocalRandom.current().nextInt(static_rune_ids.size() + 1); + int itemId = static_rune_ids.get(0); + try { + itemId = static_rune_ids.get(roll); + }catch(Exception e){ + + } + runeBase = ItemBase.getItemBase(itemId); + if(runeBase != null) { + winnings = new MobLoot(playerCharacter, runeBase, 1, false); + } + break; + case 971012: //wrapped glass + int chance = ThreadLocalRandom.current().nextInt(100); + if(chance == 50){ + int ID = 7000000; + int additional = ThreadLocalRandom.current().nextInt(0,28); + ID += (additional * 10); + ItemBase glassBase = ItemBase.getItemBase(ID); + if(glassBase != null) { + winnings = new MobLoot(playerCharacter, glassBase, 1, false); + ChatManager.chatSystemInfo(playerCharacter, "You've Won A " + glassBase.getName()); + } + }else{ + ChatManager.chatSystemInfo(playerCharacter, "Please Try Again!"); + } + break; + } + + if (winnings == null) { + itemMan.consume(gift); + itemMan.updateInventory(); + return; + } + + //early exit if the inventory of the player will not hold the item + + if (!itemMan.hasRoomInventory(winnings.getItemBase().getWeight())) { + ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); + return; + } + + winnings.setIsID(true); + + //remove gift from inventory + + itemMan.consume(gift); + + //add winnings to player inventory + + Item playerWinnings = winnings.promoteToItem(playerCharacter); + itemMan.addItemToInventory(playerWinnings); + itemMan.updateInventory(); + + } public static void peddleFate(PlayerCharacter playerCharacter, Item gift) { //get table ID for the itembase ID @@ -708,7 +821,7 @@ public enum LootManager { public static ItemBase getRandomVorg(ItemBase itemBase){ int roll = 0; if(vorg_ha_uuids.contains(itemBase.getUUID())) { - roll = ThreadLocalRandom.current().nextInt(0, 10); + roll = ThreadLocalRandom.current().nextInt(0, 9); switch (roll) { case 1: return ItemBase.getItemBase(vorg_ha_uuids.get(0)); @@ -732,7 +845,7 @@ public enum LootManager { } if(vorg_ma_uuids.contains(itemBase.getUUID())) { - roll = ThreadLocalRandom.current().nextInt(0, 10); + roll = ThreadLocalRandom.current().nextInt(0, 8); switch (roll) { case 1: return ItemBase.getItemBase(vorg_ma_uuids.get(0)); @@ -754,7 +867,7 @@ public enum LootManager { } if(vorg_la_uuids.contains(itemBase.getUUID())) { - roll = ThreadLocalRandom.current().nextInt(0, 10); + roll = ThreadLocalRandom.current().nextInt(0, 8); switch (roll) { case 1: return ItemBase.getItemBase(vorg_la_uuids.get(0)); @@ -776,7 +889,7 @@ public enum LootManager { } if(vorg_cloth_uuids.contains(itemBase.getUUID())) { - roll = ThreadLocalRandom.current().nextInt(0, 10); + roll = ThreadLocalRandom.current().nextInt(0, 5); switch (roll) { case 1: return ItemBase.getItemBase(vorg_cloth_uuids.get(0)); diff --git a/src/engine/gameManager/PowersManager.java b/src/engine/gameManager/PowersManager.java index b8d0bcb5..f121bdd3 100644 --- a/src/engine/gameManager/PowersManager.java +++ b/src/engine/gameManager/PowersManager.java @@ -28,6 +28,7 @@ import engine.net.client.ClientConnection; import engine.net.client.msg.*; import engine.objects.*; import engine.powers.*; +import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.TrackPowerAction; import engine.server.MBServerStatics; @@ -174,12 +175,34 @@ public enum PowersManager { if(pc.isMoving()) pc.stopMovement(pc.getMovementLoc()); + if(msg.getPowerUsedID() != 421084024 && origin.getPlayerCharacter().getPromotionClassID() != 2513) { + if (!origin.getPlayerCharacter().getPowers().containsKey(msg.getPowerUsedID())) { + Logger.error(origin.getPlayerCharacter().getFirstName() + " attempted to cast a power they do not have"); + return; + } + } + //crusader sacrifice + if((msg.getPowerUsedID() == 428695403 && msg.getTargetID() == pc.getObjectUUID())){ + RecyclePowerMsg recyclePowerMsg = new RecyclePowerMsg(msg.getPowerUsedID()); + Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), recyclePowerMsg); + DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); - if(msg.getPowerUsedID() == 429429978){ - applyPower(origin.getPlayerCharacter(),origin.getPlayerCharacter(),origin.getPlayerCharacter().getLoc(),429429978,msg.getNumTrains(),false); + // Send Fail to cast message + if (pc != null) { + sendPowerMsg(pc, 2, msg); + if (pc.isCasting()) { + pc.update(false); + } + + pc.setIsCasting(false); + } return; } + if(msg.getPowerUsedID() == -1851459567){//backstab + applyPower(pc,pc,pc.loc,-1851459567,msg.getNumTrains(),false); + } + if (usePowerA(msg, origin, sendCastToSelf)) { // Cast failed for some reason, reset timer @@ -198,6 +221,10 @@ public enum PowersManager { } } + + if(msg.getPowerUsedID() == 429429978){ + origin.getPlayerCharacter().getRecycleTimers().remove(429429978); + } } public static void useMobPower(Mob caster, AbstractCharacter target, PowersBase pb, int rank) { @@ -825,7 +852,6 @@ public enum PowersManager { if (playerCharacter == null || msg == null) return; - //handle sprint for bard sprint if(msg.getPowerUsedID() == 429005674){ msg.setPowerUsedID(429611355); @@ -851,7 +877,7 @@ public enum PowersManager { if(msg.getTargetType() == GameObjectType.PlayerCharacter.ordinal()) { PlayerCharacter target = PlayerCharacter.getPlayerCharacter(msg.getTargetID()); if (msg.getPowerUsedID() == 429601664) - if(target.getPromotionClassID() != 2516) + if(target.getPromotionClassID() != 2516)//templar PlayerCharacter.getPlayerCharacter(msg.getTargetID()).removeEffectBySource(EffectSourceType.Transform, msg.getNumTrains(), true); } @@ -896,6 +922,9 @@ public enum PowersManager { return; } + if(pb.targetSelf) + msg.setTargetID(playerCharacter.getObjectUUID()); + int trains = msg.getNumTrains(); // verify player is not stunned or power type is blocked @@ -1152,7 +1181,18 @@ public enum PowersManager { //DispatchMessage.dispatchMsgToInterestArea(playerCharacter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - +//handle mob hate values + HashSet mobs = WorldGrid.getObjectsInRangePartial(playerCharacter.loc,60.0f,MBServerStatics.MASK_MOB); + for(AbstractWorldObject awo : mobs){ + Mob mobTarget = (Mob)awo; + if(mobTarget.hate_values != null) { + if (mobTarget.hate_values.containsKey(playerCharacter)) { + mobTarget.hate_values.put(playerCharacter, mobTarget.hate_values.get(playerCharacter) + pb.getHateValue(trains)); + } else { + mobTarget.hate_values.put(playerCharacter, pb.getHateValue(trains)); + } + } + } } @@ -1623,18 +1663,28 @@ public enum PowersManager { // create list of characters HashSet trackChars; - switch(msg.getPowerToken()){ - case 431511776: - case 429578587: - case 429503360: - case 44106356: - trackChars = getTrackList(playerCharacter); - break; - default: - trackChars = RangeBasedAwo.getTrackList(allTargets, playerCharacter, maxTargets); - break; + + PowersBase trackPower = PowersManager.getPowerByToken(msg.getPowerToken()); + if(trackPower != null && trackPower.category.equals("TRACK")){ + trackChars = getTrackList(playerCharacter); + }else{ + trackChars = RangeBasedAwo.getTrackList(allTargets, playerCharacter, maxTargets); } + + + //switch(msg.getPowerToken()){ + // case 431511776: // Hunt Foe Huntress + // case 429578587: // Hunt Foe Scout + // case 429503360: // Track Huntsman + // case 44106356: // + // trackChars = getTrackList(playerCharacter); + // break; + // default: + // trackChars = RangeBasedAwo.getTrackList(allTargets, playerCharacter, maxTargets); + // break; + //} + TrackWindowMsg trackWindowMsg = new TrackWindowMsg(msg); // send track window @@ -1923,9 +1973,7 @@ public enum PowersManager { } } - public static void runPowerAction(AbstractCharacter source, - AbstractWorldObject awo, Vector3fImmutable targetLoc, - ActionsBase ab, int trains, PowersBase pb) { + public static void runPowerAction(AbstractCharacter source, AbstractWorldObject awo, Vector3fImmutable targetLoc, ActionsBase ab, int trains, PowersBase pb) { AbstractPowerAction pa = ab.getPowerAction(); if (pa == null) { Logger.error( @@ -1933,6 +1981,26 @@ public enum PowersManager { + ab.getEffectID()); return; } + + if(AbstractCharacter.IsAbstractCharacter(awo)) { + try { + boolean immune = false; + AbstractCharacter absChar = (AbstractCharacter) awo; + for (AbstractEffectModifier mod : ab.getPowerAction().getEffectsBase().getModifiers()) { + if (absChar.getBonuses() != null) { + if (absChar.getBonuses().getBool(ModType.ImmuneTo, mod.sourceType) || absChar.getBonuses().getBool(ModType.NoMod, mod.sourceType)) + immune = true; + } + } + + if (immune) + return; + }catch(Exception e){ + + } + } + + pa.startAction(source, awo, targetLoc, trains, ab, pb); } @@ -2425,7 +2493,8 @@ public enum PowersManager { public static boolean testAttack(PlayerCharacter pc, AbstractWorldObject awo, PowersBase pb, PerformActionMsg msg) { // Get defense for target - float atr = CharacterSkill.getATR(pc, pb.getSkillName()); + //float atr = CharacterSkill.getATR(pc, pb.getSkillName()); + float atr = PlayerCombatStats.getSpellAtr(pc, pb); float defense; if (AbstractWorldObject.IsAbstractCharacter(awo)) { @@ -2468,10 +2537,12 @@ public enum PowersManager { return true; } else if (testPassive(pc, tarAc, "Block")) { // Dodge fired, send dodge message - PerformActionMsg dodgeMsg = new PerformActionMsg(msg); - dodgeMsg.setTargetType(awo.getObjectType().ordinal()); - dodgeMsg.setTargetID(awo.getObjectUUID()); - sendPowerMsg(pc, 4, dodgeMsg); + //PerformActionMsg dodgeMsg = new PerformActionMsg(msg); + //dodgeMsg.setTargetType(awo.getObjectType().ordinal()); + //dodgeMsg.setTargetID(awo.getObjectUUID()); + //sendPowerMsg(pc, 4, dodgeMsg); + TargetedActionMsg cmm = new TargetedActionMsg(pc, 75, tarAc, MBServerStatics.COMBAT_SEND_BLOCK); + DispatchMessage.sendToAllInRange(tarAc, cmm); return true; } } @@ -3030,6 +3101,7 @@ public enum PowersManager { case 429502507: case 428398816: case 429446315: + case 429441979: return false; } return true; diff --git a/src/engine/gameManager/ZergManager.java b/src/engine/gameManager/ZergManager.java index 649f8c5a..a340b0e0 100644 --- a/src/engine/gameManager/ZergManager.java +++ b/src/engine/gameManager/ZergManager.java @@ -21,9 +21,9 @@ public class ZergManager { return 0.0f; switch(count){ - case 4: return 0.63f; - case 5: return 0.40f; - case 6: return 0.25f; + case 4: return 0.50f; + case 5: return 0.0f; + case 6: return 0.0f; default: return 1.0f; } } diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java index 2e21d979..890781d4 100644 --- a/src/engine/mobileAI/MobAI.java +++ b/src/engine/mobileAI/MobAI.java @@ -27,6 +27,7 @@ import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; @@ -94,7 +95,7 @@ public class MobAI { } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); } } @@ -133,6 +134,9 @@ public class MobAI { if (mob.isMoving() && mob.getRange() > 20) return; + if(target.combatStats == null) + target.combatStats = new PlayerCombatStats(target); + // add timer for last attack. ItemBase mainHand = mob.getWeaponItemBase(true); @@ -170,7 +174,7 @@ public class MobAI { } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage()); } } @@ -228,7 +232,7 @@ public class MobAI { //} } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage()); } } @@ -267,7 +271,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage()); } } @@ -320,7 +324,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); } } @@ -364,7 +368,7 @@ public class MobAI { return mob.nextCastTime <= System.currentTimeMillis(); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast" + " " + e.getMessage()); } return false; } @@ -450,7 +454,7 @@ public class MobAI { return true; } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); } return false; } @@ -572,7 +576,7 @@ public class MobAI { return true; } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); } return false; } @@ -608,7 +612,7 @@ public class MobAI { mob.nextCallForHelp = System.currentTimeMillis() + 60000; } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp" + " " + e.getMessage()); } } @@ -620,9 +624,6 @@ public class MobAI { if (mob == null) return; - if(mob.isAlive()) - if(!mob.getMovementLoc().equals(Vector3fImmutable.ZERO)) - mob.setLoc(mob.getMovementLoc()); if (mob.getTimestamps().containsKey("lastExecution") == false) mob.getTimestamps().put("lastExecution", System.currentTimeMillis()); @@ -678,6 +679,10 @@ public class MobAI { return; } + if(mob.isAlive()) + if(!mob.getMovementLoc().equals(Vector3fImmutable.ZERO)) + mob.setLoc(mob.getMovementLoc()); + if(mob.isPet() == false && mob.isPlayerGuard == false) CheckToSendMobHome(mob); @@ -728,12 +733,14 @@ public class MobAI { if(mob.isAlive()) RecoverHealth(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction" + " " + e.getMessage()); } } private static void CheckForAggro(Mob aiAgent) { + + //old system try { //looks for and sets mobs combatTarget @@ -768,13 +775,11 @@ public class MobAI { continue; // No aggro for this race type - - if (aiAgent.notEnemy.size() > 0 && aiAgent.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == true) + if (aiAgent.notEnemy.size() > 0 && aiAgent.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) continue; //mob has enemies and this player race is not it - - if (aiAgent.enemy.size() > 0 && aiAgent.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == false) + if (aiAgent.enemy.size() > 0 && !aiAgent.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) continue; if (MovementUtilities.inRangeToAggro(aiAgent, loadedPlayer)) { @@ -803,7 +808,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro" + " " + e.getMessage()); + //(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro" + " " + e.getMessage()); } } @@ -864,7 +869,7 @@ public class MobAI { } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement" + " " + e.getMessage()); } } @@ -918,7 +923,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn" + " " + e.getMessage()); + //(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn" + " " + e.getMessage()); } } @@ -944,7 +949,7 @@ public class MobAI { AttackTarget(mob, mob.getCombatTarget()); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage()); } } @@ -971,7 +976,8 @@ public class MobAI { if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) CheckForPlayerGuardAggro(mob); } else { - CheckForAggro(mob); + if(mob.combatTarget == null) + NewAggroMechanic(mob); } } @@ -1005,7 +1011,7 @@ public class MobAI { mob.setCombatTarget(null); } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage()); } } @@ -1048,7 +1054,7 @@ public class MobAI { mob.updateMovementState(); mob.updateLocation(); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget" + " " + e.getMessage()); } } @@ -1080,7 +1086,7 @@ public class MobAI { mob.setCombatTarget(aggroMob); } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro" + " " + e.getMessage()); } } @@ -1103,21 +1109,10 @@ public class MobAI { if (mob.getCombatTarget() == null) CheckForPlayerGuardAggro(mob); - // AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); - - //if (newTarget != null) { - - // if (newTarget.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) { - // if (GuardCanAggro(mob, (PlayerCharacter) newTarget)) - // mob.setCombatTarget(newTarget); - // } else - // mob.setCombatTarget(newTarget); - - //} CheckMobMovement(mob); CheckForAttack(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCaptainLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCaptainLogic" + " " + e.getMessage()); } } @@ -1139,7 +1134,7 @@ public class MobAI { CheckMobMovement(mob); CheckForAttack(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardMinionLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardMinionLogic" + " " + e.getMessage()); } } @@ -1153,7 +1148,7 @@ public class MobAI { else CheckForAttack(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardWallArcherLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardWallArcherLogic" + " " + e.getMessage()); } } @@ -1174,7 +1169,7 @@ public class MobAI { CheckForAttack(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic" + " " + e.getMessage()); } } @@ -1190,7 +1185,7 @@ public class MobAI { CheckForAttack(mob); } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage()); } } @@ -1205,17 +1200,11 @@ public class MobAI { if (mob.BehaviourType.isAgressive) { - //AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); - - //if (newTarget != null) - //mob.setCombatTarget(newTarget); - //else { - if (mob.getCombatTarget() == null) { - if (mob.BehaviourType == Enum.MobBehaviourType.HamletGuard) - SafeGuardAggro(mob); //safehold guard - else - CheckForAggro(mob); //normal aggro - // } + if (mob.getCombatTarget() == null) { + if (mob.BehaviourType == Enum.MobBehaviourType.HamletGuard) + SafeGuardAggro(mob); //safehold guard + else + NewAggroMechanic(mob);//CheckForAggro(mob); //normal aggro } } @@ -1231,7 +1220,7 @@ public class MobAI { } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage()); } } @@ -1281,7 +1270,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage()); } } @@ -1344,7 +1333,7 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage()); } return false; } @@ -1393,39 +1382,8 @@ public class MobAI { } } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e.getMessage()); - } - } - - public static AbstractWorldObject ChangeTargetFromHateValue(Mob mob) { - - try { - - float CurrentHateValue = 0; - - if (mob.getCombatTarget() != null && mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) - CurrentHateValue = ((PlayerCharacter) mob.getCombatTarget()).getHateValue(); - - AbstractWorldObject mostHatedTarget = null; - - for (Entry playerEntry : mob.playerAgroMap.entrySet()) { - - PlayerCharacter potentialTarget = PlayerCharacter.getFromCache((int) playerEntry.getKey()); - - if (potentialTarget.equals(mob.getCombatTarget())) - continue; - - if (potentialTarget != null && potentialTarget.getHateValue() > CurrentHateValue && MovementUtilities.inRangeToAggro(mob, potentialTarget)) { - CurrentHateValue = potentialTarget.getHateValue(); - mostHatedTarget = potentialTarget; - } - - } - return mostHatedTarget; - } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e.getMessage()); } - return null; } public static void RecoverHealth(Mob mob) { @@ -1445,7 +1403,7 @@ public class MobAI { mob.setHealth(mob.getHealthMax()); } } catch (Exception e) { - Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: RecoverHealth" + " " + e.getMessage()); + //(mob.getObjectUUID() + " " + mob.getName() + " Failed At: RecoverHealth" + " " + e.getMessage()); } } @@ -1455,4 +1413,69 @@ public class MobAI { rwss.setPlayer(mob); DispatchMessage.sendToAllInRange(mob, rwss); } + + public static void NewAggroMechanic(Mob mob){ + + if(mob == null || !mob.isAlive() || mob.playerAgroMap.isEmpty()){ + return; + } + + if(mob.BehaviourType.equals(Enum.MobBehaviourType.HamletGuard)){ + return; + } + + if(mob.hate_values == null) + mob.hate_values = new HashMap<>(); + + if(mob.combatTarget != null) + return; + + HashSet inRange = WorldGrid.getObjectsInRangePartial(mob.loc,60.0f,MBServerStatics.MASK_PLAYER); + + if(inRange.isEmpty()){ + mob.setCombatTarget(null); + return; + } + + //clear out any players who are not in hated range anymore + ArrayList toRemove = new ArrayList<>(); + for(PlayerCharacter pc : mob.hate_values.keySet()){ + if(!inRange.contains(pc)) + toRemove.add(pc); + } + for(PlayerCharacter pc : toRemove){ + mob.hate_values.remove(pc); + } + + //find most hated target + PlayerCharacter mostHated = (PlayerCharacter)inRange.iterator().next(); + for(AbstractWorldObject awo : inRange){ + PlayerCharacter loadedPlayer = (PlayerCharacter)awo; + if (loadedPlayer == null) + continue; + + //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. + if (!loadedPlayer.isAlive()) + continue; + + //Can't see target, skip aggro. + if (!mob.canSee(loadedPlayer)) + continue; + + // No aggro for this race type + if (mob.notEnemy != null && mob.notEnemy.size() > 0 && mob.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) + continue; + + //mob has enemies and this player race is not it + if (mob.enemy != null && mob.enemy.size() > 0 && !mob.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) + continue; + + if(mob.hate_values.containsKey(loadedPlayer)) + if(mob.hate_values.get(loadedPlayer) > mob.hate_values.get(mostHated)) + mostHated = loadedPlayer; + } + + if(mostHated != null) + mob.setCombatTarget(mostHated); + } } \ No newline at end of file diff --git a/src/engine/mobileAI/utilities/CombatUtilities.java b/src/engine/mobileAI/utilities/CombatUtilities.java index 4b95d5cc..6423055e 100644 --- a/src/engine/mobileAI/utilities/CombatUtilities.java +++ b/src/engine/mobileAI/utilities/CombatUtilities.java @@ -22,7 +22,6 @@ import org.pmw.tinylog.Logger; import java.util.concurrent.ThreadLocalRandom; import static engine.math.FastMath.sqr; -import static java.lang.Math.pow; public class CombatUtilities { @@ -101,6 +100,14 @@ public class CombatUtilities { if (!target.isAlive()) return; + if(agent.isPet()){ + try{ + damage *= agent.getOwner().ZergMultiplier; + }catch(Exception ignored){ + + } + } + if (AbstractWorldObject.IsAbstractCharacter(target)) { //damage = Resists.handleFortitude((AbstractCharacter) target,DamageType.Crush,damage); trueDamage = ((AbstractCharacter) target).modifyHealth(-damage, agent, false); @@ -149,6 +156,8 @@ public class CombatUtilities { switch (target.getObjectType()) { case PlayerCharacter: PlayerCharacter pc = (PlayerCharacter)target; + if(pc.combatStats == null) + pc.combatStats = new PlayerCombatStats(pc); pc.combatStats.calculateDefense(); defense = pc.combatStats.defense; break; diff --git a/src/engine/net/client/handlers/ArcLoginNotifyMsgHandler.java b/src/engine/net/client/handlers/ArcLoginNotifyMsgHandler.java index 02b0518c..fa6a35fa 100644 --- a/src/engine/net/client/handlers/ArcLoginNotifyMsgHandler.java +++ b/src/engine/net/client/handlers/ArcLoginNotifyMsgHandler.java @@ -66,6 +66,7 @@ public class ArcLoginNotifyMsgHandler extends AbstractClientMsgHandler { // Send Guild, Nation and IC MOTD GuildManager.enterWorldMOTD(player); ChatManager.sendSystemMessage(player, ConfigManager.MB_WORLD_GREETING.getValue()); + ChatManager.sendSystemMessage(player, " Experience Gain: " + ConfigManager.MB_NORMAL_EXP_RATE.getValue()); // Send branch string if available from ConfigManager. diff --git a/src/engine/net/client/handlers/DestroyBuildingHandler.java b/src/engine/net/client/handlers/DestroyBuildingHandler.java index 418601bc..11d1a4f8 100644 --- a/src/engine/net/client/handlers/DestroyBuildingHandler.java +++ b/src/engine/net/client/handlers/DestroyBuildingHandler.java @@ -54,7 +54,7 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler { return true; } - if (!BuildingManager.PlayerCanControlNotOwner(building, pc)) + if (!BuildingManager.PlayerCanControlNotOwner(building, pc) && !pc.getAccount().status.equals(Enum.AccountStatus.ADMIN)) return true; // Can't delete siege assets during an active bane. @@ -72,8 +72,8 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler { return true; // Can't destroy a shrine - if (blueprint.getBuildingGroup() == BuildingGroup.SHRINE) - return true; + //if (blueprint.getBuildingGroup() == BuildingGroup.SHRINE) + // return true; // Cannot destroy mines outside of normal mine mechanics diff --git a/src/engine/net/client/handlers/MerchantMsgHandler.java b/src/engine/net/client/handlers/MerchantMsgHandler.java index 2515646d..ddd2ccc0 100644 --- a/src/engine/net/client/handlers/MerchantMsgHandler.java +++ b/src/engine/net/client/handlers/MerchantMsgHandler.java @@ -282,6 +282,14 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler { } } if(mineTele == null){ + //must be the dungeon request? + Vector3fImmutable loc = Vector3fImmutable.getRandomPointOnCircle(BuildingManager.getBuilding(2827951).loc,30f); + ChatManager.chatSystemInfo(player, "You Will Teleport To Whitehorn Citadel In " + 10 + " Seconds."); + if (10 > 0) { + //TODO add timer to teleport + TeleportJob tj = new TeleportJob(player, npc, loc, origin, true); + JobScheduler.getInstance().scheduleJob(tj, 10 * 1000); + } return; }else { int time = MBServerStatics.TELEPORT_TIME_IN_SECONDS; diff --git a/src/engine/net/client/handlers/ObjectActionMsgHandler.java b/src/engine/net/client/handlers/ObjectActionMsgHandler.java index 045eac10..51dfe204 100644 --- a/src/engine/net/client/handlers/ObjectActionMsgHandler.java +++ b/src/engine/net/client/handlers/ObjectActionMsgHandler.java @@ -424,9 +424,9 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler { } break; case 31: - LootManager.peddleFate(player,item); + //LootManager.peddleFate(player,item); + LootManager.newFatePeddler(player,item); break; - case 30: //water bucket case 8: //potions, tears of saedron case 5: //runes, petition, warrant, scrolls diff --git a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java index 9d96dfb3..e516a963 100644 --- a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java +++ b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java @@ -1027,6 +1027,10 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler { private boolean placeCityWalls(PlayerCharacter player, ClientConnection origin, PlaceAssetMsg msg) { + if(player.getAccount().status.equals(AccountStatus.ADMIN)){ + adminCreateBuildings(player,msg); + return false; + } // Member variables Zone serverZone; @@ -1165,7 +1169,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler { return true; } - private Building createStructure(PlayerCharacter playerCharacter, PlacementInfo buildingInfo, Zone currentZone) { + private static Building createStructure(PlayerCharacter playerCharacter, PlacementInfo buildingInfo, Zone currentZone) { Blueprint blueprint; Building newMesh; @@ -1387,4 +1391,16 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler { return true; } + + public static void adminCreateBuildings(PlayerCharacter pc, PlaceAssetMsg msg){ + //handled for building dungeon layouts + Zone zone = ZoneManager.getZoneByZoneID(993); + for(PlacementInfo placement : msg.getPlacementInfo()){ + Building building = createStructure(pc,placement,zone); + if(building != null) { + building.setProtectionState(ProtectionState.NPC); + building.setRank(1); + } + } + } } \ No newline at end of file diff --git a/src/engine/net/client/handlers/RequestEnterWorldHandler.java b/src/engine/net/client/handlers/RequestEnterWorldHandler.java index 18b48254..79f276a8 100644 --- a/src/engine/net/client/handlers/RequestEnterWorldHandler.java +++ b/src/engine/net/client/handlers/RequestEnterWorldHandler.java @@ -48,7 +48,7 @@ public class RequestEnterWorldHandler extends AbstractClientMsgHandler { PlayerCharacter player = origin.getPlayerCharacter(); - WorldGrid.RemoveWorldObject(player); + Dispatch dispatch; if (player == null) { @@ -57,6 +57,11 @@ public class RequestEnterWorldHandler extends AbstractClientMsgHandler { return true; } + //if(player.isEnteredWorld()){ + // if(player != null) { + // WorldGrid.RemoveWorldObject(player); + // } + //} player.setEnteredWorld(false); Account acc = SessionManager.getAccount(origin); @@ -106,9 +111,14 @@ public class RequestEnterWorldHandler extends AbstractClientMsgHandler { player.getTimestamps().put("EnterWorld", System.currentTimeMillis()); - if (player.getLoc().equals(Vector3fImmutable.ZERO) || System.currentTimeMillis() > player.getTimeStamp("logout") + (15 * 60 * 1000)) { + Long logout = player.getTimeStamp("logout"); + if (player.getLoc().equals(Vector3fImmutable.ZERO) || System.currentTimeMillis() > logout + (15 * 60 * 1000)) { player.stopMovement(player.getBindLoc()); - player.setSafeMode(); + try { + player.setSafeMode(); + }catch(Exception e){ + Logger.error(e); + } player.updateLocation(); player.setRegion(AbstractWorldObject.GetRegionByWorldObject(player)); } diff --git a/src/engine/net/client/msg/ApplyRuneMsg.java b/src/engine/net/client/msg/ApplyRuneMsg.java index d2873d24..87fa390d 100644 --- a/src/engine/net/client/msg/ApplyRuneMsg.java +++ b/src/engine/net/client/msg/ApplyRuneMsg.java @@ -78,6 +78,27 @@ public class ApplyRuneMsg extends ClientNetMsg { } int raceID = playerCharacter.getRaceID(); //Check race is met + + //confirm sub-race runes are applicable only by proper races + switch(runeID){ + case 252134: //elf + case 252135: // elf + case 252136: // elf + if(playerCharacter.getRaceID() != 2008 && playerCharacter.getRaceID() != 2009) + return false; + break; + case 252129: // human + case 252130: // human + case 252131: // human + case 252132: // human + case 252133: // human + if(playerCharacter.getRaceID() != 2011 && playerCharacter.getRaceID() != 2012) + return false; + break; + + } + + ConcurrentHashMap races = rb.getRace(); if(runeID != 3007 && runeID != 3014) {//bounty hunter and huntsman if (races.size() > 0) { diff --git a/src/engine/net/client/msg/ManageCityAssetsMsg.java b/src/engine/net/client/msg/ManageCityAssetsMsg.java index c4cae32b..8decdb75 100644 --- a/src/engine/net/client/msg/ManageCityAssetsMsg.java +++ b/src/engine/net/client/msg/ManageCityAssetsMsg.java @@ -567,8 +567,12 @@ public class ManageCityAssetsMsg extends ClientNetMsg { writer.put(labelSiege);// 1 sets the protection under siege writer.put(labelCeaseFire); //0 with 1 set above sets to under siege // 1 with 1 set above sets protection status to under siege(cease fire) - writer.put(buttonTransfer);// 1 enables the transfer asset button - writer.put(buttonDestroy);// 1 enables the destroy asset button + writer.put(buttonTransfer); + if(building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() != null && building.getBlueprint().getBuildingGroup().equals(BuildingGroup.SHRINE)) {// 1 enables the transfer asset button + writer.put((byte)1); + }else { + writer.put(buttonDestroy);// 1 enables the destroy asset button + } writer.put(buttonAbandon);// 1 here enables the abandon asset button writer.put(buttonUpgrade); //disable upgrade building diff --git a/src/engine/net/client/msg/TeleportRepledgeListMsg.java b/src/engine/net/client/msg/TeleportRepledgeListMsg.java index 69b73e43..d623ed5b 100644 --- a/src/engine/net/client/msg/TeleportRepledgeListMsg.java +++ b/src/engine/net/client/msg/TeleportRepledgeListMsg.java @@ -10,6 +10,7 @@ package engine.net.client.msg; +import engine.Dungeons.Dungeon; import engine.net.AbstractConnection; import engine.net.AbstractNetMsg; import engine.net.ByteBufferReader; @@ -108,7 +109,7 @@ public class TeleportRepledgeListMsg extends ClientNetMsg { for (int i = 0; i < 3; i++) writer.putInt(0); - writer.putInt(cities.size() + mines.size()); + writer.putInt(cities.size() + mines.size());// + 1); for (City city : cities) City.serializeForClientMsg(city, writer); @@ -116,6 +117,7 @@ public class TeleportRepledgeListMsg extends ClientNetMsg { for(Mine mine : mines) Mine.serializeForClientMsgTeleport(mine, writer); + //Dungeon.serializeForClientMsgTeleport(writer); } public PlayerCharacter getPlayer() { diff --git a/src/engine/objects/AbstractCharacter.java b/src/engine/objects/AbstractCharacter.java index 553753e1..aac7146d 100644 --- a/src/engine/objects/AbstractCharacter.java +++ b/src/engine/objects/AbstractCharacter.java @@ -1187,13 +1187,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject { public final float modifyHealth(float value, final AbstractCharacter attacker, final boolean fromCost) { - if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ - value *= ((PlayerCharacter)attacker).ZergMultiplier; - } // Health modifications are modified by the ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ + // value *= ((PlayerCharacter)attacker).ZergMultiplier; + //} // Health modifications are modified by the ZergMechanic - if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ - value *= ((Mob)attacker).getOwner().ZergMultiplier; - }// Health modifications from pets are modified by the owner's ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ + // value *= ((Mob)attacker).getOwner().ZergMultiplier; + //}// Health modifications from pets are modified by the owner's ZergMechanic try { @@ -1262,13 +1262,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject { final boolean fromCost ) { - if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ - value *= ((PlayerCharacter)attacker).ZergMultiplier; - } // Health modifications are modified by the ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ + // value *= ((PlayerCharacter)attacker).ZergMultiplier; + //} // Health modifications are modified by the ZergMechanic - if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ - value *= ((Mob)attacker).getOwner().ZergMultiplier; - }// Health modifications from pets are modified by the owner's ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ + // value *= ((Mob)attacker).getOwner().ZergMultiplier; + //}// Health modifications from pets are modified by the owner's ZergMechanic if (!this.isAlive()) { return 0f; @@ -1309,13 +1309,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject { final boolean fromCost ) { - if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ - value *= ((PlayerCharacter)attacker).ZergMultiplier; - } // Health modifications are modified by the ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){ + // value *= ((PlayerCharacter)attacker).ZergMultiplier; + //} // Health modifications are modified by the ZergMechanic - if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ - value *= ((Mob)attacker).getOwner().ZergMultiplier; - }// Health modifications from pets are modified by the owner's ZergMechanic + //if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){ + // value *= ((Mob)attacker).getOwner().ZergMultiplier; + //}// Health modifications from pets are modified by the owner's ZergMechanic if (!this.isAlive()) { return 0f; diff --git a/src/engine/objects/AbstractWorldObject.java b/src/engine/objects/AbstractWorldObject.java index e76b6666..fced8cae 100644 --- a/src/engine/objects/AbstractWorldObject.java +++ b/src/engine/objects/AbstractWorldObject.java @@ -15,6 +15,7 @@ import engine.Enum.GameObjectType; import engine.Enum.GridObjectType; import engine.InterestManagement.HeightMap; import engine.InterestManagement.WorldGrid; +import engine.gameManager.ZoneManager; import engine.job.AbstractScheduleJob; import engine.job.JobContainer; import engine.job.JobScheduler; @@ -175,11 +176,11 @@ public abstract class AbstractWorldObject extends AbstractGameObject { } //set players new altitude to region lerp altitude. - if (region != null) - if (region.center.y == region.highLerp.y) - worldObject.loc = worldObject.loc.setY(region.center.y + worldObject.getAltitude()); - else - worldObject.loc = worldObject.loc.setY(region.lerpY(worldObject) + worldObject.getAltitude()); + //if (region != null) + // if (region.center.y == region.highLerp.y) + // worldObject.loc = worldObject.loc.setY(region.center.y + worldObject.getAltitude()); + // else + // worldObject.loc = worldObject.loc.setY(region.lerpY(worldObject) + worldObject.getAltitude()); return region; } @@ -500,8 +501,28 @@ public abstract class AbstractWorldObject extends AbstractGameObject { if (loc.x > MBServerStatics.MAX_WORLD_WIDTH || loc.z < MBServerStatics.MAX_WORLD_HEIGHT) return; this.lastLoc = new Vector3fImmutable(this.loc); - this.loc = loc; - this.loc = this.loc.setY(HeightMap.getWorldHeight(this) + this.getAltitude()); + if(AbstractCharacter.IsAbstractCharacter(this)){ + float y; + float worldHeight = HeightMap.getWorldHeight(loc); + Zone zone = ZoneManager.findSmallestZone(loc); + if(zone != null && zone.isPlayerCity()){ + worldHeight = zone.getWorldAltitude(); + } + if(this.region != null){ + float regionAlt = this.region.lerpY(this); + float altitude = this.getAltitude(); + y = regionAlt + altitude + worldHeight; + }else{ + y = HeightMap.getWorldHeight(loc) + this.getAltitude(); + } + Vector3fImmutable newLoc = new Vector3fImmutable(loc.x,y,loc.z); + this.loc = newLoc; + WorldGrid.addObject(this, newLoc.x, newLoc.z); + return; + }else{ + this.loc = loc; + } + //this.loc = this.loc.setY(HeightMap.getWorldHeight(this) + this.getAltitude()); //lets not add mob to world grid if he is currently despawned. if (this.getObjectType().equals(GameObjectType.Mob) && ((Mob) this).despawned) diff --git a/src/engine/objects/CharacterItemManager.java b/src/engine/objects/CharacterItemManager.java index d381c6a9..16376023 100644 --- a/src/engine/objects/CharacterItemManager.java +++ b/src/engine/objects/CharacterItemManager.java @@ -1058,6 +1058,7 @@ public class CharacterItemManager { i.addToCache(); try { i.stripCastableEnchants(); + this.updateInventory(); }catch(Exception ignored){ Logger.error("FAILED TO STRIP CASTABLE ENCHANTS: Move Item To Bank"); } @@ -1203,6 +1204,7 @@ public class CharacterItemManager { try { i.stripCastableEnchants(); + this.updateInventory(); }catch(Exception ignored){ Logger.error("FAILED TO STRIP CASTABLE ENCHANTS: Move Item To Vault"); } @@ -2448,6 +2450,9 @@ public class CharacterItemManager { public void damageItem(Item item, int amount) { if (item == null || amount < 1 || amount > 5) return; + if(item.getItemBase().isGlass()){ + amount = 1; + } //verify the item is equipped by this player int slot = item.getEquipSlot(); diff --git a/src/engine/objects/City.java b/src/engine/objects/City.java index ad6b3f93..f5a9207c 100644 --- a/src/engine/objects/City.java +++ b/src/engine/objects/City.java @@ -455,7 +455,7 @@ public class City extends AbstractWorldObject { if (!BuildingManager.IsPlayerHostile(city.getTOL(), pc)) cities.add(city); //verify nation or guild is same - } else if (Guild.sameNationExcludeErrant(city.getGuild(), pcG)) + } else if (city.open && Guild.sameNationExcludeErrant(city.getGuild(), pcG)) cities.add(city); } else if (city.isNpc == 1) { diff --git a/src/engine/objects/Contract.java b/src/engine/objects/Contract.java index 97d689fa..09d554b2 100644 --- a/src/engine/objects/Contract.java +++ b/src/engine/objects/Contract.java @@ -16,6 +16,7 @@ import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.client.msg.CityDataMsg; import engine.net.client.msg.ErrorPopupMsg; +import engine.net.client.msg.VendorDialogMsg; import org.joda.time.DateTime; import org.pmw.tinylog.Logger; @@ -323,6 +324,12 @@ public class Contract extends AbstractGameObject { pc.charItemManager.updateInventory(); } + + public static boolean isClassTrainer(int id){ + if(id >= 5 && id <= 30) + return true; + return false; + } public static VendorDialog HandleBaneCommanderOptions(int optionId, NPC npc, PlayerCharacter pc){ pc.setLastNPCDialog(npc); VendorDialog vd = new VendorDialog(VendorDialog.getHostileVendorDialog().getDialogType(),VendorDialog.getHostileVendorDialog().getIntro(),-1);//VendorDialog.getHostileVendorDialog(); @@ -580,6 +587,19 @@ public class Contract extends AbstractGameObject { } } + if(this.getObjectUUID() == 1502050){ + for(MobEquipment me : this.sellInventory){ + switch(me.getItemBase().getUUID()) { + case 971070: + me.magicValue = 3000000; + break; + case 971012: + me.magicValue = 1000000; + break; + } + } + } + if(this.getObjectUUID() == 1202){ //rune merchant for(MobEquipment me : this.sellInventory){ switch(me.getItemBase().getUUID()){ @@ -588,53 +608,63 @@ public class Contract extends AbstractGameObject { case 250019: case 250028: case 250037: - me.magicValue = 3000000; + me.magicValue = 1000000; break; case 250002: //10 stats case 250011: case 250020: case 250029: case 250038: - me.magicValue = 4000000; + me.magicValue = 2000000; break; case 250003: //15 stats case 250012: case 250021: case 250030: case 250039: - me.magicValue = 5000000; + me.magicValue = 3000000; break; case 250004: //20 stats case 250013: case 250022: case 250031: case 250040: - me.magicValue = 6000000; + me.magicValue = 4000000; break; case 250005: //25 stats case 250014: case 250023: case 250032: case 250041: - me.magicValue = 7000000; + me.magicValue = 5000000; break; case 250006: //30 stats case 250015: case 250024: case 250033: case 250042: - me.magicValue = 8000000; + me.magicValue = 6000000; break; case 250007: //35 stats case 250016: case 250025: case 250034: case 250043: - me.magicValue = 9000000; + me.magicValue = 7000000; break; - default: + case 250008: //40 stats + case 250017: + case 250026: + case 250035: + case 250044: me.magicValue = 10000000; break; + case 252127: + me.magicValue = 5000000; + break; + default: + me.magicValue = 1000000; + break; } } } diff --git a/src/engine/objects/Experience.java b/src/engine/objects/Experience.java index 3d2c0810..23fc3192 100644 --- a/src/engine/objects/Experience.java +++ b/src/engine/objects/Experience.java @@ -11,7 +11,6 @@ package engine.objects; import engine.Enum; import engine.Enum.TargetColor; -import engine.gameManager.LootManager; import engine.gameManager.ZoneManager; import engine.math.Vector3fImmutable; import engine.server.MBServerStatics; @@ -24,7 +23,7 @@ import static engine.gameManager.LootManager.LOOTMANAGER; public class Experience { private static final TreeMap ExpToLevel; - private static final int[] LevelToExp = {Integer.MIN_VALUE, // Pad + public static final int[] LevelToExp = {Integer.MIN_VALUE, // Pad // everything // over 1 @@ -122,6 +121,8 @@ public class Experience { 190585732, // Level 77 201714185, // Level 78 213319687, // Level 79 + + // R8 225415457, // Level 80 238014819 // Level 81 @@ -303,7 +304,7 @@ public class Experience { case Cyan: return 0.9; case Green: - return 0.7; + return 0.8; default: return 0; } @@ -353,66 +354,143 @@ public class Experience { if(killer.pvpKills.contains(mob.getObjectUUID())) return; - double baseXP; + if(true){ + if(killer.combatStats == null) + killer.combatStats = new PlayerCombatStats(killer); + + killer.combatStats.grantExperience(mob,g); + return; + } + + double grantedExperience = 0.0; + + if (g != null) { // Do group EXP stuff + + int leadership = 0; + int highestLevel = 0; + double penalty = 0.0; + + ArrayList giveEXPTo = new ArrayList<>(); + + // Check if leader is within range of kill and then get leadership + // skill + + Vector3fImmutable killLoc = mob.getLoc(); + + if (killLoc.distanceSquared2D(g.getGroupLead().getLoc()) < (MBServerStatics.EXP_RANGE * MBServerStatics.EXP_RANGE)) { + CharacterSkill leaderskill = g.getGroupLead().skills + .get("Leadership"); + + if (leaderskill != null) + leadership = leaderskill.getNumTrains(); + if (leadership > 90) + leadership = 90; // leadership caps at 90% + } + + // Check every group member for distance to see if they get xp + + for (PlayerCharacter pc : g.getMembers()) { + if (pc.isAlive()) { // Skip if the player is dead. + + // Check within range + + if (killLoc.distanceSquared2D(pc.getLoc()) < (MBServerStatics.EXP_RANGE * MBServerStatics.EXP_RANGE)) { + + giveEXPTo.add(pc); - if(g != null) { - //group experience - PlayerCharacter leader = g.getGroupLead(); - float leadership = 0.0f; - if(leader.skills.containsKey("Leadership")) - leadership = leader.skills.get("Leadership").getModifiedAmount(); + // Track highest level character - for(PlayerCharacter member : g.members){ + if (pc.getLevel() > highestLevel) + highestLevel = pc.getLevel(); + } + } + } + + // Process every player in the group getting XP - if (member.getLevel() >= MBServerStatics.LEVELCAP) + for (PlayerCharacter playerCharacter : giveEXPTo) { + if (playerCharacter.getLevel() >= MBServerStatics.LEVELCAP) continue; - if(member.level >= 75 && !mob.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) + if(playerCharacter.level >= 75 && !mob.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) continue; // cannot PVE higher than level 75 - float range = member.loc.distanceSquared(killer.loc); - if(range <= (MBServerStatics.CHARACTER_LOAD_RANGE * MBServerStatics.CHARACTER_LOAD_RANGE)){ - baseXP = LootManager.NORMAL_EXP_RATE * maxXPPerKill(member.getLevel()); - double mod = getConMod(member, mob); + // Sets Max XP with server exp mod taken into account. + + grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(playerCharacter.getLevel()); + + // Adjust XP for Mob Level + + grantedExperience *= getConMod(playerCharacter, mob); + + // Process XP for this member + + penalty = getGroupMemberPenalty(leadership, playerCharacter, giveEXPTo, + highestLevel); + + // Leadership Penalty Reduction + + if (leadership > 0) + penalty -= ((leadership) * 0.01) * penalty; - if(leadership > 0 && mod != 0) - mod += (leadership * 0.01f); + // Modify for hotzone - baseXP *= mod; + if (grantedExperience != 0) + if (ZoneManager.inHotZone(mob.getLoc())) + grantedExperience *= LOOTMANAGER.HOTZONE_EXP_RATE; - if(baseXP < 1) - baseXP = 1; + // Check for 0 XP due to white mob, otherwise subtract penalty + // xp - baseXP *= (1.0f / g.members.size()+0.9f); + if (grantedExperience == 0) + grantedExperience = 1; + else { + grantedExperience -= (penalty * 0.01) * grantedExperience; - member.grantXP((int) baseXP); + // Errant Penalty Calculation + if (playerCharacter.getGuild().isEmptyGuild()) + grantedExperience *= 0.6; } + + if (grantedExperience == 0) + grantedExperience = 1; + + //scaling + grantedExperience *= (1 / giveEXPTo.size()+0.9); + + // Grant the player the EXP + playerCharacter.grantXP((int) Math.floor(grantedExperience)); } - }else{ - //solo no group + + } else { // Give EXP to a single character + //if (!killer.isAlive()) // Skip if the player is dead. + // return; if (killer.getLevel() >= MBServerStatics.LEVELCAP) return; if(killer.level >= 75 && !mob.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) - return; // cannot PVE higher than level 75 - - baseXP = LootManager.NORMAL_EXP_RATE * maxXPPerKill(killer.getLevel()); - double mod = getConMod(killer, mob); - float leadership = 0.0f; - if(killer.skills.containsKey("Leadership")) - leadership = killer.skills.get("Leadership").getModifiedAmount(); - if(leadership > 0 && mod != 0){ - mod += (leadership * 0.01f); - } + return; + + // Get XP and adjust for Mob Level with world xp modifier taken into account + grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(killer.getLevel()); + grantedExperience *= getConMod(killer, mob); - baseXP *= mod; - if(baseXP < 1) - baseXP = 1; + // Modify for hotzone + if (ZoneManager.inHotZone(mob.getLoc())) + grantedExperience *= LOOTMANAGER.HOTZONE_EXP_RATE; + + // Errant penalty + if (grantedExperience != 1) { + if (killer.getGuild().isEmptyGuild()) + grantedExperience *= 0.6f; + } - baseXP *= 1.9f; + //bonus for no group + grantedExperience *= 1.9f; - killer.grantXP((int) baseXP); + // Grant XP + killer.grantXP((int) Math.floor(grantedExperience)); } } } diff --git a/src/engine/objects/Item.java b/src/engine/objects/Item.java index 45601326..b8937d99 100644 --- a/src/engine/objects/Item.java +++ b/src/engine/objects/Item.java @@ -818,15 +818,65 @@ public class Item extends AbstractWorldObject { } public void stripCastableEnchants(){ - ArrayList ToRemove = new ArrayList<>(); - for(Effect eff : this.effects.values()){ - if(eff.getJobContainer() != null && !eff.getJobContainer().noTimer()){ + try { + //strip EnchantWeapon + if(this.effects.get("EnchantWeapon") != null){ + this.effects.remove("EnchantWeapon"); + Effect eff = this.effects.get("EnchantWeapon"); + eff.endEffectNoPower(); + } + + //strip FGM-003 + if(this.effects.get("1000") != null){ + this.effects.remove("1000"); + Effect eff = this.effects.get("1000"); + eff.endEffectNoPower(); + } + + //strip FGM-001 + if(this.effects.get("996") != null){ + this.effects.remove("996"); + Effect eff = this.effects.get("996"); + eff.endEffectNoPower(); + } + + //strip ENC-001 + if(this.effects.get("957") != null){ + this.effects.remove("957"); + Effect eff = this.effects.get("957"); eff.endEffectNoPower(); - eff.getJobContainer().cancelJob(); - ToRemove.add(eff); } + if(this.effects.get("958") != null){ + this.effects.remove("958"); + Effect eff = this.effects.get("958"); + eff.endEffectNoPower(); + } + if(this.effects.get("959") != null){ + this.effects.remove("959"); + Effect eff = this.effects.get("959"); + eff.endEffectNoPower(); + } + if(this.effects.get("960") != null){ + this.effects.remove("960"); + Effect eff = this.effects.get("960"); + eff.endEffectNoPower(); + } + if(this.effects.get("961") != null){ + this.effects.remove("961"); + Effect eff = this.effects.get("961"); + eff.endEffectNoPower(); + } + if(this.effects.get("962") != null){ + this.effects.remove("962"); + Effect eff = this.effects.get("962"); + eff.endEffectNoPower(); + } + + this.applyAllBonuses(); + //this.effects.values().removeAll(ToRemove); + }catch(Exception ignored){ + } - this.effects.values().removeAll(ToRemove); } //Only to be used for trading public void setOwnerID(int ownerID) { diff --git a/src/engine/objects/ItemBase.java b/src/engine/objects/ItemBase.java index b6bda4bb..b5af8368 100644 --- a/src/engine/objects/ItemBase.java +++ b/src/engine/objects/ItemBase.java @@ -259,51 +259,53 @@ public class ItemBase { case 250019: case 250028: case 250037: - return 3000000; + return 1000000; case 250002: //10 stats case 250011: case 250020: case 250029: case 250038: - return 4000000; + return 2000000; case 250003: //15 stats case 250012: case 250021: case 250030: case 250039: - return 5000000; + return 3000000; case 250004: //20 stats case 250013: case 250022: case 250031: case 250040: - return 6000000; + return 4000000; case 250005: //25 stats case 250014: case 250023: case 250032: case 250041: - return 7000000; + return 5000000; case 250006: //30 stats case 250015: case 250024: case 250033: case 250042: - return 8000000; + return 6000000; case 250007: //35 stats case 250016: case 250025: case 250034: case 250043: - return 9000000; + return 7000000; case 250008: //40 stats case 250017: case 250026: case 250035: case 250044: return 10000000; + case 252127: + return 5000000; } - return 10000000; + return 1000000; } /* diff --git a/src/engine/objects/ItemFactory.java b/src/engine/objects/ItemFactory.java index 158b3422..818ea434 100644 --- a/src/engine/objects/ItemFactory.java +++ b/src/engine/objects/ItemFactory.java @@ -705,9 +705,13 @@ public class ItemFactory { int rollPrefix = ThreadLocalRandom.current().nextInt(1, 100 + 1); - if (rollPrefix < 80) { + if (rollPrefix < vendor.getLevel() + 30) { int randomPrefix = TableRoll(vendor.getLevel()); + if(vendor.contract.getName().contains("Heavy") || vendor.contract.getName().contains("Medium") || vendor.contract.getName().contains("Leather")) + randomPrefix += vendor.level * 0.5f; + if(randomPrefix > 320) + randomPrefix = 320; prefixEntry = ModTableEntry.rollTable(prefixTypeTable.modTableID, randomPrefix); if (prefixEntry != null) @@ -720,9 +724,13 @@ public class ItemFactory { // Always have at least one mod on a magic rolled item. // Suffix will be our backup plan. - if (rollSuffix < 80 || prefixEntry == null) { + if (rollSuffix < vendor.getLevel() + 30) { int randomSuffix = TableRoll(vendor.getLevel()); + if(vendor.contract.getName().contains("Heavy") || vendor.contract.getName().contains("Medium") || vendor.contract.getName().contains("Leather")) + randomSuffix += vendor.level * 0.25f; + if(randomSuffix > 320) + randomSuffix = 320; suffixEntry = ModTableEntry.rollTable(suffixTypeTable.modTableID, randomSuffix); if (suffixEntry != null) @@ -776,31 +784,31 @@ public class ItemFactory { public static int TableRoll(int vendorLevel) { // Calculate min and max based on mobLevel - int min = 60; - int max = 120; + int min = 100; + int max = 160; switch(vendorLevel){ case 20: - min = 70; - max = 140; + min = 120; + max = 180; break; case 30: - min = 80; - max = 160; + min = 140; + max = 200; break; case 40: - min = 90; - max = 180; + min = 160; + max = 220; break; case 50: - min = 100; - max = 200; + min = 180; + max = 240; break; case 60: - min = 175; + min = 200; max = 260; break; case 70: - min = 220; + min = 240; max = 320; break; } diff --git a/src/engine/objects/Mine.java b/src/engine/objects/Mine.java index 457649ad..df1be7a0 100644 --- a/src/engine/objects/Mine.java +++ b/src/engine/objects/Mine.java @@ -65,6 +65,7 @@ public class Mine extends AbstractGameObject { public boolean isStronghold = false; public ArrayList strongholdMobs; public HashMap oldBuildings; + public HashMap mineAttendees = new HashMap<>(); /** * ResultSet Constructor @@ -622,7 +623,7 @@ public class Mine extends AbstractGameObject { // Gather current list of players within the zone bounds - HashSet currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER); + HashSet currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, MBServerStatics.CHARACTER_LOAD_RANGE * 3, MBServerStatics.MASK_PLAYER); HashMap> charactersByNation = new HashMap<>(); ArrayList updatedNations = new ArrayList<>(); for (AbstractWorldObject playerObject : currentPlayers) { @@ -637,6 +638,7 @@ public class Mine extends AbstractGameObject { if(!this._playerMemory.contains(player.getObjectUUID())){ this._playerMemory.add(player.getObjectUUID()); + ChatManager.chatSystemInfo(player,"You Have Entered an Active Mine Area"); } Guild nation = player.guild.getNation(); if(charactersByNation.containsKey(nation)){ @@ -655,6 +657,19 @@ public class Mine extends AbstractGameObject { } } } + + for(Integer id : this.mineAttendees.keySet()){ + PlayerCharacter attendee = PlayerCharacter.getPlayerCharacter(id); + if(attendee == null) + continue; + + if(charactersByNation.containsKey(attendee.guild.getNation())){ + if(!charactersByNation.get(attendee.guild.getNation()).contains(attendee)){ + charactersByNation.get(attendee.guild.getNation()).add(attendee); + } + } + + } for(Guild nation : updatedNations){ float multiplier = ZergManager.getCurrentMultiplier(charactersByNation.get(nation).size(),this.capSize); for(PlayerCharacter player : charactersByNation.get(nation)){ @@ -676,18 +691,28 @@ public class Mine extends AbstractGameObject { if(tower == null) return; ArrayListtoRemove = new ArrayList<>(); - HashSet currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER); + HashSet currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, MBServerStatics.CHARACTER_LOAD_RANGE * 3, MBServerStatics.MASK_PLAYER); for(Integer id : currentMemory){ PlayerCharacter pc = PlayerCharacter.getPlayerCharacter(id); - if(currentPlayers.contains(pc) == false){ - toRemove.add(id); + if(!currentPlayers.contains(pc)){ + if(this.mineAttendees.containsKey(id)){ + long timeGone = System.currentTimeMillis() - this.mineAttendees.get(id).longValue(); + if (timeGone > 180000L) { // 3 minutes + toRemove.add(id); // Mark for removal + } + } pc.ZergMultiplier = 1.0f; + } else { + this.mineAttendees.put(id,System.currentTimeMillis()); } } // Remove players from city memory _playerMemory.removeAll(toRemove); + for(int id : toRemove){ + this.mineAttendees.remove(id); + } } public static Building getTower(Mine mine){ Building tower = BuildingManager.getBuildingFromCache(mine.buildingID); diff --git a/src/engine/objects/Mob.java b/src/engine/objects/Mob.java index 38f7f396..4d4cfdd6 100644 --- a/src/engine/objects/Mob.java +++ b/src/engine/objects/Mob.java @@ -111,6 +111,8 @@ public class Mob extends AbstractIntelligenceAgent { public boolean StrongholdEpic = false; public boolean isDropper = false; + public HashMap hate_values; + /** * No Id Constructor @@ -1450,6 +1452,7 @@ public class Mob extends AbstractIntelligenceAgent { this.stopPatrolTime = 0; this.lastPatrolPointIndex = 0; InterestManager.setObjectDirty(this); + this.hate_values = new HashMap<>(); } public void despawn() { diff --git a/src/engine/objects/MobEquipment.java b/src/engine/objects/MobEquipment.java index 7e125c04..7a0377ce 100644 --- a/src/engine/objects/MobEquipment.java +++ b/src/engine/objects/MobEquipment.java @@ -278,14 +278,14 @@ public class MobEquipment extends AbstractGameObject { EffectsBase effect = PowersManager.getEffectByToken(token); AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); - if (apa.getEffectsBase() != null) + if (apa != null && apa.getEffectsBase() != null) if (apa.getEffectsBase().getValue() > 0) { //System.out.println(apa.getEffectsBase().getValue()); value += apa.getEffectsBase().getValue(); } - if (apa.getEffectsBase2() != null) + if (apa != null && apa.getEffectsBase2() != null) value += apa.getEffectsBase2().getValue(); } diff --git a/src/engine/objects/NPC.java b/src/engine/objects/NPC.java index be456d93..c0822b6d 100644 --- a/src/engine/objects/NPC.java +++ b/src/engine/objects/NPC.java @@ -876,6 +876,11 @@ public class NPC extends AbstractCharacter { // zone collection this.parentZone = ZoneManager.getZoneByUUID(this.parentZoneUUID); + if(this.parentZone == null) { + Logger.error("PARENT ZONE NOT IDENTIFIED FOR NPC : " + this.getObjectUUID()); + return; + } + this.parentZone.zoneNPCSet.remove(this); this.parentZone.zoneNPCSet.add(this); diff --git a/src/engine/objects/PlayerCharacter.java b/src/engine/objects/PlayerCharacter.java index 20ce93ce..f42fc281 100644 --- a/src/engine/objects/PlayerCharacter.java +++ b/src/engine/objects/PlayerCharacter.java @@ -41,11 +41,11 @@ import engine.server.MBServerStatics; import engine.server.login.LoginServer; import engine.server.login.LoginServerMsgHandler; import engine.server.world.WorldServer; +import engine.util.KeyCloneAudit; import engine.util.MiscUtils; import org.joda.time.DateTime; import org.pmw.tinylog.Logger; -import javax.swing.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -183,6 +183,8 @@ public class PlayerCharacter extends AbstractCharacter { public PlayerCombatStats combatStats; + public Integer selectedUUID = 0; + /** * No Id Constructor */ @@ -1534,25 +1536,48 @@ public class PlayerCharacter extends AbstractCharacter { return true; Zone zone = ZoneManager.findSmallestZone(breather.getLoc()); + if(zone == null) + return true; + + if(zone.isPlayerCity()) + return true; + + float seaLevel = zone.getSeaLevel(); + if (zone.getSeaLevel() != 0) { + Zone parent = zone.getParent(); + if(parent != null && parent.isMacroZone()){ + float parentLevel = parent.getSeaLevel(); + seaLevel -= parentLevel; + } - float localAltitude = breather.getLoc().y; + if(seaLevel == 0) + return true; + float localAltitude = breather.getLoc().y; + float characterHeight = breather.characterHeight; - if (localAltitude + breather.characterHeight < zone.getSeaLevel() - 2) + if (localAltitude + characterHeight < seaLevel - 2) { + //ChatManager.chatSystemInfo(breather, "YOU CANNOT BREATHE!"); return false; - + } if (breather.isMoving()) { - if (localAltitude + breather.characterHeight < zone.getSeaLevel()) + if (localAltitude + breather.characterHeight < zone.getSeaLevel()) { + //ChatManager.chatSystemInfo(breather, "YOU CANNOT BREATHE!"); return false; + } } } else { - if (breather.getLoc().y + breather.characterHeight < -2) + if (breather.getLoc().y + breather.characterHeight < -2) { + //ChatManager.chatSystemInfo(breather, "YOU CANNOT BREATHE!"); return false; + } if (breather.isMoving()) { - if (breather.getLoc().y + breather.characterHeight < 0) + if (breather.getLoc().y + breather.characterHeight < 0) { + //ChatManager.chatSystemInfo(breather, "YOU CANNOT BREATHE!"); return false; + } } } @@ -1845,6 +1870,11 @@ public class PlayerCharacter extends AbstractCharacter { message += " was killed by " + att.getFirstName(); if (att.guild != null && (!(att.guild.getName().equals("Errant")))) message += " of " + att.guild.getName(); + + Zone killZone = ZoneManager.findSmallestZone(this.loc); + if(killZone != null){ + message += " in " + killZone.getName(); + } message += "!"; @@ -1964,8 +1994,7 @@ public class PlayerCharacter extends AbstractCharacter { this.altitude = (float) 0; // Release Mine Claims - - Mine.releaseMineClaims(this); + //Mine.releaseMineClaims(this); this.getCharItemManager().closeTradeWindow(); @@ -2929,6 +2958,7 @@ public class PlayerCharacter extends AbstractCharacter { } public synchronized void grantXP(int xp) { + xp *= LootManager.NORMAL_EXP_RATE; int groupSize = 1; if(GroupManager.getGroup(this)!= null) groupSize = GroupManager.getGroup(this).members.size(); @@ -3084,7 +3114,7 @@ public class PlayerCharacter extends AbstractCharacter { checkGuildStatus(); //give gold for level up if level is under or equal to 20 and over 10 - if(!this.isBoxed && this.level > 10 && this.level <= 20 && this.safeZone) { + if(!this.isBoxed && this.level > 10 && this.level <= 20) { int gold = (int) ((100000 * (this.level - 10) / 55.0) ); this.charItemManager.addGoldToInventory(gold, false); this.charItemManager.updateInventory(); @@ -4705,7 +4735,7 @@ public class PlayerCharacter extends AbstractCharacter { ModType modType = ModType.GetModType(type); // must be allowed to use this passive - if (!this.bonuses.getBool(modType, SourceType.None)) + if (!this.bonuses.getBool(modType, SourceType.None) && this.getRaceID() != 1999) return 0f; // must not be stunned @@ -4754,13 +4784,13 @@ public class PlayerCharacter extends AbstractCharacter { if(this.bonuses != null) blockChance *= 1 + this.bonuses.getFloatPercentAll(ModType.Block, SourceType.None); return blockChance; - case "Parry": if(!fromCombat) return 0; if(mainHand == null && this.getRaceID() != 1999) // saetors can always parry using their horns return 0; + int parryBonus = 0; if(mainHand != null && offHand != null && !offHand.getItemBase().isShield()) @@ -5078,6 +5108,12 @@ public class PlayerCharacter extends AbstractCharacter { Zone zone = ZoneManager.findSmallestZone(this.getLoc()); + if(zone == null) + return false; + + if(zone.isPlayerCity()) + return false; + if (zone.getSeaLevel() != 0) { float localAltitude = this.getLoc().y + this.centerHeight; @@ -5109,38 +5145,31 @@ public class PlayerCharacter extends AbstractCharacter { @Override public void update(Boolean newSystem) { - this.updateLocation(); + if(!newSystem) + this.updateLocation(); + this.updateMovementState(); if(!newSystem) return; - this.updateLocation(); - this.updateMovementState(); - try { if (this.updateLock.writeLock().tryLock()) { try { - if (!this.isAlive() && this.isEnteredWorld()) { - if (!this.timestamps.containsKey("DeathTime")) { - this.timestamps.put("DeathTime", System.currentTimeMillis()); - } else if ((System.currentTimeMillis() - this.timestamps.get("DeathTime")) > 600000) - forceRespawn(this); - return; - } if (this.isAlive() && this.isActive && this.enteredWorld) { - this.updateMovementState(); - if (this.combatStats == null) { this.combatStats = new PlayerCombatStats(this); } else { - this.combatStats.update(); + try { + this.combatStats.update(); + }catch(Exception ignored){ + + } } this.doRegen(); - //this.combatStats.regenerate(); } if (this.getStamina() < 10) { @@ -5153,24 +5182,26 @@ public class PlayerCharacter extends AbstractCharacter { this.updateBlessingMessage(); this.safeZone = this.isInSafeZone(); - if (!this.timestamps.containsKey("nextBoxCheck")) - this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000); - if (!this.isBoxed && this.timestamps.get("nextBoxCheck") < System.currentTimeMillis()) { - this.isBoxed = checkIfBoxed(this); - this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000); - } + if(this.isActive && this.enteredWorld) { + if (!this.timestamps.containsKey("nextBoxCheck")) + this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000); - if (this.level < 10 && this.enteredWorld) { - while (this.level < 10) { - grantXP(Experience.getBaseExperience(this.level + 1) - this.exp); + if (!this.isBoxed && this.timestamps.get("nextBoxCheck") < System.currentTimeMillis()) { + this.isBoxed = checkIfBoxed(this); + this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000); } - } - if (this.isBoxed && !this.containsEffect(1672601862)) { - PowersManager.applyPower(this, this, Vector3fImmutable.ZERO, 1672601862, 40, false); - } + if (this.level < 10 && this.enteredWorld) { + while (this.level < 10) { + grantXP(Experience.getBaseExperience(this.level + 1) - this.exp); + } + } + if (this.isBoxed && !this.containsEffect(1672601862)) { + PowersManager.applyPower(this, this, Vector3fImmutable.ZERO, 1672601862, 40, false); + } + } if (this.isFlying()) { if (this.effects.containsKey("MoveBuff")) { GroundPlayer(this); @@ -5338,9 +5369,11 @@ public class PlayerCharacter extends AbstractCharacter { return; } - setLoc(newLoc); + this.region = AbstractWorldObject.GetRegionByWorldObject(this); + setLoc(newLoc); + if (this.getDebug(1)) ChatManager.chatSystemInfo(this, "Distance to target " + this.getEndLoc().distance2D(this.getLoc()) + " speed " + this.getSpeed()); @@ -5637,6 +5670,8 @@ public class PlayerCharacter extends AbstractCharacter { } public void setEnteredWorld(boolean enteredWorld) { + if(enteredWorld) + this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000); this.enteredWorld = enteredWorld; } @@ -5742,10 +5777,15 @@ public class PlayerCharacter extends AbstractCharacter { } else { healthRegen = 0; manaRegen = 0; - if (this.combat == true) - stamRegen = MBServerStatics.STAMINA_REGEN_RUN_COMBAT; - else - stamRegen = MBServerStatics.STAMINA_REGEN_RUN_NONCOMBAT; + + if(this.containsEffect(441156479) || this.containsEffect(441156455)) { + stamRegen = MBServerStatics.STAMINA_REGEN_WALK; + }else { + if (this.combat == true) + stamRegen = MBServerStatics.STAMINA_REGEN_RUN_COMBAT; + else + stamRegen = MBServerStatics.STAMINA_REGEN_RUN_NONCOMBAT; + } } break; case FLYING: @@ -5876,10 +5916,16 @@ public class PlayerCharacter extends AbstractCharacter { // Reset this char's frame time. this.lastUpdateTime = System.currentTimeMillis(); this.lastStamUpdateTime = System.currentTimeMillis(); - + //this.updateMovementState(); + ///boolean updateHealth = this.regenerateHealth(); + //boolean updateMana = this.regenerateMana(); + //boolean updateStamina = this.regenerateStamina(); + //boolean consumeStamina = this.consumeStamina(); if (this.timestamps.get("SyncClient") + 5000L < System.currentTimeMillis()) { - this.syncClient(); - this.timestamps.put("SyncClient", System.currentTimeMillis()); + //if (updateHealth || updateMana || updateStamina || consumeStamina) { + this.syncClient(); + this.timestamps.put("SyncClient", System.currentTimeMillis()); + //} } } diff --git a/src/engine/objects/PlayerCombatStats.java b/src/engine/objects/PlayerCombatStats.java index 157a003f..ec3e58b6 100644 --- a/src/engine/objects/PlayerCombatStats.java +++ b/src/engine/objects/PlayerCombatStats.java @@ -1,21 +1,17 @@ package engine.objects; import engine.Enum; -import engine.gameManager.ChatManager; -import engine.math.Vector2f; -import engine.math.Vector3fImmutable; +import engine.jobs.DeferredPowerJob; import engine.powers.EffectsBase; +import engine.powers.PowersBase; import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.server.MBServerStatics; -import org.pmw.tinylog.Logger; -import javax.swing.*; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class PlayerCombatStats { @@ -26,7 +22,7 @@ public class PlayerCombatStats { public float attackSpeedHandOne; public float rangeHandOne; public float atrHandOne; - //off hand data + //offhand data public int minDamageHandTwo; public int maxDamageHandTwo; public float attackSpeedHandTwo; @@ -254,18 +250,6 @@ public class PlayerCombatStats { HIT_VALUE_MAP.put(2.50f, 100f); } - //Values for health and mana are in terms of the number of seconds it takes to recover 1% - //Values for stamina are in terms of the number of seconds it takes to recover 1 point - //HEALTH//MANA//STAMINA - private static Vector3fImmutable resting = new Vector3fImmutable(3.0f,1.2f,0.5f); - private static Vector3fImmutable idling = new Vector3fImmutable(15.0f,6.0f,5.0f); - private static Vector3fImmutable walking = new Vector3fImmutable(20.0f,8.0f,0.0f); - private static Vector3fImmutable running = new Vector3fImmutable(0.0f,0.0f,0.0f); - - //#Values for how fast mana is consumed. The first is how fast when player is not in combat - //#mode, the second is when he IS in combat mode. This is in Stamina reduction per second. - private static Vector2f consumption = new Vector2f(0.4f,0.65f); - public PlayerCombatStats(PlayerCharacter pc) { this.owner = pc; this.update(); @@ -368,20 +352,29 @@ public class PlayerCombatStats { float masteryLevel = 0; if(this.owner.skills.containsKey(skill)) { - skillLevel = this.owner.skills.get(skill).getModifiedAmount();//calculateBuffedSkillLevel(skill,this.owner);//this.owner.skills.get(skill).getTotalSkillPercet(); + skillLevel = this.owner.skills.get(skill).getModifiedAmount(); } if(this.owner.skills.containsKey(mastery)) - masteryLevel = this.owner.skills.get(mastery).getModifiedAmount();//calculateBuffedSkillLevel(mastery,this.owner);//this.owner.skills.get(mastery).getTotalSkillPercet(); + masteryLevel = this.owner.skills.get(mastery).getModifiedAmount(); float stanceValue = 0.0f; float atrEnchants = 0; - + float healerDefStance = 0.0f; for(String effID : this.owner.effects.keySet()) { if (effID.contains("Stance")) { Effect effect = this.owner.effects.get(effID); EffectsBase eb = effect.getEffectsBase(); - if(eb.getIDString().equals("STC-H-DA")) + if(eb.getIDString().equals("STC-H-DA")){ + for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.OCV)) { + float percent = mod.getPercentMod(); + int trains = this.owner.effects.get(effID).getTrains(); + float modValue = percent + (trains * mod.getRamp()); + healerDefStance += modValue * 0.01f; + } + } continue; + } for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.OCV)) { float percent = mod.getPercentMod(); @@ -432,7 +425,7 @@ public class PlayerCombatStats { preciseRune += 0.05f; } - atr = primaryStat / 2; + atr = primaryStat / 2.0f; atr += skillLevel * 4; atr += masteryLevel * 3; atr += prefixValues; @@ -441,18 +434,22 @@ public class PlayerCombatStats { atr *= 1.0f + stanceValue; if(this.owner.bonuses != null) { - float positivePercentBonuses = this.owner.bonuses.getFloatPercentPositive(Enum.ModType.OCV, Enum.SourceType.None); + float positivePercentBonuses = this.owner.bonuses.getFloatPercentPositive(Enum.ModType.OCV, Enum.SourceType.None) - stanceValue; float negativePercentBonuses = this.owner.bonuses.getFloatPercentNegative(Enum.ModType.OCV, Enum.SourceType.None); float modifier = 1 + (positivePercentBonuses + negativePercentBonuses); if(preciseRune > 1.0f) modifier -= 0.05f; - if(stanceValue > 1.0f){ - modifier -= (stanceValue - 1.0f); + if(stanceValue > 0.0f){ + modifier -= (stanceValue); } + modifier -= healerDefStance; atr *= modifier; } atr = (float) Math.round(atr); + if(atr < 0) + atr = 0; + if(mainHand){ this.atrHandOne = atr; }else{ @@ -490,7 +487,6 @@ public class PlayerCombatStats { skill = weapon.getItemBase().getSkillRequired(); mastery = weapon.getItemBase().getMastery(); if (weapon.getItemBase().isStrBased()) { - //primaryStat = this.owner.statStrCurrent; //secondaryStat = specialDex;//getDexAfterPenalty(this.owner); primaryStat = this.owner.statStrCurrent; secondaryStat = this.owner.statDexCurrent; @@ -521,6 +517,7 @@ public class PlayerCombatStats { ); if(this.owner.bonuses != null){ minDMG += this.owner.bonuses.getFloat(Enum.ModType.MinDamage, Enum.SourceType.None); + minDMG += this.owner.bonuses.getFloat(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); minDMG *= 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); } @@ -536,11 +533,13 @@ public class PlayerCombatStats { this.minDamageHandOne = roundedMin; } else { this.minDamageHandTwo = roundedMin; - if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ - if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) - this.minDamageHandOne = 0; - }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ - this.minDamageHandTwo = 0; + if(this.owner.charItemManager != null) { + if (this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null) { + if (!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) + this.minDamageHandOne = 0; + } else if (this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null) { + this.minDamageHandTwo = 0; + } } } } @@ -599,6 +598,7 @@ public class PlayerCombatStats { if(this.owner.bonuses != null){ maxDMG += this.owner.bonuses.getFloat(Enum.ModType.MaxDamage, Enum.SourceType.None); + maxDMG += this.owner.bonuses.getFloat(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); maxDMG *= 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); } @@ -612,13 +612,15 @@ public class PlayerCombatStats { if(mainHand){ this.maxDamageHandOne = roundedMax; - }else{ - this.maxDamageHandTwo = roundedMax; - if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ - if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) - this.maxDamageHandOne = 0; - }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ - this.maxDamageHandTwo = 0; + }else { + if (this.owner.charItemManager != null) { + this.maxDamageHandTwo = roundedMax; + if (this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null) { + if (!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) + this.maxDamageHandOne = 0; + } else if (this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null) { + this.maxDamageHandTwo = 0; + } } } } @@ -689,9 +691,9 @@ public class PlayerCombatStats { } float bonusValues = 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.AttackDelay,Enum.SourceType.None);//1.0f; - bonusValues -= stanceValue + delayExtra; // take away stance modifier from alac bonus values + bonusValues -= stanceValue + delayExtra; // take away stance modifier from alacrity bonus values speed *= 1 + stanceValue; // apply stance bonus - speed *= bonusValues; // apply alac bonuses without stance mod + speed *= bonusValues; // apply alacrity bonuses without stance mod if(speed < 10.0f) speed = 10.0f; @@ -745,23 +747,23 @@ public class PlayerCombatStats { float armorSkill = 0.0f; float armorDefense = 0.0f; ArrayList armorsUsed = new ArrayList<>(); - int itemdef = 0; + int itemDef; for(Item equipped : this.owner.charItemManager.getEquipped().values()){ ItemBase ib = equipped.getItemBase(); if(ib.isHeavyArmor() || ib.isMediumArmor() || ib.isLightArmor() || ib.isClothArmor()){ - itemdef = ib.getDefense(); + itemDef = ib.getDefense(); for(Effect eff : equipped.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.DR)){ - itemdef += mod.minMod + (mod.getRamp() * eff.getTrains()); + itemDef += mod.minMod + (mod.getRamp() * eff.getTrains()); } } } if(!ib.isClothArmor() && !armorsUsed.contains(ib.getSkillRequired())) { armorsUsed.add(ib.getSkillRequired()); } - armorDefense += itemdef; + armorDefense += itemDef; } } for(String armorUsed : armorsUsed){ @@ -777,16 +779,20 @@ public class PlayerCombatStats { blockSkill = this.owner.skills.get("Block").getModifiedAmount(); float shieldDefense = 0.0f; - if(this.owner.charItemManager.getEquipped(2) != null && this.owner.charItemManager.getEquipped(2).getItemBase().isShield()){ - Item shield = this.owner.charItemManager.getEquipped(2); - shieldDefense += shield.getItemBase().getDefense(); - for(Effect eff : shield.effects.values()){ - for(AbstractEffectModifier mod : eff.getEffectModifiers()){ - if(mod.modType.equals(Enum.ModType.DR)){ - shieldDefense += mod.minMod + (mod.getRamp() * eff.getTrains()); + try { + if (this.owner.charItemManager.getEquipped(2) != null && this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) { + Item shield = this.owner.charItemManager.getEquipped(2); + shieldDefense += shield.getItemBase().getDefense(); + for (Effect eff : shield.effects.values()) { + for (AbstractEffectModifier mod : eff.getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.DR)) { + shieldDefense += mod.minMod + (mod.getRamp() * eff.getTrains()); + } } } } + }catch(Exception ignore){ + } float weaponSkill = 0.0f; @@ -846,10 +852,76 @@ public class PlayerCombatStats { } } } - if(this.owner.charItemManager.getEquipped(2) == null) - blockSkill = 0; - else if(this.owner.charItemManager != null && this.owner.charItemManager.getEquipped(2) != null && !this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) - blockSkill = 0; + + //right ring + if(this.owner.charItemManager != null){ + try{ + if(this.owner.charItemManager.getEquipped(7) != null){ + for(String effID : this.owner.charItemManager.getEquipped(7).effects.keySet()) { + for (AbstractEffectModifier mod : this.owner.charItemManager.getEquipped(7).effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.DCV)) { + if (mod.getPercentMod() == 0) { + float value = mod.getMinMod(); + int trains = this.owner.effects.get(effID).getTrains(); + float modValue = value + (trains * mod.getRamp()); + flatBonuses += modValue; + } + } + } + } + } + }catch(Exception e){ + + } + //left ring + try { + if (this.owner.charItemManager.getEquipped(8) != null) { + for (String effID : this.owner.charItemManager.getEquipped(8).effects.keySet()) { + for (AbstractEffectModifier mod : this.owner.charItemManager.getEquipped(8).effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.DCV)) { + if (mod.getPercentMod() == 0) { + float value = mod.getMinMod(); + int trains = this.owner.effects.get(effID).getTrains(); + float modValue = value + (trains * mod.getRamp()); + flatBonuses += modValue; + } + } + } + } + } + }catch(Exception e){ + + } + //necklace + try{ + if(this.owner.charItemManager.getEquipped(9) != null){ + for(String effID : this.owner.charItemManager.getEquipped(9).effects.keySet()) { + for (AbstractEffectModifier mod : this.owner.charItemManager.getEquipped(9).effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.DCV)) { + if (mod.getPercentMod() == 0) { + float value = mod.getMinMod(); + int trains = this.owner.effects.get(effID).getTrains(); + float modValue = value + (trains * mod.getRamp()); + flatBonuses += modValue; + } + } + } + } + } + }catch(Exception e){ + + } + try{ + if(this.owner.charItemManager.getEquipped(2) == null) + blockSkill = 0; + else if(this.owner.charItemManager != null && this.owner.charItemManager.getEquipped(2) != null && !this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) + blockSkill = 0; + }catch(Exception e){ + + } + } + + float defense = (1 + armorSkill / 50) * armorDefense; defense += (1 + blockSkill / 100) * shieldDefense; @@ -868,6 +940,9 @@ public class PlayerCombatStats { } defense = Math.round(defense); + if(defense < 0) + defense = 0; + this.defense = (int) defense; } // PERFECT DO NOT TOUCH @@ -877,7 +952,7 @@ public class PlayerCombatStats { if(def == 0) return 100.0f; - float key = (float)((float)atr / def); + float key = ((float)atr / def); BigDecimal bd = new BigDecimal(key).setScale(2, RoundingMode.HALF_UP); key = bd.floatValue(); // handles rounding for mandatory 2 decimal places if(key < 0.40f) @@ -887,184 +962,212 @@ public class PlayerCombatStats { return HIT_VALUE_MAP.get(key); } + public static float getSpellAtr(PlayerCharacter pc, PowersBase pb) { - public void regenerate(){ - if(!this.owner.effects.containsKey("Stunned")) { - // healthRegen(this.owner); - //manaRegen(this.owner); - //staminaRegen(this.owner); - this.owner.doRegen(); - this.owner.syncClient(); - } - //staminaConsume(this.owner); - //this.owner.syncClient(); - } - public static void healthRegen(PlayerCharacter pc){ - if(!pc.timestamps.containsKey("LASTHEALTHREGEN")) - pc.timestamps.put("LASTHEALTHREGEN",System.currentTimeMillis()); - - double current = pc.health.get(); - if (Double.isNaN(current)) - current = 0.0; + if (pc == null) + return 0f; - double recovered = pc.healthMax * (0.01f / getRecoveryType(pc).health); + if(pb == null) + return 0.0f; - double mod = current + recovered; + float modifiedFocusLine = 0.0f; + if(pc.skills.containsKey(pb.skillName)){ + modifiedFocusLine = pc.skills.get(pb.skillName).getModifiedAmount(); + } - if(pc.bonuses != null) - mod *= 1 + pc.bonuses.getFloatPercentAll(Enum.ModType.HealthRecoverRate, Enum.SourceType.None); + float modifiedDexterity = pc.statDexCurrent; - boolean worked = false; - if(mod > pc.healthMax) - mod = pc.healthMax; + float weaponATR1 = 0.0f; + if(pc.charItemManager != null && pc.charItemManager.getEquipped(1) != null){ + for(Effect eff : pc.charItemManager.getEquipped(1).effects.values()){ + for (AbstractEffectModifier mod : eff.getEffectModifiers()){ + if(mod.modType.equals(Enum.ModType.OCV)){ + float base = mod.minMod; + float ramp = mod.getRamp(); + int trains = eff.getTrains(); + weaponATR1 = base + (ramp * trains); + } + } + } + } - while (!worked) { - worked = pc.health.compareAndSet((float) current, (float) mod); + float weaponATR2 = 0.0f; + if(pc.charItemManager != null && pc.charItemManager.getEquipped(2) != null){ + for(Effect eff : pc.charItemManager.getEquipped(2).effects.values()){ + for (AbstractEffectModifier mod : eff.getEffectModifiers()){ + if(mod.modType.equals(Enum.ModType.OCV)){ + float base = mod.minMod; + float ramp = mod.getRamp(); + int trains = eff.getTrains(); + weaponATR2 = base + (ramp * trains); + } + } + } } - pc.timestamps.put("LASTHEALTHREGEN",System.currentTimeMillis()); - } + float precise = 1.0f; + for(CharacterRune rune : pc.runes){ + if(rune.getRuneBase().getName().equals("Precise")) + precise += 0.05f; + } - public static void manaRegen(PlayerCharacter pc){ - if(!pc.timestamps.containsKey("LASTMANAREGEN")) - pc.timestamps.put("LASTMANAREGEN",System.currentTimeMillis()); + float stanceMod = 1.0f; + float atrBuffs = 0.0f; - if(pc.isCasting){ - pc.timestamps.put("LASTMANAREGEN",System.currentTimeMillis()); - return; + float healerDefStance = 0.0f; + for(String effID : pc.effects.keySet()) { + if (effID.contains("Stance")) { + Effect effect = pc.effects.get(effID); + EffectsBase eb = effect.getEffectsBase(); + if(eb.getIDString().equals("STC-H-DA")){ + for (AbstractEffectModifier mod : pc.effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.OCV)) { + float percent = mod.getPercentMod(); + int trains = pc.effects.get(effID).getTrains(); + float modValue = percent + (trains * mod.getRamp()); + healerDefStance += modValue * 0.01f; + } + } + continue; + } + for (AbstractEffectModifier mod : pc.effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.OCV)) { + float percent = mod.getPercentMod(); + int trains = pc.effects.get(effID).getTrains(); + float modValue = percent + (trains * mod.getRamp()); + stanceMod += modValue * 0.01f; + } + } + } else { + for (AbstractEffectModifier mod : pc.effects.get(effID).getEffectModifiers()) { + if (mod.modType.equals(Enum.ModType.OCV)) { + if(mod.getPercentMod() == 0) { + float value = mod.getMinMod(); + int trains = pc.effects.get(effID).getTrains(); + float modValue = value + (trains * mod.getRamp()); + atrBuffs += modValue; + } + } + } + } } - double current = pc.mana.get(); - if (Double.isNaN(current)) { - current = 0.0; + float atr = 7 * modifiedFocusLine; + atr += (modifiedDexterity * 0.5f) + weaponATR1 + weaponATR2; + atr *= precise; + atr += atrBuffs; + if(pc.getWeaponPower() != null){ + DeferredPowerJob dpj = pc.getWeaponPower(); + dpj.endEffect(); } - double recovered = pc.manaMax * (0.01f / getRecoveryType(pc).mana); - - double mod = current + recovered; if(pc.bonuses != null) - mod *= 1 + pc.bonuses.getFloatPercentAll(Enum.ModType.ManaRecoverRate, Enum.SourceType.None); + atr *= 1 + (pc.bonuses.getFloatPercentAll(Enum.ModType.OCV, Enum.SourceType.None) - (stanceMod - 1) - (precise - 1) - healerDefStance); - boolean worked = false; - if(mod > pc.manaMax) - mod = pc.manaMax; - - while (!worked) { - worked = pc.mana.compareAndSet((float) current, (float) mod); - } - - pc.timestamps.put("LASTMANAREGEN",System.currentTimeMillis()); + atr *= stanceMod; + return atr; } - public static void staminaRegen(PlayerCharacter pc){ - //cannot regen is moving, swimming or flying - if(pc.isFlying() || pc.isSwimming() || pc.isMoving()) { - pc.timestamps.put("LASTSTAMINAREGEN",System.currentTimeMillis()); - return; - } + public void grantExperience(AbstractCharacter killed, Group group){ - if(!pc.timestamps.containsKey("LASTSTAMINAREGEN")) - pc.timestamps.put("LASTSTAMINAREGEN",System.currentTimeMillis()); + if(killed == null) + return; + double grantedXP; - float stateMultiplier = 1.0f; - if(pc.isSit()) - stateMultiplier = 2.0f; + if(group != null){ - long deltaTime = System.currentTimeMillis() - pc.timestamps.get("LASTSTAMINAREGEN"); - float current = pc.stamina.get(); - float properDelay = (deltaTime / getRecoveryType(pc).stamina) * 0.001f; - float mod = current + (properDelay * stateMultiplier); + for(PlayerCharacter member : group.members){ + //white mob, early exit + if(Experience.getConMod(member,killed) <= 0) + continue; - if(pc.bonuses != null) - mod *= 1 + pc.bonuses.getFloatPercentAll(Enum.ModType.StaminaRecoverRate, Enum.SourceType.None); + //can only get XP over level 75 for player kills + if(member.level >= 75 && !killed.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) + continue; - boolean worked = false; - if(mod > pc.staminaMax) - mod = pc.staminaMax; + //cannot gain xp while dead + if(!member.isAlive()) + continue; - while (!worked) { - worked = pc.stamina.compareAndSet(current, mod); - } + //out of XP range + if(member.loc.distanceSquared(killed.loc) > MBServerStatics.CHARACTER_LOAD_RANGE * MBServerStatics.CHARACTER_LOAD_RANGE) + continue; - pc.timestamps.put("LASTSTAMINAREGEN",System.currentTimeMillis()); - } + float mod; + switch(group.members.size()){ + default: + mod = 1.0f; + break; + case 2: + mod = 0.8f; + break; + case 3: + mod = 0.73f; + break; + case 4: + mod = 0.69f; + break; + case 5: + mod = 0.65f; + break; + case 6: + mod = 0.58f; + break; + case 7: + mod = 0.54f; + break; + case 8: + mod = 0.50f; + break; + case 9: + mod = 0.47f; + break; + case 10: + mod = 0.45f; + break; + } + double xp = getXP(member) * mod; - public static void staminaConsume(PlayerCharacter pc){ - //no natural consumption if not moving, swimming or flying - if(!pc.isFlying() && !pc.isSwimming() && !pc.isMoving()) { - pc.timestamps.put("LASTSTAMINACONSUME",System.currentTimeMillis()); - return; - } - //no stamina consumption for TravelStance - if(pc.containsEffect(441156479) || pc.containsEffect(441156455)) { - pc.timestamps.put("LASTSTAMINACONSUME",System.currentTimeMillis()); - return; - } - float stateMultiplier = 1.0f; - if(pc.isSwimming() || pc.isFlying()) - stateMultiplier = 2.5f; - - if(!pc.timestamps.containsKey("LASTSTAMINACONSUME")) - pc.timestamps.put("LASTSTAMINACONSUME",System.currentTimeMillis()); - - long deltaTime = System.currentTimeMillis() - pc.timestamps.get("LASTSTAMINACONSUME"); - float current = pc.stamina.get(); - float consumed = ((deltaTime * 0.001f) * 0.6f * stateMultiplier); - float mod = current - consumed; - boolean worked = false; - if(mod <= 0) - mod = 0; - if(mod == 0){ - healthConsume(pc, (int) (consumed * 2.5f)); - }else { - while (!worked) { - worked = pc.stamina.compareAndSet(current,mod); + member.grantXP((int) xp); } + + }else{ + //Solo XP + + //white mob, early exit + if(Experience.getConMod(this.owner,killed) <= 0) + return; + + //can only get XP over level 75 for player kills + if(this.owner.level >= 75 && !killed.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) + return; + + //cannot gain xp while dead + if(!this.owner.isAlive()) + return; + + this.owner.grantXP(getXP(this.owner)); } - pc.timestamps.put("LASTSTAMINACONSUME",System.currentTimeMillis()); } - public static void healthConsume(PlayerCharacter pc, int amount){ - boolean worked = false; - float current = pc.health.get(); - float mod = current - amount; - if(mod <= 0){ - if (pc.isAlive.compareAndSet(true, false)) - pc.killCharacter("Water"); - return; + public static int getXP(PlayerCharacter pc){ + double xp = 0; + float mod = 0.10f; + + if (pc.level >= 26 && pc.level <= 75) + { + mod = 0.10f - (0.001f * (pc.level - 24)); } - while(!worked){ - worked = pc.health.compareAndSet(current,mod); + else if (pc.level > 75) + { + mod = 0.05f; } - } - private enum recoveryType{ - RESTING(3.0f,1.25f,0.5f), - IDLING(15.0f,6.0f,5.0f), - WALKING(20.0f,8.0f,0.0f), - RUNNING(0.0f,0.0f,0.0f); - public float health; - public float mana; - public float stamina; + float levelFull = Experience.LevelToExp[pc.level + 1] - Experience.LevelToExp[pc.level]; + xp = levelFull * mod; - recoveryType(float health,float mana, float stamina){ - this.health = health; - this.mana = mana; - this.stamina = stamina; - } - } - - public static recoveryType getRecoveryType(PlayerCharacter pc){ - if(pc.sit) - return recoveryType.RESTING; - else if(!pc.isMoving() && !pc.isFlying()) - return recoveryType.IDLING; - else - if(pc.walkMode) - return recoveryType.WALKING; - else - return recoveryType.RUNNING; + return (int) xp; } } diff --git a/src/engine/objects/VendorDialog.java b/src/engine/objects/VendorDialog.java index 674f34ea..f2071bf2 100644 --- a/src/engine/objects/VendorDialog.java +++ b/src/engine/objects/VendorDialog.java @@ -21,7 +21,7 @@ public class VendorDialog extends AbstractGameObject { private static VendorDialog vd; private final String dialogType; private final String intro; - private ArrayList options = new ArrayList<>(); + ArrayList options = new ArrayList<>(); public VendorDialog(String dialogType, String intro, int UUID) { super(UUID); diff --git a/src/engine/powers/effectmodifiers/HealthEffectModifier.java b/src/engine/powers/effectmodifiers/HealthEffectModifier.java index a72b173b..770bda54 100644 --- a/src/engine/powers/effectmodifiers/HealthEffectModifier.java +++ b/src/engine/powers/effectmodifiers/HealthEffectModifier.java @@ -9,6 +9,7 @@ package engine.powers.effectmodifiers; +import engine.Enum; import engine.Enum.DamageType; import engine.Enum.GameObjectType; import engine.Enum.ModType; @@ -122,9 +123,13 @@ public class HealthEffectModifier extends AbstractEffectModifier { float spi = (pc.getStatSpiCurrent() >= 1) ? (float) pc.getStatSpiCurrent() : 1f; // min *= (intt * 0.0045 + 0.055 * (float)Math.sqrt(intt - 0.5) + spi * 0.006 + 0.07 * (float)Math.sqrt(spi - 0.5) + 0.02 * (int)focus); // max *= (intt * 0.0117 + 0.13 * (float)Math.sqrt(intt - 0.5) + spi * 0.0024 + (float)Math.sqrt(spi - 0.5) * 0.021 + 0.015 * (int)focus); + min = HealthEffectModifier.getMinDamage(min, intt, spi, focus); max = HealthEffectModifier.getMaxDamage(max, intt, spi, focus); + //min *= pc.ZergMultiplier; + //max *= pc.ZergMultiplier; + //debug for spell damage and atr if (pc.getDebug(16)) { String smsg = "Damage: " + (int) Math.abs(min) + " - " + (int) Math.abs(max); @@ -165,9 +170,16 @@ public class HealthEffectModifier extends AbstractEffectModifier { PlayerBonuses bonus = source.getBonuses(); // Apply any power effect modifiers (such as stances) - if (bonus != null) - modAmount *= (1 + (bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None))); + if (bonus != null){ + modAmount *= (1 + bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None)); + } } + + if(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)){ + float multiplier = ((PlayerCharacter)source).ZergMultiplier; + modAmount *= multiplier; + } + if (modAmount == 0f) return; if (AbstractWorldObject.IsAbstractCharacter(awo)) { diff --git a/src/engine/powers/effectmodifiers/ManaEffectModifier.java b/src/engine/powers/effectmodifiers/ManaEffectModifier.java index d70b9a2c..3e01825d 100644 --- a/src/engine/powers/effectmodifiers/ManaEffectModifier.java +++ b/src/engine/powers/effectmodifiers/ManaEffectModifier.java @@ -129,9 +129,16 @@ public class ManaEffectModifier extends AbstractEffectModifier { PlayerBonuses bonus = source.getBonuses(); // Apply any power effect modifiers (such as stances) - if (bonus != null) + if (bonus != null){ modAmount *= (1 + bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None)); + } + } + + if(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)){ + modAmount *= ((PlayerCharacter)source).ZergMultiplier; + } + if (modAmount == 0f) return; if (AbstractWorldObject.IsAbstractCharacter(awo)) { diff --git a/src/engine/powers/effectmodifiers/StaminaEffectModifier.java b/src/engine/powers/effectmodifiers/StaminaEffectModifier.java index 59145f16..930816a2 100644 --- a/src/engine/powers/effectmodifiers/StaminaEffectModifier.java +++ b/src/engine/powers/effectmodifiers/StaminaEffectModifier.java @@ -125,9 +125,15 @@ public class StaminaEffectModifier extends AbstractEffectModifier { PlayerBonuses bonus = source.getBonuses(); // Apply any power effect modifiers (such as stances) - if (bonus != null) - modAmount *= (1 + (bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None))); + if (bonus != null){ + modAmount *= (1 + bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None)); + } + } + + if(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)){ + modAmount *= ((PlayerCharacter)source).ZergMultiplier; } + if (modAmount == 0f) return; if (AbstractWorldObject.IsAbstractCharacter(awo)) { diff --git a/src/engine/powers/poweractions/TransferStatPowerAction.java b/src/engine/powers/poweractions/TransferStatPowerAction.java index 4deea480..30f185d8 100644 --- a/src/engine/powers/poweractions/TransferStatPowerAction.java +++ b/src/engine/powers/poweractions/TransferStatPowerAction.java @@ -217,8 +217,13 @@ public class TransferStatPowerAction extends AbstractPowerAction { // Apply any power effect modifiers (such as stances) PlayerBonuses bonus = source.getBonuses(); - if (bonus != null) + if (bonus != null){ damage *= (1 + bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None)); + } + + if(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)){ + damage *= ((PlayerCharacter)source).ZergMultiplier; + } //get amount to transfer fromAmount = damage; diff --git a/src/engine/server/login/LoginServer.java b/src/engine/server/login/LoginServer.java index 2c2b5bf9..efe072fe 100644 --- a/src/engine/server/login/LoginServer.java +++ b/src/engine/server/login/LoginServer.java @@ -281,6 +281,9 @@ public class LoginServer { Logger.info("Loading All Realms"); Realm.loadAllRealms(); + Logger.info("Trashing Multibox Cheaters"); + DbManager.AccountQueries.TRASH_CHEATERS(); + Logger.info("***Boot Successful***"); return true; } diff --git a/src/engine/util/KeyCloneAudit.java b/src/engine/util/KeyCloneAudit.java index 95a89fed..9695fa6b 100644 --- a/src/engine/util/KeyCloneAudit.java +++ b/src/engine/util/KeyCloneAudit.java @@ -18,17 +18,35 @@ public enum KeyCloneAudit { public static boolean auditChatMsg(PlayerCharacter pc, String message) { - if(pc.combatTarget != null && message.contains(String.valueOf(pc.combatTarget.getObjectUUID()))) { + if(pc.selectedUUID == 0) + return false; + + int id = pc.selectedUUID; + String value = String.valueOf(id); + if(message.contains(value)) { //targeting software detected Group g = GroupManager.getGroup(pc); - if (g == null) - pc.getClientConnection().forceDisconnect(); - else - for (PlayerCharacter member : g.members) - member.getClientConnection().forceDisconnect(); - + if (g == null) { + try { + Logger.error("TARGET SOFTWARE DETECTED ON ACCOUNT: " + pc.getAccount().getUname()); + DbManager.AccountQueries.SET_TRASH(pc.getAccount().getUname(), "TARGET"); + pc.getClientConnection().forceDisconnect(); + }catch(Exception e){ + + } + }else { + for (PlayerCharacter member : g.members) { + try { + Logger.error("TARGET SOFTWARE DETECTED ON ACCOUNT: " + member.getAccount().getUname()); + DbManager.AccountQueries.SET_TRASH(member.getAccount().getUname(), "TARGET"); + member.getClientConnection().forceDisconnect(); + } catch (Exception e) { + + } + } + } return true; } @@ -49,7 +67,7 @@ public enum KeyCloneAudit { if (machineCount > Integer.parseInt(ConfigManager.MB_WORLD_KEYCLONE_MAX.getValue())) { Logger.error("Keyclone detected from: " + player.getAccount().getUname() + " with machine count of: " + machineCount); - DbManager.AccountQueries.SET_TRASH(machineID); + DbManager.AccountQueries.SET_TRASH(machineID,"MEMBERLIMIT"); } } @@ -58,11 +76,18 @@ public enum KeyCloneAudit { try { TargetObjectMsg tarMsg = (TargetObjectMsg) msg; ClientConnection origin = (ClientConnection) msg.getOrigin(); + long now = System.currentTimeMillis(); - if (tarMsg.getTargetType() != MBServerStatics.MASK_PLAYER) + if (PlayerCharacter.getPlayerCharacter(tarMsg.getTargetID()) == null) return; + PlayerCharacter pc = origin.getPlayerCharacter(); + pc.selectedUUID = tarMsg.getTargetID(); + + if(pc.getObjectUUID() == tarMsg.getTargetID()) + return; //dont trigger for targeting yourself + if (System.currentTimeMillis() > origin.finalStrikeRefresh) { origin.lastStrike = System.currentTimeMillis(); origin.strikes = 0; @@ -79,8 +104,10 @@ public enum KeyCloneAudit { if (origin.strikes > 20) { origin.finalStrikes++; } - if (origin.finalStrikes > 3) {origin.forceDisconnect(); - DbManager.AccountQueries.SET_TRASH(origin.machineID); + if (origin.finalStrikes > 3) { + origin.forceDisconnect(); + DbManager.AccountQueries.SET_TRASH(pc.getAccount().getUname(), "TABSPEED"); + Logger.error("TAB SPEED DETECTED ON ACCOUNT: " + pc.getAccount().getUname()); } } catch (Exception e) { diff --git a/src/engine/workthreads/HourlyJobThread.java b/src/engine/workthreads/HourlyJobThread.java index 118d385d..93751791 100644 --- a/src/engine/workthreads/HourlyJobThread.java +++ b/src/engine/workthreads/HourlyJobThread.java @@ -53,10 +53,8 @@ public class HourlyJobThread implements Runnable { Logger.error("missing city map"); } - //run maintenance every day at 2 am - if(LocalDateTime.now().getHour() == 2) { - MaintenanceManager.dailyMaintenance(); - + //run mines every day at 1:00 am CST + if(LocalDateTime.now().getHour() == 1) { //produce mine resources once a day for (Mine mine : Mine.getMines()) { try { @@ -68,6 +66,11 @@ public class HourlyJobThread implements Runnable { } } + //run maintenance every day at 2 am + if(LocalDateTime.now().getHour() == 2) { + MaintenanceManager.dailyMaintenance(); + } + switch(LocalDateTime.now().getHour()){ case 3: case 6: @@ -94,5 +97,27 @@ public class HourlyJobThread implements Runnable { bane.setDefaultTime(); } } + + try{ + Logger.info("Trashing Multibox Cheaters"); + DbManager.AccountQueries.TRASH_CHEATERS(); + + //disconnect all players who were banned and are still in game + for(PlayerCharacter pc : SessionManager.getAllActivePlayers()){ + Account account = pc.getClientConnection().getAccount(); + if(account == null) + continue; + try { + boolean banned = DbManager.AccountQueries.GET_ACCOUNT(account.getUname()).status.equals(Enum.AccountStatus.BANNED); + if (banned) { + pc.getClientConnection().forceDisconnect(); + } + }catch(Exception e){ + Logger.error(e.getMessage()); + } + } + }catch(Exception e){ + Logger.error("Failed To Run Ban Multibox Abusers"); + } } } diff --git a/src/engine/workthreads/UpdateThread.java b/src/engine/workthreads/UpdateThread.java index 46f4c19f..86b3ff80 100644 --- a/src/engine/workthreads/UpdateThread.java +++ b/src/engine/workthreads/UpdateThread.java @@ -32,11 +32,7 @@ public class UpdateThread implements Runnable { try { for(PlayerCharacter player : SessionManager.getAllActivePlayerCharacters()){ if (player != null) { - try { - player.update(true); - }catch(Exception e){ - Logger.error("UPDATE ERROR FOR PLAYER: " + player.getFirstName(),e); - } + player.update(true); } } } catch (Exception e) { @@ -47,30 +43,13 @@ public class UpdateThread implements Runnable { } public void run() { - //lastRun = System.currentTimeMillis(); - //while (true) { - // if (System.currentTimeMillis() >= lastRun + instancedelay) { // Correct condition - // this.processPlayerUpdate(); - // lastRun = System.currentTimeMillis(); // Update lastRun after processing - // }else { - // try { - // Thread.sleep(100); // Pause for 100ms to reduce CPU usage - // } catch (InterruptedException e) { - // Logger.error("Thread interrupted", e); - // Thread.currentThread().interrupt(); - // } - // } - // Thread.yield(); - //} - + lastRun = System.currentTimeMillis(); while (true) { try { - this.processPlayerUpdate(); // Execute update logic - Thread.sleep(250); // Always sleep for 250ms + this.processPlayerUpdate(); + Thread.sleep(100); // Pause for 100ms to reduce CPU usage } catch (InterruptedException e) { Logger.error("Thread interrupted", e); - Thread.currentThread().interrupt(); - break; // Exit loop if interrupted } } }