diff --git a/Server/src/main/core/ServerConstants.kt b/Server/src/main/core/ServerConstants.kt index 2307a894a..287350a4f 100644 --- a/Server/src/main/core/ServerConstants.kt +++ b/Server/src/main/core/ServerConstants.kt @@ -311,5 +311,11 @@ class ServerConstants { @JvmField var NEW_PLAYER_ANNOUNCEMENT = true + + @JvmField + var HOLIDAY_EVENT_RANDOMS = true + + @JvmField + var FORCE_HALLOWEEN_RANDOMS = false } } diff --git a/Server/src/main/core/game/system/config/ServerConfigParser.kt b/Server/src/main/core/game/system/config/ServerConfigParser.kt index 8f8367292..0ba6c9892 100644 --- a/Server/src/main/core/game/system/config/ServerConfigParser.kt +++ b/Server/src/main/core/game/system/config/ServerConfigParser.kt @@ -161,6 +161,8 @@ object ServerConfigParser { ServerConstants.GRAFANA_TTL_DAYS = data.getLong("integrations.grafana_log_ttl_days", 7L).toInt() ServerConstants.BETTER_DFS = data.getBoolean("world.better_dfs", true) ServerConstants.NEW_PLAYER_ANNOUNCEMENT = data.getBoolean("world.new_player_announcement", true) + ServerConstants.HOLIDAY_EVENT_RANDOMS = data.getBoolean("world.holiday_event_randoms", true) + ServerConstants.FORCE_HALLOWEEN_RANDOMS = data.getBoolean("world.force_halloween_randoms", false) val logLevel = data.getString("server.log_level", "VERBOSE").uppercase() ServerConstants.LOG_LEVEL = parseEnumEntry(logLevel) ?: LogLevel.VERBOSE diff --git a/Server/src/main/core/game/worldevents/holiday/HolidayRandomEventNPC.kt b/Server/src/main/core/game/worldevents/holiday/HolidayRandomEventNPC.kt new file mode 100644 index 000000000..8a91ada91 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/HolidayRandomEventNPC.kt @@ -0,0 +1,86 @@ +package core.game.worldevents.holiday + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.MovementPulse +import core.game.node.entity.impl.PulseType +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.game.world.map.RegionManager +import core.game.world.map.path.Pathfinder +import core.tools.secondsToTicks +import org.rs09.consts.Sounds +import kotlin.reflect.full.createInstance + +abstract class HolidayRandomEventNPC(id:Int) : NPC(id) { + lateinit var player: Player + abstract var loot: WeightBasedTable? + var spawnLocation: Location? = null + var initialized = false + var finalized = false + var timerPaused = false + var ticksLeft = secondsToTicks(30) + + open fun create(player: Player, loot: WeightBasedTable? = null, type: String = ""): HolidayRandomEventNPC { + val event = this::class.createInstance() + event.loot = loot + event.player = player + event.spawnLocation = RegionManager.getSpawnLocation(player, this) + return event + } + + open fun terminate() { + pulseManager.clear(PulseType.STANDARD) + if (initialized && !finalized) { + poofClear(this) + playGlobalAudio(this.location, Sounds.SMOKEPUFF2_1931, 100) + } + finalized = true + } + + open fun follow() { + pulseManager.run((object : MovementPulse(this, player, Pathfinder.DUMB) { + override fun pulse(): Boolean { + face(player) + return false + } + }), PulseType.STANDARD) + } + + override fun tick() { + super.tick() + if (player.getAttribute("holiday-npc", null) != this) { + terminate() + return + } + if (!player.getAttribute("holidayrandom:pause", false)) { + ticksLeft-- + } + if (!pulseManager.hasPulseRunning() && !finalized) { + follow() + } + if (!player.isActive || !player.location.withinDistance(location, 10)) { + terminate() + } + if (ticksLeft <= 0 && initialized) { + terminate() + initialized = false + } + } + + override fun init() { + initialized = true + finalized = false + timerPaused = false + spawnLocation ?: terminate() + location = spawnLocation + player.setAttribute("holiday-npc", this) + super.init() + } + + override fun clear() { + super.clear() + if(player.getAttribute("holiday-npc", null) == this) player.removeAttribute("holiday-npc") + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/HolidayRandomEvents.kt b/Server/src/main/core/game/worldevents/holiday/HolidayRandomEvents.kt new file mode 100644 index 000000000..1731f50b8 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/HolidayRandomEvents.kt @@ -0,0 +1,40 @@ +package core.game.worldevents.holiday + +import core.game.worldevents.holiday.halloween.randoms.* + +enum class HolidayRandomEvents(val npc: HolidayRandomEventNPC, val type: String) { + BLACK_CAT(npc = BlackCatHolidayRandomNPC(), "halloween"), + SPIDER(npc = SpiderHolidayRandomNPC(), "halloween"), + GHOST(npc = GhostHolidayRandomNPC(), "halloween"), + ZOMBIE(npc = ZombieHolidayRandomNPC(), "halloween"), + WITCH(npc = WitchHolidayRandomNPC(), "halloween"), + DEATH(npc = DeathHolidayRandomNPC(), "halloween"), + VAMPIRE(npc = VampireHolidayRandomNPC(), "halloween"); + + companion object { + @JvmField + val halloweenEventsList = ArrayList() + val christmasEventsList = ArrayList() + + init { + populateMappings() + } + + fun getHolidayRandom(type: String): HolidayRandomEvents { + return when (type) { + "halloween" -> halloweenEventsList.random() + "christmas" -> christmasEventsList.random() + else -> throw Exception("Invalid event type!") + } + } + + private fun populateMappings() { + for (event in values()) { + when(event.type) { + "halloween" -> halloweenEventsList.add(event) + "christmas" -> christmasEventsList.add(event) + } + } + } + } +} diff --git a/Server/src/main/core/game/worldevents/holiday/HolidayRandoms.kt b/Server/src/main/core/game/worldevents/holiday/HolidayRandoms.kt new file mode 100644 index 000000000..b7ae0ed74 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/HolidayRandoms.kt @@ -0,0 +1,253 @@ +package core.game.worldevents.holiday + +import content.global.ame.RandomEventNPC +import content.global.skill.construction.HouseLocation +import core.ServerConstants +import core.api.* +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.system.command.Privilege +import core.game.system.timer.PersistTimer +import core.game.world.map.zone.ZoneRestriction +import core.game.world.repository.Repository +import core.tools.RandomFunction +import core.tools.colorize +import core.tools.minutesToTicks +import org.json.simple.JSONObject +import java.time.LocalDate +import java.time.Month + +class HolidayRandoms() : PersistTimer(0, "holiday", isAuto = true), Commands { + var paused = false + var nextRandom: HolidayRandomEvents? = null + var currentHoliday: String? = null + val halloweenStartDate = LocalDate.of(LocalDate.now().year, Month.OCTOBER, 17) + val halloweenEndDate = LocalDate.of(LocalDate.now().year, Month.NOVEMBER, 7) + val christmasStartDate = LocalDate.of(LocalDate.now().year, Month.DECEMBER, 1) + val christmasEndDate = LocalDate.of(LocalDate.now().year, Month.DECEMBER, 31) + + override fun run(entity: Entity): Boolean { + if (entity !is Player) return false + + setNextExecution() + + if (!canSpawn(entity)) { + delayNextExecution() + return true + } + + val eventSelection = rollEventPool() + val eventNpc = eventSelection.npc.create(entity) + if (eventNpc.spawnLocation == null) { + entity.debug("[HolidayRandom] Attempted to spawn random, but spawnLoc was null.") + delayNextExecution() + return true + } + + eventNpc.init() + setAttribute(entity, EVENT_NPC, eventNpc) + setAttribute(eventNpc, EVENT_NPC, eventNpc) + entity.debug("[HolidayRandom] Fired ${eventSelection.name}.") + return true + } + + override fun onRegister(entity: Entity) { + if (entity !is Player || entity.isArtificial || !ServerConstants.HOLIDAY_EVENT_RANDOMS) { + entity.timers.removeTimer(this) + return + } + + val player = entity.asPlayer() + when (checkIfHoliday()) { + "halloween" -> { + sendMessage(player, colorize("%OA chill goes down your spine...")) + currentHoliday = "halloween" + } + "none" -> player.timers.removeTimer(this) + } + + if (runInterval == 0) + setNextExecution() + } + + fun checkIfHoliday(): String { + val currentDate = LocalDate.now() + if ((!currentDate.isBefore(halloweenStartDate) && !currentDate.isAfter(halloweenEndDate)) || ServerConstants.FORCE_HALLOWEEN_RANDOMS) + return "halloween" + + return "none" + } + + override fun save(root: JSONObject, entity: Entity) { + root["ticksRemaining"] = (nextExecution - getWorldTicks()).toString() + } + + override fun parse(root: JSONObject, entity: Entity) { + runInterval = (root["ticksRemaining"]?.toString()?.toIntOrNull() ?: 0) + nextExecution = getWorldTicks() + runInterval + } + + private fun canSpawn(entity: Entity) : Boolean { + if (entity.zoneMonitor.isRestricted(ZoneRestriction.RANDOM_EVENTS) || getAttribute(entity, "re-npc", null) != null) + return false + + val current = getAttribute(entity, EVENT_NPC, null) + if (current != null) + return false + + if (paused || entity.inCombat()) + return false + + return true + } + + private fun delayNextExecution() { + runInterval = 50 + nextExecution = getWorldTicks() + runInterval + + } + + private fun setNextExecution() { + runInterval = RandomFunction.random(MIN_DELAY_TICKS, MAX_DELAY_TICKS + 1) + nextExecution = getWorldTicks() + runInterval + } + + private fun rollEventPool() : HolidayRandomEvents { + if (nextRandom != null) { + val result = nextRandom!! + nextRandom = null + return result + } + return when (currentHoliday) { + "halloween" -> HolidayRandomEvents.getHolidayRandom("halloween") + else -> HolidayRandomEvents.SPIDER + } + } + + override fun defineCommands() { + define("hrevent", Privilege.ADMIN, "::hrevent [-p] player name [-e event name]", "Spawns a holiday random event for the target player.
Optional -e parameter to pass a specific event.") { player, args -> + if (args.size == 1) { + val possible = HolidayRandomEvents.values() + for (event in possible) { + notify(player, event.name.lowercase()) + } + return@define + } + + val arg = parseCommandArgs(args.joinToString(" ")) + val target = Repository.getPlayerByName(arg.targetPlayer) + + if (getTimer(player) == null) + reject(player, "No holiday random events are active. To force a holiday's random events use ::forcehrevents") + + if (target == null) + reject(player, "Unable to find user ${arg.targetPlayer}.") + + forceEvent(target!!, arg.targetEvent) + } + + define("forcehrevents", Privilege.ADMIN, "::forcehrevents [eventname]", "Force enable holiday random events.") { player, args -> + if (args.size == 1) { + notify(player, "Holidays: halloween") + return@define + } + val event = args[1] + if (checkIfHoliday() != "none") + reject(player, "Holiday randoms are already enabled: ${checkIfHoliday()}. Use ::stophrevents first.") + ServerConstants.HOLIDAY_EVENT_RANDOMS = true + when (event) { + "halloween" -> { + ServerConstants.FORCE_HALLOWEEN_RANDOMS = true + for (p in Repository.players) { + if (getTimer(p) != null || p.isArtificial) { + continue + } + notify(p, colorize("%RHalloween Randoms are now enabled!")) + registerTimer(p, HolidayRandoms()) + } + } + else -> reject(player, "Invalid event!") + } + } + + define("stophrevents", Privilege.ADMIN, "::stophrevents", "Stops all holiday random events.") { player, _ -> + if (checkIfHoliday() == "none") + reject(player, "No holiday random events are currently active.") + ServerConstants.HOLIDAY_EVENT_RANDOMS = false + ServerConstants.FORCE_HALLOWEEN_RANDOMS = false + for (p in Repository.players) { + if (getTimer(p) == null) { + continue + } + removeHolidayTimer(p) + notify(p, "Holiday random events are now disabled!") + } + } + } + + data class CommandArgs (val targetPlayer: String, val targetEvent: HolidayRandomEvents?) + + companion object { + const val EVENT_NPC = "holiday-npc" + val MIN_DELAY_TICKS = minutesToTicks(30) + val MAX_DELAY_TICKS = minutesToTicks(90) + + fun terminateEventNpc (player: Player) { + getEventNpc(player)?.terminate() + } + + fun getEventNpc (player: Player) : HolidayRandomEventNPC? { + return getAttribute(player, EVENT_NPC, null) + } + + fun pause (player: Player) { + val timer = getTimer(player) ?: return + timer.paused = true + } + + fun unpause (player: Player) { + val timer = getTimer(player) ?: return + timer.paused = false + } + + fun removeHolidayTimer (player: Player) { + val timer = getTimer(player) ?: return + removeTimer(player, timer) + } + + fun forceEvent (player: Player, event: HolidayRandomEvents? = null) { + val timer = getTimer(player) ?: return + timer.nextExecution = getWorldTicks() + timer.nextRandom = event + } + + fun parseCommandArgs (args: String, commandName: String = "hrevent") : CommandArgs { + val tokens = args.split(" ") + val modeTokens = arrayOf("-p", "-e") + + var userString = "" + var eventString = "" + var lastMode = "-p" + + for (token in tokens) { + when (token) { + commandName -> continue + in modeTokens -> lastMode = token + else -> when (lastMode) { + "-p" -> userString += "$token " + "-e" -> eventString += "$token " + } + } + } + + val username = userString.trim().lowercase().replace(" ", "_") + val eventName = eventString.trim().uppercase().replace(" ", "_") + + var event: HolidayRandomEvents? = null + + try { event = HolidayRandomEvents.valueOf(eventName) } catch (_: Exception) {} + + return CommandArgs(username, event) + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/ResetHolidayAppearance.kt b/Server/src/main/core/game/worldevents/holiday/ResetHolidayAppearance.kt new file mode 100644 index 000000000..079c40c51 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/ResetHolidayAppearance.kt @@ -0,0 +1,23 @@ +package core.game.worldevents.holiday + +import core.api.playAudio +import core.api.sendMessage +import core.api.visualize +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.system.timer.RSTimer +import core.tools.minutesToTicks +import core.tools.secondsToTicks +import org.rs09.consts.Sounds + +class ResetHolidayAppearance() : RSTimer(minutesToTicks(1), "reset-holiday-appearance") { + override fun run(entity: Entity): Boolean { + if (entity is Player) { + entity.asPlayer().appearance.transformNPC(-1) + playAudio(entity.asPlayer(), Sounds.WEAKEN_HIT_3010) + visualize(entity, -1, 86) + } + entity.timers.removeTimer(this) + return true + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/BlackCatHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/BlackCatHolidayRandomNPC.kt new file mode 100644 index 000000000..0d145eb82 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/BlackCatHolidayRandomNPC.kt @@ -0,0 +1,28 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler.HitsplatType +import core.game.worldevents.holiday.HolidayRandomEventNPC + +import core.game.worldevents.holiday.HolidayRandoms +import org.rs09.consts.Sounds + +class BlackCatHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(4607) { + override fun init() { + super.init() + queueScript(this, 8, QueueStrength.SOFT) { + playGlobalAudio(this.location, Sounds.CAT_ATTACK_333) + sendChat("HISS") + if (player.location.withinDistance(this.location, 3)) { + this.face(player) + sendMessage(player, "The cat scratches you and runs away.") + val hit = if (player.skills.lifepoints < 5) 0 else 1 + impact(player, hit, HitsplatType.NORMAL) + } + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/DeathHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/DeathHolidayRandomNPC.kt new file mode 100644 index 000000000..e91136de3 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/DeathHolidayRandomNPC.kt @@ -0,0 +1,39 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.game.worldevents.holiday.HolidayRandoms +import core.tools.RandomFunction +import org.rs09.consts.Sounds + +class DeathHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(2862) { + override fun init() { + super.init() + playJingle(player, 337) + queueScript(this, 6, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + this.face(player) + visualize(this, 864, -1) + playGlobalAudio(this.location, Sounds.ZOMBIE_MOAN_2324) + return@queueScript delayScript(this, 1) + } + 1 -> { + when(RandomFunction.getRandom(2)) { + 0 -> sendChat(this, "Your end is near, ${player.name.capitalize()}...") + 1 -> sendChat(this, "Time is running out, ${player.name.capitalize()}...") + 2 -> sendChat(this, "Tick tock, ${player.name.capitalize()}...") + } + return@queueScript delayScript(this, 4) + } + 2 -> { + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/GhostHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/GhostHolidayRandomNPC.kt new file mode 100644 index 000000000..aa6c50b2c --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/GhostHolidayRandomNPC.kt @@ -0,0 +1,24 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.tools.RandomFunction +import org.rs09.consts.Sounds + +class GhostHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(2716) { + override fun init() { + super.init() + this.isAggressive = false + playGlobalAudio(this.location, Sounds.BIGGHOST_APPEAR_1595) + animate(player, 2836) + sendChat(this, "WooooOOOooOOo") + sendMessage(player, "The air suddenly gets colder...") + } + + override fun tick() { + super.tick() + if (RandomFunction.roll(10)) + playGlobalAudio(this.location, Sounds.BIGGHOST_LAUGH_1600) + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomBehavior.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomBehavior.kt new file mode 100644 index 000000000..df23e763d --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomBehavior.kt @@ -0,0 +1,22 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.getAttribute +import core.api.playGlobalAudio +import core.game.node.entity.Entity +import core.game.node.entity.combat.CombatStyle +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.worldevents.holiday.HolidayRandomEventNPC +import org.rs09.consts.Sounds + +class SpiderHolidayRandomBehavior : NPCBehavior() { + override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean { + return false + } + + override fun onDeathStarted(self: NPC, killer: Entity) { + getAttribute(self, "holiday-npc", null)?.terminate() + playGlobalAudio(self.location, Sounds.SMALL_SPIDER_DEATH_3608) + super.onDeathFinished(self, killer) + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomNPC.kt new file mode 100644 index 000000000..66685e19e --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/SpiderHolidayRandomNPC.kt @@ -0,0 +1,47 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler +import core.game.world.update.flag.context.Animation +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.game.worldevents.holiday.HolidayRandoms +import org.rs09.consts.Sounds + +class SpiderHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(61) { + override fun init() { + super.init() + this.behavior = SpiderHolidayRandomBehavior() + playGlobalAudio(this.location, Sounds.SPIDER_4375) + var stomped = false + queueScript(this,4, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + sendChat(player, "Eww a spider!") + return@queueScript delayScript(this, 2) + } + 1 -> { + if (player.location.withinDistance(this.location, 3)) { + player.animate(Animation(4278)) + playGlobalAudio(this.location, Sounds.UNARMED_KICK_2565) + sendMessage(player, "You stomp the spider.") + stomped = true + } + return@queueScript delayScript(this, 1) + } + 2 -> { + if (stomped) { + impact(this, 1, ImpactHandler.HitsplatType.NORMAL) + } else { + sendMessage(player, "The spider runs away.") + playGlobalAudio(this.location, Sounds.SPIDER_4375) + HolidayRandoms.terminateEventNpc(player) + } + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/VampireHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/VampireHolidayRandomNPC.kt new file mode 100644 index 000000000..b1fdf8d30 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/VampireHolidayRandomNPC.kt @@ -0,0 +1,46 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.game.worldevents.holiday.HolidayRandoms +import core.game.worldevents.holiday.ResetHolidayAppearance +import core.tools.RandomFunction +import core.tools.colorize +import org.rs09.consts.Sounds + +class VampireHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(1023) { + override fun init() { + super.init() + playGlobalAudio(this.location, Sounds.REGULAR_VAMPIRE_APPEAR_1897) + visualize(this, -1 , 1863) + queueScript(this, 3, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + this.face(player) + visualize(this, 7183 , -1) + playGlobalAudio(this.location, Sounds.VAMPIRE_ATTACK_879) + if (RandomFunction.roll(2)) { + player.timers.registerTimer(ResetHolidayAppearance()) + sendMessage(player, colorize("%RThe vampire bites your neck!")) + val hit = if (player.skills.lifepoints < 5) 0 else 2 + impact(player, hit, ImpactHandler.HitsplatType.NORMAL) + player.appearance.transformNPC(1023) + } else { + sendMessage(player, "The vampire tries to bite your neck and misses!") + impact(player, 0, ImpactHandler.HitsplatType.NORMAL) + } + return@queueScript delayScript(this, 8) + } + 1 -> { + visualize(this, 10530, 1863) + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/WitchHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/WitchHolidayRandomNPC.kt new file mode 100644 index 000000000..53bb704f0 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/WitchHolidayRandomNPC.kt @@ -0,0 +1,149 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler +import core.game.worldevents.holiday.ResetHolidayAppearance +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.game.worldevents.holiday.HolidayRandoms +import core.tools.RandomFunction +import org.rs09.consts.Sounds + +class WitchHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(611) { + override fun init() { + super.init() + when (RandomFunction.getRandom(4)) { + 0 -> { + queueScript(this, 6, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + sendChat(this, "Brackium Emendo!") + this.face(player) + playGlobalAudio(this.location, Sounds.CONFUSE_CAST_AND_FIRE_119) + animate(this, 1978) + spawnProjectile(this, player, 109) + return@queueScript delayScript(this, 2) + } + 1 -> { + player.appearance.transformNPC(3138) + playAudio(player, Sounds.SKELETON_RESURRECT_1687) + registerTimer(player, ResetHolidayAppearance()) + return@queueScript delayScript(this, 4) + } + 2 -> { + sendChat(this, "That was not right...") + visualize(this, 857, -1) + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } + 1 -> { + queueScript(this, 6, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + sendChat(this, "Bombarda!") + this.face(player) + playGlobalAudio(this.location, Sounds.CURSE_CAST_AND_FIRE_127) + animate(this, 1978) + spawnProjectile(this, player, 109) + return@queueScript delayScript(this, 2) + } + 1 -> { + playGlobalAudio(player.location, Sounds.EXPLOSION_1487) + visualize(player, -1, 659) + val hit = if (player.skills.lifepoints < 5) 0 else 2 + impact(player, hit, ImpactHandler.HitsplatType.NORMAL) + return@queueScript delayScript(this, 2) + } + 2 -> { + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } + 2 -> { + queueScript(this, 6, QueueStrength.SOFT) {stage: Int -> + when (stage) { + 0 -> { + sendChat(this, "Tarantallegra!") + this.face(player) + playGlobalAudio(this.location, Sounds.WEAKEN_CAST_AND_FIRE_3011) + animate(this, 1978) + spawnProjectile(this, player, 109) + return@queueScript delayScript(this, 2) + } + 1 -> { + animate(player, 3543, true) + sendMessage(player, "You suddenly burst into dance.") + return@queueScript delayScript(this, 2) + } + 2 -> { + visualize(this, 861, -1) + playGlobalAudio(this.location, Sounds.HUMAN_LAUGH_1_3071) + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } + 3 -> { + queueScript(this, 6, QueueStrength.SOFT) {stage: Int -> + when (stage) { + 0 -> { + sendChat(this, "Vespertilio!") + this.face(player) + playGlobalAudio(this.location, Sounds.WEAKEN_CAST_AND_FIRE_3011) + animate(this, 1978) + spawnProjectile(this, player, 109) + return@queueScript delayScript(this, 2) + } + 1 -> { + visualize(player, 10530, 1863) + playGlobalAudio(player.location, Sounds.VAMPIRE_SUMMON_1899) + return@queueScript delayScript(this, 4) + } + 2 -> { + player.appearance.transformNPC(6835) + HolidayRandoms.terminateEventNpc(player) + registerTimer(player, ResetHolidayAppearance()) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } + 4 -> { + queueScript(this, 6, QueueStrength.SOFT) {stage: Int -> + when (stage) { + 0 -> { + sendChat(this, "Sella!") + this.face(player) + playGlobalAudio(this.location, Sounds.WEAKEN_CAST_AND_FIRE_3011) + animate(this, 1978) + spawnProjectile(this, player, 109) + return@queueScript delayScript(this, 2) + } + 1 -> { + player.appearance.transformNPC(3293) + playGlobalAudio(player.location, Sounds.KR_JUDGE_HAMMER_3822) + registerTimer(player, ResetHolidayAppearance()) + return@queueScript delayScript(this, 4) + } + 2 -> { + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/worldevents/holiday/halloween/randoms/ZombieHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/ZombieHolidayRandomNPC.kt new file mode 100644 index 000000000..241ab8ab5 --- /dev/null +++ b/Server/src/main/core/game/worldevents/holiday/halloween/randoms/ZombieHolidayRandomNPC.kt @@ -0,0 +1,57 @@ +package core.game.worldevents.holiday.halloween.randoms + +import core.api.* +import core.api.utils.WeightBasedTable +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler +import core.game.worldevents.holiday.ResetHolidayAppearance +import core.game.worldevents.holiday.HolidayRandomEventNPC +import core.game.worldevents.holiday.HolidayRandoms +import core.tools.RandomFunction +import core.tools.colorize +import org.rs09.consts.Sounds + +class ZombieHolidayRandomNPC(override var loot: WeightBasedTable? = null) : HolidayRandomEventNPC(2714) { + override fun init() { + super.init() + this.isAggressive = false + playGlobalAudio(this.location, Sounds.ZOMBIE_DEATH_922) + playJingle(player, 314) + sendMessage(player, "A zombie crawls out of the ground beneath you...") + animate(player, 7272) + queueScript(this, 2, QueueStrength.SOFT) { stage: Int -> + when (stage) { + 0 -> { + when (RandomFunction.getRandom(2)) { + 0 -> sendChat(this, "Brainnnss!") + 1 -> sendChat(this, "RArrgghhh") + 2 -> sendChat(this, "Flesshhh") + } + return@queueScript delayScript(this, 1) + } + 1 -> { + this.face(player) + visualize(this, 5568 , -1) + playGlobalAudio(this.location, Sounds.ZOMBIE_ATTACK_918) + if (RandomFunction.roll(2)) { + player.timers.registerTimer(ResetHolidayAppearance()) + sendMessage(player, colorize("%RThe zombie bites you!")) + val hit = if (player.skills.lifepoints < 5) 0 else 2 + impact(player, hit, ImpactHandler.HitsplatType.NORMAL) + player.appearance.transformNPC(2866) + } else { + impact(player, 0, ImpactHandler.HitsplatType.NORMAL) + sendMessage(player, "The zombie tries to bite you and misses!") + } + return@queueScript delayScript(this, 8) + } + 2 -> { + animate(this, 5575) + HolidayRandoms.terminateEventNpc(player) + return@queueScript stopExecuting(this) + } + else -> return@queueScript stopExecuting(this) + } + } + } +} \ No newline at end of file diff --git a/Server/worldprops/default.conf b/Server/worldprops/default.conf index 5d6ef149e..0f5271bd8 100644 --- a/Server/worldprops/default.conf +++ b/Server/worldprops/default.conf @@ -97,6 +97,10 @@ better_agility_pyramid_gp = true better_dfs = true #new player announcement new_player_announcement = true +#enables holiday random events (no effect on normal random events) +holiday_event_randoms = true +#force holiday randoms (can only force one at a time) +force_halloween_randoms = false [paths] #path to the data folder, which contains the cache subfolder and such