Random Events should now spawn correctly
Fixed an issue that was causing tick event hooks to not fire
This commit is contained in:
@@ -2,6 +2,7 @@ package core.game.node.entity;
|
||||
|
||||
import api.events.Event;
|
||||
import api.events.EventHook;
|
||||
import api.events.TickEvent;
|
||||
import core.game.content.holiday.HolidayEvent;
|
||||
import core.game.interaction.DestinationFlag;
|
||||
import core.game.node.Node;
|
||||
@@ -216,6 +217,7 @@ public abstract class Entity extends Node {
|
||||
* This methods gets called before the {@link #update()} method.
|
||||
*/
|
||||
public void tick() {
|
||||
dispatch(new TickEvent(GameWorld.getTicks()));
|
||||
skills.pulse();
|
||||
walkingQueue.update();
|
||||
updateMasks.prepare(this);
|
||||
|
||||
@@ -70,6 +70,9 @@ public final class WalkingQueue {
|
||||
boolean isPlayer = entity instanceof Player;
|
||||
this.walkDir = -1;
|
||||
this.runDir = -1;
|
||||
if(entity.getLocation() == null) {
|
||||
return;
|
||||
}
|
||||
if (updateTeleport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,4 @@ data class InteractionEvent(val target: Node, val option: String) : Event
|
||||
data class ButtonClickedEvent(val iface: Int, val buttonId: Int) : Event
|
||||
data class UsedWithEvent(val used: Int, val with: Int) : Event
|
||||
data class SelfDeath(val killer: Entity) : Event
|
||||
data class TickEvent(val source: Entity) : Event
|
||||
data class TickEvent(val worldTicks: Int) : Event
|
||||
@@ -14,9 +14,6 @@ import rs09.game.system.SystemLogger
|
||||
import rs09.game.world.GameWorld
|
||||
import kotlin.random.Random
|
||||
|
||||
private const val AVG_DELAY_TICKS = 6000 // 60 minutes
|
||||
private const val MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2
|
||||
private const val MAX_DELAY_TICKS = MIN_DELAY_TICKS + AVG_DELAY_TICKS // window of 60 min centered on 60 min (30 to 90 min)
|
||||
class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<TickEvent> {
|
||||
var event: RandomEventNPC? = null
|
||||
var enabled: Boolean = false
|
||||
@@ -47,7 +44,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
|
||||
return
|
||||
}
|
||||
if (getAttribute<RandomEventNPC?>(player, "re-npc", null) != null) return
|
||||
val currentAction = player.pulseManager.current.toString()
|
||||
val currentAction = player.pulseManager.current?.toString() ?: "None"
|
||||
val ame: RandomEvents = if(currentAction.contains("WoodcuttingSkillPulse") && Random.nextBoolean()){
|
||||
RandomEvents.TREE_SPIRIT
|
||||
} else if(currentAction.contains("FishingPulse") && Random.nextBoolean()){
|
||||
@@ -62,6 +59,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
|
||||
event = ame.npc.create(player,ame.loot,ame.type)
|
||||
if (event!!.spawnLocation == null) {
|
||||
nextSpawn = GameWorld.ticks + 3000
|
||||
SystemLogger.logWarn("Tried to spawn random event for ${player.username} but spawn location was null!")
|
||||
return
|
||||
}
|
||||
event!!.init()
|
||||
@@ -74,6 +72,10 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val AVG_DELAY_TICKS = 6000 // 60 minutes
|
||||
const val MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2
|
||||
const val MAX_DELAY_TICKS = MIN_DELAY_TICKS + AVG_DELAY_TICKS // window of 60 min centered on 60 min (30 to 90 min)
|
||||
|
||||
@JvmStatic fun getInstance(player: Player): RandomEventManager?
|
||||
{
|
||||
return getAttribute(player, "random-manager", null)
|
||||
|
||||
@@ -9,6 +9,7 @@ import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import rs09.game.content.ame.RandomEventNPC
|
||||
import rs09.game.content.global.WeightBasedTable
|
||||
import java.lang.Integer.max
|
||||
|
||||
val ids = 2463..2468
|
||||
|
||||
@@ -18,7 +19,7 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
val index = (player.properties.combatLevel / 20) - 1
|
||||
val index = max(0, (player.properties.combatLevel / 20) - 1)
|
||||
val id = ids.toList()[index]
|
||||
this.transform(id)
|
||||
this.attack(player)
|
||||
|
||||
@@ -38,7 +38,7 @@ class UpdateSequence
|
||||
playersList = renderablePlayers
|
||||
npcList = Repository.renderableNpcs
|
||||
lobbyList!!.map{ PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(it)) }
|
||||
playersList!!.forEach(Player::tick)
|
||||
renderablePlayers.forEach(Player::tick)
|
||||
npcList!!.forEach(NPC::tick)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,18 +11,21 @@ import org.rs09.consts.Items
|
||||
import rs09.ServerConstants
|
||||
import rs09.game.content.global.shops.Shop
|
||||
import rs09.game.content.global.shops.ShopItem
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.system.config.ConfigParser
|
||||
import rs09.game.system.config.ServerConfigParser
|
||||
import rs09.game.world.GameWorld
|
||||
import rs09.game.world.repository.Repository
|
||||
import rs09.game.world.update.UpdateSequence
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
object TestUtils {
|
||||
fun getMockPlayer(name: String, ironman: IronmanMode = IronmanMode.NONE): Player {
|
||||
val p = Player(PlayerDetails(name))
|
||||
p.details.session = MockSession()
|
||||
val p = MockPlayer(name)
|
||||
p.ironmanManager.mode = ironman
|
||||
Repository.addPlayer(p)
|
||||
//Update sequence has a separate list of players for some reason...
|
||||
UpdateSequence.renderablePlayers.add(p)
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -53,12 +56,23 @@ object TestUtils {
|
||||
}
|
||||
|
||||
fun advanceTicks(amount: Int) {
|
||||
SystemLogger.logInfo("Advancing ticks by $amount.")
|
||||
for(i in 0 until amount) {
|
||||
GameWorld.majorUpdateWorker.handleTickActions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MockPlayer(name: String) : Player(PlayerDetails(name)) {
|
||||
init {
|
||||
this.details.session = MockSession()
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
//do nothing. This is for rendering stuff. We don't render a mock player. Not until the spaghetti is less spaghetti.
|
||||
}
|
||||
}
|
||||
|
||||
class MockSession : IoSession(null, null) {
|
||||
val receivedPackets = ArrayList<Packet>()
|
||||
var disconnected = false
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package content
|
||||
|
||||
import TestUtils
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import rs09.game.world.GameWorld
|
||||
|
||||
class RandomEventManager {
|
||||
companion object {init {
|
||||
TestUtils.preTestSetup()
|
||||
}}
|
||||
|
||||
@Test fun loginShouldEnableManager() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
rs09.game.content.ame.RandomEventManager().login(p)
|
||||
val manager = rs09.game.content.ame.RandomEventManager.getInstance(p)
|
||||
Assertions.assertNotNull(manager)
|
||||
Assertions.assertEquals(true, manager!!.enabled)
|
||||
}
|
||||
|
||||
@Test fun loginShouldSetNextSpawn() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
rs09.game.content.ame.RandomEventManager().login(p)
|
||||
val manager = rs09.game.content.ame.RandomEventManager.getInstance(p)
|
||||
Assertions.assertNotNull(manager)
|
||||
Assertions.assertEquals(true, manager!!.nextSpawn > GameWorld.ticks)
|
||||
}
|
||||
|
||||
@Test fun shouldSpawnRandomEventWithinMAXTICKSGivenNoRestrictions() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
p.setAttribute("tutorial:complete", true) //tutorial has to be complete to spawn randoms
|
||||
rs09.game.content.ame.RandomEventManager().login(p)
|
||||
TestUtils.advanceTicks(rs09.game.content.ame.RandomEventManager.MAX_DELAY_TICKS + 5)
|
||||
Assertions.assertNotNull(p.getAttribute("re-npc", null))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user