From 6b76a3f8d0fa27d8f130a7296a8fde6709186e2d Mon Sep 17 00:00:00 2001 From: dam <27978131-real_damighty@users.noreply.gitlab.com> Date: Fri, 10 Apr 2026 19:16:59 +0300 Subject: [PATCH] Cleanup, burning catapults, player cap removed, stepping stone fixes --- .../content/minigame/castlewars/CastleWars.kt | 44 +++- .../castlewars/CastleWarsBarricadeNPC.kt | 2 +- .../castlewars/CastleWarsConstants.kt | 19 +- .../castlewars/CastleWarsDoorAttackPulse.kt | 1 - .../castlewars/CastleWarsFlagHandler.kt | 33 --- .../castlewars/CastleWarsGameState.kt | 231 ++++++++---------- .../castlewars/CastleWarsItemHandler.kt | 2 +- .../castlewars/CastleWarsListeners.kt | 29 +-- .../castlewars/CastleWarsTunnelMiningPulse.kt | 2 +- .../castlewars/areas/CastleWarsGameArea.kt | 1 - 10 files changed, 155 insertions(+), 209 deletions(-) diff --git a/Server/src/main/content/minigame/castlewars/CastleWars.kt b/Server/src/main/content/minigame/castlewars/CastleWars.kt index 784e95f77..2ca5fa970 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWars.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWars.kt @@ -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 by lazy(LazyThreadSafetyMode.NONE) { + val locations = mutableSetOf() + 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. diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsBarricadeNPC.kt b/Server/src/main/content/minigame/castlewars/CastleWarsBarricadeNPC.kt index f974e6fe7..f53b06f3c 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsBarricadeNPC.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsBarricadeNPC.kt @@ -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 diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsConstants.kt b/Server/src/main/content/minigame/castlewars/CastleWarsConstants.kt index a973d0579..e46a16e60 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsConstants.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsConstants.kt @@ -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 diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsDoorAttackPulse.kt b/Server/src/main/content/minigame/castlewars/CastleWarsDoorAttackPulse.kt index 932e621db..539f8f916 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsDoorAttackPulse.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsDoorAttackPulse.kt @@ -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, diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsFlagHandler.kt b/Server/src/main/content/minigame/castlewars/CastleWarsFlagHandler.kt index ebf9ecbfe..a031e37f6 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsFlagHandler.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsFlagHandler.kt @@ -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 } } diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsGameState.kt b/Server/src/main/content/minigame/castlewars/CastleWarsGameState.kt index 070f32c7c..ab8abb64b 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsGameState.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsGameState.kt @@ -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) { diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsItemHandler.kt b/Server/src/main/content/minigame/castlewars/CastleWarsItemHandler.kt index 54dea8aac..f6872e90c 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsItemHandler.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsItemHandler.kt @@ -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 { diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsListeners.kt b/Server/src/main/content/minigame/castlewars/CastleWarsListeners.kt index 1849ae6ca..6845467f4 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsListeners.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsListeners.kt @@ -71,6 +71,8 @@ private val barrierCoordinates: Map> = mapOf( ) private val castleWarsStairDestinationOverrides: Map = 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) { diff --git a/Server/src/main/content/minigame/castlewars/CastleWarsTunnelMiningPulse.kt b/Server/src/main/content/minigame/castlewars/CastleWarsTunnelMiningPulse.kt index 09a63b19a..e42d6838c 100644 --- a/Server/src/main/content/minigame/castlewars/CastleWarsTunnelMiningPulse.kt +++ b/Server/src/main/content/minigame/castlewars/CastleWarsTunnelMiningPulse.kt @@ -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, diff --git a/Server/src/main/content/minigame/castlewars/areas/CastleWarsGameArea.kt b/Server/src/main/content/minigame/castlewars/areas/CastleWarsGameArea.kt index e037c5240..3ff5a0850 100644 --- a/Server/src/main/content/minigame/castlewars/areas/CastleWarsGameArea.kt +++ b/Server/src/main/content/minigame/castlewars/areas/CastleWarsGameArea.kt @@ -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)