mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-09 16:45:44 -07:00
Deep wilderness balancing
Added a threat system to the deep wilderness that increases as a player kills NPCs to add balance to lucrative drop rates of PvP items in the deep wilderness Threat decreases with time Threat only increases in the deep wilderness As threat increases, the risk of encountering hostile wilderness events increases Hostile wilderness events may spawn anywhere in the wilderness Improved the safety checks on items dropped in PvP Untradeable items dropped in PvP will now yield an amount of coins proportional to the item's high alchemy value, and delete the item. This amount is halved if the killer doesn't have the level for high alchemy. An additional 250 gp is deducted (after halving, if applicable) from all items to account for the hypothetical cost of a nature rune Added admin command to view threat level ::dwthreat
This commit is contained in:
parent
8b6678d4ee
commit
0f908a1544
4 changed files with 131 additions and 3 deletions
|
|
@ -0,0 +1,90 @@
|
|||
package content.region.wilderness.handlers
|
||||
|
||||
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.player.Player
|
||||
import core.game.system.command.Privilege
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.tools.RandomFunction
|
||||
import core.tools.colorize
|
||||
import org.json.simple.JSONObject
|
||||
|
||||
object DeepWildyThreat {
|
||||
@JvmStatic fun getThreat (player: Player) : Int {
|
||||
return getOrStartTimer<DWThreatTimer>(player).ticksLeft
|
||||
}
|
||||
|
||||
@JvmStatic fun adjustThreat (player: Player, amount: Int) {
|
||||
val timer = getOrStartTimer<DWThreatTimer>(player)
|
||||
timer.ticksLeft += amount
|
||||
if (timer.ticksLeft >= 2500 && timer.lastMessage < 2000) {
|
||||
sendMessage(player, colorize("%RYou sense a great wrath upon you."))
|
||||
timer.lastMessage = 2000
|
||||
} else if (timer.ticksLeft >= 1000 && timer.lastMessage < 1000) {
|
||||
sendMessage(player, colorize("%RYou sense watchful eyes upon you."))
|
||||
timer.lastMessage = 1000
|
||||
} else if (timer.ticksLeft >= 500 && timer.lastMessage < 500) {
|
||||
sendMessage(player, colorize("%RYou sense a dark presence."))
|
||||
timer.lastMessage = 500
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if (ticksLeft > 3000) ticksLeft = 3000
|
||||
if (ticksLeft % 5 != 0) return true
|
||||
if (entity !is Player) return false
|
||||
if (!entity.skullManager.isWilderness) return true
|
||||
|
||||
val rollchance =
|
||||
if (ticksLeft >= 2500) 10
|
||||
else if (ticksLeft >= 2000) 200
|
||||
else if (ticksLeft >= 1500) 400
|
||||
else if (ticksLeft >= 1000) 800
|
||||
else if (ticksLeft >= 500) 1500
|
||||
else 2_000_000
|
||||
|
||||
if ((currentRev == null || DeathTask.isDead(currentRev) || !currentRev!!.isActive) && RandomFunction.roll(rollchance)) {
|
||||
val type = RevenantType.getClosestHigherOrEqual(entity.properties.currentCombatLevel)
|
||||
val npc = NPC.create(type.ids.random(), entity.location)
|
||||
npc.isRespawn = false
|
||||
npc.init()
|
||||
npc.attack(entity)
|
||||
Graphics.send(Graphics(86), npc.location)
|
||||
ticksLeft -= 500
|
||||
sendChat(npc, chats.random())
|
||||
currentRev = npc
|
||||
} else if (currentRev != null && !currentRev!!.location.withinDistance(entity.location, 25)) {
|
||||
poofClear(currentRev!!)
|
||||
currentRev = null
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun save(root: JSONObject, entity: Entity) {
|
||||
root["threat-time-remaining"] = ticksLeft
|
||||
}
|
||||
|
||||
override fun parse(root: JSONObject, entity: Entity) {
|
||||
ticksLeft = root.getOrDefault("threat-time-remaining", 3000) as? Int ?: 3000
|
||||
}
|
||||
|
||||
override fun defineCommands() {
|
||||
define("dwthreat", Privilege.ADMIN, "", "") {player, _ ->
|
||||
val timer = getOrStartTimer<DWThreatTimer>(player)
|
||||
notify(player, "Current Threat: ${timer.ticksLeft}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package content.region.wilderness.handlers.revenants;
|
||||
|
||||
import core.cache.def.impl.NPCDefinition;
|
||||
|
||||
/**
|
||||
* A revenant type.
|
||||
* @author Vexia
|
||||
|
|
@ -58,4 +60,12 @@ public enum RevenantType {
|
|||
public int getMaxHit() {
|
||||
return maxHit;
|
||||
}
|
||||
|
||||
public static RevenantType getClosestHigherOrEqual (int combatLevel) {
|
||||
for (RevenantType t : values()) {
|
||||
NPCDefinition def = NPCDefinition.forId(t.ids[0]);
|
||||
if (def.getCombatLevel() >= combatLevel) return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package core.game.node.entity.player;
|
|||
|
||||
import content.global.handlers.item.equipment.special.SalamanderSwingHandler;
|
||||
import content.global.skill.runecrafting.PouchManager;
|
||||
import core.api.EquipmentSlot;
|
||||
import core.game.component.Component;
|
||||
import core.game.container.Container;
|
||||
import core.game.container.ContainerType;
|
||||
|
|
@ -34,6 +35,7 @@ import core.game.node.entity.player.link.skillertasks.SkillerTasks;
|
|||
import core.game.node.entity.skill.Skills;
|
||||
import content.global.skill.construction.HouseManager;
|
||||
import content.global.skill.summoning.familiar.FamiliarManager;
|
||||
import core.game.node.item.GroundItem;
|
||||
import core.game.node.item.GroundItemManager;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.system.communication.CommunicationInfo;
|
||||
|
|
@ -613,6 +615,11 @@ public class Player extends Entity {
|
|||
if (this.isArtificial() && killer instanceof NPC) {
|
||||
return;
|
||||
}
|
||||
if (killer instanceof Player && getWorldTicks() - killer.getAttribute("/save:last-murder-news", 0) >= 500) {
|
||||
Item wep = getItemFromEquipment((Player) killer, EquipmentSlot.WEAPON);
|
||||
sendNews(killer.getName() + " has murdered " + getName() + " with " + (wep == null ? "their fists." : (StringUtils.isPlusN(wep.getName()) ? "an " : "a ") + wep.getName()));
|
||||
killer.setAttribute("/save:last-murder-news", getWorldTicks());
|
||||
}
|
||||
getPacketDispatch().sendMessage("Oh dear, you are dead!");
|
||||
incrementAttribute("/save:"+STATS_BASE+":"+STATS_DEATHS);
|
||||
|
||||
|
|
@ -653,7 +660,9 @@ public class Player extends Entity {
|
|||
g.initialize(this, location, Arrays.stream(c[1].toArray()).filter(Objects::nonNull).toArray(Item[]::new)); //note: the amount of code required to filter nulls from an array in Java is atrocious.
|
||||
} else {
|
||||
StringBuilder itemsLost = new StringBuilder();
|
||||
int coins = 0;
|
||||
for (Item item : c[1].toArray()) {
|
||||
boolean stayPrivate = false;
|
||||
if (item == null) continue;
|
||||
if (killer instanceof Player)
|
||||
itemsLost.append(getItemName(item.getId())).append("(").append(item.getAmount()).append("), ");
|
||||
|
|
@ -661,8 +670,20 @@ public class Player extends Entity {
|
|||
continue;
|
||||
if (GraveController.shouldRelease(item.getId()))
|
||||
continue;
|
||||
if (!item.getDefinition().isTradeable()) {
|
||||
if (killer instanceof Player) {
|
||||
int value = item.getDefinition().getAlchemyValue(true);
|
||||
if (getStatLevel(killer, Skills.MAGIC) < 55) value /= 2;
|
||||
coins += Math.max(0, value - 250);
|
||||
continue;
|
||||
} else stayPrivate = true;
|
||||
}
|
||||
item = GraveController.checkTransform(item);
|
||||
GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this);
|
||||
GroundItem gi = GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this);
|
||||
gi.setRemainPrivate(stayPrivate);
|
||||
}
|
||||
if (coins > 0) {
|
||||
GroundItemManager.create(new Item(Items.COINS_995, coins), location, (Player) killer);
|
||||
}
|
||||
if (killer instanceof Player)
|
||||
PlayerMonitor.log((Player) killer, LogType.PK, "Killed " + name + ", who dropped: " + itemsLost);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package core.game.world.map.zone.impl;
|
||||
|
||||
import content.region.wilderness.handlers.DeepWildyThreat;
|
||||
import core.game.component.Component;
|
||||
import core.game.interaction.Option;
|
||||
import content.global.handlers.item.equipment.brawling_gloves.BrawlingGloves;
|
||||
|
|
@ -95,6 +96,10 @@ public final class WildernessZone extends MapZone {
|
|||
boolean isDeepWildy = ((Player) killer).getSkullManager().isDeepWilderness();
|
||||
boolean isValidTarget = e instanceof NPC && (isDeepWildy || e.asNpc().getName().contains("Revenant") || e.getId() == NPCs.CHAOS_ELEMENTAL_3200);
|
||||
|
||||
if (isDeepWildy) {
|
||||
DeepWildyThreat.adjustThreat((Player) killer, 250);
|
||||
}
|
||||
|
||||
if (!isValidTarget) return;
|
||||
|
||||
int cEleGloveRate = isDeepWildy ? 50 : 150;
|
||||
|
|
@ -109,6 +114,7 @@ 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);
|
||||
}
|
||||
|
||||
for (int j : PVP_GEAR) {
|
||||
|
|
@ -122,6 +128,7 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue