Implemented timer subsystem to eventually replace pulses

Authentic subsystem supports saving/loading arbitrary data and resuming timer countdowns
Lots of documented CAPI functions for working with these new timers
Converted poison to new timers
Converted disease to new timers
Converted farming to new timers (CropGrowth and Compost)
Farming now syncs with 5 minute intervals on realtime clocks (authentic)
Converted seedling growth to new timers
Converted shooting star mining bonus to new timers
Converted entity freezing to new timers
Converted incubation to new timers
Incubation now supports using both incubators (so 2 eggs at once)
Converted miasmic states to the new timers
Converted god spell charged state to new timers
Converted teleblock to new timers
Converted skulled state to new timers
Converted Enhanced Excalibur special attack effect to new timers
Converted passive stat restoration to timers
Converted multicannon firing and decay to a timer
This commit is contained in:
Ceikry
2023-07-29 04:51:06 +00:00
committed by Ryan
parent bda000f220
commit 661390e66f
114 changed files with 1718 additions and 2112 deletions
@@ -10,14 +10,13 @@ import core.game.node.entity.combat.spell.SpellType;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.player.link.TeleportManager.TeleportType;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.isStunned;
import static core.api.ContentAPIKt.*;
/**
* Handles the bounty target locate spell.
@@ -45,7 +44,7 @@ public final class BountyLocateSpell extends MagicSpell {
player.getPacketDispatch().sendMessage("You don't have a target to teleport to.");
return true;
}
if (player.getStateManager().hasState(EntityState.FROZEN) || isStunned(player)) {
if (hasTimerActive(player, "frozen") || isStunned(player)) {
player.getPacketDispatch().sendMessage("You can't use this when " + (isStunned(player) ? "stunned." : "frozen."));
return true;
}
@@ -98,4 +97,4 @@ public final class BountyLocateSpell extends MagicSpell {
return this;
}
}
}
@@ -1,15 +1,10 @@
package rs09.game.content.activity.castlewars.areas
import content.global.skill.summoning.familiar.BurdenBeast
import core.api.LogoutListener
import core.api.MapArea
import core.api.log
import core.api.sendMessage
import core.api.*
import core.game.interaction.InteractionListener
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.node.entity.state.EntityState
import core.tools.Log
import rs09.game.content.activity.castlewars.CastleWars
abstract class CastleWarsArea : MapArea, LogoutListener, InteractionListener {
@@ -51,7 +46,7 @@ abstract class CastleWarsArea : MapArea, LogoutListener, InteractionListener {
player.interfaceManager.closeOverlay()
// Remove teleblock
player.stateManager.remove(EntityState.TELEBLOCK)
removeTimer(player, "teleblock")
// Remove any Castle Wars items
// Todo Remove any tinderboxes or other castle wars items - See Jan 2018 update: https://oldschool.runescape.wiki/w/Castle_Wars
@@ -78,4 +73,4 @@ abstract class CastleWarsArea : MapArea, LogoutListener, InteractionListener {
}
}
}
}
@@ -1,11 +1,9 @@
package rs09.game.content.activity.castlewars.areas
import core.api.TickListener
import core.api.log
import core.api.*
import core.game.component.Component
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
@@ -72,8 +70,7 @@ class CastleWarsGameArea : CastleWarsArea(), TickListener {
override fun areaEnter(entity: Entity) {
val player = entity as? Player ?: return
super.areaEnter(player)
// Block player teleport (for the remaining duration of the game)
player.stateManager.set(EntityState.TELEBLOCK, (CastleWars.gameTimeMinutes)*60*2)
registerTimer (player, spawnTimer("teleblock", (CastleWars.gameTimeMinutes)*60*2))
if (saradominPlayers.contains(player)) {
player.interfaceManager.openOverlay(Component(Components.CASTLEWARS_STATUS_OVERLAY_SARADOMIN_58))
@@ -1,14 +1,10 @@
package rs09.game.content.activity.castlewars.areas
import CastleWarsOverlay
import core.api.God
import core.api.TickListener
import core.api.hasGodItem
import core.api.sendDialogue
import core.api.*
import core.game.component.Component
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.world.map.zone.ZoneBorders
import core.tools.ticksPerMinute
@@ -37,8 +33,7 @@ class CastleWarsWaitingArea : CastleWarsArea(), TickListener {
override fun areaEnter(entity: Entity) {
val player = entity as? Player ?: return
super.areaEnter(player)
// Block player teleport (for at least the max wait time)
player.stateManager.set(EntityState.TELEBLOCK, (CastleWars.gameCooldownMinutes + CastleWars.gameTimeMinutes)*60*2)
registerTimer(player, spawnTimer("teleblock", (CastleWars.gameCooldownMinutes + CastleWars.gameTimeMinutes)*60*2))
// Set team attribute and equip the hooded cloak on the entity based on which waiting room they're in
if (zamorakWaitingRoom.insideBorder(player.location)) {
@@ -12,7 +12,6 @@ import core.game.container.impl.EquipmentContainer;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.LogType;
import core.game.node.entity.player.info.login.PlayerParser;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.plugin.Plugin;
import core.tools.RandomFunction;
@@ -205,8 +204,8 @@ public final class DuelSession extends ComponentPlugin {
*/
public void heal(Player p) {
p.fullRestore();
if (p.getStateManager().hasState(EntityState.POISONED)) {
p.getStateManager().remove(EntityState.POISONED);
if (isPoisoned(p)) {
curePoison(p);
}
p.getSkills().restore();
}
@@ -3,14 +3,13 @@ package content.minigame.fishingtrawler
import core.api.LogoutListener
import core.api.MapArea
import core.api.getRegionBorders
import core.api.log
import core.api.*
import core.game.component.Component
import core.game.node.entity.Entity
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
@@ -81,7 +80,7 @@ class FishingTrawlerSession(val activity: FishingTrawlerActivity? = null) : Logo
updateOverlay(player)
player.properties.teleportLocation = base.transform(36,24,0)
player.setAttribute("ft-session",this)
player.stateManager.set(EntityState.TELEBLOCK,timeLeft)
registerTimer (player, spawnTimer("teleblock", timeLeft))
}
zone.register(getRegionBorders(region.id))
}
@@ -105,7 +104,7 @@ class FishingTrawlerSession(val activity: FishingTrawlerActivity? = null) : Logo
player.appearance.setAnimations(Animation(188))
player.properties.teleportLocation = session.base.transform(36,24,0)
player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_SHIPS_SANK")
player.stateManager.remove(EntityState.TELEBLOCK)
removeTimer(player, "teleblock")
}
return true
}
@@ -15,7 +15,6 @@ import core.game.node.entity.Entity;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.Rights;
import core.game.node.entity.state.EntityState;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
@@ -30,6 +29,8 @@ import core.plugin.ClassScanner;
import core.tools.RandomFunction;
import core.tools.StringUtils;
import static core.api.ContentAPIKt.*;
/**
* Handles the Pest Control activity.
@@ -147,8 +148,8 @@ public final class PestControlActivityPlugin extends ActivityPlugin {
p.removeAttribute("pc_zeal");
p.removeExtension(PestControlSession.class);
p.fullRestore();
if (p.getStateManager().hasState(EntityState.POISONED)) {
p.getStateManager().remove(EntityState.POISONED);
if (isPoisoned(p)) {
curePoison(p);
}
PulseManager.cancelDeathTask(p);
GameWorld.getPulser().submit(new Pulse(1, p) {
@@ -11,7 +11,6 @@ import core.game.node.entity.impl.PulseType;
import core.game.node.entity.npc.AbstractNPC;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.state.EntityState;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
@@ -20,6 +19,8 @@ import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.tools.RandomFunction;
import static core.api.ContentAPIKt.*;
/**
* Handles a pest control spinner NPC.
* @author Emperor
@@ -101,8 +102,7 @@ public final class PCSpinnerNPC extends AbstractNPC {
animate(getProperties().getDeathAnimation());
for (Player p : RegionManager.getLocalPlayers(this, 1)) {
p.getImpactHandler().manualHit(this, 5, HitsplatType.POISON);
p.setAttribute("/save:poison_damage", 18);
p.getStateManager().register(EntityState.POISONED, false, 18, this);
applyPoison(p, this, 1);
}
GameWorld.getPulser().submit(new Pulse(1, this) {
@Override
@@ -3,7 +3,6 @@ package content.minigame.pyramidplunder
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.entity.state.EntityState
import core.game.system.task.Pulse
import core.game.world.map.Direction
import core.game.world.map.Location
@@ -117,7 +116,7 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
animate(player, URN_BIT)
sendMessage(player, "You've been bitten by something moving around in the urn.")
impact(player, RandomFunction.random(1,5))
player.stateManager.register(EntityState.POISONED, true, 20, player)
applyPoison(player, player, 2)
}
else {
animate(player, URN_SUCCESS)
@@ -169,7 +168,7 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
animate(player, URN_BIT)
sendMessage(player, "You've been bitten by something moving around in the urn.")
impact(player, RandomFunction.random(1,5))
player.stateManager.register(EntityState.POISONED, true, 20, player)
applyPoison(player, player, 2)
}
else {
animate(player, URN_SUCCESS)
@@ -13,7 +13,6 @@ import core.game.node.entity.npc.AbstractNPC
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.entity.state.EntityState
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.node.scenery.Scenery
@@ -498,7 +497,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea {
object VinesweeperTeleport {
@JvmStatic
fun teleport(npc: NPC, player: Player) {
if (player.stateManager.hasState(EntityState.TELEBLOCK)) {
if (hasTimerActive(player, "teleblock")) {
sendNPCDialogue(player, npc.id, "I can't do that, you're teleblocked!", core.game.dialogue.FacialExpression.OLD_ANGRY1)
return
}