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
@@ -12,7 +12,6 @@ import core.game.node.entity.impl.Projectile;
import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.player.link.audio.Audio;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
@@ -20,6 +19,8 @@ import core.game.world.update.flag.context.Graphics;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.*;
/**
* Handles the Ice spells from the Ancient spellbook.
* @author Emperor
@@ -133,8 +134,8 @@ public final class IceSpells extends CombatSpell {
}
int ticks = (1 + (type.ordinal() - SpellType.RUSH.ordinal())) * 8;
if (state.getEstimatedHit() > -1) {
if (victim.getAttribute("freeze_immunity", -1) < GameWorld.getTicks()) {
victim.getStateManager().set(EntityState.FROZEN, ticks);
if (!hasTimerActive(victim, "frozen:immunity")) {
registerTimer(victim, spawnTimer("frozen", ticks, true));
} else if (type == SpellType.BARRAGE) {
state.setFrozen(true);
}
@@ -14,13 +14,14 @@ import core.game.node.entity.impl.Projectile;
import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.*;
/**
* Handles the Miasmic spells that are a part of the Ancient spellbook.
* @author Splinter
@@ -119,8 +120,8 @@ public final class MiasmicSpells extends CombatSpell {
@Override
public void fireEffect(Entity entity, Entity victim, BattleState state) {
if (victim.getAttribute("miasmic_immunity", -1) < GameWorld.getTicks()) {
victim.getStateManager().register(EntityState.MIASMIC, true, (getSpellId() - 15) * 20);
if (!hasTimerActive(victim, "miasmic:immunity")) {
registerTimer(victim, spawnTimer("miasmic", (getSpellId() - 15) * 20));
}
}
@@ -11,13 +11,14 @@ import core.game.node.entity.combat.spell.SpellType;
import core.game.node.entity.impl.Projectile;
import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
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 static core.api.ContentAPIKt.*;
/**
* Handles the Smoke spells from the Ancient spellbook.
* @author Emperor
@@ -111,7 +112,7 @@ public final class SmokeSpells extends CombatSpell {
@Override
public void fireEffect(Entity entity, Entity victim, BattleState state) {
if (state.getEstimatedHit() > -1) {
victim.getStateManager().register(EntityState.POISONED, false, type.ordinal() >= SpellType.BLITZ.ordinal() ? 48 : 28, entity);
applyPoison(victim, entity, type.ordinal() >= SpellType.BLITZ.ordinal() ? 4 : 2);
}
}
@@ -15,7 +15,6 @@ import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.skill.Skills
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.node.scenery.Scenery
import core.game.system.command.Privilege
@@ -206,7 +205,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
return@define
}
if(dmg != null) {
p?.let { addState(it, EntityState.POISONED, false, (dmg * 10 + 8), player) }
p?.let { applyPoison(it, it, dmg) }
} else {
sendMessage(player, "Damage must be an integer. Format:")
sendMessage(player, "::poison username damage")
@@ -480,14 +479,14 @@ class LunarListeners : SpellListener("lunar"), Commands {
}
private fun cureMe(player: Player) {
if(!hasState(player, EntityState.POISONED)) {
if(!isPoisoned(player)) {
sendMessage(player, "You are not poisoned.")
return
}
requires(player, 71, arrayOf(Item(Items.ASTRAL_RUNE_9075, 2), Item(Items.LAW_RUNE_563, 1), Item(Items.COSMIC_RUNE_564, 2)))
removeRunes(player, true)
visualizeSpell(player, CURE_ME_ANIM, CURE_ME_GFX, 2880)
removeState(player, EntityState.POISONED)
curePoison(player)
addXP(player, 69.0)
playAudio(player, Audio(2900))
sendMessage(player, "You have been cured of poison.")
@@ -497,7 +496,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
requires(player, 74, arrayOf(Item(Items.ASTRAL_RUNE_9075, 2), Item(Items.LAW_RUNE_563, 2), Item(Items.COSMIC_RUNE_564, 2)))
removeRunes(player, true)
visualizeSpell(player, CURE_GROUP_ANIM, CURE_GROUP_GFX, 2882)
removeState(player, EntityState.POISONED)
curePoison(player)
for(acct in RegionManager.getLocalPlayers(player, 1)) {
if(!acct.isActive || acct.locks.isInteractionLocked) {
continue
@@ -505,7 +504,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
if(!acct.settings.isAcceptAid) {
continue
}
removeState(acct, EntityState.POISONED)
curePoison(acct)
sendMessage(acct, "You have been cured of poison.")
playAudio(acct, Audio(2889), true)
visualize(acct, -1, CURE_GROUP_GFX)
@@ -527,7 +526,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
sendMessage(player, "This player is not accepting any aid.")
return
}
if(!hasState(p, EntityState.POISONED)) {
if(!isPoisoned(p)) {
sendMessage(player, "This player is not poisoned.")
return
}
@@ -537,7 +536,7 @@ class LunarListeners : SpellListener("lunar"), Commands {
visualize(p, -1, CURE_OTHER_GFX)
playAudio(p, Audio(2889), true)
removeRunes(player, true)
removeState(p, EntityState.POISONED)
curePoison(p)
sendMessage(p, "You have been cured of poison.")
addXP(player, 65.0)
}
@@ -15,6 +15,8 @@ import core.plugin.Initializable;
import core.plugin.Plugin;
import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.*;
/**
* Represents the charge spell magic spell.
* @author Emperor
@@ -49,8 +51,8 @@ public final class ChargeSpell extends MagicSpell {
p.getLocks().lock("charge_cast", 100);
visualize(entity, target);
// Remove the previous copy of the state in order to refresh the duration if recast before 7 minutes
p.clearState("godcharge");
p.registerState("godcharge").init();
removeTimer (p, "magic:spellcharge");
registerTimer (p, spawnTimer("magic:spellcharge"));
p.getPacketDispatch().sendMessage("You feel charged with magic power.");
return true;
}
@@ -1,46 +0,0 @@
package content.global.skill.magic.modern
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.audio.Audio
import core.game.system.task.Pulse
import org.json.simple.JSONObject
import core.game.node.entity.state.PlayerState
import core.game.node.entity.state.State
import core.game.world.GameWorld;
@PlayerState("godcharge")
class GodspellChargedState(player: Player? = null) : State(player) {
val DURATION = 700
var startTick: Int = 0
override fun save(root: JSONObject) {
root.put("ticks_elapsed", GameWorld.ticks - startTick)
}
override fun parse(_data: JSONObject) {
if(_data.containsKey("ticks_elapsed")){
startTick = GameWorld.ticks - _data["ticks_elapsed"].toString().toInt()
}
}
override fun newInstance(player: Player?): State {
var ret = GodspellChargedState(player)
ret.startTick = GameWorld.ticks
return ret
}
override fun createPulse() {
player ?: return
if(GameWorld.ticks - startTick >= DURATION) return
pulse = object : Pulse(DURATION) {
override fun pulse(): Boolean {
player.sendMessage("Your magical charge fades away.")
player.clearState("godcharge")
player.audioManager.send(Audio(1650))
pulse = null
return true
}
}
}
}
@@ -0,0 +1,16 @@
package content.global.skill.magic.modern
import core.api.*
import org.json.simple.*
import core.game.system.timer.*
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
class SpellCharge : PersistTimer (700, "magic:spellcharge") {
override fun run (entity: Entity) : Boolean {
if (entity !is Player) return false
sendMessage(entity, "Your magical charge fades away.")
playAudio(entity, getAudio(1650))
return false
}
}
@@ -11,13 +11,14 @@ import core.game.node.entity.impl.Projectile;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
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 static core.api.ContentAPIKt.*;
/**
* Handles the teleportation block spell in the modern spellbook.
* @author Splinter
@@ -117,7 +118,7 @@ public final class TeleblockSpell extends CombatSpell {
if(((Player) victim).getPrayer().get(PrayerType.PROTECT_FROM_MAGIC)){
ticks /= 2;
}
victim.getStateManager().set(EntityState.TELEBLOCK, ticks);
registerTimer(victim, spawnTimer("teleblock", ticks));
} else if(victim.isTeleBlocked()){
entity.asPlayer().sendMessage("Your target is already blocked from teleporting.");
}