diff --git a/app/PotatoCactus/Game/Movement/MovementEntity.hs b/app/PotatoCactus/Game/Movement/MovementEntity.hs index af428cb..b6ae691 100644 --- a/app/PotatoCactus/Game/Movement/MovementEntity.hs +++ b/app/PotatoCactus/Game/Movement/MovementEntity.hs @@ -1,9 +1,10 @@ module PotatoCactus.Game.Movement.MovementEntity where -import PotatoCactus.Game.Movement.PlayerWalkMovement +import PotatoCactus.Game.Movement.PlayerWalkMovement (PlayerWalkMovement (isRunning, queue_, shouldUpdateRegion), queueWalk) import qualified PotatoCactus.Game.Movement.PlayerWalkMovement as PlayerWalkMovement import PotatoCactus.Game.Movement.PositionXY (PositionXY) import PotatoCactus.Game.Movement.StaticMovement (StaticMovement) +import qualified PotatoCactus.Game.Movement.StaticMovement as S import PotatoCactus.Game.Movement.WalkingStep (WalkingStep) import PotatoCactus.Game.Position (GetPosition (getPosition), Position) import PotatoCactus.Game.Typing (Advance (advance)) @@ -47,3 +48,9 @@ immediatelyQueueMovement :: MovementEntity -> [Position] -> MovementEntity immediatelyQueueMovement (PlayerWalkMovement_ m) path = PlayerWalkMovement_ $ advance m {queue_ = path} immediatelyQueueMovement m _ = m + +immediatelySetPosition :: MovementEntity -> Position -> MovementEntity +immediatelySetPosition (PlayerWalkMovement_ m) pos = + PlayerWalkMovement_ $ PlayerWalkMovement.setPosition m pos +immediatelySetPosition (StaticMovement_ m) pos = + StaticMovement_ $ m {S.position_ = pos} diff --git a/app/PotatoCactus/Game/Movement/PlayerWalkMovement.hs b/app/PotatoCactus/Game/Movement/PlayerWalkMovement.hs index 3356d06..538d10e 100644 --- a/app/PotatoCactus/Game/Movement/PlayerWalkMovement.hs +++ b/app/PotatoCactus/Game/Movement/PlayerWalkMovement.hs @@ -81,3 +81,7 @@ shouldUpdateRegion_ lastUpdate currentPos = isStopped :: PlayerWalkMovement -> Bool isStopped = null . queue_ + +setPosition :: PlayerWalkMovement -> Position -> PlayerWalkMovement +setPosition m pos = + m {position_ = pos, isTeleporting = True, shouldUpdateRegion = True, lastRegionUpdate_ = pos} diff --git a/app/PotatoCactus/Game/Player.hs b/app/PotatoCactus/Game/Player.hs index b78ff4d..943aafe 100644 --- a/app/PotatoCactus/Game/Player.hs +++ b/app/PotatoCactus/Game/Player.hs @@ -10,7 +10,7 @@ import PotatoCactus.Game.Entity.Interaction.Interaction (Interaction) import qualified PotatoCactus.Game.Entity.Interaction.Interaction as Interaction import PotatoCactus.Game.Entity.Npc.Npc (NpcIndex) import PotatoCactus.Game.ItemContainer (ItemContainer, playerEquipmentContainer, playerInventory) -import PotatoCactus.Game.Movement.MovementEntity (playerWalkMovement) +import PotatoCactus.Game.Movement.MovementEntity (immediatelySetPosition, playerWalkMovement) import qualified PotatoCactus.Game.Movement.MovementEntity as M (MovementEntity, issueWalkCommand) import PotatoCactus.Game.Movement.PositionXY (PositionXY) import PotatoCactus.Game.Movement.WalkingStep (WalkingStep) @@ -116,3 +116,9 @@ clearTargetIfEngagedWithNpc npcId p = sendChatboxMessage :: Player -> String -> Player sendChatboxMessage p msg = p {chatboxMessages = msg : chatboxMessages p} + +setPosition :: Player -> Position -> Player +setPosition p pos = + p + { movement = immediatelySetPosition (movement p) pos + } diff --git a/app/PotatoCactus/Game/Scripting/Bridge/Serialization/ActionResultMapper.hs b/app/PotatoCactus/Game/Scripting/Bridge/Serialization/ActionResultMapper.hs index b5da484..7068631 100644 --- a/app/PotatoCactus/Game/Scripting/Bridge/Serialization/ActionResultMapper.hs +++ b/app/PotatoCactus/Game/Scripting/Bridge/Serialization/ActionResultMapper.hs @@ -15,7 +15,7 @@ import PotatoCactus.Game.Entity.Object.DynamicObjectCollection (DynamicObject (A import qualified PotatoCactus.Game.Entity.Object.GameObject as O import PotatoCactus.Game.Position (Position (Position)) import PotatoCactus.Game.Scripting.Actions.SpawnNpcRequest (SpawnNpcRequest (SpawnNpcRequest)) -import PotatoCactus.Game.Scripting.ScriptUpdates (ScriptActionResult (AddGameObject, ClearPlayerInteraction, InternalNoop, InternalProcessingComplete, NpcQueueWalk, NpcSetAnimation, NpcSetForcedChat, SendMessage, ServerPrintMessage, SpawnNpc)) +import PotatoCactus.Game.Scripting.ScriptUpdates (ScriptActionResult (AddGameObject, ClearPlayerInteraction, InternalNoop, InternalProcessingComplete, NpcQueueWalk, NpcSetAnimation, NpcSetForcedChat, SendMessage, ServerPrintMessage, SetPlayerPosition, SpawnNpc)) mapResult :: ByteString -> ScriptActionResult mapResult bytes = @@ -144,6 +144,16 @@ decodeBody "sendMessage" body = body of Error msg -> InternalNoop Success decoded -> decoded +decodeBody "setPlayerPosition" body = + case parse + ( \obj -> do + playerIndex <- obj .: "playerIndex" + posObj <- obj .: "position" + return (SetPlayerPosition playerIndex $ decodePos_ posObj) + ) + body of + Error msg -> InternalNoop + Success decoded -> decoded decodeBody _ _ = InternalNoop data DecodedMessage = DecodedMessage diff --git a/app/PotatoCactus/Game/Scripting/Events/ApplyScriptActionResult.hs b/app/PotatoCactus/Game/Scripting/Events/ApplyScriptActionResult.hs index fb4487c..e6788eb 100644 --- a/app/PotatoCactus/Game/Scripting/Events/ApplyScriptActionResult.hs +++ b/app/PotatoCactus/Game/Scripting/Events/ApplyScriptActionResult.hs @@ -16,7 +16,7 @@ import qualified PotatoCactus.Game.Player as P import qualified PotatoCactus.Game.PlayerUpdate.PlayerAnimationDefinitions as PAnim import PotatoCactus.Game.Position (GetPosition (getPosition)) import qualified PotatoCactus.Game.Scripting.Actions.SpawnNpcRequest as SpawnReq -import PotatoCactus.Game.Scripting.ScriptUpdates (ScriptActionResult (AddGameObject, ClearPlayerInteraction, DispatchAttackNpcToPlayer, DispatchAttackPlayerToNpc, InternalNoop, InternalProcessingComplete, InternalRemoveNpcTargetReferences, NpcMoveTowardsTarget, NpcQueueWalk, NpcSetAnimation, NpcSetForcedChat, SendMessage, ServerPrintMessage, SpawnNpc, UpdateNpc)) +import PotatoCactus.Game.Scripting.ScriptUpdates (ScriptActionResult (AddGameObject, ClearPlayerInteraction, DispatchAttackNpcToPlayer, DispatchAttackPlayerToNpc, InternalNoop, InternalProcessingComplete, InternalRemoveNpcTargetReferences, NpcMoveTowardsTarget, NpcQueueWalk, NpcSetAnimation, NpcSetForcedChat, SendMessage, ServerPrintMessage, SetPlayerPosition, SpawnNpc, UpdateNpc)) import PotatoCactus.Game.World (World (npcs, objects, players)) import qualified PotatoCactus.Game.World as W import PotatoCactus.Game.World.MobList (findByIndex, remove, updateAll, updateAtIndex) @@ -143,3 +143,7 @@ applyScriptResult world (SendMessage playerIndex message) = world { players = updateAtIndex (players world) playerIndex (`P.sendChatboxMessage` message) } +applyScriptResult world (SetPlayerPosition playerIndex pos) = + world + { players = updateAtIndex (players world) playerIndex (`P.setPosition` pos) + } diff --git a/app/PotatoCactus/Game/Scripting/ScriptUpdates.hs b/app/PotatoCactus/Game/Scripting/ScriptUpdates.hs index 4dbfa29..4f345ea 100644 --- a/app/PotatoCactus/Game/Scripting/ScriptUpdates.hs +++ b/app/PotatoCactus/Game/Scripting/ScriptUpdates.hs @@ -33,6 +33,7 @@ data ScriptActionResult | NpcSetForcedChat NpcIndex String | SpawnNpc SpawnNpcRequest | SendMessage PlayerIndex String + | SetPlayerPosition PlayerIndex Position | InternalRemoveNpcTargetReferences NpcIndex | InternalProcessingComplete -- Sentinel token to indicate script execution complete | InternalNoop diff --git a/app/PotatoCactus/Network/Packets/Out/PlayerUpdate/EncodePlayerMovement.hs b/app/PotatoCactus/Network/Packets/Out/PlayerUpdate/EncodePlayerMovement.hs index d294b4e..dde76ea 100644 --- a/app/PotatoCactus/Network/Packets/Out/PlayerUpdate/EncodePlayerMovement.hs +++ b/app/PotatoCactus/Network/Packets/Out/PlayerUpdate/EncodePlayerMovement.hs @@ -33,9 +33,10 @@ encode_ (PlayerWalkMovement_ m) updateType needsUpdate = putNBits 2 $ toWord_ 3 putNBits 2 $ toWord_ (z (getPosition m)) -- position.z putBit $ not (shouldUpdateRegion m) - putBit True -- needs update + putBit needsUpdate -- needs update putNBits 7 $ toWord_ (localY (getPosition m)) -- local Y putNBits 7 $ toWord_ (localX (getPosition m)) -- local X + -- putBit needsUpdate UpdateOther -> do putBit False -- if needsUpdate diff --git a/app/PotatoCactus/Persistence/PlayerRepository.hs b/app/PotatoCactus/Persistence/PlayerRepository.hs index 98c52dd..b9750b1 100644 --- a/app/PotatoCactus/Persistence/PlayerRepository.hs +++ b/app/PotatoCactus/Persistence/PlayerRepository.hs @@ -15,7 +15,7 @@ mockPlayer_ :: String -> Player mockPlayer_ username = (Player.create username mockPosition_) {inventory = mockInventory_} mockPosition_ :: Position -mockPosition_ = Position 3093 3244 0 +mockPosition_ = Position 3222 3218 0 mockInventory_ :: ItemContainer mockInventory_ = diff --git a/script-engine/potato_cactus/api/actions.py b/script-engine/potato_cactus/api/actions.py index ab10ac7..fbc5f41 100644 --- a/script-engine/potato_cactus/api/actions.py +++ b/script-engine/potato_cactus/api/actions.py @@ -73,6 +73,12 @@ def SendMessage(playerIndex: int, text: str) -> ScriptAction: "text": text }) +def SetPlayerPosition(playerIndex: int, position: Union[Position, Tuple[int, int, int]]) -> ScriptAction: + return ScriptAction("setPlayerPosition", { + "playerIndex": playerIndex, + "position": _map_position(position) + }) + def _map_position(position: Union[Position, Tuple[int, int, int]]) -> dict: if isinstance(position, Position): return {"x": position.x, "y": position.y, "z": position.z} diff --git a/scripts/builtin/commands/teleport_command.py b/scripts/builtin/commands/teleport_command.py new file mode 100644 index 0000000..4519182 --- /dev/null +++ b/scripts/builtin/commands/teleport_command.py @@ -0,0 +1,14 @@ +from potato_cactus import EventHandler, GameEvent, Context +from potato_cactus.api.actions import SetPlayerPosition, SendMessage +from potato_cactus.api.events import PlayerCommandEventPayload + + +@EventHandler(GameEvent.PlayerCommandEvent, command="teleport") +@EventHandler(GameEvent.PlayerCommandEvent, command="tp") +def on_command(e: PlayerCommandEventPayload, context: Context): + player = context.find_player_by_index(e.playerIndex) + if player is None: + return [] + if len(e.args) < 3: + return [SendMessage(e.playerIndex, f"Usage: ::{e.command} ")] + return [SetPlayerPosition(e.playerIndex, (int(e.args[0]), int(e.args[1]), int(e.args[2])))] diff --git a/scripts/example/hans.py b/scripts/example/hans.py index 73f948a..1546cec 100644 --- a/scripts/example/hans.py +++ b/scripts/example/hans.py @@ -18,4 +18,4 @@ def onNpcInteraction(e: NpcInteractionEventPayload, context: Context): @EventHandler(GameEvent.ServerInitEvent) def onServerInit(e): - return [SpawnNpc(0, Position(3093, 3250, 0))] + return [SpawnNpc(0, Position(3219, 3223, 0))]