mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-24 20:05:13 -06:00
Climbing rope fixes
Same-tile interaction still fails
This commit is contained in:
parent
e258be1898
commit
7c8aa93ce0
2 changed files with 96 additions and 35 deletions
|
|
@ -16,6 +16,7 @@ import core.game.node.scenery.Scenery
|
|||
import core.game.node.scenery.SceneryBuilder
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.update.flag.chunk.ObjectUpdateFlag
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.tools.ticksPerMinute
|
||||
import org.rs09.consts.Items
|
||||
|
|
@ -61,6 +62,11 @@ enum class BoulderState {
|
|||
COLLAPSED, WEAKENED, CLEARED
|
||||
}
|
||||
|
||||
data class ActiveClimbingRope(
|
||||
val rope: Scenery,
|
||||
val originalWall: Scenery
|
||||
)
|
||||
|
||||
/**
|
||||
* Manages the state of a Castle Wars game including scores, flags, and game lifecycle.
|
||||
* This is a singleton that tracks the current game state.
|
||||
|
|
@ -91,6 +97,8 @@ object CastleWarsGameState {
|
|||
var zamorakDroppedFlagScenery: Scenery? = null
|
||||
private set
|
||||
|
||||
private val activeClimbingRopes: MutableMap<Location, ActiveClimbingRope> = mutableMapOf()
|
||||
|
||||
// Tick when each flag was dropped (for auto-return timer)
|
||||
private var saradominFlagDroppedTick: Int = 0
|
||||
private var zamorakFlagDroppedTick: Int = 0
|
||||
|
|
@ -263,22 +271,47 @@ object CastleWarsGameState {
|
|||
resetBattlefield()
|
||||
}
|
||||
|
||||
fun registerClimbingRope(rope: Scenery, originalWall: Scenery) {
|
||||
val key = Location.create(rope.location)
|
||||
val chunk = RegionManager.getRegionChunk(rope.location)
|
||||
|
||||
rope.isActive = true
|
||||
rope.isRenderable = true
|
||||
activeClimbingRopes[key] = ActiveClimbingRope(rope, Scenery(originalWall))
|
||||
chunk.objects[rope.location.chunkOffsetX][rope.location.chunkOffsetY] = rope
|
||||
}
|
||||
|
||||
fun getClimbingRope(location: Location): Scenery? {
|
||||
return activeClimbingRopes[Location.create(location)]?.rope?.takeIf { it.isActive }
|
||||
}
|
||||
|
||||
fun removeClimbingRope(location: Location, sendUpdate: Boolean = true): Boolean {
|
||||
val activeRope = activeClimbingRopes.remove(Location.create(location)) ?: return false
|
||||
val chunk = RegionManager.getRegionChunk(activeRope.rope.location)
|
||||
|
||||
activeRope.rope.isActive = false
|
||||
chunk.objects[activeRope.rope.location.chunkOffsetX][activeRope.rope.location.chunkOffsetY] =
|
||||
activeRope.originalWall
|
||||
|
||||
if (sendUpdate) {
|
||||
chunk.flag(ObjectUpdateFlag(activeRope.rope, true))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun clearClimbingRopes(sendUpdate: Boolean = true) {
|
||||
val ropeLocations = activeClimbingRopes.keys.map { Location.create(it) }
|
||||
for (location in ropeLocations) {
|
||||
removeClimbingRope(location, sendUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the battlefield by removing climbing ropes, restoring modified battlements,
|
||||
* and closing any open doors. Called at the end of each match.
|
||||
*/
|
||||
private fun resetBattlefield() {
|
||||
for (x in 2368..2431) {
|
||||
for (y in 3072..3135) {
|
||||
for (z in 0..3) {
|
||||
val loc = Location.create(x, y, z)
|
||||
val obj = RegionManager.getObject(loc)
|
||||
if (obj != null && obj.id == CastleWars.cwCastleClimbingRope) {
|
||||
SceneryBuilder.remove(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clearClimbingRopes()
|
||||
// Reset modified battlements back to original state
|
||||
// 36313 -> 4446, 36314 -> 4447
|
||||
for (x in 2368..2431) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ data class BarrierData(
|
|||
val insideTile: Location
|
||||
)
|
||||
|
||||
data class ClimbingRopeTraversal(
|
||||
val topOfWallTile: Location,
|
||||
val baseOfWallTile: Location
|
||||
)
|
||||
|
||||
private val barrierCoordinates: Map<Int, List<BarrierData>> = mapOf(
|
||||
CastleWars.zamorakEnergyBarrier to listOf(
|
||||
BarrierData(
|
||||
|
|
@ -111,19 +116,49 @@ internal fun getBarrierPassTiles(playerLoc: Location, barrierData: BarrierData):
|
|||
}
|
||||
}
|
||||
|
||||
internal fun getClimbingRopeTraversal(rope: Scenery): ClimbingRopeTraversal {
|
||||
val ropeLoc = rope.location
|
||||
val wallDirection = rope.direction.opposite
|
||||
val topOfWallTile = Location(wallDirection.stepY + ropeLoc.x, -wallDirection.stepX + ropeLoc.y, ropeLoc.z)
|
||||
val baseOfWallTile = Location(-wallDirection.stepY + ropeLoc.x, wallDirection.stepX + ropeLoc.y, ropeLoc.z)
|
||||
return ClimbingRopeTraversal(topOfWallTile, baseOfWallTile)
|
||||
}
|
||||
|
||||
internal fun isOnClimbingRopeBaseSide(playerLoc: Location, rope: Scenery): Boolean {
|
||||
val traversal = getClimbingRopeTraversal(rope)
|
||||
if (playerLoc == traversal.baseOfWallTile) {
|
||||
return true
|
||||
}
|
||||
|
||||
val ropeLoc = rope.location
|
||||
val baseVectorX = traversal.baseOfWallTile.x - ropeLoc.x
|
||||
val baseVectorY = traversal.baseOfWallTile.y - ropeLoc.y
|
||||
val playerVectorX = playerLoc.x - ropeLoc.x
|
||||
val playerVectorY = playerLoc.y - ropeLoc.y
|
||||
|
||||
return playerVectorX * baseVectorX + playerVectorY * baseVectorY > 0
|
||||
}
|
||||
|
||||
internal fun getClimbingRopeInteractionDestination(playerLoc: Location, rope: Scenery): Location {
|
||||
val traversal = getClimbingRopeTraversal(rope)
|
||||
return if (isOnClimbingRopeBaseSide(playerLoc, rope)) {
|
||||
traversal.baseOfWallTile
|
||||
} else {
|
||||
traversal.topOfWallTile
|
||||
}
|
||||
}
|
||||
|
||||
internal fun canClimbUpClimbingRope(playerLoc: Location, rope: Scenery): Boolean {
|
||||
return playerLoc == getClimbingRopeTraversal(rope).baseOfWallTile
|
||||
}
|
||||
|
||||
class CastleWarsListeners : InteractionListener {
|
||||
|
||||
private val pickaxeIds = intArrayOf(1265, 1267, 1269, 1271, 1273, 1275)
|
||||
|
||||
override fun defineDestinationOverrides() {
|
||||
setDest(IntType.SCENERY, intArrayOf(CastleWars.cwCastleClimbingRope), "climb") { entity, node ->
|
||||
val rope = node.asScenery()
|
||||
val playerLoc = entity.location
|
||||
val ropeLoc = rope.location
|
||||
if (playerLoc.getDistance(ropeLoc) <= 2.0) {
|
||||
return@setDest playerLoc
|
||||
}
|
||||
return@setDest ropeLoc
|
||||
return@setDest getClimbingRopeInteractionDestination(entity.location, node.asScenery())
|
||||
}
|
||||
|
||||
setDest(
|
||||
|
|
@ -242,17 +277,20 @@ class CastleWarsListeners : InteractionListener {
|
|||
CastleWars.cwClimbingRope,
|
||||
*CastleWars.cwCastleBattlementsMap.keys.toIntArray()
|
||||
) { player, rope, wall ->
|
||||
if (CastleWarsGameState.getClimbingRope(wall.location) != null) {
|
||||
sendDialogue(player, "There is already a rope tied to the battlements.")
|
||||
return@onUseWith true
|
||||
}
|
||||
removeItem(player, rope)
|
||||
val wallScenery = wall.asScenery()
|
||||
val ropeWall = wallScenery.transform(CastleWars.cwCastleBattlementsMap.getValue(wall.id))
|
||||
SceneryBuilder.replace(wallScenery, ropeWall, CastleWars.ropeAliveTicks, false)
|
||||
val hangingRope = Scenery(CastleWars.cwCastleClimbingRope, wall.location, 4, wall.direction.toInteger())
|
||||
CastleWarsGameState.registerClimbingRope(hangingRope, wallScenery)
|
||||
RegionManager.getRegionChunk(hangingRope.location).flag(ObjectUpdateFlag(hangingRope, false))
|
||||
hangingRope.isActive = true
|
||||
GameWorld.Pulser.submit(object : Pulse(CastleWars.ropeAliveTicks) {
|
||||
override fun pulse(): Boolean {
|
||||
RegionManager.getRegionChunk(hangingRope.location).flag(ObjectUpdateFlag(hangingRope, true))
|
||||
hangingRope.isActive = false
|
||||
CastleWarsGameState.removeClimbingRope(hangingRope.location)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
|
@ -260,21 +298,11 @@ class CastleWarsListeners : InteractionListener {
|
|||
}
|
||||
|
||||
on(CastleWars.cwCastleClimbingRope, SCENERY, "climb") { player, rope ->
|
||||
val ropeLoc = rope.asScenery().location
|
||||
val dir = rope.asScenery().direction.opposite
|
||||
val ropeScenery = rope.asScenery()
|
||||
val traversal = getClimbingRopeTraversal(ropeScenery)
|
||||
|
||||
val topOfWallLoc = Location(dir.stepY + ropeLoc.x, -dir.stepX + ropeLoc.y, ropeLoc.z)
|
||||
|
||||
val baseOfWallLoc = Location(-dir.stepY + ropeLoc.x, dir.stepX + ropeLoc.y, ropeLoc.z)
|
||||
|
||||
val distToTop = player.location.getDistance(topOfWallLoc)
|
||||
val distToBase = player.location.getDistance(baseOfWallLoc)
|
||||
|
||||
val onRopeTile =
|
||||
player.location.x == ropeLoc.x && player.location.y == ropeLoc.y && player.location.z == ropeLoc.z
|
||||
|
||||
if (onRopeTile || distToBase <= distToTop) {
|
||||
teleport(player, topOfWallLoc, TeleportManager.TeleportType.INSTANT)
|
||||
if (canClimbUpClimbingRope(player.location, ropeScenery)) {
|
||||
teleport(player, traversal.topOfWallTile, TeleportManager.TeleportType.INSTANT)
|
||||
} else {
|
||||
sendMessage(player, "You can't climb down the rope.")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue