From 6a3e91f13c93f6ea88f0ea711aedc190868c3c60 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Fri, 11 Aug 2023 00:09:07 +0000 Subject: [PATCH] Deep wilderness threat balancing Killing the hostile event now removes all built up threat Hostile event can now follow the player up/down stairs, through cave entrances, etc. Hostile event now applies disease status for 25 hits when killed Reduced the threat gained by killing NPCs by 5x Increased the threat gained by brawlers drops by 3.75x PvP gear drops now award maximum threat (30 minutes to return to zero) In summary, the hostile event will trigger less often but will be more dangerous --- .../wilderness/handlers/DeepWildyThreat.kt | 58 ++++++++++++++++--- .../handlers/revenants/RevenantController.kt | 5 +- .../handlers/revenants/RevenantNPC.java | 3 +- .../handlers/revenants/RevenantType.java | 13 ++++- .../core/game/system/timer/impl/Frozen.kt | 1 - .../world/map/zone/impl/WildernessZone.java | 17 ++++-- .../core/game/world/update/UpdateSequence.kt | 8 +-- 7 files changed, 84 insertions(+), 21 deletions(-) diff --git a/Server/src/main/content/region/wilderness/handlers/DeepWildyThreat.kt b/Server/src/main/content/region/wilderness/handlers/DeepWildyThreat.kt index 9bc2f593c..1b0aa0d65 100644 --- a/Server/src/main/content/region/wilderness/handlers/DeepWildyThreat.kt +++ b/Server/src/main/content/region/wilderness/handlers/DeepWildyThreat.kt @@ -1,13 +1,19 @@ package content.region.wilderness.handlers +import content.region.wilderness.handlers.revenants.RevenantController +import content.region.wilderness.handlers.revenants.RevenantNPC import content.region.wilderness.handlers.revenants.RevenantType import core.api.* import core.game.node.entity.Entity import core.game.node.entity.combat.DeathTask import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior import core.game.node.entity.player.Player +import core.game.node.item.Item import core.game.system.command.Privilege import core.game.system.timer.PersistTimer +import core.game.system.timer.impl.Disease +import core.game.world.map.zone.impl.WildernessZone import core.game.world.update.flag.context.Graphics import core.tools.RandomFunction import core.tools.colorize @@ -38,7 +44,6 @@ class DWThreatTimer : PersistTimer(1, "dw-threat"), Commands { var ticksLeft = 0 var lastMessage = 0 var currentRev: NPC? = null - var chats = arrayOf("Leave this place!", "Suffer!", "Death to you!", "Flee, coward!", "Leave my resting place!", "Let me rest in peace!", "You belong to me!") override fun run(entity: Entity): Boolean { if (ticksLeft-- <= 0) return false @@ -59,13 +64,12 @@ class DWThreatTimer : PersistTimer(1, "dw-threat"), Commands { val type = RevenantType.getClosestHigherOrEqual(entity.properties.currentCombatLevel) val npc = NPC.create(type.ids.random(), entity.location) npc.isRespawn = false + npc.behavior = RevGuardianBehavior() npc.init() - npc.attack(entity) - Graphics.send(Graphics(86), npc.location) - ticksLeft -= 500 - sendChat(npc, chats.random()) + npc.setAttribute("dw-threat-target", entity) + RevenantController.unregisterRevenant(npc as RevenantNPC, false) currentRev = npc - } else if (currentRev != null && !currentRev!!.location.withinDistance(entity.location, 25)) { + } else if (currentRev != null && !currentRev!!.location.withinDistance(entity.location, 25) && currentRev!!.properties.teleportLocation == null) { poofClear(currentRev!!) currentRev = null } @@ -74,11 +78,11 @@ class DWThreatTimer : PersistTimer(1, "dw-threat"), Commands { } override fun save(root: JSONObject, entity: Entity) { - root["threat-time-remaining"] = ticksLeft + root["threat-time-remaining"] = ticksLeft.toString() } override fun parse(root: JSONObject, entity: Entity) { - ticksLeft = root.getOrDefault("threat-time-remaining", 3000) as? Int ?: 3000 + ticksLeft = root["threat-time-remaining"]?.toString()?.toIntOrNull() ?: 0 } override fun defineCommands() { @@ -87,4 +91,42 @@ class DWThreatTimer : PersistTimer(1, "dw-threat"), Commands { notify(player, "Current Threat: ${timer.ticksLeft}") } } +} + +class RevGuardianBehavior : NPCBehavior() { + val deathMessages = arrayOf("Curses upon thee!", "Rot in blight!", "Suffer my wrath!", "Nevermore!", "May ye be undone!") + var chats = arrayOf("Leave this place!", "Suffer!", "Death to thee!", "Flee, coward!", "Leave my resting place!", "Let me rest in peace!", "Thou belongeth to me!") + + override fun tick(self: NPC): Boolean { + val target = getAttribute(self, "dw-threat-target", null) ?: return true + if (!target.isActive) { + self.clear() + return true + } + if (target.properties.teleportLocation != null && self.properties.teleportLocation == null) { + if (WildernessZone.isInZone(target.properties.teleportLocation)) + self.properties.teleportLocation = target.properties.teleportLocation + } + sendChat(self, "ticking") + self.attack(target) + return true + } + + override fun onCreation(self: NPC) { + Graphics.send(Graphics(86), self.location) + sendChat(self, chats.random()) + } + + override fun onDeathStarted(self: NPC, killer: Entity) { + val target = getAttribute(self, "dw-threat-target", null) ?: return + sendChat(self, deathMessages.random()) + val disease = getOrStartTimer(target, 25) + disease.hitsLeft = 25 + } + + override fun onDropTableRolled(self: NPC, killer: Entity, drops: ArrayList) { + val target = getAttribute(self, "dw-threat-target", null) ?: return + val timer = getOrStartTimer(target) + timer.ticksLeft = 0 + } } \ No newline at end of file diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt index ef861325a..1a1bdc055 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt @@ -35,11 +35,12 @@ class RevenantController : TickListener, Commands { Repository.RENDERABLE_NPCS.add(revenantNPC) } - @JvmStatic fun unregisterRevenant(revenantNPC: RevenantNPC) { + @JvmStatic fun unregisterRevenant(revenantNPC: RevenantNPC, removeRender: Boolean = true) { trackedRevenants.remove(revenantNPC) taskTimeRemaining.remove(revenantNPC) currentTask.remove(revenantNPC) - Repository.RENDERABLE_NPCS.remove(revenantNPC) + if (removeRender) + Repository.RENDERABLE_NPCS.remove(revenantNPC) } val routes = listOf( diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java index 34f921773..67a018d6a 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java @@ -99,7 +99,7 @@ public class RevenantNPC extends AbstractNPC { @Override public void clear() { super.clear(); - RevenantController.unregisterRevenant(this); + RevenantController.unregisterRevenant(this, true); } @Override @@ -125,6 +125,7 @@ public class RevenantNPC extends AbstractNPC { } setAttribute("eat-delay", GameWorld.getTicks() + 6); } + behavior.tick(this); if (aggressiveHandler != null && aggressiveHandler.selectTarget()) { return; } diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantType.java b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantType.java index b2f06aba3..0e7bfb000 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantType.java +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantType.java @@ -2,6 +2,9 @@ package content.region.wilderness.handlers.revenants; import core.cache.def.impl.NPCDefinition; +import java.util.ArrayList; +import java.util.List; + /** * A revenant type. * @author Vexia @@ -66,6 +69,14 @@ public enum RevenantType { NPCDefinition def = NPCDefinition.forId(t.ids[0]); if (def.getCombatLevel() >= combatLevel) return t; } - return null; + return RevenantType.DRAGON; + } + + public static List getAllIds() { + ArrayList ids = new ArrayList<>(); + for (RevenantType t : values()) { + for (int id : t.ids) ids.add(id); + } + return ids; } } diff --git a/Server/src/main/core/game/system/timer/impl/Frozen.kt b/Server/src/main/core/game/system/timer/impl/Frozen.kt index d028259d7..ed99a9253 100644 --- a/Server/src/main/core/game/system/timer/impl/Frozen.kt +++ b/Server/src/main/core/game/system/timer/impl/Frozen.kt @@ -40,7 +40,6 @@ class Frozen : PersistTimer (1, "frozen") { override fun getTimer (vararg args: Any) : RSTimer { val inst = Frozen() - println(args) inst.runInterval = args.getOrNull(0) as? Int ?: 10 inst.shouldApplyImmunity = args.getOrNull(1) as? Boolean ?: false return inst diff --git a/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java b/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java index fd7211e08..fd67844ea 100644 --- a/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java @@ -97,13 +97,13 @@ public final class WildernessZone extends MapZone { boolean isValidTarget = e instanceof NPC && (isDeepWildy || e.asNpc().getName().contains("Revenant") || e.getId() == NPCs.CHAOS_ELEMENTAL_3200); if (isDeepWildy) { - DeepWildyThreat.adjustThreat((Player) killer, 250); + DeepWildyThreat.adjustThreat((Player) killer, 50); } if (!isValidTarget) return; int cEleGloveRate = isDeepWildy ? 50 : 150; - int normalGloveRate = isDeepWildy ? 75 : 150; + int normalGloveRate = isDeepWildy ? 100 : 150; int pvpGearRate = getNewDropRate(e.asNpc().getDefinition().getCombatLevel()); if (isDeepWildy) @@ -114,7 +114,8 @@ public final class WildernessZone extends MapZone { Item reward = new Item(BrawlingGloves.forIndicator(glove).getId()); GroundItemManager.create(reward, e.asNpc().getDropLocation(), killer.asPlayer()); Repository.sendNews(killer.getUsername() + " has received " + reward.getName().toLowerCase() + " from a " + e.asNpc().getName() + "!"); - DeepWildyThreat.adjustThreat((Player) killer, 200); + if (isDeepWildy) + DeepWildyThreat.adjustThreat((Player) killer, 750); } for (int j : PVP_GEAR) { @@ -128,7 +129,8 @@ public final class WildernessZone extends MapZone { } Repository.sendNews(killer.asPlayer().getUsername() + " has received a " + reward.getName() + " from a " + e.asNpc().getName() + "!"); GroundItemManager.create(reward, ((NPC) e).getDropLocation(), killer.asPlayer()); - DeepWildyThreat.adjustThreat((Player) killer, 1000); + if (isDeepWildy) + DeepWildyThreat.adjustThreat((Player) killer, 3000); } } } @@ -307,6 +309,13 @@ public final class WildernessZone extends MapZone { return false; } + public static boolean isInZone (Location l) { + for (ZoneBorders z : INSTANCE.borders) { + if (z.insideBorder(l)) return true; + } + return false; + } + /** * The wilderness level. * @return the level. diff --git a/Server/src/main/core/game/world/update/UpdateSequence.kt b/Server/src/main/core/game/world/update/UpdateSequence.kt index e50650f70..bc17fbd65 100644 --- a/Server/src/main/core/game/world/update/UpdateSequence.kt +++ b/Server/src/main/core/game/world/update/UpdateSequence.kt @@ -33,14 +33,14 @@ class UpdateSequence playersList = renderablePlayers npcList = Repository.renderableNpcs lobbyList!!.map{ PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(it)) } - - var playerTickStart = System.currentTimeMillis() - renderablePlayers.forEach(Player::tick) - Grafana.playerTickTime = (System.currentTimeMillis() - playerTickStart).toInt() var npcTickStart = System.currentTimeMillis() npcList!!.forEach(NPC::tick) Grafana.npcTickTime = (System.currentTimeMillis() - npcTickStart).toInt() + + var playerTickStart = System.currentTimeMillis() + renderablePlayers.forEach(Player::tick) + Grafana.playerTickTime = (System.currentTimeMillis() - playerTickStart).toInt() } /**