From 53dc16977452012dd1ff4806d8889a68e3f43637 Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 14 Nov 2024 11:36:09 +0000 Subject: [PATCH] Corporeal beast authenticity improvements Dark core will no longer jump to players in safe area Adjusted maximum attack hits Protect from magic now blocks the big dart attack by 40% Now resummons the dark core when it dies Made the dark core respawn mechanics more authentic Dark core now drops ashes --- Server/data/configs/drop_tables.json | 14 ++ .../handlers/CorporealBeastNPC.java | 138 ++++++++++-------- .../handlers/DarkEnergyCoreNPC.java | 27 ++-- .../node/entity/combat/MultiSwingHandler.kt | 2 +- 4 files changed, 106 insertions(+), 75 deletions(-) diff --git a/Server/data/configs/drop_tables.json b/Server/data/configs/drop_tables.json index 1a8525af4..8aff52d67 100644 --- a/Server/data/configs/drop_tables.json +++ b/Server/data/configs/drop_tables.json @@ -58878,5 +58878,19 @@ "maxAmount": "1" } ] + }, + { + "default": [ + { + "minAmount": "1", + "weight": "1.0", + "id": "592", + "maxAmount": "1" + } + ], + "charm": [], + "ids": "8127", + "description": "Dark energy core", + "main": [] } ] \ No newline at end of file diff --git a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java index ea1849876..67ad9c876 100644 --- a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java @@ -2,15 +2,11 @@ package content.region.wilderness.handlers; import content.data.BossKillCounter; import core.game.node.entity.Entity; -import core.game.node.entity.combat.BattleState; -import core.game.node.entity.combat.CombatStyle; -import core.game.node.entity.combat.CombatSwingHandler; +import core.game.node.entity.combat.*; import core.game.node.entity.combat.ImpactHandler.HitsplatType; -import core.game.node.entity.combat.MultiSwingHandler; import core.game.node.entity.combat.equipment.SwitchAttack; import core.game.node.entity.combat.equipment.Weapon; import core.game.node.entity.impl.Projectile; -import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.npc.NPC; import core.game.node.entity.npc.NPCBehavior; import core.game.node.entity.player.Player; @@ -22,7 +18,6 @@ import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; -import core.plugin.Plugin; import core.tools.RandomFunction; import org.rs09.consts.NPCs; @@ -32,7 +27,6 @@ import java.util.List; /** * Handles the Corporeal beast NPC. * @author Emperor - * */ @Initializable public final class CorporealBeastNPC extends NPCBehavior { @@ -41,19 +35,24 @@ public final class CorporealBeastNPC extends NPCBehavior { * The combat handler. */ private final MultiSwingHandler combatHandler = new CombatHandler(); - + /** * The dark energy core NPC. */ public NPC darkEnergyCore; - + + /** + * Whether to force a dark core spawn roll on our next swing (only done if we just got hit >= 32 damage). + */ + public boolean forceCoreRoll = false; + /** * Constructs a new {@code CorporealBeastNPC} {@code Object}. */ public CorporealBeastNPC() { - super(new int[]{NPCs.CORPOREAL_BEAST_8133}); + super(new int[] { NPCs.CORPOREAL_BEAST_8133 }); } - + @Override public void onCreation(NPC self) { self.configureBossData(); @@ -64,27 +63,31 @@ public final class CorporealBeastNPC extends NPCBehavior { return combatHandler; } - @Override - public void beforeDamageReceived(NPC self, Entity attacker, BattleState state) { - if(state.getStyle() == CombatStyle.MELEE || state.getStyle() == CombatStyle.RANGE) { - Weapon w = state.getWeapon(); - String name = w != null ? w.getName() : ""; - if(w == null || name.toLowerCase().indexOf("spear") == -1) { - if(state.getEstimatedHit() > 0) { - state.setEstimatedHit(state.getEstimatedHit()/2); - } - if(state.getSecondaryHit() > 0) { - state.setSecondaryHit(state.getSecondaryHit()/2); - } - } - } - if(state.getEstimatedHit() > 100) { - state.setEstimatedHit(100); - } - if(state.getSecondaryHit() > 100) { - state.setSecondaryHit(100); - } - } + @Override + public void beforeDamageReceived(NPC self, Entity attacker, BattleState state) { + if (state.getStyle() == CombatStyle.MELEE || state.getStyle() == CombatStyle.RANGE) { + Weapon w = state.getWeapon(); + String name = w != null ? w.getName() : ""; + if (w == null || name.toLowerCase().indexOf("spear") == -1) { + if (state.getEstimatedHit() > 0) { + state.setEstimatedHit(state.getEstimatedHit() / 2); + } + if (state.getSecondaryHit() > 0) { + state.setSecondaryHit(state.getSecondaryHit() / 2); + } + } + } + if (state.getEstimatedHit() >= 32) { + CorporealBeastNPC corp = (CorporealBeastNPC) self.behavior; + corp.forceCoreRoll = true; + } + if (state.getEstimatedHit() > 100) { + state.setEstimatedHit(100); + } + if (state.getSecondaryHit() > 100) { + state.setSecondaryHit(100); + } + } @Override public void onDeathFinished(NPC self, Entity killer) { @@ -94,41 +97,46 @@ public final class CorporealBeastNPC extends NPCBehavior { darkEnergyCore = null; } } - + /** * Handles the Corporeal beast's combat. * @author Emperor - * */ static class CombatHandler extends MultiSwingHandler { - /** * Constructs a new {@code CombatHandler} {@code Object}. */ public CombatHandler() { super( - //Melee (crush) - new SwitchAttack(CombatStyle.MELEE.getSwingHandler(), Animation.create(10057)).setMaximumHit(52), - //Melee (slash) - new SwitchAttack(CombatStyle.MELEE.getSwingHandler(), Animation.create(10058)).setMaximumHit(51), - //Magic (drain skill) - new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1823, 60, 36, 41, 46)).setMaximumHit(55), - //Magic (location based) - new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1824, 60, 36, 41, 46)).setMaximumHit(42), - //Magic (hit through prayer) - new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1825, 60, 36, 41, 46)).setMaximumHit(66) - ); + //Melee (crush) + new SwitchAttack(CombatStyle.MELEE.getSwingHandler(), Animation.create(10057)).setMaximumHit(51), + //Melee (slash) + new SwitchAttack(CombatStyle.MELEE.getSwingHandler(), Animation.create(10058)).setMaximumHit(51), + //Magic (drain skill, blocked by prayer) + new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1823, 60, 36, 41, 46)).setMaximumHit(55), + //Magic (location-based, hits through prayer) + new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1824, 60, 36, 41, 46)).setMaximumHit(42), + //Magic (hits through prayer) + new SwitchAttack(CombatStyle.MAGIC.getSwingHandler(), Animation.create(10410), null, null, Projectile.create(null, null, 1825, 60, 36, 41, 46)).setMaximumHit(65) + ); } @Override public int swing(Entity entity, Entity victim, BattleState state) { - spawnDarkCore(entity, (CorporealBeastNPC)((NPC) entity).behavior, victim); + // If we're below the right HP threshold, roll a chance to spawn the dark core + CorporealBeastNPC corp = (CorporealBeastNPC) ((NPC) entity).behavior; + double thresh = entity.getSkills().getMaximumLifepoints() * (0.3 + (entity.getViewport().getCurrentPlane().getPlayers().size() * 0.05)); + if (corp.forceCoreRoll || entity.getSkills().getLifepoints() < thresh) { + rollDarkCore(entity, corp, victim); + corp.forceCoreRoll = false; + } + // If we can stomp, do that for our turn if (doStompAttack(entity)) { entity.getProperties().getCombatPulse().setNextAttack(entity.getProperties().getAttackSpeed()); return -1; } - //Location based attack. + // Location-based attack. if (super.getNext().getProjectile() != null && super.getNext().getProjectile().getProjectileId() == 1824) { setCurrent(getNext()); CombatStyle style = getCurrent().getStyle(); @@ -142,18 +150,17 @@ public final class CorporealBeastNPC extends NPCBehavior { } return super.swing(entity, victim, state); } - + /** - * Spawns a dark core. + * Rolls a 1/8 chance to spawn a dark core. * @param npc The corporeal beast NPC. * @param victim The victim. */ - private void spawnDarkCore(Entity corp, final CorporealBeastNPC npc, Entity victim) { - if (npc.darkEnergyCore != null && npc.darkEnergyCore.isActive()) { + private void rollDarkCore(Entity corp, final CorporealBeastNPC npc, Entity victim) { + if (npc.darkEnergyCore != null && npc.darkEnergyCore.isActive() && !DeathTask.isDead(npc.darkEnergyCore)) { return; } - double max = corp.getSkills().getMaximumLifepoints() * (0.3 + (corp.getViewport().getCurrentPlane().getPlayers().size() * 0.05)); - if (corp.getSkills().getLifepoints() > max) { + if (!RandomFunction.roll(8)) { return; } Location l = RegionManager.getTeleportLocation(victim.getLocation(), 3); @@ -163,8 +170,8 @@ public final class CorporealBeastNPC extends NPCBehavior { GameWorld.getPulser().submit(new Pulse(2, corp) { @Override public boolean pulse() { - if (npc.darkEnergyCore == null) - return true; + if (npc.darkEnergyCore == null) + return true; npc.darkEnergyCore.init(); return true; } @@ -184,6 +191,7 @@ public final class CorporealBeastNPC extends NPCBehavior { boolean secondStage = false; List players = RegionManager.getLocalPlayers(entity); Location[] locations = null; + @Override public boolean pulse() { if (!secondStage) { @@ -215,11 +223,14 @@ public final class CorporealBeastNPC extends NPCBehavior { locations = null; return true; } + private void hit(Player p) { - int max = p.hasProtectionPrayer(CombatStyle.MAGIC) ? 13 : 42; int hit = 0; if (isAccurateImpact(entity, p)) { - hit = RandomFunction.random(max); + hit = RandomFunction.random(42); + if (p.hasProtectionPrayer(CombatStyle.MAGIC)) { + hit = (int) (hit * 0.6); + } } p.getImpactHandler().handleImpact(entity, hit, CombatStyle.MAGIC); } @@ -252,7 +263,7 @@ public final class CorporealBeastNPC extends NPCBehavior { } return false; } - + @Override public void adjustBattleState(Entity entity, Entity victim, BattleState state) { super.adjustBattleState(entity, victim, state); @@ -262,10 +273,9 @@ public final class CorporealBeastNPC extends NPCBehavior { int skill = random == 0 ? Skills.PRAYER : random == 1 ? Skills.MAGIC : Skills.SUMMONING; int drain = 1 + RandomFunction.random(6); if ((skill == Skills.PRAYER ? victim.getSkills().getPrayerPoints() : victim.getSkills().getLevel(skill)) < 1) { - victim.getImpactHandler().manualHit(entity, drain, HitsplatType.NORMAL,2); + victim.getImpactHandler().manualHit(entity, drain, HitsplatType.NORMAL, 2); ((Player) victim).getPacketDispatch().sendMessage("Your Hitpoints have been slightly drained!"); - } - else { + } else { if (skill == Skills.PRAYER) { victim.getSkills().decrementPrayerPoints(drain); } else { @@ -278,11 +288,13 @@ public final class CorporealBeastNPC extends NPCBehavior { } } } - + @Override protected int getFormattedHit(Entity entity, Entity victim, BattleState state, int hit) { if (getCurrent().getProjectile() == null || getCurrent().getProjectile().getProjectileId() != 1825) { hit = (int) entity.getFormattedHit(state, hit); + } else if (victim.hasProtectionPrayer(CombatStyle.MAGIC)) { + hit = (int) (hit * 0.6); } return formatHit(victim, hit); } diff --git a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java index bcc8930cd..0695955ba 100644 --- a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java @@ -9,6 +9,8 @@ import core.game.node.entity.player.Player; import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; +import core.game.world.map.path.Path; +import core.game.world.map.path.Pathfinder; import core.plugin.Initializable; import core.tools.RandomFunction; @@ -16,8 +18,7 @@ import static core.api.ContentAPIKt.*; /** * Handles the Dark Energy Core NPC. - * @author Emperor - * + * @author Emperor, Player Name */ @Initializable public final class DarkEnergyCoreNPC extends AbstractNPC { @@ -31,21 +32,22 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { * The amount of ticks. */ private int ticks = 0; - + /** * The amount of failed attacks. */ private int fails = 0; - + /** * Constructs a new {@code DarkEnergyCoreNPC} {@code Object}. */ public DarkEnergyCoreNPC() { this(8127, null); } - + /** * Constructs a new {@code DarkEnergyCoreNPC} {@code Object}. + * * @param id The NPC id. * @param location The location. */ @@ -59,14 +61,15 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { if (objects.length > 0) { core.master = (NPC) objects[0]; } + core.setRespawn(false); return core; } - + @Override public boolean canStartCombat(Entity victim) { return false; //No combat needed. } - + @Override public void handleTickActions() { ticks++; @@ -91,8 +94,11 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { if (jump) { Entity victim = master.getProperties().getCombatPulse().getVictim(); if (++fails >= 3 && victim != null && victim.getViewport().getCurrentPlane() == getViewport().getCurrentPlane()) { - jump(victim.getLocation()); - fails = 0; + Path path = Pathfinder.find(getLocation(), victim.getLocation(), 1); + if (path.isSuccessful() || !path.isMoveNear()) { + jump(victim.getLocation()); + fails = 0; + } } } else { fails = 0; @@ -119,7 +125,6 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { @Override public int[] getIds() { - return new int[] { 8127 }; + return new int[]{8127}; } - } diff --git a/Server/src/main/core/game/node/entity/combat/MultiSwingHandler.kt b/Server/src/main/core/game/node/entity/combat/MultiSwingHandler.kt index 41ac8dca3..d283f3aff 100644 --- a/Server/src/main/core/game/node/entity/combat/MultiSwingHandler.kt +++ b/Server/src/main/core/game/node/entity/combat/MultiSwingHandler.kt @@ -8,7 +8,7 @@ import core.tools.RandomFunction /** * Handles combat swings with switching combat styles. * @author Emperor - * @author Ceirky, Kotlin conversion + * @author Ceikry, Kotlin conversion */ open class MultiSwingHandler(meleeDistance: Boolean, vararg attacks: SwitchAttack) : CombatSwingHandler(CombatStyle.RANGE) { /**