Cleanup, burning catapults, player cap removed, stepping stone fixes

This commit is contained in:
dam 2026-04-10 19:16:59 +03:00
parent f1bf63d353
commit 6b76a3f8d0
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB
10 changed files with 155 additions and 209 deletions

View file

@ -4,6 +4,7 @@ import content.minigame.castlewars.CastleWarsConstants.GAME_COOLDOWN_MINUTES
import content.minigame.castlewars.CastleWarsConstants.GAME_TIME_MINUTES
import content.minigame.castlewars.CastleWarsConstants.ROPE_DURATION_TICKS
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.map.zone.ZoneBorders
import org.rs09.consts.Items
import org.rs09.consts.NPCs
@ -21,11 +22,22 @@ object CastleWars {
const val castleWaterTap: Int = Scenery.TAP_4482
const val cwSteppingStones: Int = Scenery.STEPPING_STONE_4411
// Stepping stone tile locations for flag auto-return check.
// If a flag is dropped on any of these tiles, it immediately returns to base.
private val steppingStoneLocations: Set<Location> by lazy(LazyThreadSafetyMode.NONE) {
val locations = mutableSetOf<Location>()
for (x in 2368..2431) {
for (y in 3072..3135) {
val location = Location.create(x, y, 0)
if (RegionManager.getObject(location)?.id == cwSteppingStones) {
locations += location
}
}
}
locations
}
// Stepping stone tile locations are cached so dropped flag scenery cannot mask the underlying stone tile.
fun isSteppingStoneTile(location: Location): Boolean {
val obj = core.game.world.map.RegionManager.getObject(location)
return obj != null && obj.id == cwSteppingStones
return steppingStoneLocations.contains(Location.create(location))
}
// Energy barriers
@ -71,15 +83,24 @@ object CastleWars {
const val tunnelRocksWeakened: Int = 4438 // Weakened rocks (1 explosive hit, still blocking)
const val caveWall: Int = 4448 // Cave wall for causing collapse
// Catapults - can be operated, destroyed, and repaired
// Both 4381 and 4382 are operational catapults (different orientations in the map)
// Both 4385 and 4386 are damaged/destroyed catapults (have "Repair" option instead of "Operate")
// Catapults - can be operated, set on fire, destroyed, and repaired.
// 4381/4382 are the operational variants, 4904/4905 are the burning variants, 4385/4386 are damaged.
const val catapult: Int = 4381 // Operational catapult variant 1
const val catapultAlt: Int = 4382 // Operational catapult variant 2 (different orientation)
const val catapultBurning1: Int = 4904 // Burning catapult variant 1
const val catapultBurning2: Int = 4905 // Burning catapult variant 2
const val catapultDamaged1: Int = 4385 // Damaged catapult variant 1
const val catapultDamaged2: Int = 4386 // Damaged catapult variant 2
val burningCatapultIds: IntArray = intArrayOf(catapultBurning1, catapultBurning2)
val damagedCatapultIds: IntArray = intArrayOf(catapultDamaged1, catapultDamaged2)
val allCatapultIds: IntArray = intArrayOf(catapult, catapultAlt, catapultDamaged1, catapultDamaged2)
val allCatapultIds: IntArray = intArrayOf(
catapult,
catapultAlt,
catapultBurning1,
catapultBurning2,
catapultDamaged1,
catapultDamaged2
)
fun getOperationalCatapultId(team: CastleWarsTeam): Int = when (team) {
CastleWarsTeam.SARADOMIN -> catapultAlt
@ -91,6 +112,11 @@ object CastleWars {
CastleWarsTeam.ZAMORAK -> catapultDamaged1
}
fun getBurningCatapultId(team: CastleWarsTeam): Int = when (team) {
CastleWarsTeam.SARADOMIN -> catapultBurning2
CastleWarsTeam.ZAMORAK -> catapultBurning1
}
// Trapdoors - allow going down from 2nd floor to respawn room
const val saradominTrapdoor: Int = 4471 // Saradomin castle trapdoor
const val zamorakTrapdoor: Int = 4472 // Zamorak castle trapdoor
@ -144,7 +170,7 @@ object CastleWars {
const val cwBandages: Int = Items.BANDAGES_4049
const val cwToolkit: Int = Items.TOOLKIT_4051
const val cwBarricade: Int = Items.BARRICADE_4053
const val cwManualBook: Int = Items.CASTLEWARS_MANUAL_4055 // TODO: unused? what happened
const val cwManualBook: Int = Items.CASTLEWARS_MANUAL_4055
const val cwTicketRewardCurrency: Int = Items.CASTLE_WARS_TICKET_4067
// Authoritative list of items to remove from players on game end or area exit.

View file

@ -10,7 +10,7 @@ import org.rs09.consts.NPCs
/**
* Custom NPC class for Castle Wars barricades.
*
* - Block all entity movement through them (like Pest Control Brawlers) TODO: so... it sucks? shit
* - Block all entity movement through them (like Pest Control Brawlers)
* - Never retaliate when attacked (this was scary man they squared up)
* - Never turn to face attackers or any direction
* - Cannot attack or move

View file

@ -10,10 +10,10 @@ object CastleWarsConstants {
/** Grace period after picking up own flag before castle entry check (prevents instant return) */
const val FLAG_RETURN_GRACE_PERIOD_TICKS = 3
/** Ticks before a dropped flag automatically returns to its stand (~90 seconds) */
/** Ticks before a dropped flag automatically returns to its stand */
const val FLAG_AUTO_RETURN_TICKS = 150
/** Duration of climbing ropes before despawning (45 seconds at 600ms/tick) */
/** Duration of climbing ropes before despawning */
const val ROPE_DURATION_TICKS = 75
/** Burning barricade pulse interval (3 ticks = 1.8 seconds) */
@ -39,23 +39,20 @@ object CastleWarsConstants {
/** Maximum barricades per team */
const val MAX_BARRICADES_PER_TEAM = 10
/** Maximum players per team */
const val MAX_PLAYERS_PER_TEAM = 25 // TODO: I dont believe this, where? Says who
/** Minimum players per team required to start a game */
const val MIN_PLAYERS_PER_TEAM = 2
/** Catapult targeting inaccuracy radius */
const val CATAPULT_INACCURACY_RADIUS = 2 // TODO: says who
const val CATAPULT_INACCURACY_RADIUS = 2
/** Catapult impact damage radius */
const val CATAPULT_IMPACT_RADIUS = 3 // TODO: says who
const val CATAPULT_IMPACT_RADIUS = 3
/** Catapult minimum damage */
const val CATAPULT_MIN_DAMAGE = 10 // TODO: says who
const val CATAPULT_MIN_DAMAGE = 10
/** Catapult maximum damage */
const val CATAPULT_MAX_DAMAGE = 20 // TODO: says who
const val CATAPULT_MAX_DAMAGE = 20
// ==================== Coordinate Defaults ====================
/** Default X coordinate for catapult targeting */
@ -75,7 +72,7 @@ object CastleWarsConstants {
const val BANDAGE_RUN_ENERGY_RESTORE = 30.0
/** Bandage cooldown in ticks (1 tick = faster than food's 2 ticks) */
const val BANDAGE_COOLDOWN_TICKS = 1 // TODO: says who
const val BANDAGE_COOLDOWN_TICKS = 1
// ==================== Castle Wars Bracelet ====================
/** Bracelet damage bonus multiplier against flag carriers (20% extra) */
@ -88,7 +85,7 @@ object CastleWarsConstants {
/** Run energy drained when passing through an energy barrier */
const val ENERGY_BARRIER_DRAIN = 4.0
// ==================== Backdoor Pick-Lock ==================== // TODO: says who
// ==================== Backdoor Pick-Lock ====================
/** Thieving level required for pick-lock (1 = no real requirement, all players can attempt) */
const val BACKDOOR_PICKLOCK_LEVEL = 1

View file

@ -14,7 +14,6 @@ import org.rs09.consts.Sounds
* - Uses player's attack speed based on weapon
* - Calculates damage based on combat stats
* - Damages door health until destroyed or player stops
* TODO: 100% wild guesses and needs a fat refactoring
*/
class CastleWarsDoorAttackPulse(
private val player: Player,

View file

@ -155,39 +155,6 @@ class CastleWarsFlagHandler : InteractionListener {
}
}
return@on true
}
// Legacy: Handle picking up dropped flags from the ground (ground items)
// This is kept for backwards compatibility but scenery is the primary method now
// TODO: cut
on(intArrayOf(CastleWars.saradominFlag, CastleWars.zamorakFlag), IntType.GROUNDITEM, "take") { player, node ->
if (!CastleWarsGameState.isGameActive) {
return@on false
}
val playerTeam = CastleWarsGameState.getPlayerTeam(player) ?: return@on false
val groundItem = node as? GroundItem ?: return@on false
val flagTeam = when (groundItem.id) {
CastleWars.saradominFlag -> CastleWarsTeam.SARADOMIN
CastleWars.zamorakFlag -> CastleWarsTeam.ZAMORAK
else -> return@on false
}
val isDroppedFlag = when (flagTeam) {
CastleWarsTeam.SARADOMIN -> CastleWarsGameState.saradominFlagState == FlagState.DROPPED
CastleWarsTeam.ZAMORAK -> CastleWarsGameState.zamorakFlagState == FlagState.DROPPED
}
if (!isDroppedFlag) {
return@on false
}
if (flagTeam == playerTeam) {
if (CastleWarsGameState.pickUpOwnFlag(player, flagTeam)) {
return@on true
}
} else {
if (CastleWarsGameState.pickUpFlag(player, flagTeam)) {
return@on true
}
}
return@on true
}
}

View file

@ -266,14 +266,8 @@ object CastleWarsGameState {
for (key in boulderLocations.keys) {
updateBoulderScenery(key, BoulderState.COLLAPSED)
}
replaceCatapultScenery(
saradominCatapultLocation,
CastleWars.getOperationalCatapultId(CastleWarsTeam.SARADOMIN)
)
replaceCatapultScenery(
zamorakCatapultLocation,
CastleWars.getOperationalCatapultId(CastleWarsTeam.ZAMORAK)
)
updateCatapultScenery(CastleWarsTeam.SARADOMIN)
updateCatapultScenery(CastleWarsTeam.ZAMORAK)
resetBattlefield()
}
@ -575,23 +569,21 @@ object CastleWarsGameState {
*/
fun dropFlag(player: Player) {
val carriedFlag = getCarriedFlag(player) ?: return
val dropLocation = Location.create(player.location)
val shouldReturnToStand = CastleWars.isSteppingStoneTile(dropLocation)
when (carriedFlag) {
CastleWarsTeam.SARADOMIN -> {
saradominFlagCarrier = null
saradominFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.saradominDroppedFlagScenery, player.location, 10, 0)
SceneryBuilder.add(droppedFlag)
saradominDroppedFlagScenery = droppedFlag
saradominFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.SARADOMIN, dropLocation)
}
}
CastleWarsTeam.ZAMORAK -> {
zamorakFlagCarrier = null
zamorakFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.zamorakDroppedFlagScenery, player.location, 10, 0)
SceneryBuilder.add(droppedFlag)
zamorakDroppedFlagScenery = droppedFlag
zamorakFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.ZAMORAK, dropLocation)
}
}
}
if (player.equipment.get(EquipmentContainer.SLOT_WEAPON)?.id == carriedFlag.flagItemId) {
@ -601,13 +593,12 @@ object CastleWarsGameState {
player.inventory.remove(Item(carriedFlag.flagItemId))
}
removeAttribute(player, CastleWarsConstants.ATTR_FLAG_PICKUP_TICK)
announceToAllPlayers("${carriedFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
// Stepping stone auto-return: if the flag was dropped on a stepping stone tile,
// immediately return it to the base stand (authentic RS behavior)
if (CastleWars.isSteppingStoneTile(player.location)) {
if (shouldReturnToStand) {
returnFlagToStand(carriedFlag)
} else {
announceToAllPlayers("${carriedFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
}
}
@ -617,23 +608,21 @@ object CastleWarsGameState {
*/
fun dropOwnFlag(player: Player) {
val carriedFlag = getOwnCarriedFlag(player) ?: return
val dropLocation = Location.create(player.location)
val shouldReturnToStand = CastleWars.isSteppingStoneTile(dropLocation)
when (carriedFlag) {
CastleWarsTeam.SARADOMIN -> {
saradominOwnFlagCarrier = null
saradominFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.saradominDroppedFlagScenery, player.location, 10, 0)
SceneryBuilder.add(droppedFlag)
saradominDroppedFlagScenery = droppedFlag
saradominFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.SARADOMIN, dropLocation)
}
}
CastleWarsTeam.ZAMORAK -> {
zamorakOwnFlagCarrier = null
zamorakFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.zamorakDroppedFlagScenery, player.location, 10, 0)
SceneryBuilder.add(droppedFlag)
zamorakDroppedFlagScenery = droppedFlag
zamorakFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.ZAMORAK, dropLocation)
}
}
}
if (player.equipment.get(EquipmentContainer.SLOT_WEAPON)?.id == carriedFlag.flagItemId) {
@ -642,13 +631,12 @@ object CastleWarsGameState {
if (player.inventory.contains(carriedFlag.flagItemId, 1)) {
player.inventory.remove(Item(carriedFlag.flagItemId))
}
announceToAllPlayers("${carriedFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
// Stepping stone auto-return: if the flag was dropped on a stepping stone tile,
// immediately return it to the base stand (authentic RS behavior)
if (CastleWars.isSteppingStoneTile(player.location)) {
if (shouldReturnToStand) {
returnFlagToStand(carriedFlag)
} else {
announceToAllPlayers("${carriedFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
}
}
@ -660,25 +648,23 @@ object CastleWarsGameState {
* @param dropLocation The location where the flag should be dropped
*/
fun dropFlagAtLocation(player: Player, dropLocation: Location) {
val actualDropLocation = Location.create(dropLocation)
val shouldReturnToStand = CastleWars.isSteppingStoneTile(actualDropLocation)
val carriedEnemyFlag = getCarriedFlag(player)
if (carriedEnemyFlag != null) {
when (carriedEnemyFlag) {
CastleWarsTeam.SARADOMIN -> {
saradominFlagCarrier = null
saradominFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.saradominDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
saradominDroppedFlagScenery = droppedFlag
saradominFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.SARADOMIN, actualDropLocation)
}
}
CastleWarsTeam.ZAMORAK -> {
zamorakFlagCarrier = null
zamorakFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.zamorakDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
zamorakDroppedFlagScenery = droppedFlag
zamorakFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.ZAMORAK, actualDropLocation)
}
}
}
if (player.equipment.get(EquipmentContainer.SLOT_WEAPON)?.id == carriedEnemyFlag.flagItemId) {
@ -687,12 +673,12 @@ object CastleWarsGameState {
if (player.inventory.contains(carriedEnemyFlag.flagItemId, 1)) {
player.inventory.remove(Item(carriedEnemyFlag.flagItemId))
}
announceToAllPlayers("${carriedEnemyFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
// Stepping stone auto-return check
if (CastleWars.isSteppingStoneTile(dropLocation)) {
if (shouldReturnToStand) {
returnFlagToStand(carriedEnemyFlag)
} else {
announceToAllPlayers("${carriedEnemyFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
}
return
}
@ -701,20 +687,16 @@ object CastleWarsGameState {
when (carriedOwnFlag) {
CastleWarsTeam.SARADOMIN -> {
saradominOwnFlagCarrier = null
saradominFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.saradominDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
saradominDroppedFlagScenery = droppedFlag
saradominFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.SARADOMIN, actualDropLocation)
}
}
CastleWarsTeam.ZAMORAK -> {
zamorakOwnFlagCarrier = null
zamorakFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.zamorakDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
zamorakDroppedFlagScenery = droppedFlag
zamorakFlagDroppedTick = getWorldTicks()
if (!shouldReturnToStand) {
addDroppedFlagScenery(CastleWarsTeam.ZAMORAK, actualDropLocation)
}
}
}
if (player.equipment.get(EquipmentContainer.SLOT_WEAPON)?.id == carriedOwnFlag.flagItemId) {
@ -723,13 +705,32 @@ object CastleWarsGameState {
if (player.inventory.contains(carriedOwnFlag.flagItemId, 1)) {
player.inventory.remove(Item(carriedOwnFlag.flagItemId))
}
announceToAllPlayers("${carriedOwnFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
// Stepping stone auto-return check
if (CastleWars.isSteppingStoneTile(dropLocation)) {
if (shouldReturnToStand) {
returnFlagToStand(carriedOwnFlag)
} else {
announceToAllPlayers("${carriedOwnFlag.teamName} flag has been dropped!")
updateAllOverlays()
updateAllHintIcons()
}
}
}
private fun addDroppedFlagScenery(flagTeam: CastleWarsTeam, dropLocation: Location) {
when (flagTeam) {
CastleWarsTeam.SARADOMIN -> {
saradominFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.saradominDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
saradominDroppedFlagScenery = droppedFlag
saradominFlagDroppedTick = getWorldTicks()
}
CastleWarsTeam.ZAMORAK -> {
zamorakFlagState = FlagState.DROPPED
val droppedFlag = Scenery(CastleWars.zamorakDroppedFlagScenery, dropLocation, 10, 0)
SceneryBuilder.add(droppedFlag)
zamorakDroppedFlagScenery = droppedFlag
zamorakFlagDroppedTick = getWorldTicks()
}
}
}
@ -855,45 +856,6 @@ object CastleWarsGameState {
updateAllHintIcons()
}
/**
* Return a dropped flag to its stand (legacy)
* TODO: This is now only used for ground item pickup which is being cut coz its fake. Not real
* The new behavior uses pickUpOwnFlag() and castle entry detection.
* @param player The player returning the flag
* @param flagTeam The team whose flag is being returned
* @return true if the flag was successfully returned
*/
fun returnFlag(player: Player, flagTeam: CastleWarsTeam): Boolean {
val playerTeam = getPlayerTeam(player) ?: return false
if (playerTeam != flagTeam) {
return false
}
val flagState =
if (flagTeam == CastleWarsTeam.SARADOMIN) saradominFlagState else zamorakFlagState
if (flagState != FlagState.DROPPED) {
return false
}
when (flagTeam) {
CastleWarsTeam.SARADOMIN -> {
saradominFlagState = FlagState.SAFE
saradominDroppedFlagScenery?.let { SceneryBuilder.remove(it) }
saradominDroppedFlagScenery = null
updateFlagStandObject(CastleWarsTeam.SARADOMIN, FlagState.SAFE)
}
CastleWarsTeam.ZAMORAK -> {
zamorakFlagState = FlagState.SAFE
zamorakDroppedFlagScenery?.let { SceneryBuilder.remove(it) }
zamorakDroppedFlagScenery = null
updateFlagStandObject(CastleWarsTeam.ZAMORAK, FlagState.SAFE)
}
}
announceToTeam(flagTeam, "${player.username} has returned the ${flagTeam.teamName} flag!")
updateAllOverlays()
updateAllHintIcons()
return true
}
/**
* Return a dropped flag directly to its stand (instant, no player involved).
* Used for auto-return (timeout, stepping stone) scenarios.
@ -1429,15 +1391,18 @@ object CastleWarsGameState {
* Destroy a team's catapult
*/
fun destroyCatapult(team: CastleWarsTeam) {
val location = when (team) {
CastleWarsTeam.SARADOMIN -> saradominCatapultLocation
CastleWarsTeam.ZAMORAK -> zamorakCatapultLocation
}
when (team) {
CastleWarsTeam.SARADOMIN -> saradominCatapultOperational = false
CastleWarsTeam.ZAMORAK -> zamorakCatapultOperational = false
CastleWarsTeam.SARADOMIN -> {
saradominCatapultOperational = false
saradominCatapultOnFire = false
}
CastleWarsTeam.ZAMORAK -> {
zamorakCatapultOperational = false
zamorakCatapultOnFire = false
}
}
replaceCatapultScenery(location, CastleWars.getDamagedCatapultId(team))
updateCatapultScenery(team)
updateAllOverlays()
}
@ -1450,6 +1415,7 @@ object CastleWarsGameState {
CastleWarsTeam.SARADOMIN -> saradominCatapultOnFire = true
CastleWarsTeam.ZAMORAK -> zamorakCatapultOnFire = true
}
updateCatapultScenery(team)
updateAllOverlays()
}
@ -1461,6 +1427,7 @@ object CastleWarsGameState {
CastleWarsTeam.SARADOMIN -> saradominCatapultOnFire = false
CastleWarsTeam.ZAMORAK -> zamorakCatapultOnFire = false
}
updateCatapultScenery(team)
updateAllOverlays()
}
@ -1478,15 +1445,18 @@ object CastleWarsGameState {
* Repair a team's catapult
*/
fun repairCatapult(team: CastleWarsTeam) {
val location = when (team) {
CastleWarsTeam.SARADOMIN -> saradominCatapultLocation
CastleWarsTeam.ZAMORAK -> zamorakCatapultLocation
}
when (team) {
CastleWarsTeam.SARADOMIN -> saradominCatapultOperational = true
CastleWarsTeam.ZAMORAK -> zamorakCatapultOperational = true
CastleWarsTeam.SARADOMIN -> {
saradominCatapultOperational = true
saradominCatapultOnFire = false
}
CastleWarsTeam.ZAMORAK -> {
zamorakCatapultOperational = true
zamorakCatapultOnFire = false
}
}
replaceCatapultScenery(location, CastleWars.getOperationalCatapultId(team))
updateCatapultScenery(team)
updateAllOverlays()
}
@ -1614,6 +1584,19 @@ object CastleWarsGameState {
* Replace catapult scenery at a location with a new catapult ID.
* Searches for any catapult object at the location and replaces it.
*/
private fun updateCatapultScenery(team: CastleWarsTeam) {
val location = when (team) {
CastleWarsTeam.SARADOMIN -> saradominCatapultLocation
CastleWarsTeam.ZAMORAK -> zamorakCatapultLocation
}
val newId = when {
!isCatapultOperational(team) -> CastleWars.getDamagedCatapultId(team)
isCatapultOnFire(team) -> CastleWars.getBurningCatapultId(team)
else -> CastleWars.getOperationalCatapultId(team)
}
replaceCatapultScenery(location, newId)
}
private fun replaceCatapultScenery(location: Location, newId: Int) { // Get the object at the catapult location
val existingObj = RegionManager.getObject(location)
if (existingObj != null && existingObj.id in CastleWars.allCatapultIds) {

View file

@ -27,7 +27,7 @@ import org.rs09.consts.NPCs
/**
* Handles Castle Wars item mechanics:
* - Bandages: Heal 10% of max HP, restore 30% run energy, can heal teammates
* - Barricades: Place barricade NPC with 5000 HP, max 10 per team TODO: 5000 HP BARRICADE HAHHAH FAT CHANCE. keeping that in for now
* - Barricades: Place barricade NPC with 50 HP, max 10 per team
* - Explosive Potions: Instant-destroy barricades, 15% max HP self-damage on drop
*/
class CastleWarsItemHandler : InteractionListener {

View file

@ -71,6 +71,8 @@ private val barrierCoordinates: Map<Int, List<BarrierData>> = mapOf(
)
private val castleWarsStairDestinationOverrides: Map<Location, Location> = mapOf(
Location.create(2419, 3077, 0) to Location.create(2420, 3080, 1),
Location.create(2419, 3078, 0) to Location.create(2420, 3080, 1),
Location.create(2425, 3076, 2) to Location.create(2426, 3074, 3),
Location.create(2425, 3074, 3) to Location.create(2425, 3077, 2),
Location.create(2430, 3081, 2) to Location.create(2427, 3081, 1),
@ -179,10 +181,6 @@ class CastleWarsListeners : InteractionListener {
on(CastleWars.joinSaradominTeamPortal, IntType.SCENERY, "Enter") { player, _ ->
if (GameWorld.settings?.enable_castle_wars != true) return@on false
if (!player.isArtificial && joinError(player)) return@on true
if (CastleWarsWaitingArea.waitingSaradominPlayers.size + CastleWarsGameArea.saradominPlayers.size >= CastleWarsConstants.MAX_PLAYERS_PER_TEAM) {
sendMessage(player, "The team is currently full.")
return@on true
}
player.properties.teleportLocation = CastleWarsWaitingArea.saradominWaitingRoom.randomWalkableLoc
player.setAttribute(CastleWars.portalAttribute, CastleWars.saradominName)
return@on true
@ -190,10 +188,6 @@ class CastleWarsListeners : InteractionListener {
on(CastleWars.joinZamorakTeamPortal, IntType.SCENERY, "Enter") { player, _ ->
if (GameWorld.settings?.enable_castle_wars != true) return@on false
if (!player.isArtificial && joinError(player)) return@on true
if (CastleWarsWaitingArea.waitingZamorakPlayers.size + CastleWarsGameArea.zamorakPlayers.size >= CastleWarsConstants.MAX_PLAYERS_PER_TEAM) {
sendMessage(player, "The team is currently full.")
return@on true
}
player.properties.teleportLocation = CastleWarsWaitingArea.zamorakWaitingRoom.randomWalkableLoc
player.setAttribute(CastleWars.portalAttribute, CastleWars.zamorakName)
return@on true
@ -212,21 +206,7 @@ class CastleWarsListeners : InteractionListener {
val saraTotal =
CastleWarsWaitingArea.waitingSaradominPlayers.size + CastleWarsGameArea.saradominPlayers.size
val zamTotal = CastleWarsWaitingArea.waitingZamorakPlayers.size + CastleWarsGameArea.zamorakPlayers.size
val saraFull = saraTotal >= CastleWarsConstants.MAX_PLAYERS_PER_TEAM
val zamFull = zamTotal >= CastleWarsConstants.MAX_PLAYERS_PER_TEAM
if (saraFull && zamFull) {
sendMessage(player, "The team is currently full.")
return@on true
}
when {
saraFull -> {
player.properties.teleportLocation = CastleWarsWaitingArea.zamorakWaitingRoom.randomWalkableLoc
}
zamFull -> {
player.properties.teleportLocation = CastleWarsWaitingArea.saradominWaitingRoom.randomWalkableLoc
}
saraTotal < zamTotal -> {
player.properties.teleportLocation = CastleWarsWaitingArea.saradominWaitingRoom.randomWalkableLoc
}
@ -323,11 +303,6 @@ class CastleWarsListeners : InteractionListener {
return@on true
}
if (CastleWarsGameState.isCarryingAnyFlag(player)) {
CastleWarsGameState.dropFlagAtLocation(player, player.location)
sendMessage(player, "You drop the flag as you jump across!")
}
lock(player, 3)
AgilityHandler.forceWalk(player, -1, player.location, stone.location, Animation(741), 10, 0.0, null, 1)
runTask(player, 1) {

View file

@ -18,7 +18,7 @@ import core.game.world.update.flag.context.Animation
* This pulse replaces the instant 3-tick delay with proper mining mechanics
* where players must successfully "hit" the rock multiple times to clear it.
*/
class CastleWarsTunnelMiningPulse( // TODO: tunnels in general are working great. but this... needs a thorough check from start to finish
class CastleWarsTunnelMiningPulse(
private val player: Player,
private val rocks: Scenery,
private val boulderKey: String,

View file

@ -116,7 +116,6 @@ class CastleWarsGameArea : CastleWarsArea(), TickListener {
CastleWarsTeam.ZAMORAK -> zamorakPlayers
}
if (waitingSet.isEmpty()) return
if (gameSet.size >= CastleWarsConstants.MAX_PLAYERS_PER_TEAM) return
val replacement = waitingSet.first()
waitingSet.remove(replacement)
gameSet.add(replacement)