Implemented a brand new cutscene system
Converted Lost Tribe's cutscene to the new system
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package core.game.node.entity.combat;
|
||||
|
||||
import api.events.SelfDeath;
|
||||
import core.game.container.Container;
|
||||
import core.game.container.ContainerType;
|
||||
import core.game.node.Node;
|
||||
@@ -84,6 +85,7 @@ public final class DeathTask extends NodeTask {
|
||||
e.getImpactHandler().getImpactLog().clear();// check if this needs to be
|
||||
// before finalize
|
||||
e.getImpactHandler().setDisabledTicks(4);
|
||||
e.dispatch(new SelfDeath(killer));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
import api.*
|
||||
import api.events.EventHook
|
||||
import api.events.SelfDeath
|
||||
import core.game.component.Component
|
||||
import core.game.content.dialogue.FacialExpression
|
||||
import core.game.interaction.MovementPulse
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.Region
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import org.rs09.consts.Components
|
||||
import rs09.ServerConstants
|
||||
import rs09.game.Event
|
||||
import rs09.game.camerautils.PlayerCamera
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.world.GameWorld
|
||||
|
||||
/**
|
||||
* A utility class for making cutscenes.
|
||||
* @author Ceikry
|
||||
*/
|
||||
abstract class Cutscene(val player: Player) {
|
||||
lateinit var region: Region
|
||||
lateinit var base: Location
|
||||
var exitLocation: Location = player.location.transform(0,0,0)
|
||||
var ended = false
|
||||
|
||||
val camera = PlayerCamera(player)
|
||||
private val addedNPCs = HashMap<Int, ArrayList<NPC>>()
|
||||
|
||||
abstract fun setup()
|
||||
abstract fun runStage(stage: Int)
|
||||
|
||||
/**
|
||||
* Creates a new dynamic copy of the region identified by regionId, sets this cutscene's region as this new copy, and clears any cutscene-spawned NPCs from the previous region.
|
||||
* @param regionId the region ID to duplicate.
|
||||
*/
|
||||
fun loadRegion(regionId: Int)
|
||||
{
|
||||
clearNPCs()
|
||||
logCutscene("Creating new instance of region $regionId for ${player.username}.")
|
||||
region = DynamicRegion.create(regionId)
|
||||
logCutscene("Dynamic region instantiated for ${player.username}. Global coordinates: ${region.baseLocation}.")
|
||||
base = region.baseLocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the player's view to black. This process can be safely assumed to take about 8 ticks to complete.
|
||||
*/
|
||||
fun fadeToBlack()
|
||||
{
|
||||
logCutscene("Fading ${player.username}'s screen to black.")
|
||||
player.interfaceManager.closeOverlay()
|
||||
player.interfaceManager.openOverlay(Component(Components.FADE_TO_BLACK_120))
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the player's view from black back to normal. This process can be safely assumed to take about 6 ticks to complete.
|
||||
*/
|
||||
fun fadeFromBlack()
|
||||
{
|
||||
logCutscene("Fading ${player.username}'s screen from black to normal.")
|
||||
player.interfaceManager.closeOverlay()
|
||||
player.interfaceManager.openOverlay(Component(Components.FADE_FROM_BLACK_170))
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports an entity to a pair of coordinates within the currently active cutscene region
|
||||
* @param entity the entity to teleport
|
||||
* @param regionX the region X coordinate to teleport the entity to (0-63)
|
||||
* @param regionY the region Y coordinate to teleport the entity to (0-63)
|
||||
* @param plane (optional) the plane to teleport to (0-3)
|
||||
*/
|
||||
fun teleport(entity: Entity, regionX: Int, regionY: Int, plane: Int = 0)
|
||||
{
|
||||
val newLoc = base.transform(regionX, regionY, plane)
|
||||
logCutscene("Teleporting ${entity.username} to coordinates: LOCAL[$regionX,$regionY,$plane] GLOBAL[${newLoc.x},${newLoc.y},$plane].")
|
||||
entity.properties.teleportLocation = newLoc
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an entity to the given coordinates within the currently active cutscene region
|
||||
* @param entity the entity to move
|
||||
* @param regionX the region X coordinate to move the entity to (0-63)
|
||||
* @param regionY the region Y coordinate to move the entity to (0-63)
|
||||
*/
|
||||
fun move(entity: Entity, regionX: Int, regionY: Int)
|
||||
{
|
||||
logCutscene("Moving ${entity.username} to LOCAL[$regionX,$regionY].")
|
||||
entity.pulseManager.run(object : MovementPulse(entity, base.transform(regionX,regionY,0)) {
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a dialogue to the player using the given NPC ID, which updates the cutscene stage by default when continued.
|
||||
* @param npcId the ID of the NPC to send a dialogue for
|
||||
* @param expression the FacialExpression the NPC should use
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun dialogueUpdate(npcId: Int, expression: FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending NPC dialogue update.")
|
||||
sendNPCDialogue(player, npcId, message, expression)
|
||||
player.dialogueInterpreter.addAction { _,_ -> onContinue.invoke() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a non-NPC dialogue to the player, which updates the cutscene stage by default when continued
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun dialogueUpdate(message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending standard dialogue update.")
|
||||
sendDialogue(player, message)
|
||||
player.dialogueInterpreter.addAction {_,_ -> onContinue.invoke()}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a player dialogue, which updates the cutscene stage by default when continued
|
||||
* @param expression the FacialExpression to use
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun playerDialogueUpdate(expression: FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending player dialogue update")
|
||||
sendPlayerDialogue(player, message, expression)
|
||||
player.dialogueInterpreter.addAction{_,_ -> onContinue.invoke()}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the stage after a set number of ticks.
|
||||
* @param ticks the number of ticks to wait
|
||||
* @param newStage (optional) the new stage to update to. If not passed, stage is incremented instead.
|
||||
*/
|
||||
fun timedUpdate(ticks: Int, newStage: Int = -1)
|
||||
{
|
||||
logCutscene("Executing timed updated for $ticks ticks.")
|
||||
GameWorld.Pulser.submit(object : Pulse(ticks)
|
||||
{
|
||||
override fun pulse(): Boolean {
|
||||
if(newStage == -1)
|
||||
incrementStage()
|
||||
else
|
||||
updateStage(newStage)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first NPC from the added-to-cutscene NPCs with a matching ID.
|
||||
* @param id the ID to grab for.
|
||||
* @return the first NPC, or null if there are no matching NPCs.
|
||||
*/
|
||||
fun getNPC(id: Int): NPC?
|
||||
{
|
||||
return addedNPCs[id]?.firstOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all NPCs from the added-to-cutscene NPCs with a matching ID.
|
||||
* @param id the ID to grab for.
|
||||
* @return an ArrayList of the matching NPCs, which will be empty if there were no matches.
|
||||
*/
|
||||
fun getNPCs(id: Int): ArrayList<NPC>
|
||||
{
|
||||
return addedNPCs[id] ?: ArrayList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object in the region at the given regionX and regionY
|
||||
* @param regionX the region-local X coordinate to grab the object from (0-63)
|
||||
* @param regionY the region-local Y coordinate to grab the object from (0-63)
|
||||
* @param plane the plane to grab the object from (0-3)
|
||||
*/
|
||||
fun getObject(regionX: Int, regionY: Int, plane: Int = 0): Scenery?
|
||||
{
|
||||
val obj = RegionManager.getObject(base.transform(regionX,regionY,plane))
|
||||
logCutscene("Retrieving object at LOCAL[$regionX,$regionY], GOT: ${obj?.definition?.name ?: "null"}.")
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an NPC to the cutscene with the given ID, at the region-local X and Y coordinates.
|
||||
* @param id the ID of the NPC to add.
|
||||
* @param regionX the region-local X coordinate to place the NPC at
|
||||
* @param regionY the region-local Y coordinate to place the NPC at
|
||||
* @param direction the direction the NPC faces when it is initially placed.
|
||||
* @param plane the plane to place te NPC on. Default is 0.
|
||||
*/
|
||||
fun addNPC(id: Int, regionX: Int, regionY: Int, direction: Direction, plane: Int = 0)
|
||||
{
|
||||
val npc = NPC(id)
|
||||
npc.isRespawn = false
|
||||
npc.isAggressive = false
|
||||
npc.isWalks = false
|
||||
npc.location = base.transform(regionX, regionY, plane)
|
||||
npc.init()
|
||||
npc.faceLocation(npc.location.transform(direction))
|
||||
|
||||
val npcs = addedNPCs[id] ?: ArrayList()
|
||||
npcs.add(npc)
|
||||
addedNPCs[id] = npcs
|
||||
logCutscene("Added NPC $id at location LOCAL[$regionX,$regionY,$plane] GLOBAL[${npc.location.x},${npc.location.y},$plane]")
|
||||
}
|
||||
|
||||
fun start()
|
||||
{
|
||||
logCutscene("Starting cutscene for ${player.username}.")
|
||||
region = RegionManager.forId(player.location.regionId)
|
||||
base = RegionManager.forId(player.location.regionId).baseLocation
|
||||
setup()
|
||||
runStage(player.getCutsceneStage())
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE, this)
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, 0)
|
||||
player.interfaceManager.removeTabs(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
|
||||
player.properties.isSafeZone = true
|
||||
player.properties.safeRespawn = player.location
|
||||
player.lock()
|
||||
player.hook(Event.SelfDeath, CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners["cutscene"] = {player -> player.location = exitLocation; player.getCutscene()?.end() }
|
||||
player.antiMacroHandler.enabled = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends this cutscene, fading the screen to black, teleporting the player to the exit location, and then fading it back in and executing the endActions passed to this method.
|
||||
* @param endActions (optional) a method that executes when the cutscene fully completes
|
||||
*/
|
||||
fun end(endActions: (() -> Unit)? = null)
|
||||
{
|
||||
ended = true
|
||||
fadeToBlack()
|
||||
GameWorld.Pulser.submit(object : Pulse(){
|
||||
var tick: Int = 0
|
||||
override fun pulse(): Boolean {
|
||||
when(tick++)
|
||||
{
|
||||
8 -> player.properties.teleportLocation = exitLocation
|
||||
9 -> fadeFromBlack()
|
||||
16 -> {
|
||||
endActions?.invoke()
|
||||
player.removeAttribute(ATTRIBUTE_CUTSCENE)
|
||||
player.removeAttribute(ATTRIBUTE_CUTSCENE_STAGE)
|
||||
player.properties.isSafeZone = false
|
||||
player.properties.safeRespawn = ServerConstants.HOME_LOCATION
|
||||
player.interfaceManager.restoreTabs()
|
||||
player.unlock()
|
||||
clearNPCs()
|
||||
player.unhook(CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners.remove("cutscene")
|
||||
player.antiMacroHandler.enabled = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the camera to the specified regionX and regionY
|
||||
* @param regionX the region-local X coordinate to move the camera to (0-63)
|
||||
* @param regionY the region-local Y coordinate to move the camera to (0-63)
|
||||
* @param height (optional) the height of the camera, defaults to 300.
|
||||
* @param speed (optional) the speed of the camera transition, defaults to 100.
|
||||
*/
|
||||
fun moveCamera(regionX: Int, regionY: Int, height: Int = 300, speed: Int = 100)
|
||||
{
|
||||
val globalLoc = base.transform(regionX, regionY, 0)
|
||||
camera.panTo(globalLoc.x, globalLoc.y, height, speed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the camera to face the given region-local X and Y coordinates
|
||||
* @param regionX the region-local X coordinate to rotate the camera to (0-63)
|
||||
* @param regionY the region-local Y coordinate to rotate the camera to (0-63)
|
||||
* @param height (optional) the height of the camera, defaults to 300.
|
||||
* @param speed (optional) the speed of the camera transition, defaults to 100.
|
||||
*/
|
||||
fun rotateCamera(regionX: Int, regionY: Int, height: Int = 300, speed: Int = 100)
|
||||
{
|
||||
val globalLoc = base.transform(regionX, regionY, 0)
|
||||
camera.rotateTo(globalLoc.x, globalLoc.y, height, speed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location the player is placed at when the cutscene ends.
|
||||
*/
|
||||
fun setExit(location: Location)
|
||||
{
|
||||
exitLocation = location
|
||||
}
|
||||
|
||||
private fun loadCurrentStage()
|
||||
{
|
||||
if(ended) return
|
||||
runStage(player.getCutsceneStage())
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the player's stage attribute by 1
|
||||
*/
|
||||
fun incrementStage()
|
||||
{
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, player.getCutsceneStage() + 1)
|
||||
loadCurrentStage()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's stage attribute to a new stage
|
||||
*/
|
||||
fun updateStage(newStage: Int)
|
||||
{
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, newStage)
|
||||
loadCurrentStage()
|
||||
}
|
||||
|
||||
fun logCutscene(message: String)
|
||||
{
|
||||
if(ServerConstants.LOG_CUTSCENE)
|
||||
SystemLogger.logInfo("[CUTSCENE: ${this.javaClass.simpleName}] $message")
|
||||
}
|
||||
|
||||
fun clearNPCs() {
|
||||
for(entry in addedNPCs.entries)
|
||||
{
|
||||
logCutscene("Clearing ${entry.value.size} NPCs with ID ${entry.key} for ${player.username}.")
|
||||
for(npc in entry.value) npc.clear()
|
||||
}
|
||||
addedNPCs.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ATTRIBUTE_CUTSCENE = "cutscene"
|
||||
const val ATTRIBUTE_CUTSCENE_STAGE = "cutscene:stage"
|
||||
object CUTSCENE_DEATH_HOOK : EventHook<SelfDeath>
|
||||
{
|
||||
override fun process(entity: Entity, event: SelfDeath) {
|
||||
if(entity !is Player) return
|
||||
entity.getCutscene()?.end() ?: entity.unhook(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package api
|
||||
|
||||
import Cutscene
|
||||
import core.cache.def.impl.ItemDefinition
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.component.Component
|
||||
@@ -1439,3 +1440,11 @@ fun dumpContainer(player: Player, container: core.game.container.Container) {
|
||||
fun hasHouse(player: Player): Boolean {
|
||||
return player.houseManager.hasHouse()
|
||||
}
|
||||
|
||||
fun Player.getCutscene(): Cutscene? {
|
||||
return getAttribute<Cutscene?>(this, Cutscene.ATTRIBUTE_CUTSCENE, null)
|
||||
}
|
||||
|
||||
fun Player.getCutsceneStage(): Int {
|
||||
return getAttribute(this, Cutscene.ATTRIBUTE_CUTSCENE_STAGE, 0)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package api.events
|
||||
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.link.TeleportManager.TeleportType
|
||||
|
||||
@@ -11,3 +12,4 @@ data class LitFireEvent(val logId: Int) : Event
|
||||
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
|
||||
@@ -113,6 +113,9 @@ class ServerConstants {
|
||||
@JvmField
|
||||
var MS_SECRET_KEY = ""
|
||||
|
||||
@JvmField
|
||||
var LOG_CUTSCENE = true
|
||||
|
||||
//location names for the ::to command.
|
||||
val TELEPORT_DESTINATIONS = arrayOf(
|
||||
arrayOf(Location.create(2974, 4383, 2), "corp", "corporal", "corporeal"),
|
||||
|
||||
@@ -10,4 +10,5 @@ object Event {
|
||||
val Interaction = InteractionEvent::class.java
|
||||
val ButtonClicked = ButtonClickedEvent::class.java
|
||||
val UsedWith = UsedWithEvent::class.java
|
||||
val SelfDeath = SelfDeath::class.java
|
||||
}
|
||||
@@ -13,6 +13,7 @@ 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) {
|
||||
var event: RandomEventNPC? = null
|
||||
var enabled: Boolean = false
|
||||
var nextSpawn = 0
|
||||
val skills = arrayOf("WoodcuttingSkillPulse","FishingPulse","MiningSkillPulse","BoneBuryingOptionPlugin")
|
||||
|
||||
@@ -22,6 +23,10 @@ class RandomEventManager(val player: Player) {
|
||||
}
|
||||
|
||||
fun fireEvent() {
|
||||
if(!enabled){
|
||||
rollNextSpawn()
|
||||
return
|
||||
}
|
||||
if (player.zoneMonitor.isRestricted(ZoneRestriction.RANDOM_EVENTS)) {
|
||||
nextSpawn = GameWorld.ticks + 3000
|
||||
return
|
||||
@@ -60,6 +65,7 @@ class RandomEventManager(val player: Player) {
|
||||
if (player.isArtificial) return
|
||||
rollNextSpawn()
|
||||
SystemLogger.logRE("Initialized REManager for ${player.username}")
|
||||
enabled = true
|
||||
}
|
||||
|
||||
private fun rollNextSpawn() {
|
||||
|
||||
+91
-208
@@ -1,239 +1,122 @@
|
||||
package rs09.game.content.quest.members.thelosttribe
|
||||
|
||||
import core.game.content.activity.ActivityPlugin
|
||||
import core.game.content.activity.CutscenePlugin
|
||||
import Cutscene
|
||||
import api.animate
|
||||
import api.face
|
||||
import core.game.content.dialogue.FacialExpression
|
||||
import core.game.content.global.action.DoorActionHandler
|
||||
import core.game.interaction.MovementPulse
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.emote.Emotes
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import rs09.game.camerautils.PlayerCamera
|
||||
import rs09.game.world.GameWorld.Pulser
|
||||
|
||||
private const val DUKE = 2088
|
||||
private const val MISTAG = 2089
|
||||
private const val SIGMUND = 2090
|
||||
private const val URTAG = 5858
|
||||
private const val BOW_ANIM = 6000
|
||||
@Initializable
|
||||
/**
|
||||
* Final cutscene for the lost tribe
|
||||
* @author Ceikry
|
||||
*/
|
||||
class LostTribeCutscene(val pl: Player? = null) : CutscenePlugin("Lost Tribe Cutscene",true) {
|
||||
var camera: PlayerCamera = PlayerCamera(null)
|
||||
|
||||
init {
|
||||
this.player = pl
|
||||
}
|
||||
|
||||
override fun configure() {
|
||||
region = DynamicRegion.create(12850)
|
||||
setRegionBase()
|
||||
registerRegion(region.id)
|
||||
}
|
||||
|
||||
override fun getStartLocation(): Location {
|
||||
return base.transform(7,17,0)
|
||||
}
|
||||
|
||||
override fun newInstance(p: Player?): ActivityPlugin {
|
||||
return LostTribeCutscene(player)
|
||||
}
|
||||
|
||||
override fun getSpawnLocation(): Location {
|
||||
return Location.create(3208, 3213, 0)
|
||||
}
|
||||
|
||||
override fun open() {
|
||||
player.setAttribute("cutscene:original-loc",player.location)
|
||||
player.setAttribute("real-end",Location.create(3207, 3221, 0))
|
||||
player.interfaceManager.removeTabs(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
|
||||
class LostTribeCutscene(player: Player) : Cutscene(player) {
|
||||
override fun setup() {
|
||||
setExit(Location.create(3207, 3221, 0))
|
||||
if(player.settings.isRunToggled){
|
||||
player.settings.toggleRun()
|
||||
}
|
||||
loadRegion(12850)
|
||||
addNPC(DUKE, 6, 23, Direction.SOUTH)
|
||||
addNPC(MISTAG, 8, 17, Direction.NORTH)
|
||||
addNPC(URTAG, 8, 15, Direction.NORTH)
|
||||
addNPC(SIGMUND, 13, 22, Direction.NORTH_WEST)
|
||||
}
|
||||
|
||||
camera = PlayerCamera(player)
|
||||
var loc = coords(8,26)
|
||||
camera.panTo(loc.x,loc.y,300,100)
|
||||
loc = coords(5,18)
|
||||
camera.rotateTo(loc.x,loc.y,300,100)
|
||||
|
||||
player.faceLocation(coords(7,18))
|
||||
|
||||
val mistag = npcs.get(1)
|
||||
val urtag = npcs.get(2)
|
||||
val duke = npcs.get(0)
|
||||
val sigmund = npcs.get(3)
|
||||
|
||||
Pulser.submit(object: Pulse(){
|
||||
var counter = 0
|
||||
var stage = 0
|
||||
override fun pulse(): Boolean {
|
||||
if(!player.isPlaying || !player.isActive) return true
|
||||
when(counter++){
|
||||
5 -> DoorActionHandler.handleDoor(player, RegionManager.getObject(coords(7,17)))
|
||||
override fun runStage(stage: Int) {
|
||||
when(stage)
|
||||
{
|
||||
0 -> {
|
||||
fadeToBlack()
|
||||
timedUpdate(6)
|
||||
}
|
||||
1 -> {
|
||||
teleport(player, 7, 17)
|
||||
timedUpdate(2)
|
||||
}
|
||||
2 -> {
|
||||
fadeFromBlack()
|
||||
moveCamera(8, 26)
|
||||
rotateCamera(5, 18)
|
||||
timedUpdate(6)
|
||||
}
|
||||
3 -> {
|
||||
DoorActionHandler.handleDoor(player, getObject(7, 17))
|
||||
timedUpdate(3)
|
||||
}
|
||||
4 -> {
|
||||
move(player, 7, 22)
|
||||
move(getNPC(MISTAG)!!, 7, 19)
|
||||
move(getNPC(URTAG)!!, 7, 18)
|
||||
timedUpdate(5)
|
||||
}
|
||||
5 -> {
|
||||
move(getNPC(MISTAG)!!, 7, 20)
|
||||
move(getNPC(URTAG)!!, 6, 21)
|
||||
timedUpdate(3)
|
||||
}
|
||||
6 -> {
|
||||
player.faceLocation(getNPC(DUKE)!!.location)
|
||||
playerDialogueUpdate(FacialExpression.FRIENDLY, "Your grace, I present Ur-tag, headman of the Dorgeshuun.")
|
||||
Emotes.BOW.play(player)
|
||||
}
|
||||
7 -> {
|
||||
player.pulseManager.run(object: MovementPulse(player,coords(7,22),false){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
move(player, 7, 24)
|
||||
timedUpdate(5)
|
||||
}
|
||||
}, "movement")
|
||||
mistag.pulseManager.run(object : MovementPulse(mistag,coords(7,19)){//coords(7,20)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
8 -> {
|
||||
animate(getNPC(DUKE)!!, Emotes.BOW.animation)
|
||||
animate(getNPC(URTAG)!!, URTAG_BOW_ANIM)
|
||||
dialogueUpdate(DUKE, FacialExpression.FRIENDLY, "Welcome, Ur-tag. I am sorry that your race came under suspicion.")
|
||||
}
|
||||
}, "movement")
|
||||
urtag.pulseManager.run(object : MovementPulse(urtag,coords(7,18)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
9 -> {
|
||||
dialogueUpdate(DUKE, FacialExpression.ANGRY, "I assure you that the warmongering element has been dealt with.")
|
||||
moveCamera(9, 22)
|
||||
rotateCamera(6, 22)
|
||||
}
|
||||
10 -> dialogueUpdate(URTAG, FacialExpression.OLD_NORMAL, "I apologize for the damage to your cellar. I will send workers to repair the hole.")
|
||||
11 -> dialogueUpdate(DUKE, FacialExpression.FRIENDLY, "No, let it stay. It can be a route of commerce between our lands.")
|
||||
12 -> {
|
||||
mistag.pulseManager.run(object : MovementPulse(mistag,coords(7,20)){//coords(7,20)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
val duke = getNPC(DUKE)!!
|
||||
face(duke, player.location)
|
||||
face(player, duke.location)
|
||||
rotateCamera(6, 22, 300, 3)
|
||||
moveCamera(11, 22, 325, 3)
|
||||
dialogueUpdate(DUKE, FacialExpression.FRIENDLY, "${player.username}, Lumbridge is in your debt. Please accept this ring as a token of my thanks.")
|
||||
}
|
||||
}, "movement")
|
||||
urtag.pulseManager.run(object : MovementPulse(urtag,coords(6,21)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
13 -> dialogueUpdate(DUKE, FacialExpression.FRIENDLY, "It is enchanted to save you in your hour of need.")
|
||||
14 -> {
|
||||
move(getNPC(URTAG)!!, 7, 23)
|
||||
dialogueUpdate(URTAG, FacialExpression.OLD_NORMAL,"I too thank you. Accept the freedom of the Dorgeshuun mines." )
|
||||
}
|
||||
15 -> {
|
||||
player.faceLocation(duke.location)
|
||||
player.dialogueInterpreter.sendDialogues(player,FacialExpression.FRIENDLY,"Your grace, I present Ur-tag, headman of the","Dorgeshuun.")
|
||||
Emotes.BOW.play(player)
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
Pulser.submit(object: MovementPulse(player,coords(7,24)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
dialogueUpdate(URTAG, FacialExpression.OLD_NORMAL, "These are strange times. I never dreamed that I would see the surface, still less that I would be on friendly terms with its people." )
|
||||
moveCamera(16, 21, 300, 3)
|
||||
rotateCamera(6, 22, 300, 2)
|
||||
}
|
||||
})
|
||||
Pulser.submit(object : Pulse(5){
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
duke.animator.animate(Emotes.BOW.animation)
|
||||
urtag.animator.animate(Animation(BOW_ANIM))
|
||||
player.dialogueInterpreter.sendDialogues(duke,FacialExpression.FRIENDLY,"Welcome, Ur-tag. I am sorry that your race came","under suspicion.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(duke,FacialExpression.ANGRY,"I assure you that the warmongering element has been","dealt with.")
|
||||
loc = coords(9,22)
|
||||
camera.panTo(loc.x,loc.y,300,2)
|
||||
loc = coords(6,22)
|
||||
camera.rotateTo(loc.x,loc.y,300,2)
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(urtag,FacialExpression.OLD_NORMAL,"I apologize for the damage to your cellar. I will send","workers to repair the hole.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(duke,FacialExpression.FRIENDLY,"No, let it stay. It can be a route of commerce between","our lands.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
duke.faceLocation(player.location)
|
||||
player.faceLocation(duke.location)
|
||||
camera.rotateTo(duke.location.x,duke.location.y,350,4)
|
||||
loc = coords(11,22)
|
||||
camera.panTo(loc.x,loc.y,325,3)
|
||||
loc = coords(6,22)
|
||||
camera.rotateTo(loc.x,loc.y,300,3)
|
||||
player.dialogueInterpreter.sendDialogues(duke,FacialExpression.FRIENDLY,"${player.name}, Lumbridge is in your debt. Please accept","this ring as a token of my thanks.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(duke,FacialExpression.FRIENDLY,"It is enchanted to save you in your hour of need.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
urtag.pulseManager.run(object: MovementPulse(urtag,coords(7,23)){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
16 -> dialogueUpdate(SIGMUND, FacialExpression.ANGRY, "Prattle on, goblin.")
|
||||
17 -> {
|
||||
animate(getNPC(SIGMUND)!!, Emotes.LAUGH.animation)
|
||||
dialogueUpdate(SIGMUND, FacialExpression.EVIL_LAUGH, "Soon you will be destroyed!")
|
||||
}
|
||||
})
|
||||
urtag.faceLocation(player.location)
|
||||
player.dialogueInterpreter.sendDialogues(urtag,FacialExpression.OLD_NORMAL,"I too thank you. Accept the freedom of the Dorgeshuun","mines.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(urtag,FacialExpression.OLD_NORMAL,"These are strange times. I never dreamed that I would","see the surface, still less that I would be on friendly","terms with its people.")
|
||||
loc = coords(16,21)
|
||||
camera.panTo(loc.x,loc.y,300,3)
|
||||
loc = coords(6,22)
|
||||
camera.rotateTo(loc.x,loc.y,300,2)
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
Pulser.submit(object : Pulse(5) {
|
||||
override fun pulse(): Boolean {
|
||||
player.dialogueInterpreter.sendDialogues(sigmund,FacialExpression.ANGRY,"Prattle on, goblin.")
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
player.dialogueInterpreter.sendDialogues(sigmund,FacialExpression.EVIL_LAUGH,"Soon you will be destroyed!")
|
||||
sigmund.animator.animate(Emotes.LAUGH.animation)
|
||||
player.dialogueInterpreter.addAction { player, buttonId ->
|
||||
loc = coords(16,17)
|
||||
sigmund.pulseManager.run(object: MovementPulse(sigmund,loc){
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
18 -> {
|
||||
move(getNPC(SIGMUND)!!, 16, 17)
|
||||
timedUpdate(4)
|
||||
}
|
||||
})
|
||||
Pulser.submit(object : Pulse(4){
|
||||
override fun pulse(): Boolean {
|
||||
Pulser.submit(endPulse)
|
||||
Pulser.submit(object : Pulse(7){
|
||||
override fun pulse(): Boolean {
|
||||
player.questRepository.getQuest("Lost Tribe").setStage(player,100)
|
||||
19 -> {
|
||||
end {
|
||||
player.questRepository.getQuest("Lost Tribe").setStage(player, 100)
|
||||
player.questRepository.getQuest("Lost Tribe").finish(player)
|
||||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
loc = coords(7,25)
|
||||
camera.panTo(loc.x,loc.y,300,3)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun start(player: Player?, login: Boolean, vararg args: Any?): Boolean {
|
||||
val duke = NPC(DUKE,coords(6,23))
|
||||
val mistag = NPC(MISTAG,coords(8,17))
|
||||
val urtag = NPC(URTAG,coords(8,15))
|
||||
val sigmund = NPC(SIGMUND,coords(13,22))
|
||||
duke.init()
|
||||
duke.faceLocation(coords(6,22))
|
||||
mistag.init()
|
||||
urtag.init()
|
||||
sigmund.init()
|
||||
sigmund.faceLocation(coords(11,18))
|
||||
npcs.add(duke)
|
||||
npcs.add(mistag)
|
||||
npcs.add(urtag)
|
||||
npcs.add(sigmund)
|
||||
return super.start(player, login, *args)
|
||||
companion object {
|
||||
private const val DUKE = 2088
|
||||
private const val MISTAG = 2089
|
||||
private const val SIGMUND = 2090
|
||||
private const val URTAG = 5858
|
||||
private const val URTAG_BOW_ANIM = 6000
|
||||
}
|
||||
|
||||
fun coords(x: Int, y: Int): Location {
|
||||
return base.transform(x,y,0)
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,6 @@
|
||||
package rs09.game.content.quest.members.thelosttribe
|
||||
|
||||
import core.game.component.Component
|
||||
import core.game.content.activity.ActivityManager
|
||||
import core.game.content.dialogue.FacialExpression
|
||||
import rs09.game.content.dialogue.DialogueFile
|
||||
import rs09.tools.END_DIALOGUE
|
||||
@@ -45,7 +44,8 @@ class MistagLTDialogue(val isGreeting: Boolean, val questStage: Int) : DialogueF
|
||||
3 -> npc("I will summon Ur-tag, our headman, at once.").also { stage++ }
|
||||
4 -> {
|
||||
end()
|
||||
ActivityManager.start(player,"Lost Tribe Cutscene",false)
|
||||
LostTribeCutscene(player!!).start()
|
||||
//ActivityManager.start(player,"Lost Tribe Cutscene",false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ object ServerConfigParser {
|
||||
ServerConstants.HOME_LOCATION = parseLocation(data.getString("world.home_location"))
|
||||
ServerConstants.START_LOCATION = parseLocation(data.getString("world.new_player_location"))
|
||||
ServerConstants.DAILY_RESTART = data.getBoolean("world.daily_restart")
|
||||
ServerConstants.LOG_CUTSCENE = data.getBoolean("world.verbose_cutscene", false)
|
||||
ServerConstants.GRAND_EXCHANGE_DATA_PATH = data.getPath("paths.eco_data")
|
||||
ServerConstants.CELEDT_DATA_PATH = data.getPath("paths.cele_drop_table_path")
|
||||
ServerConstants.SERVER_GE_NAME = data.getString("world.name_ge") ?: ServerConstants.SERVER_NAME
|
||||
|
||||
Reference in New Issue
Block a user