From cb16fe4305f6b4e2a4381c911f1158359d74fdf0 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Thu, 29 Jun 2023 11:10:25 +0000 Subject: [PATCH] Reintroduced PvP to level 49 deep wilderness and above (beyond the gate) Traveling into the PvP area will auto-skull the player, but only whilst they remain in the area PvP in the deep wilderness does not apply a hard skull Deep wilderness soft skull is removed immediately upon leaving the deep wilderness Gates into the deep wilderness now give a warning about the danger of entering Gates allowing exit from the deep wilderness will not allow a player to leave if they are in combat The obelisk teleporter in the deep wilderness will not allow a player to use it if they are in combat All NPCs in the deep wilderness now drop PvP gear and brawlers The drop rate of PvP gear and brawlers in the deep wilderness has been boosted Fixed an issue that allowed PvP outside of explicit PvP scenarios --- Server/data/ObjectParser.xml | 1 - .../handlers/scenery/BankBoothListener.kt | 58 +++++++++-------- .../allfiredup/BeaconTenderDialogue.kt | 10 +-- .../handlers/WildernessGateHandler.kt | 52 ++++++++++++++++ .../handlers/WildernessObeliskPlugin.java | 6 ++ .../core/game/node/entity/player/Player.java | 24 +++++++ .../node/entity/player/link/SkullManager.java | 27 +++++++- .../world/map/zone/impl/WildernessZone.java | 62 +++++++++++-------- Server/worldprops/default.conf | 2 +- 9 files changed, 182 insertions(+), 60 deletions(-) create mode 100644 Server/src/main/content/region/wilderness/handlers/WildernessGateHandler.kt diff --git a/Server/data/ObjectParser.xml b/Server/data/ObjectParser.xml index 3a354d63b..b10a0d445 100644 --- a/Server/data/ObjectParser.xml +++ b/Server/data/ObjectParser.xml @@ -22,7 +22,6 @@ - diff --git a/Server/src/main/content/global/handlers/scenery/BankBoothListener.kt b/Server/src/main/content/global/handlers/scenery/BankBoothListener.kt index c5dc0ac8f..00b275e85 100644 --- a/Server/src/main/content/global/handlers/scenery/BankBoothListener.kt +++ b/Server/src/main/content/global/handlers/scenery/BankBoothListener.kt @@ -38,6 +38,34 @@ class BankBoothListener : InteractionListener { Scenery.BANK_BOOTH_29085, Scenery.BANK_BOOTH_30015, Scenery.BANK_BOOTH_30016, Scenery.BANK_BOOTH_34205, Scenery.BANK_BOOTH_34752, Scenery.BANK_BOOTH_35647, Scenery.BANK_BOOTH_36786, Scenery.BANK_BOOTH_37474 ) + + public fun convertToNotes (used: Node, player: Player) { + val item = used as Item + + if (item.noteChange != item.id) { + if (item.definition.isUnnoted) { + val amount = amountInInventory(player, item.id) + if (removeItem(player, Item(item.id, amount))) { + addItem(player, item.noteChange, amount) + } + } else { + var amount = item.amount + val freeSlotCount = freeSlots(player) + + if (amount > freeSlotCount) { + amount = freeSlotCount + } + + if (removeItem(player, Item(item.id, amount))) { + addItem(player, item.noteChange, amount) + } + } + + return + } + + sendMessage(player, "This item can't be noted.") + } } /** @@ -146,32 +174,8 @@ class BankBoothListener : InteractionListener { tryInvokeBankerDialogue(player, with) return true } - - val item = used as Item - - if (item.noteChange != item.id) { - if (item.definition.isUnnoted) { - val amount = amountInInventory(player, item.id) - if (removeItem(player, Item(item.id, amount))) { - addItem(player, item.noteChange, amount) - } - } else { - var amount = item.amount - val freeSlotCount = freeSlots(player) - - if (amount > freeSlotCount) { - amount = freeSlotCount - } - - if (removeItem(player, Item(item.id, amount))) { - addItem(player, item.noteChange, amount) - } - } - - return true - } - - sendMessage(player, "This item can't be noted.") + + convertToNotes (used, player) return true } @@ -184,4 +188,4 @@ class BankBoothListener : InteractionListener { onUseAnyWith(IntType.SCENERY, *BANK_BOOTHS, handler = ::attemptToConvertItems) } } -} \ No newline at end of file +} diff --git a/Server/src/main/content/minigame/allfiredup/BeaconTenderDialogue.kt b/Server/src/main/content/minigame/allfiredup/BeaconTenderDialogue.kt index 4933c0e29..c02ebd0e4 100644 --- a/Server/src/main/content/minigame/allfiredup/BeaconTenderDialogue.kt +++ b/Server/src/main/content/minigame/allfiredup/BeaconTenderDialogue.kt @@ -1,11 +1,13 @@ package content.minigame.allfiredup -import core.game.dialogue.DialoguePlugin +import core.ServerConstants +import core.game.dialogue.* import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills import core.game.node.item.Item import core.plugin.Initializable +import content.region.wilderness.dialogue.* import org.rs09.consts.Items private val VALID_LOGS = arrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521, Items.WILLOW_LOGS_1519, Items.MAPLE_LOGS_1517, Items.YEW_LOGS_1515, Items.MAGIC_LOGS_1513) @@ -20,6 +22,7 @@ class BeaconTenderDialogue(player: Player? = null) : core.game.dialogue.Dialogue } override fun open(vararg args: Any?): Boolean { + npc = (args[0] as NPC).getShownNPC(player) index = getIndexOf((args[0] as NPC).originalId) if(index == content.minigame.allfiredup.AFUBeacon.GWD.ordinal && player.skills.getLevel(Skills.SUMMONING) < 81){ npc("Awwf uurrrhur","(You need 81 Summoning to communicate with Nanuq.)") @@ -27,11 +30,10 @@ class BeaconTenderDialogue(player: Player? = null) : core.game.dialogue.Dialogue return true } if(index == content.minigame.allfiredup.AFUBeacon.MONASTERY.ordinal && player.skills.getLevel(Skills.PRAYER) < 53){ - npc("I will aid you when your devotion is","strong enough.","(You need 53 Prayer for him to watch the beacon.)") + npc("I will aid you when your devotion is","strong enough.","(You need 53 Prayer for him to assist you.)") stage = 1000 return true } - npc = (args[0] as NPC).getShownNPC(player) npc("Hello, adventurer.") return true } @@ -88,4 +90,4 @@ class BeaconTenderDialogue(player: Player? = null) : core.game.dialogue.Dialogue return intArrayOf(8067,8068,8069,8070,8071,8072,8073,8074,8075,8076) } -} \ No newline at end of file +} diff --git a/Server/src/main/content/region/wilderness/handlers/WildernessGateHandler.kt b/Server/src/main/content/region/wilderness/handlers/WildernessGateHandler.kt new file mode 100644 index 000000000..d8f8b099a --- /dev/null +++ b/Server/src/main/content/region/wilderness/handlers/WildernessGateHandler.kt @@ -0,0 +1,52 @@ +package content.region.wilderness.handlers + +import core.api.* +import core.game.interaction.* +import core.game.node.entity.player.Player +import core.game.node.scenery.Scenery +import core.game.node.Node +import core.game.global.action.DoorActionHandler +import core.game.dialogue.* +import core.tools.* + +class WildernessGateHandler : InteractionListener { + val gates = intArrayOf(1597, 1596) + + override fun defineListeners() { + on (gates, IntType.SCENERY, "open", handler = ::handleGate) + } + + private fun handleGate (player: Player, node: Node) : Boolean { + val isEntering = !player.skullManager.isDeepWilderness() + + if (isEntering) + openDialogue (player, GateDialogue(node.asScenery())) + else { + if (player.properties.combatPulse.isInCombat) + sendMessage (player, "You cannot leave while you are under attack.") + else { + DoorActionHandler.handleAutowalkDoor (player, node.asScenery()) + player.skullManager.isDeepWilderness = false + } + } + + return true + } + + class GateDialogue (val gate: Scenery) : DialogueFile() { + override fun handle (interfaceId: Int, buttonId: Int) { + when (stage) { + 0 -> sendDialogueLines(player!!, "WARNING!", "Beyond this gate you enter the deep wilderness!", "Anyone will be able to attack you without consequence!", "You WILL NOT be able to leave during combat!").also { stage++ } + 1 -> showTopics ( + Topic(FacialExpression.NEUTRAL, "I wish to proceed.", 10, true), + Topic(FacialExpression.NEUTRAL, "Nevermind.", END_DIALOGUE, true) + ) + 10 -> { + end() + DoorActionHandler.handleAutowalkDoor (player!!, gate) + player!!.skullManager.isDeepWilderness = true + } + } + } + } +} diff --git a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java index 6c9b66448..ee3b0641f 100644 --- a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java +++ b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java @@ -43,6 +43,12 @@ public final class WildernessObeliskPlugin extends OptionHandler { if (stationObelisk == null) { return false; } + if (player.getSkullManager().isDeepWilderness()) { + if (player.getProperties().getCombatPulse().isInCombat()) { + player.sendMessage("You can't use this while in combat."); + return false; + } + } for (int i = 0; i < 4; i++) { int x = stationObelisk.getLocation().getX(); int y = stationObelisk.getLocation().getY(); diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 3edc198fb..78055a720 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -86,6 +86,8 @@ import static core.api.ContentAPIKt.*; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_BASE; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_DEATHS; import static core.tools.GlobalsKt.colorize; +import static core.game.world.map.zone.impl.WildernessZone.WILDERNESS_PROT_ATTR; +import static core.game.world.map.zone.impl.WildernessZone.WILDERNESS_HIGHER_NEXTFEE; /** * Represents a player entity. @@ -549,6 +551,16 @@ public class Player extends Entity { return this.getIndex() | 0x8000; } + @Override + public void onAttack (Entity e) { + if (e instanceof Player) { + Player p = (Player) e; + if (skullManager.isWildernessDisabled()) { + return; + } + } + } + @Override public CombatSwingHandler getSwingHandler(boolean swing) { CombatStyle style = getProperties().getCombatPulse().getStyle(); @@ -716,6 +728,18 @@ public class Player extends Entity { if (entity instanceof NPC && !((NPC) entity).getDefinition().hasAction("attack") && !((NPC) entity).isIgnoreAttackRestrictions(this)) { return false; } + if (entity instanceof Player) { + Player p = (Player) entity; + if (p.getSkullManager().isWilderness() && skullManager.isWilderness()) { + if (!GameWorld.getSettings().getWild_pvp_enabled()) + return false; + if (p.getSkullManager().hasWildernessProtection()) + return false; + if (skullManager.hasWildernessProtection()) + return false; + return true; + } else return false; + } return super.isAttackable(entity, style, message); } diff --git a/Server/src/main/core/game/node/entity/player/link/SkullManager.java b/Server/src/main/core/game/node/entity/player/link/SkullManager.java index 2bba76e78..de4d4161c 100644 --- a/Server/src/main/core/game/node/entity/player/link/SkullManager.java +++ b/Server/src/main/core/game/node/entity/player/link/SkullManager.java @@ -3,10 +3,14 @@ package core.game.node.entity.player.link; import core.game.node.entity.Entity; import core.game.node.entity.player.Player; import core.game.node.entity.state.EntityState; +import core.ServerConstants; import java.util.ArrayList; import java.util.List; +import static core.tools.GlobalsKt.colorize; +import static core.game.world.map.zone.impl.WildernessZone.WILDERNESS_PROT_ATTR; + /** * Represents a managing class of the active player skulls. * @author Vexia @@ -49,6 +53,8 @@ public final class SkullManager { */ private boolean skullCheckDisabled; + private boolean deepWilderness; + /** * Constructs a new {@code SkullManager} {@code Object}. * @param player the player. @@ -95,6 +101,7 @@ public final class SkullManager { skullCauses.clear(); setSkullIcon(-1); setSkulled(false); + player.getAppearance().sync(); } /** @@ -118,6 +125,10 @@ public final class SkullManager { * @param level the level to set. */ public void setLevel(int level) { + if (!deepWilderness && level >= 49) + setDeepWilderness(true); + else if (deepWilderness && level < 48) + setDeepWilderness(false); this.level = level; } @@ -161,6 +172,10 @@ public final class SkullManager { return wildernessDisabled; } + public boolean hasWildernessProtection() { + return level < 49; + } + /** * Sets the wildernessDisabled. * @param wildernessDisabled The wildernessDisabled to set. @@ -174,9 +189,19 @@ public final class SkullManager { * @return The skulled. */ public boolean isSkulled() { - return skulled; + return skulled || deepWilderness; } + public boolean isDeepWilderness() { + return deepWilderness; + } + + public void setDeepWilderness (boolean deepWildy) { + setSkullIcon(deepWildy ? 1 : skulled ? 0 : -1); + setSkullCheckDisabled(deepWildy); + deepWilderness = deepWildy; + } + /** * Sets the skulled. * @param skulled The skulled to set. 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 6d38f312b..6a0c77a05 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 @@ -39,6 +39,9 @@ public final class WildernessZone extends MapZone { */ private static final WildernessZone INSTANCE = new WildernessZone(new ZoneBorders(2944, 3525, 3400, 3975), new ZoneBorders(3070, 9924, 3135, 10002), ZoneBorders.forRegion(12193), ZoneBorders.forRegion(11937)); + public static final String WILDERNESS_PROT_ATTR = "/save:wilderness-protection-active"; + public static final String WILDERNESS_HIGHER_NEXTFEE = "/save:wilderness-higher-next-fee"; + /** * The zone borders. */ @@ -69,7 +72,7 @@ public final class WildernessZone extends MapZone { double x = combatLevel; double A = 44044.5491; double B = -7360.19548; - return (int) (A + (B * Math.log(x))) / 2; + return (int) (A + (B * Math.log(x))); } /** @@ -87,33 +90,40 @@ public final class WildernessZone extends MapZone { } private void rollWildernessExclusiveLoot(Entity e, Entity killer) { - //Roll for PVP gear and Brawling Gloves from revenants - if (e instanceof NPC && killer instanceof Player && (e.asNpc().getName().contains("Revenant") || e.getId() == NPCs.CHAOS_ELEMENTAL_3200)) { + if (!(killer instanceof Player)) return; + + boolean isDeepWildy = ((Player) killer).getSkullManager().isDeepWilderness(); + boolean isValidTarget = e instanceof NPC && (isDeepWildy || e.asNpc().getName().contains("Revenant") || e.getId() == NPCs.CHAOS_ELEMENTAL_3200); + + if (!isValidTarget) return; - boolean gloveDrop = e.getId() == NPCs.CHAOS_ELEMENTAL_3200 ? RandomFunction.roll(75) : RandomFunction.roll(100); - if (gloveDrop) { - byte glove = (byte) RandomFunction.random(1, 13); - 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() + "!"); - } + int cEleGloveRate = isDeepWildy ? 50 : 150; + int normalGloveRate = isDeepWildy ? 75 : 150; - int combatLevel = e.asNpc().getDefinition().getCombatLevel(); - int dropRate = getNewDropRate(combatLevel); - for (int j : PVP_GEAR) { - boolean chance = RandomFunction.roll(dropRate); - if (chance) { - Item reward; - if (j == 13879 || j == 13883) { // checks if it's a javelin or throwing axe - reward = new Item(j, RandomFunction.random(15, 50)); - } else { - reward = new Item(j); - } - Repository.sendNews(killer.asPlayer().getUsername() + " has received a " + reward.getName() + " from a " + e.asNpc().getName() + "!"); - GroundItemManager.create(reward, ((NPC) e).getDropLocation(), killer.asPlayer()); - } - } - } + int pvpGearRate = getNewDropRate(e.asNpc().getDefinition().getCombatLevel()); + if (isDeepWildy) + pvpGearRate /= 2; + + if (RandomFunction.roll(e.getId() == NPCs.CHAOS_ELEMENTAL_3200 ? cEleGloveRate : normalGloveRate)) { + byte glove = (byte) RandomFunction.random(1, 13); + 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() + "!"); + } + + for (int j : PVP_GEAR) { + boolean chance = RandomFunction.roll(pvpGearRate); + if (chance) { + Item reward; + if (j == 13879 || j == 13883) { // checks if it's a javelin or throwing axe + reward = new Item(j, RandomFunction.random(15, 50)); + } else { + reward = new Item(j); + } + Repository.sendNews(killer.asPlayer().getUsername() + " has received a " + reward.getName() + " from a " + e.asNpc().getName() + "!"); + GroundItemManager.create(reward, ((NPC) e).getDropLocation(), killer.asPlayer()); + } + } } /** diff --git a/Server/worldprops/default.conf b/Server/worldprops/default.conf index 7ae65e2d8..c80e4c6e4 100644 --- a/Server/worldprops/default.conf +++ b/Server/worldprops/default.conf @@ -67,7 +67,7 @@ increased_door_time = false enable_botting = false max_adv_bots = 100 enable_doubling_money_scammers = true -wild_pvp_enabled = false +wild_pvp_enabled = true jad_practice_enabled = true #minimum HA value for announcements of bots selling on ge ge_announcement_limit = 500