diff --git a/Server/src/main/core/api/utils/CameraUtils.kt b/Server/src/main/core/api/utils/CameraUtils.kt index f242b5b49..d2d95f672 100644 --- a/Server/src/main/core/api/utils/CameraUtils.kt +++ b/Server/src/main/core/api/utils/CameraUtils.kt @@ -2,4 +2,22 @@ package core.api.utils object CameraUtils { +} + +/* + * All camera shake types were found by facing the camera North using + * these values: + * Type [0-4] Jit: 0 Amp: 0 Freq: 128 Speed: 2 + * + * **See Also:** [This forum post](https://forum.2009scape.org/viewtopic.php?t=173-in-game-camera-movement-documentation-server-sided) + * + * WARNING: Playing around with camera shake values may potentially trigger seizures for people with photosensitive epilepsy. + * Please use care when discovering camera values. + */ +enum class CameraShakeType { + TRUCK, // camera movement from left to right + PEDESTAL, // camera movement vertically up to down, fixated on one location + DOLLY, // camera movement forwards to backwards + PAN, // camera movement horizontally, fixed on a certain point + TILT // camera movement vertically, fixed on a certain point } \ No newline at end of file diff --git a/Server/src/main/core/api/utils/PlayerCamera.kt b/Server/src/main/core/api/utils/PlayerCamera.kt index a775cc7ae..8be7bed91 100644 --- a/Server/src/main/core/api/utils/PlayerCamera.kt +++ b/Server/src/main/core/api/utils/PlayerCamera.kt @@ -5,6 +5,16 @@ import core.net.packet.PacketRepository import core.net.packet.context.CameraContext import core.net.packet.out.CameraViewPacket +/** + * Player camera + * + * @property player + * @constructor Create empty Player camera + * **See Also:** [This forum post](https://forum.2009scape.org/viewtopic.php?t=173-in-game-camera-movement-documentation-server-sided) + * + * WARNING: Playing around with camera values may potentially trigger seizures for people with photosensitive epilepsy. + * Please use care when using camera values. + */ class PlayerCamera(val player: Player?) { var ctx: CameraContext? = null @@ -29,4 +39,14 @@ class PlayerCamera(val player: Player?) { ctx = CameraContext(player,CameraContext.CameraType.POSITION,x,y,height,speed,1) PacketRepository.send(CameraViewPacket::class.java,ctx) } + fun shake(cameraType: Int, jitter: Int, amplitude: Int, frequency: Int, speed: Int){ + player ?: return + ctx = CameraContext(player,CameraContext.CameraType.SHAKE,cameraType,jitter,amplitude,frequency,speed) + PacketRepository.send(CameraViewPacket::class.java,ctx) + } + fun reset(){ + player ?: return + ctx = CameraContext(player,CameraContext.CameraType.RESET, -1, -1, -1, -1, -1) + PacketRepository.send(CameraViewPacket::class.java,ctx) + } } \ No newline at end of file diff --git a/Server/src/main/core/game/activity/Cutscene.kt b/Server/src/main/core/game/activity/Cutscene.kt index 992090c4d..68c4bba85 100644 --- a/Server/src/main/core/game/activity/Cutscene.kt +++ b/Server/src/main/core/game/activity/Cutscene.kt @@ -22,9 +22,9 @@ import core.net.packet.out.MinimapState import org.rs09.consts.Components import core.ServerConstants import core.api.Event +import core.api.utils.CameraShakeType import core.api.utils.PlayerCamera import core.game.system.timer.impl.AntiMacro -import core.tools.SystemLogger import core.game.world.GameWorld import core.tools.Log @@ -314,6 +314,42 @@ abstract class Cutscene(val player: Player) { camera.rotateTo(globalLoc.x, globalLoc.y, height, speed) } + /** + * Rotates the camera to face the given difference of the X and Y coordinates + * @param regionX the difference X value to rotate the camera to (0-63) + * @param regionY the difference Y value 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 rotateCameraBy(diffX: Int, diffY: Int, diffHeight: Int = 300, diffSpeed: Int = 100) + { + camera.rotateBy(diffX, diffY, diffHeight, diffSpeed) + } + + /** + * Manipulates the camera using different camera types. Also known as "shake" + * @param cameraType the "type" of shake: TRUCK, PEDESTAL, DOLLY, PAN, TILT + * @param jitter (optional) the amount to rock the camera while looping + * @param amplitude (optional) the maximum extent of camera vibration + * @param frequency (optional) the rate at which jitter and amplitude are repeated + * @param speed (optional) the rate at which the whole camera "shake" loop is repeated + * + * WARNING: Playing around with camera shake values may potentially trigger seizures for people with photosensitive epilepsy. + * Please use care when using the "shake" camera values. + */ + fun shakeCamera(cameraType: CameraShakeType, jitter: Int = 0, amplitude: Int = 0, frequency: Int = 128, speed: Int = 2) + { + camera.shake(cameraType.ordinal, jitter, amplitude, frequency, speed) + } + + /** + * Resets the camera to the current player position + */ + fun resetCamera() + { + camera.reset() + } + /** * Sets the location the player is placed at when the cutscene ends. */ diff --git a/Server/src/main/core/game/system/command/sets/CameraCommandSet.kt b/Server/src/main/core/game/system/command/sets/CameraCommandSet.kt new file mode 100644 index 000000000..e501da9a9 --- /dev/null +++ b/Server/src/main/core/game/system/command/sets/CameraCommandSet.kt @@ -0,0 +1,117 @@ +package core.game.system.command.sets + +import core.api.sendMessage +import core.api.utils.PlayerCamera +import core.game.system.command.Privilege +import core.game.world.map.RegionManager +import core.plugin.Initializable + +/** + * Camera command set + * + * @constructor Create empty Camera command set + * + * WARNING: Playing around with camera values may potentially trigger seizures for people with photosensitive epilepsy. + * Please use care when discovering camera values. + */ +@Initializable +class CameraCommandSet : CommandSet(Privilege.ADMIN) { + + override fun defineCommands() { + define("poscam", Privilege.ADMIN, "::poscam Region X Region Y [Height]", "Positions the camera to the given region-local coordinates.") { player, args -> + val regionX = args[1].toIntOrNull() ?: return@define + val regionY = args[2].toIntOrNull() ?: return@define + var height = 300 + + if (args.size > 3) { + height = args[3].toIntOrNull() ?: return@define + } + + val region = RegionManager.forId(player.location.regionId) + val base = region.baseLocation + + val globalLoc = base.transform(regionX, regionY, 0) + sendMessage(player, "CAMERA POSITION | loc:[$regionX, $regionY] settings:[height:$height]") + PlayerCamera(player).setPosition(globalLoc.x, globalLoc.y, height) + } + + define("movcam", Privilege.ADMIN, "::movcam Region X Region Y [Height Speed]", "Moves the camera to the given region-local coordinates.") { player, args -> + val regionX = args[1].toIntOrNull() ?: return@define + val regionY = args[2].toIntOrNull() ?: return@define + var height = 300 + var speed = 100 + + if (args.size > 3) + height = args[3].toIntOrNull() ?: return@define + + if (args.size > 4) + speed = args[4].toIntOrNull() ?: return@define + + val region = RegionManager.forId(player.location.regionId) + val base = region.baseLocation + + val globalLoc = base.transform(regionX, regionY, 0) + sendMessage(player, "CAMERA MOVE | loc:[$regionX, $regionY] settings:[height:$height, speed:$speed]") + PlayerCamera(player).panTo(globalLoc.x, globalLoc.y, height, speed) + } + + define("rotcam", Privilege.ADMIN, "::rotcam Region X Region Y [Height Speed]", "Rotates the camera to face the given region-local coordinates.") { player, args -> + val regionX = args[1].toIntOrNull() ?: return@define + val regionY = args[2].toIntOrNull() ?: return@define + var height = 300 + var speed = 100 + + if (args.size > 3) { + height = args[3].toIntOrNull() ?: return@define + } + + if (args.size > 4) { + speed = args[4].toIntOrNull() ?: return@define + } + + val region = RegionManager.forId(player.location.regionId) + val base = region.baseLocation + + val globalLoc = base.transform(regionX, regionY, 0) + sendMessage(player, "CAMERA ROTATE | loc:[$regionX, $regionY] settings:[height:$height, speed:$speed]") + PlayerCamera(player).rotateTo(globalLoc.x, globalLoc.y, height, speed) + } + + define("shakecam", Privilege.ADMIN, "::shakecam Camera Movement Type (0-4) [Jitter Amplitude Frequency Speed]", + "Type (0-4) Jitter, Amplitude, Frequency (0-255)") {player, args -> + val cameraMovementType = args[1].toIntOrNull() ?: return@define + if (cameraMovementType < 0 || cameraMovementType > 4) { + return@define + } + // Type [0-4] Jit: 0 Amp: 0 Freq: 128 Speed: 2 + var jitter = 0 + var amplitude = 0 + var frequency = 128 + var speed = 2 + + if (args.size > 2) { + jitter = args[2].toIntOrNull() ?: return@define + } + + if (args.size > 3) { + amplitude = args[3].toIntOrNull() ?: return@define + } + + if (args.size > 4) { + frequency = args[4].toIntOrNull() ?: return@define + } + + if (args.size > 5) { + speed = args[5].toIntOrNull() ?: return@define + } + + sendMessage(player, "CAMERA SHAKE | type:$cameraMovementType settings:[jit:$jitter, amp:$amplitude, freq:$frequency, speed:$speed]") + PlayerCamera(player).shake(cameraMovementType, jitter, amplitude, frequency, speed) + } + + define("resetcam", Privilege.ADMIN, "::resetcam", "Resets the current camera position.") {player, args -> + sendMessage(player, "CAMERA RESET") + PlayerCamera(player).reset() + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt index 752429b6d..da16f0a52 100644 --- a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt @@ -64,44 +64,6 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){ } } - define("movcam", Privilege.ADMIN, "::movcam Region X Region Y [Height Speed]", "Moves the camera to the given region-local coordinates.") {player, args -> - val regionX = args[1].toIntOrNull() ?: return@define - val regionY = args[2].toIntOrNull() ?: return@define - var height = 300 - var speed = 100 - - if (args.size > 3) - height = args[3].toIntOrNull() ?: return@define - - if (args.size > 4) - speed = args[4].toIntOrNull() ?: return@define - - val region = RegionManager.forId(player.location.regionId) - val base = region.baseLocation - - val globalLoc = base.transform(regionX, regionY, 0) - PlayerCamera(player).panTo(globalLoc.x, globalLoc.y, height, speed) - } - - define("rotcam", Privilege.ADMIN, "::rotcam Region X Region Y [Height Speed]", "Rotates the camera to face the given region-local coordinates.") {player, args -> - val regionX = args[1].toIntOrNull() ?: return@define - val regionY = args[2].toIntOrNull() ?: return@define - var height = 300 - var speed = 100 - - if (args.size > 3) - height = args[3].toIntOrNull() ?: return@define - - if (args.size > 4) - speed = args[4].toIntOrNull() ?: return@define - - val region = RegionManager.forId(player.location.regionId) - val base = region.baseLocation - - val globalLoc = base.transform(regionX, regionY, 0) - PlayerCamera(player).rotateTo(globalLoc.x, globalLoc.y, height, speed) - } - define("anmacs", Privilege.ADMIN) { player, _ -> AnmaCutscene(player).start() }