From 582df460ea055977501ef77b1ebe92a3f193821f Mon Sep 17 00:00:00 2001 From: CloneTrooper1019 Date: Mon, 4 Nov 2019 18:39:59 -0600 Subject: [PATCH] Initialize This is still a WIP! --- Character/Animate.server.lua | 26 + Character/Bounciness.server.lua | 21 + Character/DropHats/HatPickup.server.lua | 34 + Character/DropHats/LocalDropHat.client.lua | 15 + Character/DropHats/init.server.lua | 50 + Character/EdgeWalking.client.lua | 45 + Character/FloorDrag.client.lua | 58 + Character/GoofyBalance.server.lua | 26 + Character/GoofyMotion.client.lua | 60 + Character/InputGateway.server.lua | 18 + Character/JumpLimiter.client.lua | 12 + Character/RetroClimbing.client.lua | 235 + Character/Sound.server.lua | 68 + Character/TeamColors.server.lua | 35 + Character/ToolSoundGlitch.server.lua | 43 + Client/Animator.client.lua | 262 + Client/Camera/Main.lua | 1042 ++ Client/Camera/Opacity.lua | 176 + Client/Camera/Popper.lua | 129 + Client/Camera/init.client.lua | 60 + Client/CharacterBevels.client.lua | 25 + Client/ClickToMove.client.lua | 301 + Client/ConsoleTweaks.client.lua | 34 + Client/Explosions/ClassicExp.rbxmx | 38 + Client/Explosions/init.client.lua | 50 + Client/ForceFields.client.lua | 55 + Client/GamepadPatch.client.lua | 29 + Client/HumanoidLabels/Health.rbxmx | 237 + Client/HumanoidLabels/init.client.lua | 139 + Client/InputGateway.client.lua | 185 + Client/Music.client.lua | 5 + Client/Shared.client.lua | 9 + Client/ToolSoundGlitch.client.lua | 12 + DataModel/ReplicatedStorage/ChatRemote.rbxmx | 10 + .../ReplicatedStorage/RequestCharacter.rbxmx | 10 + .../ScriptRef[SafeChatTree].txt | 1 + .../ServerScriptService/ScriptRef[Badges].txt | 1 + .../ServerScriptService/ScriptRef[Bevels].txt | 1 + .../ScriptRef[BuildTools].txt | 1 + .../ScriptRef[CaptureTheFlag].txt | 1 + .../ScriptRef[Characters].txt | 1 + .../ServerScriptService/ScriptRef[Chat].txt | 1 + .../ScriptRef[Cylinders].txt | 1 + .../ScriptRef[Explosions].txt | 1 + .../ScriptRef[ForceFields].txt | 1 + .../ScriptRef[HatGranter].txt | 1 + .../ServerScriptService/ScriptRef[Heads].txt | 1 + .../ScriptRef[Leaderboard].txt | 1 + .../ScriptRef[LoadTools].txt | 1 + .../ServerScriptService/ScriptRef[Parts].txt | 1 + .../ScriptRef[Regeneration].txt | 1 + .../ScriptRef[SessionTracker].txt | 1 + .../ServerScriptService/ScriptRef[Time].txt | 1 + .../CoreBevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx | 99 + .../CoreBevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx | 99 + .../CoreBevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx | 99 + DataModel/ServerStorage/GrantHatToUser.rbxmx | 10 + .../ServerStorage/InputGateway/Gateway.rbxmx | 10 + .../InputGateway/ScriptRef[Client].txt | 1 + .../InputGateway/ScriptRef[Server].txt | 1 + .../ScriptRef[Animate].txt | 1 + .../ScriptRef[BouncinessReplica].txt | 1 + .../ScriptRef[DropHats].txt | 1 + .../ScriptRef[EdgeWalking].txt | 1 + .../ScriptRef[FloorDrag].txt | 1 + .../ScriptRef[GoofyBalance].txt | 1 + .../ScriptRef[GoofyMotion].txt | 1 + .../ScriptRef[InputGateway].txt | 1 + .../ScriptRef[JumpLimiter].txt | 1 + .../ScriptRef[RetroClimbing].txt | 1 + .../ScriptRef[Sound].txt | 1 + .../ScriptRef[TeamColorScript].txt | 1 + .../ScriptRef[ToolSoundGlitch].txt | 1 + .../Backpack/ScriptRef[BackpackScript].txt | 1 + .../RootFrame/Chat/ScriptRef[ChatScript].txt | 1 + .../ClassicMouse/ScriptRef[ClickToMove].txt | 1 + .../ClassicMouse/ScriptRef[Mouse].txt | 1 + .../Health/ScriptRef[HealthScript].txt | 1 + .../PlayerList/ScriptRef[PlayerList].txt | 1 + .../SafeChat/ScriptRef[SafeChatScript].txt | 1 + .../UI/RootFrame/ScriptRef[ConsoleTweaks].txt | 1 + .../UI/RootFrame/ScriptRef[MessageScript].txt | 1 + .../ZoomControls/ScriptRef[ZoomControls].txt | 1 + .../PassCameraEvent.rbxmx | 10 + .../ScriptRef[Animator].txt | 1 + .../ScriptRef[CharacterBevels].txt | 1 + .../ScriptRef[Explosions].txt | 1 + .../ScriptRef[ForceFields].txt | 1 + .../ScriptRef[FpsCap].txt | 1 + .../ScriptRef[GamepadPatch].txt | 1 + .../ScriptRef[HumanoidLabels].txt | 1 + .../ScriptRef[LensFlare].txt | 1 + .../ScriptRef[LensFlare]/Moon.rbxmx | 194 + .../StarterPlayerScripts/ScriptRef[Moon].txt | 1 + .../ScriptRef[Moon]/Moon.rbxmx | 194 + .../StarterPlayerScripts/ScriptRef[Music].txt | 1 + .../ScriptRef[RetroCam].txt | 1 + .../StarterPlayerScripts/ScriptRef[Sky].txt | 1 + .../ScriptRef[Sky]/SkyAdorn.rbxmx | 186 + .../ScriptRef[Sky]/Star.rbxmx | 109 + .../ScriptRef[SunRays].txt | 1 + .../ScriptRef[SunRays]/Moon.rbxmx | 194 + .../ScriptRef[ToolSoundGlitch].txt | 1 + Resources/BevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx | 99 + Resources/BevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx | 99 + Resources/BevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx | 99 + Resources/CharacterAssets/BodyColors.rbxmx | 40 + Resources/CharacterAssets/Pants.rbxmx | 18 + Resources/CharacterAssets/Shirt.rbxmx | 18 + Resources/CharacterAssets/ShirtGraphic.rbxmx | 18 + Resources/GameJoin/GuiRoot.rbxmx | 1169 ++ .../GuiRoot/Topbar/Buttons.client.lua | 22 + .../GuiRoot/Topbar/Exit/Exit.client.lua | 55 + .../Topbar/Fullscreen/Fullscreen.client.lua | 31 + .../GuiRoot/Topbar/Help/Help.client.lua | 16 + Resources/GameJoin/init.client.lua | 160 + Resources/SafeChat/RawTreeData.lua | 447 + Resources/SafeChat/init.lua | 35 + Server/Badges.server.lua | 224 + Server/Bevels.server.lua | 537 + Server/BuildTools/Dragger.client.lua | 256 + Server/BuildTools/init.server.lua | 341 + Server/CaptureTheFlag.server.lua | 295 + Server/Characters.server.lua | 199 + Server/Chat.server.lua | 66 + Server/Cylinders/CylinderSurface.rbxmx | 137 + Server/Cylinders/init.server.lua | 76 + Server/Explosions.server.lua | 185 + Server/ForceFields.server.lua | 60 + Server/HatGranter.server.lua | 64 + Server/Heads.server.lua | 27 + Server/InputGateway.server.lua | 48 + Server/Leaderboard.server.lua | 194 + Server/LoadTools.server.lua | 19 + Server/Parts.server.lua | 295 + Server/Regeneration.server.lua | 98 + Server/SessionTracker.server.lua | 52 + Server/Time.server.lua | 10 + Shared/ReplicatedStorage/AssetUtil.lua | 78 + Shared/ReplicatedStorage/BrickColors.lua | 35 + Shared/ReplicatedStorage/Client/FpsCap.lua | 17 + Shared/ReplicatedStorage/Client/LensFlare.lua | 134 + Shared/ReplicatedStorage/Client/Moon.lua | 24 + .../ReplicatedStorage/Client/Moon/Moon.rbxmx | 194 + Shared/ReplicatedStorage/Client/Mouse.lua | 133 + Shared/ReplicatedStorage/Client/Sky.lua | 146 + .../Client/Sky/SkyAdorn.rbxmx | 186 + .../ReplicatedStorage/Client/Sky/Star.rbxmx | 109 + Shared/ReplicatedStorage/Client/SunRays.lua | 79 + .../Client/SunRays/Rays.rbxmx | 153 + Shared/ReplicatedStorage/ItemData/Face.lua | 195 + Shared/ReplicatedStorage/ItemData/Hat.lua | 609 + Shared/ReplicatedStorage/ItemData/Pants.lua | 94 + Shared/ReplicatedStorage/ItemData/Shirt.lua | 95 + Shared/ReplicatedStorage/PlaceData.lua | 60 + .../LightingConfig.server.lua | 25 + Shared/ServerStorage/PlayerDataStore.lua | 831 + Shared/init.lua | 18 + Test.rbxmx | 14732 ++++++++++++++++ Tools/Models/JetBoots.rbxmx | 32 + Tools/Models/Multirocket.rbxmx | 76 + Tools/Models/PaintballGun.rbxmx | 163 + Tools/Models/Plane.rbxmx | 171 + Tools/Models/Reset.rbxmx | 41 + Tools/Models/RocketLauncher.rbxmx | 185 + Tools/Models/Slingshot.rbxmx | 163 + Tools/Models/Superball.rbxmx | 136 + Tools/Models/Sword.rbxmx | 207 + Tools/Models/Timebomb.rbxmx | 141 + Tools/Models/Trowel.rbxmx | 163 + .../Scripts/GravityHammer/GravityHammer.rbxmx | 163 + .../GravityHammer/SwordScript.server.lua | 158 + Tools/Scripts/JetBoots/Jetboots.server.lua | 76 + .../Multirocket/RocketScript.server.lua | 71 + .../Multirocket/ServerLauncher.server.lua | 93 + .../PaintballGun/BrickCleanup.server.lua | 4 + .../Scripts/PaintballGun/Paintball.server.lua | 83 + .../PaintballGun/PaintballShooter.server.lua | 85 + Tools/Scripts/Plane/ControlScheme.lua | 32 + Tools/Scripts/Plane/IconOverride.txt | 1 + .../Plane/PlaneTool/FlyScript.server.lua | 19 + Tools/Scripts/Plane/PlaneTool/init.server.lua | 311 + .../Plane/Rocket/RocketScript.server.lua | 95 + Tools/Scripts/Reset/IconOverride.txt | 1 + Tools/Scripts/Reset/Reset.server.lua | 13 + .../RocketLauncher/RocketScript.server.lua | 91 + .../RocketLauncher/ServerLauncher.server.lua | 93 + .../Scripts/Slingshot/PelletScript.server.lua | 63 + Tools/Scripts/Slingshot/Slingshot.server.lua | 138 + Tools/Scripts/Superball/CannonBall.server.lua | 79 + .../Scripts/Superball/CannonScript.server.lua | 65 + Tools/Scripts/Sword/SwordScript.server.lua | 181 + Tools/Scripts/Timebomb/Bomb.server.lua | 83 + Tools/Scripts/Timebomb/PlantBomb.server.lua | 69 + Tools/Scripts/Trowel/BrickCleanup.server.lua | 4 + Tools/Scripts/Trowel/WallMaker.server.lua | 96 + UI/Backpack/SlotTemp.rbxmx | 650 + UI/Backpack/init.client.lua | 300 + UI/Chat/GetCoreGateway.lua | 96 + UI/Chat/LinkedList.lua | 84 + UI/Chat/MessageTemplate.rbxmx | 220 + UI/Chat/init.client.lua | 181 + UI/Health.client.lua | 32 + UI/Messages/Hint.rbxmx | 76 + UI/Messages/Message.rbxmx | 76 + UI/Messages/Player.rbxmx | 76 + UI/Messages/init.client.lua | 92 + UI/PlayerList/BaseGroup.rbxmx | 362 + UI/PlayerList/BasePlayerLbl.rbxmx | 184 + UI/PlayerList/BaseStat.rbxmx | 76 + UI/PlayerList/init.client.lua | 632 + UI/RootFrame.rbxmx | 1790 ++ UI/SafeChat/Click.rbxmx | 24 + UI/SafeChat/NullSelectionImageObject.rbxmx | 56 + UI/SafeChat/TempBranch.rbxmx | 72 + UI/SafeChat/TempButton.rbxmx | 80 + UI/SafeChat/init.client.lua | 204 + UI/ZoomControls.client.lua | 112 + default.project.json | 54 + main.lua | 174 + place.project.json | 38 + rojo-build.bat | 4 + rojo-build.sh | 1 + rojo-serve.bat | 4 + rojo-serve.sh | 1 + 225 files changed, 37667 insertions(+) create mode 100644 Character/Animate.server.lua create mode 100644 Character/Bounciness.server.lua create mode 100644 Character/DropHats/HatPickup.server.lua create mode 100644 Character/DropHats/LocalDropHat.client.lua create mode 100644 Character/DropHats/init.server.lua create mode 100644 Character/EdgeWalking.client.lua create mode 100644 Character/FloorDrag.client.lua create mode 100644 Character/GoofyBalance.server.lua create mode 100644 Character/GoofyMotion.client.lua create mode 100644 Character/InputGateway.server.lua create mode 100644 Character/JumpLimiter.client.lua create mode 100644 Character/RetroClimbing.client.lua create mode 100644 Character/Sound.server.lua create mode 100644 Character/TeamColors.server.lua create mode 100644 Character/ToolSoundGlitch.server.lua create mode 100644 Client/Animator.client.lua create mode 100644 Client/Camera/Main.lua create mode 100644 Client/Camera/Opacity.lua create mode 100644 Client/Camera/Popper.lua create mode 100644 Client/Camera/init.client.lua create mode 100644 Client/CharacterBevels.client.lua create mode 100644 Client/ClickToMove.client.lua create mode 100644 Client/ConsoleTweaks.client.lua create mode 100644 Client/Explosions/ClassicExp.rbxmx create mode 100644 Client/Explosions/init.client.lua create mode 100644 Client/ForceFields.client.lua create mode 100644 Client/GamepadPatch.client.lua create mode 100644 Client/HumanoidLabels/Health.rbxmx create mode 100644 Client/HumanoidLabels/init.client.lua create mode 100644 Client/InputGateway.client.lua create mode 100644 Client/Music.client.lua create mode 100644 Client/Shared.client.lua create mode 100644 Client/ToolSoundGlitch.client.lua create mode 100644 DataModel/ReplicatedStorage/ChatRemote.rbxmx create mode 100644 DataModel/ReplicatedStorage/RequestCharacter.rbxmx create mode 100644 DataModel/ReplicatedStorage/ScriptRef[SafeChatTree].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Badges].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Bevels].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[BuildTools].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[CaptureTheFlag].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Characters].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Chat].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Cylinders].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Explosions].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[ForceFields].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[HatGranter].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Heads].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Leaderboard].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[LoadTools].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Parts].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Regeneration].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[SessionTracker].txt create mode 100644 DataModel/ServerScriptService/ScriptRef[Time].txt create mode 100644 DataModel/ServerStorage/CoreBevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx create mode 100644 DataModel/ServerStorage/CoreBevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx create mode 100644 DataModel/ServerStorage/CoreBevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx create mode 100644 DataModel/ServerStorage/GrantHatToUser.rbxmx create mode 100644 DataModel/ServerStorage/InputGateway/Gateway.rbxmx create mode 100644 DataModel/ServerStorage/InputGateway/ScriptRef[Client].txt create mode 100644 DataModel/ServerStorage/InputGateway/ScriptRef[Server].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[Animate].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[BouncinessReplica].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[DropHats].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[EdgeWalking].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[FloorDrag].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[GoofyBalance].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[GoofyMotion].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[InputGateway].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[JumpLimiter].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[RetroClimbing].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[Sound].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[TeamColorScript].txt create mode 100644 DataModel/StarterCharacterScripts/ScriptRef[ToolSoundGlitch].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/Backpack/ScriptRef[BackpackScript].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/Chat/ScriptRef[ChatScript].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[ClickToMove].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[Mouse].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/Health/ScriptRef[HealthScript].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/PlayerList/ScriptRef[PlayerList].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/SafeChat/ScriptRef[SafeChatScript].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/ScriptRef[ConsoleTweaks].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/ScriptRef[MessageScript].txt create mode 100644 DataModel/StarterGui/UI/RootFrame/ZoomControls/ScriptRef[ZoomControls].txt create mode 100644 DataModel/StarterPlayerScripts/PassCameraEvent.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Animator].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[CharacterBevels].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Explosions].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[ForceFields].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[FpsCap].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[GamepadPatch].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[HumanoidLabels].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[LensFlare].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[LensFlare]/Moon.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Moon].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Moon]/Moon.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Music].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[RetroCam].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Sky].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Sky]/SkyAdorn.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[Sky]/Star.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[SunRays].txt create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[SunRays]/Moon.rbxmx create mode 100644 DataModel/StarterPlayerScripts/ScriptRef[ToolSoundGlitch].txt create mode 100644 Resources/BevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx create mode 100644 Resources/BevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx create mode 100644 Resources/BevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx create mode 100644 Resources/CharacterAssets/BodyColors.rbxmx create mode 100644 Resources/CharacterAssets/Pants.rbxmx create mode 100644 Resources/CharacterAssets/Shirt.rbxmx create mode 100644 Resources/CharacterAssets/ShirtGraphic.rbxmx create mode 100644 Resources/GameJoin/GuiRoot.rbxmx create mode 100644 Resources/GameJoin/GuiRoot/Topbar/Buttons.client.lua create mode 100644 Resources/GameJoin/GuiRoot/Topbar/Exit/Exit.client.lua create mode 100644 Resources/GameJoin/GuiRoot/Topbar/Fullscreen/Fullscreen.client.lua create mode 100644 Resources/GameJoin/GuiRoot/Topbar/Help/Help.client.lua create mode 100644 Resources/GameJoin/init.client.lua create mode 100644 Resources/SafeChat/RawTreeData.lua create mode 100644 Resources/SafeChat/init.lua create mode 100644 Server/Badges.server.lua create mode 100644 Server/Bevels.server.lua create mode 100644 Server/BuildTools/Dragger.client.lua create mode 100644 Server/BuildTools/init.server.lua create mode 100644 Server/CaptureTheFlag.server.lua create mode 100644 Server/Characters.server.lua create mode 100644 Server/Chat.server.lua create mode 100644 Server/Cylinders/CylinderSurface.rbxmx create mode 100644 Server/Cylinders/init.server.lua create mode 100644 Server/Explosions.server.lua create mode 100644 Server/ForceFields.server.lua create mode 100644 Server/HatGranter.server.lua create mode 100644 Server/Heads.server.lua create mode 100644 Server/InputGateway.server.lua create mode 100644 Server/Leaderboard.server.lua create mode 100644 Server/LoadTools.server.lua create mode 100644 Server/Parts.server.lua create mode 100644 Server/Regeneration.server.lua create mode 100644 Server/SessionTracker.server.lua create mode 100644 Server/Time.server.lua create mode 100644 Shared/ReplicatedStorage/AssetUtil.lua create mode 100644 Shared/ReplicatedStorage/BrickColors.lua create mode 100644 Shared/ReplicatedStorage/Client/FpsCap.lua create mode 100644 Shared/ReplicatedStorage/Client/LensFlare.lua create mode 100644 Shared/ReplicatedStorage/Client/Moon.lua create mode 100644 Shared/ReplicatedStorage/Client/Moon/Moon.rbxmx create mode 100644 Shared/ReplicatedStorage/Client/Mouse.lua create mode 100644 Shared/ReplicatedStorage/Client/Sky.lua create mode 100644 Shared/ReplicatedStorage/Client/Sky/SkyAdorn.rbxmx create mode 100644 Shared/ReplicatedStorage/Client/Sky/Star.rbxmx create mode 100644 Shared/ReplicatedStorage/Client/SunRays.lua create mode 100644 Shared/ReplicatedStorage/Client/SunRays/Rays.rbxmx create mode 100644 Shared/ReplicatedStorage/ItemData/Face.lua create mode 100644 Shared/ReplicatedStorage/ItemData/Hat.lua create mode 100644 Shared/ReplicatedStorage/ItemData/Pants.lua create mode 100644 Shared/ReplicatedStorage/ItemData/Shirt.lua create mode 100644 Shared/ReplicatedStorage/PlaceData.lua create mode 100644 Shared/ServerScriptService/LightingConfig.server.lua create mode 100644 Shared/ServerStorage/PlayerDataStore.lua create mode 100644 Shared/init.lua create mode 100644 Test.rbxmx create mode 100644 Tools/Models/JetBoots.rbxmx create mode 100644 Tools/Models/Multirocket.rbxmx create mode 100644 Tools/Models/PaintballGun.rbxmx create mode 100644 Tools/Models/Plane.rbxmx create mode 100644 Tools/Models/Reset.rbxmx create mode 100644 Tools/Models/RocketLauncher.rbxmx create mode 100644 Tools/Models/Slingshot.rbxmx create mode 100644 Tools/Models/Superball.rbxmx create mode 100644 Tools/Models/Sword.rbxmx create mode 100644 Tools/Models/Timebomb.rbxmx create mode 100644 Tools/Models/Trowel.rbxmx create mode 100644 Tools/Scripts/GravityHammer/GravityHammer.rbxmx create mode 100644 Tools/Scripts/GravityHammer/SwordScript.server.lua create mode 100644 Tools/Scripts/JetBoots/Jetboots.server.lua create mode 100644 Tools/Scripts/Multirocket/RocketScript.server.lua create mode 100644 Tools/Scripts/Multirocket/ServerLauncher.server.lua create mode 100644 Tools/Scripts/PaintballGun/BrickCleanup.server.lua create mode 100644 Tools/Scripts/PaintballGun/Paintball.server.lua create mode 100644 Tools/Scripts/PaintballGun/PaintballShooter.server.lua create mode 100644 Tools/Scripts/Plane/ControlScheme.lua create mode 100644 Tools/Scripts/Plane/IconOverride.txt create mode 100644 Tools/Scripts/Plane/PlaneTool/FlyScript.server.lua create mode 100644 Tools/Scripts/Plane/PlaneTool/init.server.lua create mode 100644 Tools/Scripts/Plane/Rocket/RocketScript.server.lua create mode 100644 Tools/Scripts/Reset/IconOverride.txt create mode 100644 Tools/Scripts/Reset/Reset.server.lua create mode 100644 Tools/Scripts/RocketLauncher/RocketScript.server.lua create mode 100644 Tools/Scripts/RocketLauncher/ServerLauncher.server.lua create mode 100644 Tools/Scripts/Slingshot/PelletScript.server.lua create mode 100644 Tools/Scripts/Slingshot/Slingshot.server.lua create mode 100644 Tools/Scripts/Superball/CannonBall.server.lua create mode 100644 Tools/Scripts/Superball/CannonScript.server.lua create mode 100644 Tools/Scripts/Sword/SwordScript.server.lua create mode 100644 Tools/Scripts/Timebomb/Bomb.server.lua create mode 100644 Tools/Scripts/Timebomb/PlantBomb.server.lua create mode 100644 Tools/Scripts/Trowel/BrickCleanup.server.lua create mode 100644 Tools/Scripts/Trowel/WallMaker.server.lua create mode 100644 UI/Backpack/SlotTemp.rbxmx create mode 100644 UI/Backpack/init.client.lua create mode 100644 UI/Chat/GetCoreGateway.lua create mode 100644 UI/Chat/LinkedList.lua create mode 100644 UI/Chat/MessageTemplate.rbxmx create mode 100644 UI/Chat/init.client.lua create mode 100644 UI/Health.client.lua create mode 100644 UI/Messages/Hint.rbxmx create mode 100644 UI/Messages/Message.rbxmx create mode 100644 UI/Messages/Player.rbxmx create mode 100644 UI/Messages/init.client.lua create mode 100644 UI/PlayerList/BaseGroup.rbxmx create mode 100644 UI/PlayerList/BasePlayerLbl.rbxmx create mode 100644 UI/PlayerList/BaseStat.rbxmx create mode 100644 UI/PlayerList/init.client.lua create mode 100644 UI/RootFrame.rbxmx create mode 100644 UI/SafeChat/Click.rbxmx create mode 100644 UI/SafeChat/NullSelectionImageObject.rbxmx create mode 100644 UI/SafeChat/TempBranch.rbxmx create mode 100644 UI/SafeChat/TempButton.rbxmx create mode 100644 UI/SafeChat/init.client.lua create mode 100644 UI/ZoomControls.client.lua create mode 100644 default.project.json create mode 100644 main.lua create mode 100644 place.project.json create mode 100644 rojo-build.bat create mode 100644 rojo-build.sh create mode 100644 rojo-serve.bat create mode 100644 rojo-serve.sh diff --git a/Character/Animate.server.lua b/Character/Animate.server.lua new file mode 100644 index 0000000..431f879 --- /dev/null +++ b/Character/Animate.server.lua @@ -0,0 +1,26 @@ +local Players = game:GetService("Players") + +local character = script.Parent +local player = Players:GetPlayerFromCharacter(character) + +local climbing = Instance.new("BoolValue") +climbing.Name = "Climbing" +climbing.Parent = character + +local setValue = Instance.new("RemoteEvent") +setValue.Name = "SetValue" +setValue.Parent = climbing + +local function onSetValue(requester, value) + if requester ~= player then + return + end + + if typeof(value) ~= "boolean" then + return + end + + climbing.Value = value +end + +setValue.OnServerEvent:Connect(onSetValue) \ No newline at end of file diff --git a/Character/Bounciness.server.lua b/Character/Bounciness.server.lua new file mode 100644 index 0000000..0b3e423 --- /dev/null +++ b/Character/Bounciness.server.lua @@ -0,0 +1,21 @@ +local Debris = game:GetService("Debris") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local head = char:WaitForChild("Head") + +local function onStateChanged(old,new) + if new.Name == "Landed" then + local velocity = humanoid.Torso.Velocity + local power = (-velocity.Y * workspace.Gravity) / 2 + + local force = Instance.new("BodyForce") + force.Name = "Bounce" + force.Force = Vector3.new(0,power,0) + force.Parent = head + + Debris:AddItem(force, 1/30) + end +end + +humanoid.StateChanged:connect(onStateChanged) \ No newline at end of file diff --git a/Character/DropHats/HatPickup.server.lua b/Character/DropHats/HatPickup.server.lua new file mode 100644 index 0000000..fb4503b --- /dev/null +++ b/Character/DropHats/HatPickup.server.lua @@ -0,0 +1,34 @@ +local handle = script.Parent +local hat = handle:FindFirstChildWhichIsA("Accoutrement") +local equipSignal + +local function onTouched(hit) + local char = hit:FindFirstAncestorWhichIsA("Model") + + if char then + local hitHum = char:FindFirstChild("Humanoid") + + if hitHum then + local existingHat = char:FindFirstChildWhichIsA("Accoutrement") + + if existingHat == nil or existingHat == hat then + if equipSignal then + equipSignal:Disconnect() + equipSignal = nil + end + + hat.Parent = workspace + handle.Parent = hat + + handle:SetNetworkOwnershipAuto() + hitHum:AddAccessory(hat) + + script:Destroy() + else + hat.Parent = workspace + end + end + end +end + +equipSignal = handle.Touched:Connect(onTouched) \ No newline at end of file diff --git a/Character/DropHats/LocalDropHat.client.lua b/Character/DropHats/LocalDropHat.client.lua new file mode 100644 index 0000000..853abf9 --- /dev/null +++ b/Character/DropHats/LocalDropHat.client.lua @@ -0,0 +1,15 @@ +local UserInputService = game:GetService("UserInputService") + +local server = script.Parent +local dropHat = server:WaitForChild("DropHat") + +local function onInputBegan(input, gameProcessed) + if not gameProcessed then + local keyCode = input.KeyCode.Name + if keyCode == "Equals" or keyCode == "DPadDown" then + dropHat:FireServer() + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) \ No newline at end of file diff --git a/Character/DropHats/init.server.lua b/Character/DropHats/init.server.lua new file mode 100644 index 0000000..dc0374d --- /dev/null +++ b/Character/DropHats/init.server.lua @@ -0,0 +1,50 @@ +local Players = game:GetService("Players") + +local char = script.Parent +local torso = char:WaitForChild("HumanoidRootPart") + +local humanoid = char:WaitForChild("Humanoid") +local hatPickup = script:WaitForChild("HatPickup") + +local dropHat = Instance.new("RemoteEvent") +dropHat.Name = "DropHat" +dropHat.Parent = script + +local function onDropHat(player) + local myPlayer = Players:GetPlayerFromCharacter(char) + assert(player == myPlayer, "Cannot drop hats unless it is your character.") + + local dropPos = torso.CFrame * CFrame.new(0, 5.4, -8) + + for _,hat in pairs(humanoid:GetAccessories()) do + local handle = hat:FindFirstChild("Handle") + + if handle then + local newHandle = handle:Clone() + + for _,joint in pairs(newHandle:GetJoints()) do + joint:Destroy() + end + + newHandle.CFrame = dropPos + newHandle.Anchored = true + newHandle.CanCollide = false + newHandle.Parent = workspace + + handle:Destroy() + hat.Parent = newHandle + + wait(.1) + + newHandle.Anchored = false + newHandle.CanCollide = true + newHandle:SetNetworkOwner(nil) + + local pickup = hatPickup:Clone() + pickup.Parent = newHandle + pickup.Disabled = false + end + end +end + +dropHat.OnServerEvent:Connect(onDropHat) \ No newline at end of file diff --git a/Character/EdgeWalking.client.lua b/Character/EdgeWalking.client.lua new file mode 100644 index 0000000..0d53c76 --- /dev/null +++ b/Character/EdgeWalking.client.lua @@ -0,0 +1,45 @@ +local RunService = game:GetService("RunService") + +local char = script.Parent +local rootPart = char:WaitForChild("HumanoidRootPart") + +local platform = Instance.new("Part") +platform.Name = "NoForceField" +platform.TopSurface = 0 +platform.BottomSurface = 0 +platform.BrickColor = BrickColor.new("Bright orange") +platform.Size = Vector3.new(5, 1, 2) +platform.Anchored = true +platform.Transparency = 1 + +local down = Vector3.new(0, -100, 0) +local platformOffset = Vector3.new(0, -.5, 0) + +while wait() do + local start = rootPart.CFrame + local startPos = start.p + local startRay = Ray.new(startPos, start.lookVector * 5) + + local hit, pos, norm = workspace:FindPartOnRay(startRay, char) + local floorCheckRay + + local pass = false + + if hit and hit.CanCollide and hit:IsGrounded() then + if hit:IsA("UnionOperation") or (not hit:IsA("Part") or hit.Shape.Name == "Block") then + local floorCheckRay = Ray.new(pos - (norm / 5), down) + local floor, floorPos = workspace:FindPartOnRayWithIgnoreList(floorCheckRay, {char, hit}) + + if floor and floor.CanCollide and startPos.Y - 2 > floorPos.Y then + floorPos = floorPos + platformOffset + platform.Parent = char + platform.CFrame = CFrame.new(Vector3.new(pos.X + norm.X, floorPos.Y, pos.Z + norm.Z),floorPos) + pass = true + end + end + end + + if not pass then + platform.Parent = nil + end +end \ No newline at end of file diff --git a/Character/FloorDrag.client.lua b/Character/FloorDrag.client.lua new file mode 100644 index 0000000..2949c9c --- /dev/null +++ b/Character/FloorDrag.client.lua @@ -0,0 +1,58 @@ +local RunService = game:GetService("RunService") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local rootPart = char:WaitForChild("HumanoidRootPart") +local climbForce = rootPart:WaitForChild("ClimbForce") +local rayDown = Vector3.new(0, -5000, 0) + +local function moveTowards(value, goal, rate) + if value < goal then + return math.min(goal, value + rate) + elseif value > goal then + return math.max(goal, value - rate) + else + return goal + end +end + +local lastFloorLevel = 0 + +local function getFloorLevel() + local origin = rootPart.Position + local ray = Ray.new(origin, rayDown) + local hit, pos = workspace:FindPartOnRay(ray, char) + return pos.Y, math.clamp(math.abs(pos.Y - origin.Y), -1, 1) +end + +local lastLevel = getFloorLevel() +local updateCon + +local function update() + if humanoid.Health == 0 then + updateCon:Disconnect() + return + end + + local level, dist = getFloorLevel() + + if humanoid.SeatPart then + humanoid.HipHeight = 0 + lastLevel = level + return + end + + local yVel = rootPart.Velocity.Y + + if math.abs(yVel) > 8 then + local goal = math.sign(yVel) + humanoid.HipHeight = moveTowards(humanoid.HipHeight, goal, 0.1) + elseif lastLevel ~= level then + humanoid.HipHeight = math.sign(lastLevel - level) * math.clamp(dist - 3, 0, 1) + lastLevel = level + else + humanoid.HipHeight = humanoid.HipHeight * 0.925 + end +end + +updateCon = RunService.RenderStepped:Connect(update) \ No newline at end of file diff --git a/Character/GoofyBalance.server.lua b/Character/GoofyBalance.server.lua new file mode 100644 index 0000000..109f10a --- /dev/null +++ b/Character/GoofyBalance.server.lua @@ -0,0 +1,26 @@ +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") + +local function onStateChanged(old,new) + if new == Enum.HumanoidStateType.RunningNoPhysics then + humanoid:ChangeState(Enum.HumanoidStateType.Running) + elseif new == Enum.HumanoidStateType.FallingDown then + humanoid:ChangeState("Ragdoll") + + while wait(0.5) do + if humanoid.RootPart then + local velocity = humanoid.RootPart.Velocity + + if velocity.Magnitude < 0.1 then + wait(2) + humanoid:ChangeState("GettingUp") + break + end + else + break + end + end + end +end + +humanoid.StateChanged:Connect(onStateChanged) \ No newline at end of file diff --git a/Character/GoofyMotion.client.lua b/Character/GoofyMotion.client.lua new file mode 100644 index 0000000..36d5f21 --- /dev/null +++ b/Character/GoofyMotion.client.lua @@ -0,0 +1,60 @@ +local RunService = game:GetService("RunService") +local GameSettings = UserSettings():GetService("UserGameSettings") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local climbing = char:WaitForChild("Climbing") +local rootPart = humanoid.RootPart + +local c = workspace.CurrentCamera +local blankV3 = Vector3.new() +local xz = Vector3.new(1,0,1) +local bg = rootPart:FindFirstChild("FirstPersonGyro") + +local runState = Enum.HumanoidStateType.Running + +if not bg then + bg = Instance.new("BodyGyro") + bg.Name = "FirstPersonGyro" + bg.MaxTorque = Vector3.new(0,10e6,0) + bg.D = 100 +end + +local function toRotation(dir) + return CFrame.new(blankV3,dir) +end + +local velocityThreshold = 200 +spawn(function () + local threshold = char:WaitForChild("VelocityThreshold",5) + if threshold then + velocityThreshold = threshold.Value + end +end) + +local function update() + local rotationType = GameSettings.RotationType + local seatPart = humanoid.SeatPart + + if rotationType.Name == "CameraRelative" and not seatPart then + local dir = c.CFrame.lookVector * xz + bg.CFrame = toRotation(dir) + bg.Parent = rootPart + humanoid.AutoRotate = false + else + local state = humanoid:GetState() + local isRunning = (state == runState) + local isClimbing = climbing.Value + humanoid.AutoRotate = (isRunning or isClimbing) + bg.Parent = nil + end + + if rootPart.Velocity.Magnitude > velocityThreshold and not seatPart then + humanoid:ChangeState("FallingDown") + end +end + +humanoid.AutoRotate = false +humanoid:SetStateEnabled("Climbing",false) +RunService.RenderStepped:connect(update) +c.FieldOfView = 65 \ No newline at end of file diff --git a/Character/InputGateway.server.lua b/Character/InputGateway.server.lua new file mode 100644 index 0000000..8cbc89d --- /dev/null +++ b/Character/InputGateway.server.lua @@ -0,0 +1,18 @@ +local ServerStorage = game:GetService("ServerStorage") +local inputGateway = ServerStorage:WaitForChild("InputGateway") +local char = script.Parent + +local function onChildAdded(child) + if child:IsA("Tool") and not child:FindFirstChild("InputGateway") then + wait(.1) + local gateway = inputGateway:Clone() + gateway.Parent = child + end +end + +local tool = char:FindFirstChildWhichIsA("Tool") +if tool then + onChildAdded(tool) +end + +char.ChildAdded:Connect(onChildAdded) \ No newline at end of file diff --git a/Character/JumpLimiter.client.lua b/Character/JumpLimiter.client.lua new file mode 100644 index 0000000..9890da0 --- /dev/null +++ b/Character/JumpLimiter.client.lua @@ -0,0 +1,12 @@ +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") + +local function onStateChanged(old,new) + if old == Enum.HumanoidStateType.Freefall and new == Enum.HumanoidStateType.Landed then + humanoid:SetStateEnabled("Jumping",false) + wait(0.5) + humanoid:SetStateEnabled("Jumping",true) + end +end + +humanoid.StateChanged:Connect(onStateChanged) diff --git a/Character/RetroClimbing.client.lua b/Character/RetroClimbing.client.lua new file mode 100644 index 0000000..cda33e7 --- /dev/null +++ b/Character/RetroClimbing.client.lua @@ -0,0 +1,235 @@ +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Setup +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local char = script.Parent + +local humanoid = char:WaitForChild("Humanoid") +humanoid:SetStateEnabled("Climbing", false) + +local rootPart = humanoid.RootPart +local bv = rootPart:FindFirstChild("ClimbForce") + +if not bv then + bv = Instance.new("BodyVelocity") + bv.Name = "ClimbForce" + bv.Parent = humanoid.RootPart +end + +bv.MaxForce = Vector3.new() + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Climbing State +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local climbing = char:WaitForChild("Climbing") +local setValue = climbing:WaitForChild("SetValue") + +local function onClimbing(value) + setValue:FireServer(value) +end + +climbing.Changed:Connect(onClimbing) + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Debug Visuals +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local Debris = game:GetService("Debris") +local isDevTest = false + +local DEBUG_COLOR_RED = Color3.new(1, 0, 0) +local DEBUG_COLOR_YLW = Color3.new(1, 1, 0) +local DEBUG_COLOR_GRN = Color3.new(0, 1, 0) + +local debugBox = Instance.new("BoxHandleAdornment") +debugBox.Adornee = workspace.Terrain +debugBox.Color3 = DEBUG_COLOR_RED +debugBox.Visible = false +debugBox.Parent = script + +local debugCylinder = Instance.new("CylinderHandleAdornment") +debugCylinder.Color = BrickColor.new("Bright violet") +debugCylinder.Adornee = workspace.Terrain +debugCylinder.Height = 0.2 +debugCylinder.Radius = 1.0 +debugCylinder.Visible = false +debugCylinder.Parent = script + +local debugSBox = Instance.new("SelectionBox") +debugSBox.Color3 = DEBUG_COLOR_RED +debugSBox.Parent = script + +local function drawRayIfDebugging(rayStart, look, length, color) + if isDevTest then + local line = Instance.new("LineHandleAdornment") + line.CFrame = CFrame.new(rayStart, rayStart + (look.Unit * length)) + line.Adornee = workspace.Terrain + line.Length = length + line.Color3 = color + line.Thickness = 4 + line.Parent = script + + local cone = Instance.new("ConeHandleAdornment") + cone.CFrame = CFrame.new(rayStart + (look.Unit * (length - 0.32)), rayStart + (look.Unit * length)) + cone.Adornee = workspace.Terrain + cone.Color3 = color + cone.Radius = 1 / 10 + cone.Height = 1 / 3 + cone.Parent = script + + Debris:AddItem(line, .5) + Debris:AddItem(cone, .5) + end +end + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Main Climbing Logic +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local searchDepth = 0.7 +local maxClimbDist = 2.45 +local sampleSpacing = 1 / 7 +local lowLadderSearch = 2.7 +local stepForwardFrames = 0 +local ladderSearchDist = 2.0 + +local running = Enum.HumanoidStateType.Running +local freefall = Enum.HumanoidStateType.Freefall + +local function findPartInLadderZone() + debug.profilebegin("FastClimbCheck") + -- + + local cf = rootPart.CFrame + + local top = -humanoid.HipHeight + local bottom = -lowLadderSearch + top + local radius = 0.5 * ladderSearchDist + + local center = cf.Position + (cf.LookVector * ladderSearchDist * 0.5) + local min = Vector3.new(-radius, bottom, -radius) + local max = Vector3.new(radius, top, radius) + + local extents = Region3.new(center + min, center + max) + local parts = workspace:FindPartsInRegion3(extents, char) + + if isDevTest then + if #parts > 0 then + debugBox.Visible = false + debugSBox.Visible = true + debugSBox.Adornee = parts[1] + else + debugBox.Visible = true + debugSBox.Visible = false + + debugBox.Size = extents.Size + debugBox.CFrame = extents.CFrame + + debugCylinder.Visible = false + end + end + + -- + debug.profileend() + return #parts > 0 +end + +local function findLadder() + if not findPartInLadderZone() then + return false + end + + debug.profilebegin("ExpensiveClimbCheck") + + local torsoCoord = rootPart.CFrame + local torsoLook = torsoCoord.LookVector + + local firstSpace = 0 + local firstStep = 0 + + local lookForSpace = true + local lookForStep = false + + local debugColor = DEBUG_COLOR_YLW + local topRay = math.floor(lowLadderSearch / sampleSpacing) + + for i = 1, topRay do + local distFromBottom = i * sampleSpacing + local originOnTorso = Vector3.new(0, -lowLadderSearch + distFromBottom, 0) + + local casterOrigin = torsoCoord.Position + originOnTorso + local casterDirection = torsoLook * ladderSearchDist + + local ray = Ray.new(casterOrigin, casterDirection) + local hitPrim, hitLoc = workspace:FindPartOnRay(ray, char) + + -- make trusses climbable. + if hitPrim and hitPrim:IsA("TrussPart") then + return true + end + + local mag = (hitLoc - casterOrigin).Magnitude + + if mag < searchDepth then + if lookForSpace then + debugColor = DEBUG_COLOR_GRN + firstSpace = distFromBottom + + lookForSpace = false + lookForStep = true + end + elseif lookForStep then + firstStep = distFromBottom - firstSpace + debugColor = DEBUG_COLOR_RED + lookForStep = false + end + + drawRayIfDebugging(casterOrigin, casterDirection, mag, debugColor) + end + + local found = (firstSpace < maxClimbDist and firstStep > 0 and firstStep < maxClimbDist) + debugCylinder.Visible = isDevTest and found + + if debugCylinder.Visible then + local y = Vector3.FromAxis('Y') + local pos = torsoCoord.Position + Vector3.new(0, 5, 0) + debugCylinder.CFrame = CFrame.new(pos, pos + y) + end + + debug.profileend() + return found +end + +while wait() do + local canClimb = false + + local state = humanoid:GetState() + local speed = humanoid.WalkSpeed + + if state == freefall or state == running then + canClimb = findLadder() + end + + if canClimb then + local climbSpeed = speed * 0.7 + bv.Velocity = Vector3.new(0, climbSpeed, 0) + bv.MaxForce = Vector3.new(climbSpeed * 100, 10e6, climbSpeed * 100) + else + if climbing.Value then + stepForwardFrames = 2 + end + + bv.MaxForce = Vector3.new() + end + + if stepForwardFrames > 0 then + local cf = rootPart.CFrame + humanoid:Move(cf.LookVector) + stepForwardFrames = stepForwardFrames - 1 + end + + climbing.Value = canClimb +end + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Character/Sound.server.lua b/Character/Sound.server.lua new file mode 100644 index 0000000..e6ebcdb --- /dev/null +++ b/Character/Sound.server.lua @@ -0,0 +1,68 @@ +-- util + +function waitForChild(parent, childName) + local child = parent:findFirstChild(childName) + if child then return child end + while true do + child = parent.ChildAdded:wait() + if child.Name==childName then return child end + end +end + +function newSound(id) + local sound = Instance.new("Sound") + sound.SoundId = id + sound.archivable = false + sound.Parent = script.Parent.Head + return sound +end + +-- declarations + +local sDied = newSound("rbxasset://sounds/uuhhh.wav") +local sFallingDown = newSound("rbxasset://sounds/splat.wav") +local sFreeFalling = newSound("rbxasset://sounds/swoosh.wav") +local sGettingUp = newSound("rbxasset://sounds/hit.wav") +local sJumping = newSound("rbxasset://sounds/button.wav") +local sRunning = newSound("rbxasset://sounds/bfsl-minifigfoots1.mp3") +sRunning.Looped = true + +local Figure = script.Parent +local Head = waitForChild(Figure, "Head") +local Humanoid = waitForChild(Figure, "Humanoid") +--local Climbing = Figure:WaitForChild("Climbing") + +-- functions + +function onDied() + sDied:Play() +end + +function onJumping() + sJumping:Play() + wait(0.2) + sJumping:Stop() +end + +function onState(state, sound) + sound.TimePosition = 0 + sound.Playing = state +end + +function onRunning(speed) + sRunning.Playing = (speed>0.1) +end + +-- connect up + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.GettingUp:connect(function(state) onState(state, sGettingUp) end) +Humanoid.FreeFalling:connect(function(state) + --if not Climbing.Value then + onState(state, sFreeFalling) + --end +end) + +Humanoid.FallingDown:connect(function(state) onState(state, sFallingDown) end) diff --git a/Character/TeamColors.server.lua b/Character/TeamColors.server.lua new file mode 100644 index 0000000..bd8f7fd --- /dev/null +++ b/Character/TeamColors.server.lua @@ -0,0 +1,35 @@ +local CollectionService = game:GetService("CollectionService") +local Players = game:GetService("Players") + +local char = script.Parent +local player = Players:GetPlayerFromCharacter(char) +local teamListener = player:GetPropertyChangedSignal("TeamColor") +local bodyColors = char:WaitForChild("BodyColors") + +local teamColors = Instance.new("BodyColors") +teamColors.Name = "TeamColors" +teamColors.HeadColor = BrickColor.new("Bright yellow") +teamColors.LeftArmColor = BrickColor.Black() +teamColors.LeftLegColor = BrickColor.Black() +teamColors.RightArmColor = BrickColor.Black() +teamColors.RightLegColor = BrickColor.Black() + +CollectionService:AddTag(teamColors, "RespectCharacterAsset") + +local function onTeamChanged() + local team = player.Team + if team then + teamColors.TorsoColor = player.TeamColor + bodyColors.Parent = nil + + if not CollectionService:HasTag(team, "NoAutoColor") then + teamColors.Parent = char + end + else + teamColors.Parent = nil + bodyColors.Parent = char + end +end + +onTeamChanged() +teamListener:Connect(onTeamChanged) \ No newline at end of file diff --git a/Character/ToolSoundGlitch.server.lua b/Character/ToolSoundGlitch.server.lua new file mode 100644 index 0000000..92a2d97 --- /dev/null +++ b/Character/ToolSoundGlitch.server.lua @@ -0,0 +1,43 @@ +-- This replicates an old sound bug that used to occur with tools back then. + +local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") + +local char = script.Parent +local torso = char:WaitForChild("Torso") +local marked = {} + +local function processHandle(handle) + for _,child in pairs(handle:GetChildren()) do + if child:IsA("Sound") then + if not marked[child.SoundId] then + marked[child.SoundId] = true + else + local replica = child:Clone() + replica.Name = "ToolSoundGlitch" + replica.MaxDistance = 0 + replica.Parent = torso + + CollectionService:AddTag(replica, "ToolSoundGlitch") + replica:Play() + + replica.Ended:connect(function () + Debris:AddItem(replica, 1) + end) + end + end + end +end + +local function onChild(child) + if child:IsA("Tool") then + local handle = child:FindFirstChild("Handle") + + if handle then + processHandle(handle) + end + end +end + +char.ChildAdded:connect(onChild) +char.ChildRemoved:connect(onChild) \ No newline at end of file diff --git a/Client/Animator.client.lua b/Client/Animator.client.lua new file mode 100644 index 0000000..661e3a6 --- /dev/null +++ b/Client/Animator.client.lua @@ -0,0 +1,262 @@ +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Services +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Animator Data +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local Animators = {} + +local function createAnimator(humanoid) + local Figure = humanoid.Parent + local Torso = Figure:WaitForChild("Torso") + local Climbing = Figure:WaitForChild("Climbing") + + local animator = {} + animator.Joints = {} + + do + local joints = + { + RightShoulder = Torso:WaitForChild("Right Shoulder", 5); + LeftShoulder = Torso:WaitForChild("Left Shoulder", 5); + RightHip = Torso:WaitForChild("Right Hip", 5); + LeftHip = Torso:WaitForChild("Left Hip", 5); + } + + if not (joints.RightShoulder and joints.LeftShoulder) then + return + end + + if not (joints.RightHip and joints.LeftHip) then + return + end + + for name, joint in pairs(joints) do + local object = + { + JointObject = joint; + MaxVelocity = joint.MaxVelocity; + DesiredAngle = joint.DesiredAngle; + CurrentAngle = joint.CurrentAngle; + } + + animator.Joints[name] = object + end + end + + local joints = animator.Joints + + local pi = math.pi + local sin = math.sin + + local pose = "Standing" + local toolAnim = "None" + local toolAnimTime = 0 + + local RightShoulder = joints.RightShoulder + local LeftShoulder = joints.LeftShoulder + + local RightHip = joints.RightHip + local LeftHip = joints.LeftHip + + function animator:SetMaxVelocities(value) + RightShoulder.MaxVelocity = value + LeftShoulder.MaxVelocity = value + + RightHip.MaxVelocity = value + LeftHip.MaxVelocity = value + end + + function animator:Update() + local now = tick() + + if Climbing.Value then + pose = "Climbing" + else + local stateType = humanoid:GetState() + pose = stateType.Name + + if pose == "Running" then + local speed = humanoid.WalkSpeed + local movement = (Torso.Velocity * Vector3.new(1, 0, 1)).Magnitude + + if (speed * movement) < 1 then + pose = "Standing" + end + end + end + + if pose == "Jumping" then + self:SetMaxVelocities(.5) + + RightShoulder.DesiredAngle = 1 + LeftShoulder.DesiredAngle = -1 + + RightHip.DesiredAngle = 0 + LeftHip.DesiredAngle = 0 + elseif pose == "Freefall" then + self:SetMaxVelocities(.5) + + RightShoulder.DesiredAngle = pi + LeftShoulder.DesiredAngle = -pi + + RightHip.DesiredAngle = 0 + LeftHip.DesiredAngle = 0 + elseif pose == "Seated" then + self:SetMaxVelocities(.15) + + RightShoulder.DesiredAngle = pi / 2 + LeftShoulder.DesiredAngle = -pi / 2 + + RightHip.DesiredAngle = pi / 2 + LeftHip.DesiredAngle = -pi / 2 + else + local climbFudge = 0 + local amplitude = .1 + local frequency = 1 + + if pose == "Running" then + self:SetMaxVelocities(0.15) + amplitude = 1 + frequency = 9 + elseif pose == "Climbing" then + self:SetMaxVelocities(0.5) + climbFudge = pi + + amplitude = 1 + frequency = 9 + end + + local desiredAngle = amplitude * sin(now * frequency) + + RightShoulder.DesiredAngle = desiredAngle + climbFudge + LeftShoulder.DesiredAngle = desiredAngle - climbFudge + + RightHip.DesiredAngle = -desiredAngle + LeftHip.DesiredAngle = -desiredAngle + + local tool = Figure:FindFirstChildWhichIsA("Tool") + + if tool and tool.RequiresHandle and not CollectionService:HasTag(tool, "Flag") then + local animString = tool:FindFirstChild("toolanim") + + if animString and animString:IsA("StringValue") then + -- apply tool animation + toolAnim = animString.Value + toolAnimTime = now + .3 + + -- delete event sender + animString:Destroy() + end + + if now > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + if toolAnim == "None" then + RightShoulder.DesiredAngle = pi / 2 + elseif toolAnim == "Slash" then + RightShoulder.MaxVelocity = 0.5 + RightShoulder.DesiredAngle = 0 + elseif toolAnim == "Lunge" then + self:SetMaxVelocities(0.5) + + RightShoulder.DesiredAngle = pi / 2 + RightHip.DesiredAngle = pi / 2 + + LeftShoulder.DesiredAngle = 1 + LeftHip.DesiredAngle = 1 + end + else + toolAnim = "None" + toolAnimTime = 0 + end + end + end + + return animator +end + +local function onAnimatorAdded(humanoid) + if humanoid:IsA("Humanoid") then + local animator = createAnimator(humanoid) + Animators[humanoid] = animator + end +end + +local function onAnimatorRemoved(humanoid) + if Animators[humanoid] then + Animators[humanoid] = nil + end +end + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Collection Handler +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local animTag = "Animator" + +local animAdded = CollectionService:GetInstanceAddedSignal(animTag) +local animRemoved = CollectionService:GetInstanceRemovedSignal(animTag) + +for _,humanoid in pairs(CollectionService:GetTagged(animTag)) do + spawn(function () + onAnimatorAdded(humanoid) + end) +end + +animAdded:Connect(onAnimatorAdded) +animRemoved:Connect(onAnimatorRemoved) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Motor Angle Updater +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local desiredFPS = 1 / 30 -- The framerate that would be expected given the MaxVelocity in use. +local lastUpdate = tick() + +local function updateAnimations(deltaTime) + local velocityAdjust = (1 / desiredFPS) * deltaTime + + for humanoid, animator in pairs(Animators) do + -- Update the motor states + animator:Update() + + -- Step the motor angles + for name, jointData in pairs(animator.Joints) do + local joint = jointData.JointObject + local maxVelocity = jointData.MaxVelocity + + local desiredAngle = jointData.DesiredAngle + local currentAngle = jointData.CurrentAngle + + -- Adjust the MaxVelocity based on the current framerate + maxVelocity = math.abs(maxVelocity * velocityAdjust) + + -- Update the CurrentAngle + local delta = (desiredAngle - currentAngle) + + if math.abs(delta) < maxVelocity then + currentAngle = desiredAngle + elseif delta > 0 then + currentAngle = currentAngle + maxVelocity + else + currentAngle = currentAngle - maxVelocity + end + + -- Apply the motor transform + joint.Transform = CFrame.Angles(0, 0, currentAngle) + jointData.CurrentAngle = currentAngle + end + end +end + +RunService:BindToRenderStep("UpdateAnimations", 301, updateAnimations) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Client/Camera/Main.lua b/Client/Camera/Main.lua new file mode 100644 index 0000000..a53faf4 --- /dev/null +++ b/Client/Camera/Main.lua @@ -0,0 +1,1042 @@ +local Players = game:GetService("Players") +local UserInputService = game:GetService("UserInputService") +local StarterGui = game:GetService("StarterGui") +local GuiService = game:GetService("GuiService") +local ContextActionService = game:GetService("ContextActionService") +local TeleportService = game:GetService("TeleportService") +local Debris = game:GetService("Debris") + +local LocalPlayer = Players.LocalPlayer +local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") +local GameSettings = UserSettings():GetService("UserGameSettings") + +local math_abs = math.abs +local math_asin = math.asin +local math_atan2 = math.atan2 +local math_floor = math.floor +local math_min = math.min +local math_max = math.max +local math_pi = math.pi +local math_rad = math.rad +local Vector2_new = Vector2.new +local Vector3_new = Vector3.new +local CFrame_Angles = CFrame.Angles +local CFrame_new = CFrame.new + +local MIN_Y = math_rad(-80) +local MAX_Y = math_rad(80) + +local ZERO_VECTOR2 = Vector2_new() +local ZERO_VECTOR3 = Vector3_new() +local UP_VECTOR = Vector3_new(0, 1, 0) +local XZ_VECTOR = Vector3_new(1, 0, 1) + +local TOUCH_SENSITIVTY = Vector2_new(math_pi*2.25, math_pi*2) +local MOUSE_SENSITIVITY = Vector2_new(math_pi*4, math_pi*1.9) + +local THUMBSTICK_DEADZONE = 0.2 +local DEADZONE = 0.1 +local ZOOM_FACTOR = 0.25 + +local humanoid + +local function findPlayerHumanoid(player) + local character = player and player.Character + if character then + if not (humanoid and humanoid.Parent == character) then + humanoid = character:FindFirstChildOfClass("Humanoid") + end + end + return humanoid +end + +local function clamp(low, high, num) + return (num > high and high or num < low and low or num) +end + +local function findAngleBetweenXZVectors(vec2, vec1) + return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z) +end + +local function IsFinite(num) + return num == num and num ~= 1/0 and num ~= -1/0 +end + +local function SCurveTranform(t) + t = clamp(-1,1,t) + if t >= 0 then + return (.35*t) / (.35 - t + 1) + end + return -((.8*-t) / (.8 + t + 1)) +end + +local function toSCurveSpace(t) + return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE +end + +local function fromSCurveSpace(t) + return t/2 + 0.5 +end + +local function gamepadLinearToCurve(thumbstickPosition) + local function onAxis(axisValue) + local sign = 1 + if axisValue < 0 then + sign = -1 + end + local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math_abs(axisValue)))) + point = point * sign + return clamp(-1, 1, point) + end + return Vector2_new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y)) +end + +-- Reset the camera look vector when the camera is enabled for the first time +local SetCameraOnSpawn = true +local this = {} + +local isFirstPerson = false +local isRightMouseDown = false +local isMiddleMouseDown = false + +this.Enabled = false +this.RotateInput = ZERO_VECTOR2 +this.DefaultZoom = 10 +this.activeGamepad = nil +this.PartSubjectHack = nil + +function this:GetHumanoid() + local player = Players.LocalPlayer + return findPlayerHumanoid(player) +end + +function this:GetHumanoidRootPart() + local humanoid = this:GetHumanoid() + return humanoid and humanoid.Torso +end + +function this:GetSubjectPosition() + local camera = workspace.CurrentCamera + local result = camera.Focus.p + + local cameraSubject = camera and camera.CameraSubject + if cameraSubject then + if cameraSubject:IsA("Humanoid") then + local char = cameraSubject.Parent + if char then + local head = char:FindFirstChild("Head") + if head and head:IsA("BasePart") then + result = head.Position + end + end + if this.PartSubjectHack then + this:ZoomCamera(this.PartSubjectHack) + this.PartSubjectHack = nil + this:UpdateMouseBehavior() + end + elseif cameraSubject:IsA("BasePart") then + result = cameraSubject.Position + if not this.PartSubjectHack then + this.PartSubjectHack = this:GetCameraZoom() + this:ZoomCamera(10) + this:UpdateMouseBehavior() + end + end + end + + return result +end + +function this:GetCameraLook() + return workspace.CurrentCamera and workspace.CurrentCamera.CFrame.lookVector or Vector3.new(0,0,1) +end + +function this:GetCameraZoom() + if this.currentZoom == nil then + local player = Players.LocalPlayer + this.currentZoom = player and clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, this.DefaultZoom) or this.DefaultZoom + end + return this.currentZoom +end + +function this:GetCameraActualZoom() + local camera = workspace.CurrentCamera + if camera then + return (camera.CFrame.p - camera.Focus.p).Magnitude + end +end + +function this:ViewSizeX() + local result = 1024 + local camera = workspace.CurrentCamera + if camera then + result = camera.ViewportSize.X + end + return result +end + +function this:ViewSizeY() + local result = 768 + local camera = workspace.CurrentCamera + if camera then + result = camera.ViewportSize.Y + end + return result +end + +function this:ScreenTranslationToAngle(translationVector) + local screenX = this:ViewSizeX() + local screenY = this:ViewSizeY() + local xTheta = (translationVector.x / screenX) + local yTheta = (translationVector.y / screenY) + return Vector2_new(xTheta, yTheta) +end + +function this:MouseTranslationToAngle(translationVector) + local xTheta = (translationVector.x / 1920) + local yTheta = (translationVector.y / 1200) + return Vector2_new(xTheta, yTheta) +end + +function this:RotateVector(startVector, xyRotateVector) + local startCFrame = CFrame_new(ZERO_VECTOR3, startVector) + local resultLookVector = (CFrame_Angles(0, -xyRotateVector.x, 0) * startCFrame * CFrame_Angles(-xyRotateVector.y,0,0)).lookVector + return resultLookVector, Vector2_new(xyRotateVector.x, xyRotateVector.y) +end + +function this:RotateCamera(startLook, xyRotateVector) + local startVertical = math_asin(startLook.y) + local yTheta = clamp(-MAX_Y + startVertical, -MIN_Y + startVertical, xyRotateVector.y) + return self:RotateVector(startLook, Vector2_new(xyRotateVector.x, yTheta)) +end + +function this:IsInFirstPerson() + return isFirstPerson +end + +function this:UpdateMouseBehavior() + if isFirstPerson or this.PartSubjectHack then + GameSettings.RotationType = Enum.RotationType.CameraRelative + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + else + GameSettings.RotationType = Enum.RotationType.MovementRelative + if isRightMouseDown or isMiddleMouseDown then + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition + else + UserInputService.MouseBehavior = Enum.MouseBehavior.Default + end + end +end + +function this:PlayTick() + local now = tick() + local lastTickSound = this.LastTickSound + if not lastTickSound then + lastTickSound = 0 + end + + if (now - lastTickSound) > .03 then + local s = Instance.new("Sound") + s.SoundId = "rbxasset://sounds/switch3.wav" + s.Parent = script + s:Play() + Debris:AddItem(s,1) + this.LastTickSound = now + end +end + +function this:ZoomCamera(desiredZoom) + this.currentZoom = clamp(0.25, 400, desiredZoom) + isFirstPerson = self:GetCameraZoom() < 1.5 + + -- set mouse behavior + self:UpdateMouseBehavior() + return self:GetCameraZoom() +end + +function this:ZoomCameraBy(input) + if TeleportService:GetTeleportSetting("FPSCapTo30") then + input = input * 1.5 + end + + local zoom = this:GetCameraActualZoom() + if zoom then + if input > 0 then + zoom = math.max( 1, zoom / (1 + ZOOM_FACTOR*input)) + elseif input < 0 then + zoom = math.min(5000, zoom * (1 - ZOOM_FACTOR*input)) + end + self:ZoomCamera(zoom) + end + + self:PlayTick() + return self:GetCameraZoom() +end + +function this:ZoomCameraFixedBy(zoomIncrement) + return self:ZoomCamera(self:GetCameraZoom() + zoomIncrement) +end + +------------------------ +---- Input Events ---- +------------------------ + +do + local startPos = nil + local lastPos = nil + local panBeginLook = nil + local lastTapTime = nil + + local fingerTouches = {} + local NumUnsunkTouches = 0 + + local inputStartPositions = {} + local inputStartTimes = {} + + local StartingDiff = nil + local pinchBeginZoom = nil + + local dynamicThumbstickFrame = nil + local flaggedDynamic = {} + + local function getDynamicThumbstickFrame() + if dynamicThumbstickFrame and dynamicThumbstickFrame:IsDescendantOf(game) then + return dynamicThumbstickFrame + else + local touchGui = PlayerGui:FindFirstChild("TouchGui") + if not touchGui then return nil end + + local touchControlFrame = touchGui:FindFirstChild("TouchControlFrame") + if not touchControlFrame then return nil end + + dynamicThumbstickFrame = touchControlFrame:FindFirstChild("DynamicThumbstickFrame") + return dynamicThumbstickFrame + end + end + + this.ZoomEnabled = true + this.PanEnabled = true + this.KeyPanEnabled = true + + local function inputIsDynamic(input) + if flaggedDynamic[input] ~= nil then + return flaggedDynamic[input] + end + + if GameSettings.TouchMovementMode ~= Enum.TouchMovementMode.DynamicThumbstick then + return false + end + + local df = getDynamicThumbstickFrame() + if not df then return end + + local pos = input.Position + local p0 = df.AbsolutePosition + local p1 = p0 + df.AbsoluteSize + + if p0.X <= pos.X and p0.Y <= pos.Y then + if pos.X <= p1.X and pos.Y <= p1.Y then + flaggedDynamic[input] = true + return true + end + end + + flaggedDynamic[input] = false + return false + end + + local function OnTouchBegan(input, processed) + if not inputIsDynamic(input) then + fingerTouches[input] = processed + if not processed then + + inputStartPositions[input] = input.Position + inputStartTimes[input] = tick() + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + end + + local function OnTouchChanged(input, processed) + if inputIsDynamic(input) then + return + end + + if fingerTouches[input] == nil then + fingerTouches[input] = processed + if not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + + if NumUnsunkTouches == 1 then + if fingerTouches[input] == false then + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + + local delta = input.Position - lastPos + + delta = Vector2.new(delta.X, delta.Y * GameSettings:GetCameraYInvertValue()) + + if this.PanEnabled then + local desiredXYVector = this:ScreenTranslationToAngle(delta) * TOUCH_SENSITIVTY + this.RotateInput = this.RotateInput + desiredXYVector + end + + lastPos = input.Position + end + else + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + + if NumUnsunkTouches == 2 then + local unsunkTouches = {} + for touch, wasSunk in pairs(fingerTouches) do + if not wasSunk then + table.insert(unsunkTouches, touch) + end + end + if #unsunkTouches == 2 then + local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude + if StartingDiff and pinchBeginZoom then + local scale = difference / math_max(0.01, StartingDiff) + local clampedScale = clamp(0.1, 10, scale) + if this.ZoomEnabled then + this:ZoomCamera(pinchBeginZoom / clampedScale) + this:PlayTick() + end + else + StartingDiff = difference + pinchBeginZoom = this:GetCameraActualZoom() + end + end + else + StartingDiff = nil + pinchBeginZoom = nil + end + end + + local function calcLookBehindRotateInput(torso) + if torso then + local newDesiredLook = (torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit + local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook()) + local vertShift = math_asin(this:GetCameraLook().y) - math_asin(newDesiredLook.y) + if not IsFinite(horizontalShift) then + horizontalShift = 0 + end + if not IsFinite(vertShift) then + vertShift = 0 + end + + return Vector2.new(horizontalShift, vertShift) + end + return nil + end + + local function OnTouchEnded(input, processed) + if fingerTouches[input] == false then + if NumUnsunkTouches == 1 then + panBeginLook = nil + startPos = nil + lastPos = nil + elseif NumUnsunkTouches == 2 then + StartingDiff = nil + pinchBeginZoom = nil + end + end + + if fingerTouches[input] ~= nil and fingerTouches[input] == false then + NumUnsunkTouches = NumUnsunkTouches - 1 + end + fingerTouches[input] = nil + inputStartPositions[input] = nil + inputStartTimes[input] = nil + flaggedDynamic[input] = nil + end + + local function OnMousePanButtonPressed(input, processed) + if processed then return end + this:UpdateMouseBehavior() + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + end + + local function OnMousePanButtonReleased(input, processed) + this:UpdateMouseBehavior() + if not (isRightMouseDown or isMiddleMouseDown) then + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + end + + local function OnMouse2Down(input, processed) + if processed then return end + + isRightMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse2Up(input, processed) + isRightMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouse3Down(input, processed) + if processed then return end + + isMiddleMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse3Up(input, processed) + isMiddleMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouseMoved(input, processed) + + local inputDelta = input.Delta + inputDelta = Vector2.new(inputDelta.X, inputDelta.Y * GameSettings:GetCameraYInvertValue()) + + if startPos and lastPos and panBeginLook then + local currPos = lastPos + input.Delta + local totalTrans = currPos - startPos + if this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + lastPos = currPos + elseif (this:IsInFirstPerson() or this.PartSubjectHack) and this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + end + + local function OnMouseWheel(input, processed) + if not processed then + if this.ZoomEnabled then + this:ZoomCameraBy(clamp(-1, 1, input.Position.Z)) + end + end + end + + local function round(num) + return math_floor(num + 0.5) + end + + local eight2Pi = math_pi / 4 + + local function rotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount) + if camLook ~= ZERO_VECTOR3 then + camLook = camLook.unit + local currAngle = math_atan2(camLook.z, camLook.x) + local newAngle = round((math_atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount + return newAngle - currAngle + end + return 0 + end + + local function OnKeyDown(input, processed) + if processed then return end + if this.ZoomEnabled then + if input.KeyCode == Enum.KeyCode.I then + this:ZoomCameraBy(1) + elseif input.KeyCode == Enum.KeyCode.O then + this:ZoomCameraBy(-1) + end + end + if panBeginLook == nil and this.KeyPanEnabled then + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = true + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = true + elseif input.KeyCode == Enum.KeyCode.Comma then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), -eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.Period then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.PageUp then + this.RotateInput = this.RotateInput + Vector2.new(0,math_pi/12) + this.LastCameraTransform = nil + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.PageDown then + this.RotateInput = this.RotateInput + Vector2.new(0,-math_pi/12) + this.LastCameraTransform = nil + this:PlayTick() + end + end + end + + local function OnKeyUp(input, processed) + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = false + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = false + end + end + + local lastThumbstickRotate = nil + local numOfSeconds = 0.7 + local currentSpeed = 0 + local maxSpeed = 6 + local lastThumbstickPos = Vector2.new(0,0) + local ySensitivity = 0.65 + local lastVelocity = nil + + function this:UpdateGamepad() + local gamepadPan = this.GamepadPanningCamera + if gamepadPan then + gamepadPan = gamepadLinearToCurve(gamepadPan) + local currentTime = tick() + if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then + this.userPanningTheCamera = true + elseif gamepadPan == ZERO_VECTOR2 then + lastThumbstickRotate = nil + if lastThumbstickPos == ZERO_VECTOR2 then + currentSpeed = 0 + end + end + + local finalConstant = 0 + + if lastThumbstickRotate then + local elapsed = (currentTime - lastThumbstickRotate) * 10 + currentSpeed = currentSpeed + (maxSpeed * ((elapsed*elapsed)/numOfSeconds)) + + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + + if lastVelocity then + local velocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + local velocityDeltaMag = (velocity - lastVelocity).magnitude + + if velocityDeltaMag > 12 then + currentSpeed = currentSpeed * (20/velocityDeltaMag) + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + end + end + + local gamepadCameraSensitivity = GameSettings.GamepadCameraSensitivity + finalConstant = (gamepadCameraSensitivity * currentSpeed) + lastVelocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + end + + lastThumbstickPos = gamepadPan + lastThumbstickRotate = currentTime + + return Vector2_new( gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * ySensitivity * GameSettings:GetCameraYInvertValue()) + end + + return ZERO_VECTOR2 + end + + local InputEvents = {} + + function this:DisconnectInputEvents() + -- Disconnect all input events. + while true do + local signalName = next(InputEvents) + if signalName then + InputEvents[signalName]:Disconnect() + InputEvents[signalName] = nil + else + break + end + end + + this.TurningLeft = false + this.TurningRight = false + this.LastCameraTransform = nil + this.UserPanningTheCamera = false + this.RotateInput = ZERO_VECTOR2 + this.GamepadPanningCamera = ZERO_VECTOR2 + + -- Reset input states + startPos = nil + lastPos = nil + panBeginLook = nil + isRightMouseDown = false + isMiddleMouseDown = false + + fingerTouches = {} + NumUnsunkTouches = 0 + + StartingDiff = nil + pinchBeginZoom = nil + + -- Unlock mouse for example if right mouse button was being held down + if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then + UserInputService.MouseBehavior = Enum.MouseBehavior.Default + end + end + + local function resetInputStates() + isRightMouseDown = false + isMiddleMouseDown = false + OnMousePanButtonReleased() -- this function doesn't seem to actually need parameters + + if UserInputService.TouchEnabled then + --[[menu opening was causing serious touch issues + this should disable all active touch events if + they're active when menu opens.]] + for inputObject, value in pairs(fingerTouches) do + fingerTouches[inputObject] = nil + end + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + StartingDiff = nil + pinchBeginZoom = nil + NumUnsunkTouches = 0 + end + end + + local function getGamepadPan(name, state, input) + if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then + + if state == Enum.UserInputState.Cancel then + this.GamepadPanningCamera = ZERO_VECTOR2 + return + end + + local inputVector = Vector2.new(input.Position.X, -input.Position.Y) + if inputVector.magnitude > THUMBSTICK_DEADZONE then + this.GamepadPanningCamera = Vector2_new(input.Position.X, -input.Position.Y) + else + this.GamepadPanningCamera = ZERO_VECTOR2 + end + end + end + + local function doGamepadZoom(name, state, input) + if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.ButtonR3 and state == Enum.UserInputState.Begin then + if this.ZoomEnabled then + if this:GetCameraZoom() > 0.5 then + this:ZoomCamera(0) + else + this:ZoomCamera(10) + end + end + end + end + + local function assignActivateGamepad() + local connectedGamepads = UserInputService:GetConnectedGamepads() + if #connectedGamepads > 0 then + for i = 1, #connectedGamepads do + if this.activeGamepad == nil then + this.activeGamepad = connectedGamepads[i] + elseif connectedGamepads[i].Value < this.activeGamepad.Value then + this.activeGamepad = connectedGamepads[i] + end + end + end + + if this.activeGamepad == nil then -- nothing is connected, at least set up for gamepad1 + this.activeGamepad = Enum.UserInputType.Gamepad1 + end + end + + local function onInputBegan(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchBegan(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Down(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Down(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyDown(input, processed) + end + end + + local function onInputChanged(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchChanged(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseMovement then + OnMouseMoved(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseWheel then + OnMouseWheel(input, processed) + end + end + + local function onInputEnded(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchEnded(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Up(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Up(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyUp(input, processed) + end + end + + local inputPassCmds = + { + ZoomIn = Enum.KeyCode.I; + ZoomOut = Enum.KeyCode.O; + RotateUp = Enum.KeyCode.PageUp; + RotateDown = Enum.KeyCode.PageDown; + } + + local function onInputPassed(command) + local passKey = inputPassCmds[command] + if passKey then + OnKeyDown({KeyCode = passKey}, false) + end + end + + local function onGamepadConnected(gamepadEnum) + if this.activeGamepad == nil then + assignActivateGamepad() + end + end + + local function onGamepadDisconnected(gamepadEnum) + if this.activeGamepad ~= gamepadEnum then return end + this.activeGamepad = nil + assignActivateGamepad() + end + + function this:ConnectInputEvents() + local player = Players.LocalPlayer + local playerScripts = player:WaitForChild("PlayerScripts") + local passCameraEvent = playerScripts:WaitForChild("PassCameraEvent") + + this.RotateInput = ZERO_VECTOR2 + this.activeGamepad = nil + + InputEvents = + { + InputBegan = UserInputService.InputBegan:Connect(onInputBegan); + InputChanged = UserInputService.InputChanged:Connect(onInputChanged); + InputEnded = UserInputService.InputEnded:Connect(onInputEnded); + MenuOpened = GuiService.MenuOpened:Connect(resetInputStates); + MenuOpenedConn = GuiService.MenuOpened:Connect(resetInputStates); + GamepadConnected = UserInputService.GamepadConnected:Connect(onGamepadConnected); + GamepadDisconnected = UserInputService.GamepadDisconnected:Connect(onGamepadDisconnected); + InputPassed = passCameraEvent.Event:Connect(onInputPassed); + } + + ContextActionService:BindAction("RootCamGamepadPan", getGamepadPan, false, Enum.KeyCode.Thumbstick2) + ContextActionService:BindAction("RootCamGamepadZoom", doGamepadZoom, false, Enum.KeyCode.ButtonR3) + + assignActivateGamepad() + + -- set mouse behavior + self:UpdateMouseBehavior() + end + + function this:SetEnabled(newState) + if newState ~= self.Enabled then + self.Enabled = newState + if self.Enabled then + self:ConnectInputEvents() + else + self:DisconnectInputEvents() + end + end + end + + local function OnPlayerAdded(player) + player.Changed:Connect(function (prop) + if this.Enabled then + if prop == "CameraMode" or prop == "CameraMaxZoomDistance" or prop == "CameraMinZoomDistance" then + this:ZoomCameraFixedBy(0) + end + end + end) + + local function OnCharacterAdded(newCharacter) + local humanoid = findPlayerHumanoid(player) + local start = tick() + while tick() - start < 0.3 and (humanoid == nil or humanoid.Torso == nil) do + wait() + humanoid = findPlayerHumanoid(player) + end + + if humanoid and humanoid.Torso and player.Character == newCharacter then + local newDesiredLook = (humanoid.Torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit + local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook()) + local vertShift = math_asin(this:GetCameraLook().y) - math_asin(newDesiredLook.y) + if not IsFinite(horizontalShift) then + horizontalShift = 0 + end + if not IsFinite(vertShift) then + vertShift = 0 + end + this.RotateInput = Vector2.new(horizontalShift, vertShift) + + -- reset old camera info so follow cam doesn't rotate us + this.LastCameraTransform = nil + end + + -- Need to wait for camera cframe to update before we zoom in + -- Not waiting will force camera to original cframe + wait() + this:ZoomCamera(this.DefaultZoom) + end + + player.CharacterAdded:Connect(function (character) + if this.Enabled or SetCameraOnSpawn then + OnCharacterAdded(character) + SetCameraOnSpawn = false + end + end) + + if player.Character then + spawn(function () OnCharacterAdded(player.Character) end) + end + end + + if Players.LocalPlayer then + OnPlayerAdded(Players.LocalPlayer) + end + + Players.ChildAdded:Connect(function (child) + if child and Players.LocalPlayer == child then + OnPlayerAdded(Players.LocalPlayer) + end + end) + +end + +------------------------ +---- Main Updater ---- +------------------------ + +do + local tweenAcceleration = math_rad(220) + local tweenSpeed = math_rad(0) + local tweenMaxSpeed = math_rad(250) + local timeBeforeAutoRotate = 2 + + local lastUpdate = tick() + this.LastUserPanCamera = lastUpdate + + + function this:Update() + local now = tick() + local timeDelta = (now - lastUpdate) + + local userPanningTheCamera = (self.UserPanningTheCamera == true) + local camera = workspace.CurrentCamera + local humanoid = self:GetHumanoid() + local cameraSubject = camera and camera.CameraSubject + local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat') + local isOnASkateboard = cameraSubject and cameraSubject:IsA('SkateboardPlatform') + + if isInVehicle and cameraSubject.Occupant == humanoid then + cameraSubject = humanoid + camera.CameraSubject = humanoid + isInVehicle = false + end + + if lastUpdate == nil or (now - lastUpdate) > 1 then + self.LastCameraTransform = nil + end + + if lastUpdate then + local gamepadRotation = self:UpdateGamepad() + + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math_min(0.1, now - lastUpdate) + + if gamepadRotation ~= ZERO_VECTOR2 then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + + local angle = 0 + if not (isInVehicle or isOnASkateboard) then + angle = angle + (self.TurningLeft and -120 or 0) + angle = angle + (self.TurningRight and 120 or 0) + end + + if angle ~= 0 then + self.RotateInput = self.RotateInput + Vector2.new(math_rad(angle * delta), 0) + userPanningTheCamera = true + end + end + + -- Reset tween speed if user is panning + if userPanningTheCamera then + tweenSpeed = 0 + self.LastUserPanCamera = now + end + + local userRecentlyPannedCamera = now - self.LastUserPanCamera < timeBeforeAutoRotate + local subjectPosition = self:GetSubjectPosition() + + if subjectPosition and camera then + local zoom = self:GetCameraZoom() + if zoom < 0.25 then + zoom = 0.25 + end + + if TeleportService:GetTeleportSetting("FollowCamera") then + if self.LastCameraTransform and not self:IsInFirstPerson() then + local lastVec = -(self.LastCameraTransform.p - subjectPosition) + local y = findAngleBetweenXZVectors(lastVec, self:GetCameraLook()) + -- Check for NaNs + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + end + end + + camera.Focus = CFrame_new(subjectPosition) + + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = ZERO_VECTOR2 + + if self.LastZoom ~= zoom then + self.LastZoom = zoom + + if camera.CameraSubject and camera.CameraSubject:IsA("Humanoid") then + -- Flatten the lookVector + newLookVector = (newLookVector * XZ_VECTOR).Unit + + -- Apply upwards tilt + local upY = -math_min(6, zoom/40) + newLookVector = (newLookVector + (UP_VECTOR * upY)).Unit + end + end + + local newCF = CFrame_new(subjectPosition - (zoom * newLookVector), subjectPosition) + camera.CFrame = camera.CFrame:Lerp(newCF,.8) + self.LastCameraTransform = camera.CFrame + end + + lastUpdate = now + end + + GameSettings:SetCameraYInvertVisible() + GameSettings:SetGamepadCameraSensitivityVisible() +end + +return this \ No newline at end of file diff --git a/Client/Camera/Opacity.lua b/Client/Camera/Opacity.lua new file mode 100644 index 0000000..ee8a60f --- /dev/null +++ b/Client/Camera/Opacity.lua @@ -0,0 +1,176 @@ +-- SolarCrane + +local module = {} + +local LastUpdate = tick() +local TransparencyDirty = false +local Enabled = false +local LastTransparency = nil + +local DescendantAddedConn, DescendantRemovingConn = nil, nil +local ToolDescendantAddedConns = {} +local ToolDescendantRemovingConns = {} +local CachedParts = {} + +local function HasToolAncestor(object) + return (object:FindFirstAncestorWhichIsA("Tool")) ~= nil +end + +local function IsValidPartToModify(part) + if part:IsA('BasePart') or part:IsA('Decal') then + return not HasToolAncestor(part) + end + return false +end + +local function TeardownTransparency() + for child, _ in pairs(CachedParts) do + child.LocalTransparencyModifier = 0 + end + + CachedParts = {} + TransparencyDirty = true + LastTransparency = nil + + if DescendantAddedConn then + DescendantAddedConn:disconnect() + DescendantAddedConn = nil + end + + if DescendantRemovingConn then + DescendantRemovingConn:disconnect() + DescendantRemovingConn = nil + end + + for object, conn in pairs(ToolDescendantAddedConns) do + conn:disconnect() + ToolDescendantAddedConns[object] = nil + end + + for object, conn in pairs(ToolDescendantRemovingConns) do + conn:disconnect() + ToolDescendantRemovingConns[object] = nil + end +end + +local function SetupTransparency(character) + TeardownTransparency() + + if DescendantAddedConn then + DescendantAddedConn:Disconnect() + end + + DescendantAddedConn = character.DescendantAdded:connect(function (object) + -- This is a part we want to invisify + if IsValidPartToModify(object) then + CachedParts[object] = true + TransparencyDirty = true + -- There is now a tool under the character + elseif object:IsA('Tool') then + if ToolDescendantAddedConns[object] then + ToolDescendantAddedConns[object]:Disconnect() + end + + ToolDescendantAddedConns[object] = object.DescendantAdded:connect(function (toolChild) + CachedParts[toolChild] = nil + if toolChild:IsA('BasePart') or toolChild:IsA('Decal') then + -- Reset the transparency + toolChild.LocalTransparencyModifier = 0 + end + end) + + if ToolDescendantRemovingConns[object] then + ToolDescendantRemovingConns[object]:Disconnect() + end + + ToolDescendantRemovingConns[object] = object.DescendantRemoving:connect(function (formerToolChild) + wait() -- wait for new parent + if character and formerToolChild and formerToolChild:IsDescendantOf(character) then + if IsValidPartToModify(formerToolChild) then + CachedParts[formerToolChild] = true + TransparencyDirty = true + end + end + end) + end + end) + + if DescendantRemovingConn then + DescendantRemovingConn:Disconnect() + end + + DescendantRemovingConn = character.DescendantRemoving:connect(function (object) + if CachedParts[object] then + CachedParts[object] = nil + -- Reset the transparency + object.LocalTransparencyModifier = 0 + end + end) + + for _,desc in pairs(character:GetDescendants()) do + if IsValidPartToModify(desc) then + CachedParts[desc] = true + TransparencyDirty = true + end + end +end + + +function module:SetEnabled(newState) + if Enabled ~= newState then + Enabled = newState + self:Update() + end +end + +function module:SetSubject(subject) + local character = nil + if subject and subject:IsA("Humanoid") then + character = subject.Parent + end + if subject and subject:IsA("VehicleSeat") and subject.Occupant then + character = subject.Occupant.Parent + end + if character then + SetupTransparency(character) + else + TeardownTransparency() + end +end + +function module:Update() + local instant = false + local now = tick() + local currentCamera = workspace.CurrentCamera + + if currentCamera then + local transparency = 0 + if not Enabled then + instant = true + else + local distance = (currentCamera.Focus.p - currentCamera.CFrame.p).magnitude + if distance < 2 then + transparency = 1 + elseif distance < 6 then + transparency = 0.5 + else + transparency = 0 + end + end + + if TransparencyDirty or LastTransparency ~= transparency then + for child in pairs(CachedParts) do + if child.ClassName == "Decal" then + child.LocalTransparencyModifier = math.floor(transparency) + else + child.LocalTransparencyModifier = transparency + end + end + TransparencyDirty = false + LastTransparency = transparency + end + end + LastUpdate = now +end + +return module \ No newline at end of file diff --git a/Client/Camera/Popper.lua b/Client/Camera/Popper.lua new file mode 100644 index 0000000..cd4d47b --- /dev/null +++ b/Client/Camera/Popper.lua @@ -0,0 +1,129 @@ +-- PopperCam Version 16 +-- OnlyTwentyCharacters + +local PopperCam = {} -- Guarantees your players won't see outside the bounds of your map! + +----------------- +--| Constants |-- +----------------- + +local POP_RESTORE_RATE = 0.3 +local MIN_CAMERA_ZOOM = 0.5 + +local VALID_SUBJECTS = { + 'Humanoid', + 'VehicleSeat', + 'SkateboardPlatform', +} + +----------------- +--| Variables |-- +----------------- + +local Players = game:GetService('Players') + +local Camera = nil +local CameraSubjectChangeConn = nil + +local SubjectPart = nil + +local PlayerCharacters = {} -- For ignoring in raycasts +local VehicleParts = {} -- Also just for ignoring + +local LastPopAmount = 0 +local LastZoomLevel = 0 +local PopperEnabled = true + +local CFrame_new = CFrame.new + +----------------------- +--| Local Functions |-- +----------------------- + +local math_abs = math.abs + +local function OnCharacterAdded(player, character) + PlayerCharacters[player] = character +end + +local function OnPlayersChildAdded(child) + if child:IsA('Player') then + child.CharacterAdded:connect(function(character) + OnCharacterAdded(child, character) + end) + if child.Character then + OnCharacterAdded(child, child.Character) + end + end +end + +local function OnPlayersChildRemoved(child) + if child:IsA('Player') then + PlayerCharacters[child] = nil + end +end + +------------------------- +--| Exposed Functions |-- +------------------------- + +function PopperCam:Update() + if PopperEnabled then + -- First, prep some intermediate vars + local Camera = workspace.CurrentCamera + local cameraCFrame = Camera.CFrame + local focusPoint = Camera.Focus.p + + if SubjectPart then + focusPoint = SubjectPart.CFrame.p + end + + local ignoreList = {} + for _, character in pairs(PlayerCharacters) do + ignoreList[#ignoreList + 1] = character + end + for i = 1, #VehicleParts do + ignoreList[#ignoreList + 1] = VehicleParts[i] + end + + -- Get largest cutoff distance + local largest = Camera:GetLargestCutoffDistance(ignoreList) + + -- Then check if the player zoomed since the last frame, + -- and if so, reset our pop history so we stop tweening + local zoomLevel = (cameraCFrame.p - focusPoint).Magnitude + if math_abs(zoomLevel - LastZoomLevel) > 0.001 then + LastPopAmount = 0 + end + + -- Finally, zoom the camera in (pop) by that most-cut-off amount, or the last pop amount if that's more + local popAmount = largest + if LastPopAmount > popAmount then + popAmount = LastPopAmount + end + + if popAmount > 0 then + Camera.CFrame = cameraCFrame + (cameraCFrame.lookVector * popAmount) + LastPopAmount = popAmount - POP_RESTORE_RATE -- Shrink it for the next frame + if LastPopAmount < 0 then + LastPopAmount = 0 + end + end + + LastZoomLevel = zoomLevel + end +end + +-------------------- +--| Script Logic |-- +-------------------- + + +-- Connect to all Players so we can ignore their Characters +Players.ChildRemoved:connect(OnPlayersChildRemoved) +Players.ChildAdded:connect(OnPlayersChildAdded) +for _, player in pairs(Players:GetPlayers()) do + OnPlayersChildAdded(player) +end + +return PopperCam \ No newline at end of file diff --git a/Client/Camera/init.client.lua b/Client/Camera/init.client.lua new file mode 100644 index 0000000..764f7a5 --- /dev/null +++ b/Client/Camera/init.client.lua @@ -0,0 +1,60 @@ +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local Players = game:GetService("Players") + +local playerScripts = script.Parent +local playerModule = require(playerScripts:WaitForChild("PlayerModule")) + +local cameraSystem = playerModule:GetCameras() + +local main = require(script:WaitForChild("Main")) +local popper = require(script:WaitForChild("Popper")) +local opacity = require(script:WaitForChild("Opacity")) + +local cameraSubjectChangedConn = nil +local renderSteppedConn = nil + +local function onCameraSubjectChanged() + local currentCamera = workspace.CurrentCamera + if currentCamera then + local newSubject = currentCamera.CameraSubject + opacity:SetSubject(newSubject) + end +end + +local function onNewCamera() + local currentCamera = workspace.CurrentCamera + if currentCamera then + if cameraSubjectChangedConn then + cameraSubjectChangedConn:Disconnect() + end + + local cameraSubjectChanged = currentCamera:GetPropertyChangedSignal("CameraSubject") + cameraSubjectChangedConn = cameraSubjectChanged:Connect(onCameraSubjectChanged) + + onCameraSubjectChanged() + end +end + +-- Initialize cameras. +local cameraUpdated = workspace:GetPropertyChangedSignal("CurrentCamera") +cameraUpdated:Connect(onNewCamera) + +onNewCamera() +main:SetEnabled(true) +opacity:SetEnabled(true) + +-- Overload the camera update function. +function cameraSystem:Update() + if cameraSystem.activeCameraController then + cameraSystem.activeCameraController:Enable(false) + cameraSystem.activeCameraController = nil + end + + main:Update() + popper:Update() + opacity:Update() +end + +playerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Default) +playerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Default) \ No newline at end of file diff --git a/Client/CharacterBevels.client.lua b/Client/CharacterBevels.client.lua new file mode 100644 index 0000000..4bd288a --- /dev/null +++ b/Client/CharacterBevels.client.lua @@ -0,0 +1,25 @@ +local CollectionService = game:GetService("CollectionService") +local TeleportService = game:GetService("TeleportService") + +local noBevelsTag = "NoCharacterBevels" +local bevelTracker = CollectionService:GetInstanceAddedSignal(noBevelsTag) + +local function safeDestroy(obj) + spawn(function () + obj:Destroy() + end) +end + +local function onInstanceAdded(inst) + if TeleportService:GetTeleportSetting("CharacterBevels") then + safeDestroy(inst) + end +end + +for _,inst in pairs(CollectionService:GetTagged(noBevelsTag)) do + onInstanceAdded(inst) +end + +bevelTracker:Connect(onInstanceAdded) + + diff --git a/Client/ClickToMove.client.lua b/Client/ClickToMove.client.lua new file mode 100644 index 0000000..183f74b --- /dev/null +++ b/Client/ClickToMove.client.lua @@ -0,0 +1,301 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- @CloneTrooper1019, 2018 +-- ClickToMove +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constants +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local ContextActionService = game:GetService("ContextActionService") +local GuiService = game:GetService("GuiService") +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local TeleportService = game:GetService("TeleportService") +local UserInputService = game:GetService("UserInputService") + +local IS_TOUCH = UserInputService.TouchEnabled + +local ICON_IDLE = "rbxassetid://334630296" +local ICON_HOVER = "rbxassetid://1000000" +local ICON_CLICK = "rbxasset://textures/DragCursor.png" + +local DISK_OFFSET = CFrame.Angles(math.pi / 2,0,0) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Character Listener +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local player = game.Players.LocalPlayer +local character,humanoid + +local function onCharacterAdded(char) + humanoid = char:WaitForChild("Humanoid") + character = char +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:Connect(onCharacterAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Gui Focus +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local isMouseHoveringUi = false + +local function onInputChanged(input, gameProcessed) + local inputType = input.UserInputType.Name + + if inputType == "MouseMovement" then + isMouseHoveringUi = gameProcessed + end +end + +local function isGuiFocused() + return isMouseHoveringUi or GuiService.SelectedObject ~= nil +end + +UserInputService.InputChanged:Connect(onInputChanged) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Movement Goal +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local currentGoal, moveSignal + +local function findAngleBetweenXZVectors(vec2, vec1) + return math.atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z) +end + +local function isFinite(num) + return num == num and num ~= 1/0 and num ~= -1/0 +end + +local function rotateCameraTowardsGoal() + local c = workspace.CurrentCamera + if c then + local cf = c.CFrame + local focus = c.Focus + + local desiredAngle = CFrame.new(cf.p,currentGoal).lookVector + local currentAngle = cf.lookVector + + local angleBetween = findAngleBetweenXZVectors(desiredAngle,currentAngle) + + if isFinite(angleBetween) then + local abs = math.abs(angleBetween) + local sign = math.sign(angleBetween) + local rotation = math.min(0.01,abs) + + local cfLocal = focus:toObjectSpace(cf) + c.CFrame = focus * CFrame.Angles(0,-rotation*sign,0) * cfLocal + end + end +end + +local function finishGoal() + if currentGoal then + currentGoal = nil + end + if moveSignal then + moveSignal:Disconnect() + moveSignal = nil + end +end + +local function clickToMove(goal) + finishGoal() + currentGoal = goal + + moveSignal = humanoid.MoveToFinished:Connect(finishGoal) + + humanoid:Move(Vector3.new(1,1,1)) + humanoid:MoveTo(currentGoal) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Green Disk +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mouse = player:GetMouse() +local mouseIcon = script.Parent +mouse.TargetFilter = workspace.CurrentCamera + +local lastTarget +local lastTargetCanClick = false + +local disk = Instance.new("CylinderHandleAdornment") +disk.Name = "Disk" +disk.Color3 = Color3.new(0,1,0) +disk.Radius = 1 +disk.Height = 0.2 +disk.Visible = false +disk.Adornee = workspace.Terrain +disk.Parent = script + +local goalDisk = disk:Clone() +goalDisk.Name = "Goal" +goalDisk.Parent = script + +local function hasTool() + if character then + return character:FindFirstChildOfClass("Tool") ~= nil + end + + return false +end + +local function isFirstPerson() + if character then + local head = character:FindFirstChild("Head") + if head then + return head.LocalTransparencyModifier == 1 + end + end + return false +end + +local function canClickTarget() + local target = mouse.Target + if target then + if target ~= lastTarget then + local canClick = false + local clickDetector = target:FindFirstChildOfClass("ClickDetector") + + if clickDetector then + local dist = player:DistanceFromCharacter(target.Position) + if dist <= clickDetector.MaxActivationDistance then + canClick = true + end + end + + lastTarget = target + lastTargetCanClick = canClick + end + + return lastTargetCanClick + end +end + +local function canRenderDisk(rendering) + if not TeleportService:GetTeleportSetting("ClickToMove") then + return false + end + + if rendering and IS_TOUCH then + return false + end + + if humanoid then + local movement = humanoid.MoveDirection + if movement.Magnitude == 0 then + local pos = mouse.Hit.p + local dist = player:DistanceFromCharacter(pos) + + if dist < 32 then + local blockers = {hasTool, isFirstPerson, canClickTarget, isGuiFocused} + + for _,blocker in pairs(blockers) do + if blocker() then + return false + end + end + + return true + end + else + finishGoal() + end + end + + return false +end + +local function render3dAdorn() + disk.Visible = canRenderDisk(true) + + if disk.Visible then + disk.CFrame = CFrame.new(mouse.Hit.p) * DISK_OFFSET + mouseIcon.Image = ICON_HOVER + elseif canClickTarget() then + mouseIcon.Image = ICON_CLICK + elseif not hasTool() then + mouseIcon.Image = ICON_IDLE + end + + if currentGoal then + goalDisk.Visible = true + goalDisk.CFrame = CFrame.new(currentGoal) * DISK_OFFSET + rotateCameraTowardsGoal() + else + goalDisk.Visible = false + end +end + +RunService.Heartbeat:Connect(render3dAdorn) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Click Action +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function onInputBegan(input,gameProcessed) + local goal = mouse.Hit.p + if not gameProcessed and canRenderDisk() and humanoid then + local name = input.UserInputType.Name + + if name == "MouseButton1" then + clickToMove(goal) + elseif name == "Touch" then + wait(.1) + if input.UserInputState == Enum.UserInputState.End then + clickToMove(goal) + end + elseif name == "Gamepad1" then + if input.KeyCode == Enum.KeyCode.ButtonR2 then + clickToMove(goal) + end + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- OBLITERATE the invasive click to move mode that Roblox provides +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +pcall(function () + if IS_TOUCH then + local playerScripts = player:WaitForChild("PlayerScripts") + local no = function () end + + spawn(function () + local controlScript = playerScripts:WaitForChild("ControlScript", 86400) + if controlScript then + local masterControl = controlScript:WaitForChild("MasterControl") + + local clickToMove = masterControl:WaitForChild("ClickToMoveController") + clickToMove = require(clickToMove) + + clickToMove:Disable() + clickToMove.Enable = no + end + end) + + spawn(function () + local playerModule = playerScripts:WaitForChild("PlayerModule", 86400) + if playerModule then + local controlModule = playerModule:WaitForChild("ControlModule") + + local clickToMove = controlModule:WaitForChild("ClickToMoveController") + clickToMove = require(clickToMove) + + clickToMove:Stop() + clickToMove.Enable = no + end + end) + end +end) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Client/ConsoleTweaks.client.lua b/Client/ConsoleTweaks.client.lua new file mode 100644 index 0000000..dcfee95 --- /dev/null +++ b/Client/ConsoleTweaks.client.lua @@ -0,0 +1,34 @@ +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +local function addUIScale(obj,scale) + local uiScale = Instance.new("UIScale") + uiScale.Scale = scale + uiScale.Parent = obj +end + +if GuiService:IsTenFootInterface() then + local gui = script.Parent + local zoomControls = gui:WaitForChild("ZoomControls") + zoomControls.Visible = false + + local backpack = gui:WaitForChild("Backpack") + backpack.Position = UDim2.new(0, 0, 1, 0) + + local chat = gui:WaitForChild("Chat") + addUIScale(chat, 1.5) + + local chatPadding = gui:WaitForChild("ChatPadding", 1) + if chatPadding then + chatPadding:Destroy() + end + + local safeChat = gui:WaitForChild("SafeChat") + addUIScale(safeChat, 1.5) + + local health = gui:WaitForChild("Health") + addUIScale(health, 1.5) +end + +wait() +script:Destroy() \ No newline at end of file diff --git a/Client/Explosions/ClassicExp.rbxmx b/Client/Explosions/ClassicExp.rbxmx new file mode 100644 index 0000000..e79d7c2 --- /dev/null +++ b/Client/Explosions/ClassicExp.rbxmx @@ -0,0 +1,38 @@ + + + + + 0 + 0 + 0 + + + 0 1 1 1 0 1 0.498039 0.498039 0.498039 0 + 0 + 1 + false + 0.3 0.5 + 1 + 0 + false + ClassicExp + 500 + 0 0 + 0 0 + 0 3 1.1875 0.75 2.62 0 1 0 0 + 20 25 + + 360 + 360 + + + + rbxassetid://334788053 + + 0 0 0 0.993111 0.1625 0 1 1 0 + 0 + 3 + true + + + \ No newline at end of file diff --git a/Client/Explosions/init.client.lua b/Client/Explosions/init.client.lua new file mode 100644 index 0000000..b559745 --- /dev/null +++ b/Client/Explosions/init.client.lua @@ -0,0 +1,50 @@ +local TeleportService = game:GetService("TeleportService") + +local classicExp = script:WaitForChild("ClassicExp") +local c = workspace.CurrentCamera + +local baseExpAdorn = Instance.new("UnionOperation") +baseExpAdorn.Name = "ExplosionAdorn" +baseExpAdorn.Anchored = true +baseExpAdorn.CanCollide = false +baseExpAdorn.Locked = true +baseExpAdorn.Transparency = 1 +baseExpAdorn.Size = Vector3.new() + +local function onDescendantAdded(exp) + if exp:IsA("Explosion") then + local cf = CFrame.new(exp.Position) + local expAdorn = baseExpAdorn:Clone() + local lifeTime = 1.5 + exp.Visible = false + if TeleportService:GetTeleportSetting("RetroExplosions") then + local expObj = Instance.new("SphereHandleAdornment") + expObj.Adornee = expAdorn + expObj.Radius = exp.BlastRadius + expObj.Color3 = Color3.new(1,0,0) + expObj.CFrame = cf + expObj.Parent = expAdorn + lifeTime = 1 + if exp.BlastRadius > 1 then + lifeTime = lifeTime - (1/exp.BlastRadius) + end + else + spawn(function () + local e = classicExp:Clone() + e.Parent = expAdorn + expAdorn.CFrame = cf + local lessParticles = TeleportService:GetTeleportSetting("ReducedParticles") + local count = lessParticles and 25 or 100 + for i = 1,8 do + e:Emit(count) + wait(0.125) + end + end) + end + expAdorn.Parent = c + wait(lifeTime) + expAdorn:Destroy() + end +end + +workspace.DescendantAdded:Connect(onDescendantAdded) \ No newline at end of file diff --git a/Client/ForceFields.client.lua b/Client/ForceFields.client.lua new file mode 100644 index 0000000..814f3a2 --- /dev/null +++ b/Client/ForceFields.client.lua @@ -0,0 +1,55 @@ +local RunService = game:GetService("RunService") + +local ffAdorns = workspace:WaitForChild("_ForceFieldAdorns") +local registry = {} +local cycleStates = {} +local cycles = 60 + +local function onChildAdded(child) + if child:IsA("SelectionBox") then + spawn(function () + while not child.Adornee do + child.Changed:Wait() + end + registry[child] = child.Adornee + end) + end +end + +local function onChildRemoved(child) + if registry[child] then + registry[child] = nil + end +end + +local function update() + local now = tick() + for adorn,adornee in pairs(registry) do + local model = adornee:FindFirstAncestorWhichIsA("Model") + local key + if model then + local key = model:GetFullName() + local startTime = cycleStates[key] + if not startTime then + startTime = tick() + cycleStates[key] = startTime + end + local cycle = math.floor(((now-startTime)*2) * cycles) % (cycles*2) + if cycle > cycles then + cycle = cycles - (cycle - cycles) + end + local invertCycle = cycles - cycle + adorn.Color3 = Color3.new(cycle/cycles, 0, invertCycle/cycles) + adorn.Transparency = 0 + end + adorn.Visible = adornee:IsDescendantOf(workspace) and adornee.LocalTransparencyModifier < 1 + end +end + +for _,v in pairs(ffAdorns:GetChildren()) do + onChildAdded(v) +end + +RunService.Heartbeat:Connect(update) +ffAdorns.ChildAdded:Connect(onChildAdded) +ffAdorns.ChildRemoved:Connect(onChildRemoved) \ No newline at end of file diff --git a/Client/GamepadPatch.client.lua b/Client/GamepadPatch.client.lua new file mode 100644 index 0000000..2a0cae9 --- /dev/null +++ b/Client/GamepadPatch.client.lua @@ -0,0 +1,29 @@ +-- Seriously Roblox? + +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") + +local player = Players.LocalPlayer +local playerScripts = player:WaitForChild("PlayerScripts") + +local playerModule = playerScripts:WaitForChild("PlayerModule") +local controlModule = playerModule:WaitForChild("ControlModule") +local gamepad = require(controlModule:WaitForChild("Gamepad")) + +playerModule = require(playerModule) +controlModule = playerModule:GetControls() + +local function fixGamepad() + local lastInputType = UserInputService:GetLastInputType() + + if lastInputType.Name == "Gamepad1" then + local controllers = controlModule.controllers + + if controlModule.activeController ~= controllers[gamepad] then + controlModule:SwitchToController(gamepad) + end + end +end + +RunService:BindToRenderStep("GamepadPatch", 0, fixGamepad) \ No newline at end of file diff --git a/Client/HumanoidLabels/Health.rbxmx b/Client/HumanoidLabels/Health.rbxmx new file mode 100644 index 0000000..a39636c --- /dev/null +++ b/Client/HumanoidLabels/Health.rbxmx @@ -0,0 +1,237 @@ + + + + false + null + true + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 0 + INF + Health + null + true + null + + 0 + 96 + 0 + 24 + + + 0 + 0 + + + 0 + 0 + 0 + + + 0 + 1.5 + 0 + + + 0 + true + + + + false + + 0.5 + 0.75 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + PlayerName + null + null + null + null + + 0.5 + 0 + 0 + 0 + + null + 0 + false + null + + 10 + 0 + 1 + 0 + + 0 + + CloneTrooper1019 + + 1 + 1 + 1 + + true + 24 + + 0 + 0 + 0 + + 0 + 0 + 0 + true + 2 + 1 + true + 1 + true + + + + + false + + 0.5 + 0.5 + + + true + + 1 + 0 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + RedBar + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.6 + 0 + 0.3 + 0 + + 0 + 0 + + true + 1 + true + + + + false + + 0 + 0 + + + true + + 0.5058824 + 0.7725491 + 0.08627451 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + GreenBar + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/Client/HumanoidLabels/init.client.lua b/Client/HumanoidLabels/init.client.lua new file mode 100644 index 0000000..191d4f8 --- /dev/null +++ b/Client/HumanoidLabels/init.client.lua @@ -0,0 +1,139 @@ +local humanoids = {} +local player = game.Players.LocalPlayer +local pgui = player:WaitForChild("PlayerGui") +local healthBase = script:WaitForChild("Health") +local rs = game:GetService("RunService") + +local farStudsOffset = Vector3.new(0,2,0) +local closeStudsOffset = Vector3.new(0,1,0) + +local farSize = UDim2.new(0,50,0,20) +local closeSize = UDim2.new(0,100,0,30) + +local function isFinite(num) + return num == num and num ~= -1/0 and num ~= 1/0 +end + +local function setupHumanoid(h) + local updateCon = nil + local currentHealth = nil + + local function onAncestryChanged() + if updateCon then + updateCon:disconnect() + updateCon = nil + end + + if currentHealth then + currentHealth:Destroy() + currentHealth = nil + end + + local char = h.Parent + + if char then + while not char:FindFirstChild("Head") do + if h.Parent ~= char then break end + char.ChildAdded:wait() + end + + local head = char:FindFirstChild("Head") + + if head then + local health = healthBase:Clone() + local playerName = health:WaitForChild("PlayerName") + local redBar = health:WaitForChild("RedBar") + local greenBar = redBar:WaitForChild("GreenBar") + local inOverWrite = false + local overWriter = nil + + local hPlayer = game.Players:GetPlayerFromCharacter(char) + playerName.Text = char.Name + health.Adornee = head + health.PlayerToHideFrom = hPlayer + health.Parent = head + + local c = workspace.CurrentCamera + + local function update() + local dist = (c.CFrame.p - head.Position).magnitude + local fontSize = 12 + + if dist < 20 then + fontSize = 24 + elseif dist < 50 then + fontSize = 18 + end + + local ratio = h.Health / h.MaxHealth + redBar.Visible = isFinite(ratio) + redBar.BackgroundTransparency = math.floor(ratio) + redBar.Size = UDim2.new(0, fontSize * 4, 0, fontSize / 2) + greenBar.Size = UDim2.new(ratio, 0, 1, 0) + + local width = fontSize * 4 + health.Size = UDim2.new(0, width, 0, fontSize) + health.Enabled = (dist <= 100 and head.Transparency < 1) + health.StudsOffsetWorldSpace = Vector3.new(0, 1.5, 0) + + if hPlayer and game:FindService("Teams") then + playerName.TextColor = hPlayer.TeamColor + else + playerName.TextColor3 = Color3.new(1, 1, 1) + end + + local overWriter = char:FindFirstChild("NameOverwrite") + if overWriter and overWriter:IsA("StringValue") then + playerName.Text = overWriter.Value + else + playerName.Text = char.Name + end + end + + updateCon = rs.RenderStepped:Connect(update) + currentHealth = health + h.DisplayDistanceType = "None" + end + end + end + onAncestryChanged() + h.AncestryChanged:Connect(onAncestryChanged) +end + +local function recurse(obj) + for _,v in pairs(obj:GetChildren()) do + if v:IsA("Humanoid") then + humanoids[v] = true + else + recurse(v) + end + end +end + +recurse(workspace) + +for h in pairs(humanoids) do + humanoids[h] = true + + spawn(function () + setupHumanoid(h) + end) +end + +local function onDescendantAdded(child) + if child:IsA("Humanoid") then + humanoids[child] = true + setupHumanoid(child) + end +end + +local function onDescendantRemoved(child) + if humanoids[child] then + humanoids[child] = nil + end +end + +recurse(workspace) + +workspace.DescendantAdded:connect(onDescendantAdded) +workspace.DescendantRemoving:connect(onDescendantRemoved) \ No newline at end of file diff --git a/Client/InputGateway.client.lua b/Client/InputGateway.client.lua new file mode 100644 index 0000000..a61ce51 --- /dev/null +++ b/Client/InputGateway.client.lua @@ -0,0 +1,185 @@ +local UserInputService = game:GetService("UserInputService") +local ContextActionService = game:GetService("ContextActionService") +local Debris = game:GetService("Debris") + +local gateway = script.Parent +local tool = gateway.Parent +local remote = gateway:WaitForChild("Gateway") +local player = game.Players.LocalPlayer +local mouse = player:GetMouse() +local isActive = false + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Standard Input +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function activate(active,cf) + isActive = active + remote:FireServer("SetActive",active,cf) + while isActive do + wait(.1) + remote:FireServer("SetTarget",mouse.Hit) + end +end + +local function onKey(input) + local keyCode = input.KeyCode.Name + local down = (input.UserInputState.Name == "Begin") + remote:FireServer("KeyEvent",keyCode,down) +end + +local function onInputBegan(input,gameProcessed) + if not gameProcessed then + local name = input.UserInputType.Name + if name == "MouseButton1" then + activate(true,mouse.Hit) + elseif name == "Touch" then + wait(.1) + local state = input.UserInputState.Name + if state == "End" or state == "Cancel" then + activate(true,mouse.Hit) + end + elseif name == "Gamepad1" then + local keyCode = input.KeyCode.Name + if keyCode == "ButtonR2" then + activate(true,mouse.Hit) + end + elseif name == "Keyboard" then + onKey(input) + end + end +end + +local function onInputEnded(input,gameProcessed) + if not gameProcessed and isActive then + local name = input.UserInputType.Name + if name == "MouseButton1" or name == "Touch" or name == "Gamepad1" then + activate(false,mouse.Hit) + elseif name == "Keyboard" then + onKey(input) + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) +UserInputService.InputEnded:Connect(onInputEnded) + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Special case Input +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mControlScheme = tool:WaitForChild("ControlScheme",5) + +if mControlScheme then + local controlSchemeData = require(mControlScheme) + local controlScheme = controlSchemeData.Buttons + local activateContext = controlSchemeData.ActivateContext + local keyEvent = tool:WaitForChild("KeyEvent") + local callbacks = {} + + local hands = { L = "Left", R = "Right" } + local handTypes = {"Bumper","Trigger","Joystick (Press)"} + + local schemeDocs = + { + Keyboard = {"Hold Left Mouse Button - " .. activateContext}; + Gamepad = {"Hold Right Trigger - " .. activateContext}; + } + + for key,data in pairs(controlScheme) do + local down = false + callbacks[key] = function (actionName,inputState,inputObject) + if (inputState.Name == "Begin") and not down then + down = true + if data.Client then + keyEvent:Fire(key,true) + else + remote:FireServer("KeyEvent",key,true) + end + elseif (inputState.Name == "End") and down then + down = false + if data.Client then + keyEvent:Fire(key,false) + else + remote:FireServer("KeyEvent",key,false) + end + end + end + + local xBtn = data.XboxButton:gsub("Button","") + if #xBtn == 2 then + local handId,hTypeId = xBtn:match("(%u)(%d)") + local hand = hands[handId] + local hType = handTypes[tonumber(hTypeId)] + xBtn = hand .. " " .. hType + else + xBtn = "(" .. xBtn .. ")" + end + table.insert(schemeDocs.Keyboard,key .. " - " .. data.Label) + table.insert(schemeDocs.Gamepad,xBtn .. " - " .. data.Label) + end + + local currentSchemeDocMsg + + local function onLastInputTypeChanged(inputType) + if currentSchemeDocMsg and not UserInputService.TouchEnabled and not controlSchemeData.HideControls then + local schemeDoc + if inputType.Name:find("Gamepad") then + schemeDoc = "Gamepad" + else + schemeDoc = "Keyboard" + end + currentSchemeDocMsg.Text = schemeDoc .. " Controls:\n\n" .. table.concat(schemeDocs[schemeDoc],"\n") + end + end + + local diedCon + local equipped = false + + local function onUnequipped() + if equipped then + equipped = false + for key,data in pairs(controlScheme) do + ContextActionService:UnbindAction(data.Label) + end + currentSchemeDocMsg:Destroy() + currentSchemeDocMsg = nil + end + end + + local function onEquipped() + if not equipped then + equipped = true + for key,data in pairs(controlScheme) do + ContextActionService:BindAction(data.Label,callbacks[key],true,Enum.KeyCode[data.XboxButton]) + ContextActionService:SetTitle(data.Label,data.Label) + end + if UserInputService.TouchEnabled then + spawn(function () + local playerGui = player:WaitForChild("PlayerGui") + local contextActionGui = playerGui:WaitForChild("ContextActionGui") + local contextButtonFrame = contextActionGui:WaitForChild("ContextButtonFrame") + contextButtonFrame.Size = UDim2.new(3/8,0,3/8,0) + contextButtonFrame.AnchorPoint = Vector2.new(1,1) + contextButtonFrame.Position = UDim2.new(1,0,1,0) + end) + end + currentSchemeDocMsg = Instance.new("Message") + currentSchemeDocMsg.Parent = player + onLastInputTypeChanged(UserInputService:GetLastInputType()) + if not diedCon then + local char = tool.Parent + if char then + local humanoid = char:FindFirstChildWhichIsA("Humanoid") + if humanoid then + diedCon = humanoid.Died:Connect(onUnequipped) + end + end + end + end + end + + tool.Equipped:Connect(onEquipped) + tool.Unequipped:Connect(onUnequipped) + UserInputService.LastInputTypeChanged:Connect(onLastInputTypeChanged) +end \ No newline at end of file diff --git a/Client/Music.client.lua b/Client/Music.client.lua new file mode 100644 index 0000000..b1fde17 --- /dev/null +++ b/Client/Music.client.lua @@ -0,0 +1,5 @@ +local TeleportService = game:GetService("TeleportService") +local gameMusic = workspace:WaitForChild("GameMusic",10) +if gameMusic and TeleportService:GetTeleportSetting("AllowMusic") then + gameMusic:Play() +end \ No newline at end of file diff --git a/Client/Shared.client.lua b/Client/Shared.client.lua new file mode 100644 index 0000000..d359e26 --- /dev/null +++ b/Client/Shared.client.lua @@ -0,0 +1,9 @@ +local TARGET = script.Name + +do + local ReplicatedStorage = game:GetService("ReplicatedStorage") + local client = ReplicatedStorage:WaitForChild("Client") + local targetScript = client:WaitForChild(TARGET) + local activation = require(targetScript) + activation(script) +end \ No newline at end of file diff --git a/Client/ToolSoundGlitch.client.lua b/Client/ToolSoundGlitch.client.lua new file mode 100644 index 0000000..9a880e5 --- /dev/null +++ b/Client/ToolSoundGlitch.client.lua @@ -0,0 +1,12 @@ +local CollectionService = game:GetService("CollectionService") +local TeleportService = game:GetService("TeleportService") + +local function onGlitchSoundAdded(glitchSound) + if TeleportService:GetTeleportSetting("SoundEquipBug") then + glitchSound.MaxDistance = 10000 + glitchSound:Play() + end +end + +local addSignal = CollectionService:GetInstanceAddedSignal("ToolSoundGlitch") +addSignal:Connect(onGlitchSoundAdded) \ No newline at end of file diff --git a/DataModel/ReplicatedStorage/ChatRemote.rbxmx b/DataModel/ReplicatedStorage/ChatRemote.rbxmx new file mode 100644 index 0000000..720c5c2 --- /dev/null +++ b/DataModel/ReplicatedStorage/ChatRemote.rbxmx @@ -0,0 +1,10 @@ + + + + + ChatRemote + + true + + + \ No newline at end of file diff --git a/DataModel/ReplicatedStorage/RequestCharacter.rbxmx b/DataModel/ReplicatedStorage/RequestCharacter.rbxmx new file mode 100644 index 0000000..1cfc84b --- /dev/null +++ b/DataModel/ReplicatedStorage/RequestCharacter.rbxmx @@ -0,0 +1,10 @@ + + + + + RequestCharacter + + true + + + \ No newline at end of file diff --git a/DataModel/ReplicatedStorage/ScriptRef[SafeChatTree].txt b/DataModel/ReplicatedStorage/ScriptRef[SafeChatTree].txt new file mode 100644 index 0000000..8f3a782 --- /dev/null +++ b/DataModel/ReplicatedStorage/ScriptRef[SafeChatTree].txt @@ -0,0 +1 @@ +Shared/Safechat \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Badges].txt b/DataModel/ServerScriptService/ScriptRef[Badges].txt new file mode 100644 index 0000000..fa514df --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Badges].txt @@ -0,0 +1 @@ +Server/Badges \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Bevels].txt b/DataModel/ServerScriptService/ScriptRef[Bevels].txt new file mode 100644 index 0000000..a3bc009 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Bevels].txt @@ -0,0 +1 @@ +Server/Bevels \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[BuildTools].txt b/DataModel/ServerScriptService/ScriptRef[BuildTools].txt new file mode 100644 index 0000000..1b9f538 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[BuildTools].txt @@ -0,0 +1 @@ +Server/BuildTools \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[CaptureTheFlag].txt b/DataModel/ServerScriptService/ScriptRef[CaptureTheFlag].txt new file mode 100644 index 0000000..08d6ad1 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[CaptureTheFlag].txt @@ -0,0 +1 @@ +Server/CaptureTheFlag \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Characters].txt b/DataModel/ServerScriptService/ScriptRef[Characters].txt new file mode 100644 index 0000000..d3368f9 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Characters].txt @@ -0,0 +1 @@ +Server/Characters \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Chat].txt b/DataModel/ServerScriptService/ScriptRef[Chat].txt new file mode 100644 index 0000000..6b38a1b --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Chat].txt @@ -0,0 +1 @@ +Server/Chat \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Cylinders].txt b/DataModel/ServerScriptService/ScriptRef[Cylinders].txt new file mode 100644 index 0000000..d8fc0a5 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Cylinders].txt @@ -0,0 +1 @@ +Server/Cylinders \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Explosions].txt b/DataModel/ServerScriptService/ScriptRef[Explosions].txt new file mode 100644 index 0000000..9a83a88 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Explosions].txt @@ -0,0 +1 @@ +Server/Explosions \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[ForceFields].txt b/DataModel/ServerScriptService/ScriptRef[ForceFields].txt new file mode 100644 index 0000000..73b7a11 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[ForceFields].txt @@ -0,0 +1 @@ +Server/ForceFields \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[HatGranter].txt b/DataModel/ServerScriptService/ScriptRef[HatGranter].txt new file mode 100644 index 0000000..2a748f4 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[HatGranter].txt @@ -0,0 +1 @@ +Server/HatGranter \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Heads].txt b/DataModel/ServerScriptService/ScriptRef[Heads].txt new file mode 100644 index 0000000..41e6d52 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Heads].txt @@ -0,0 +1 @@ +Server/Heads \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Leaderboard].txt b/DataModel/ServerScriptService/ScriptRef[Leaderboard].txt new file mode 100644 index 0000000..0e2f085 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Leaderboard].txt @@ -0,0 +1 @@ +Server/Leaderboard \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[LoadTools].txt b/DataModel/ServerScriptService/ScriptRef[LoadTools].txt new file mode 100644 index 0000000..a6ef3fb --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[LoadTools].txt @@ -0,0 +1 @@ +Server/LoadTools \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Parts].txt b/DataModel/ServerScriptService/ScriptRef[Parts].txt new file mode 100644 index 0000000..53e206d --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Parts].txt @@ -0,0 +1 @@ +Server/Parts \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Regeneration].txt b/DataModel/ServerScriptService/ScriptRef[Regeneration].txt new file mode 100644 index 0000000..5e0880b --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Regeneration].txt @@ -0,0 +1 @@ +Server/Regeneration \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[SessionTracker].txt b/DataModel/ServerScriptService/ScriptRef[SessionTracker].txt new file mode 100644 index 0000000..a777492 --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[SessionTracker].txt @@ -0,0 +1 @@ +Server/SessionTracker \ No newline at end of file diff --git a/DataModel/ServerScriptService/ScriptRef[Time].txt b/DataModel/ServerScriptService/ScriptRef[Time].txt new file mode 100644 index 0000000..63244ff --- /dev/null +++ b/DataModel/ServerScriptService/ScriptRef[Time].txt @@ -0,0 +1 @@ +Server/Time \ No newline at end of file diff --git a/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx b/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx new file mode 100644 index 0000000..65ffc6e --- /dev/null +++ b/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 1.800009 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + + 1 + 0.4 + 1 + + + -0.5 + 0.5 + 0 + 0 + false + false + 272 + + rbxassetid://3188648073 + + + rbxassetid://3188648073 + + 1.00 ~ 0.40 ~ 1.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1 + 0.4 + 1 + + 0 + true + + + + + + \ No newline at end of file diff --git a/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx b/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx new file mode 100644 index 0000000..e4dfcba --- /dev/null +++ b/DataModel/ServerStorage/CoreBevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 3 + 0 + -0.5 + 0.5 + 3 + 0 + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 3 + 0 + + 1 + 1 + 4 + + + -0.5 + 0.5 + 3 + 0 + false + false + 272 + + rbxassetid://3188498185 + + + rbxassetid://3188498185 + + 1.00 ~ 1.00 ~ 4.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + + 1 + 1 + 4 + + 0 + true + + + + + + \ No newline at end of file diff --git a/DataModel/ServerStorage/CoreBevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx b/DataModel/ServerStorage/CoreBevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx new file mode 100644 index 0000000..6271c1c --- /dev/null +++ b/DataModel/ServerStorage/CoreBevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 11.80001 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + + 2 + 1.2 + 4 + + + -0.5 + 0.5 + 0 + 0 + false + false + 272 + + rbxassetid://3188159241 + + + rbxassetid://3188159241 + + 2.00 ~ 1.20 ~ 4.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 2 + 1.2 + 4 + + 0 + true + + + + + + \ No newline at end of file diff --git a/DataModel/ServerStorage/GrantHatToUser.rbxmx b/DataModel/ServerStorage/GrantHatToUser.rbxmx new file mode 100644 index 0000000..fb38727 --- /dev/null +++ b/DataModel/ServerStorage/GrantHatToUser.rbxmx @@ -0,0 +1,10 @@ + + + + + GrantHatToUser + + true + + + \ No newline at end of file diff --git a/DataModel/ServerStorage/InputGateway/Gateway.rbxmx b/DataModel/ServerStorage/InputGateway/Gateway.rbxmx new file mode 100644 index 0000000..55f7415 --- /dev/null +++ b/DataModel/ServerStorage/InputGateway/Gateway.rbxmx @@ -0,0 +1,10 @@ + + + + + Gateway + + true + + + \ No newline at end of file diff --git a/DataModel/ServerStorage/InputGateway/ScriptRef[Client].txt b/DataModel/ServerStorage/InputGateway/ScriptRef[Client].txt new file mode 100644 index 0000000..6ed542c --- /dev/null +++ b/DataModel/ServerStorage/InputGateway/ScriptRef[Client].txt @@ -0,0 +1 @@ +Client/InputGateway \ No newline at end of file diff --git a/DataModel/ServerStorage/InputGateway/ScriptRef[Server].txt b/DataModel/ServerStorage/InputGateway/ScriptRef[Server].txt new file mode 100644 index 0000000..c6b231b --- /dev/null +++ b/DataModel/ServerStorage/InputGateway/ScriptRef[Server].txt @@ -0,0 +1 @@ +Server/InputGateway \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[Animate].txt b/DataModel/StarterCharacterScripts/ScriptRef[Animate].txt new file mode 100644 index 0000000..2ff7774 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[Animate].txt @@ -0,0 +1 @@ +Character/Animate \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[BouncinessReplica].txt b/DataModel/StarterCharacterScripts/ScriptRef[BouncinessReplica].txt new file mode 100644 index 0000000..c50d43d --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[BouncinessReplica].txt @@ -0,0 +1 @@ +Character/Bounciness \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[DropHats].txt b/DataModel/StarterCharacterScripts/ScriptRef[DropHats].txt new file mode 100644 index 0000000..e8d2c28 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[DropHats].txt @@ -0,0 +1 @@ +Character/DropHats \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[EdgeWalking].txt b/DataModel/StarterCharacterScripts/ScriptRef[EdgeWalking].txt new file mode 100644 index 0000000..ab00f28 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[EdgeWalking].txt @@ -0,0 +1 @@ +Character/EdgeWalking \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[FloorDrag].txt b/DataModel/StarterCharacterScripts/ScriptRef[FloorDrag].txt new file mode 100644 index 0000000..679232f --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[FloorDrag].txt @@ -0,0 +1 @@ +Character/FloorDrag \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[GoofyBalance].txt b/DataModel/StarterCharacterScripts/ScriptRef[GoofyBalance].txt new file mode 100644 index 0000000..07081df --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[GoofyBalance].txt @@ -0,0 +1 @@ +Character/GoofyBalance \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[GoofyMotion].txt b/DataModel/StarterCharacterScripts/ScriptRef[GoofyMotion].txt new file mode 100644 index 0000000..907b0a3 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[GoofyMotion].txt @@ -0,0 +1 @@ +Character/GoofyMotion \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[InputGateway].txt b/DataModel/StarterCharacterScripts/ScriptRef[InputGateway].txt new file mode 100644 index 0000000..6e56109 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[InputGateway].txt @@ -0,0 +1 @@ +Character/InputGateway \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[JumpLimiter].txt b/DataModel/StarterCharacterScripts/ScriptRef[JumpLimiter].txt new file mode 100644 index 0000000..f33b63b --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[JumpLimiter].txt @@ -0,0 +1 @@ +Character/JumpLimiter \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[RetroClimbing].txt b/DataModel/StarterCharacterScripts/ScriptRef[RetroClimbing].txt new file mode 100644 index 0000000..741473f --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[RetroClimbing].txt @@ -0,0 +1 @@ +Character/RetroClimbing \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[Sound].txt b/DataModel/StarterCharacterScripts/ScriptRef[Sound].txt new file mode 100644 index 0000000..9cca5fd --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[Sound].txt @@ -0,0 +1 @@ +Character/Sound \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[TeamColorScript].txt b/DataModel/StarterCharacterScripts/ScriptRef[TeamColorScript].txt new file mode 100644 index 0000000..d252674 --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[TeamColorScript].txt @@ -0,0 +1 @@ +Character/TeamColors \ No newline at end of file diff --git a/DataModel/StarterCharacterScripts/ScriptRef[ToolSoundGlitch].txt b/DataModel/StarterCharacterScripts/ScriptRef[ToolSoundGlitch].txt new file mode 100644 index 0000000..fd1141e --- /dev/null +++ b/DataModel/StarterCharacterScripts/ScriptRef[ToolSoundGlitch].txt @@ -0,0 +1 @@ +Character/ToolSoundGlitch \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/Backpack/ScriptRef[BackpackScript].txt b/DataModel/StarterGui/UI/RootFrame/Backpack/ScriptRef[BackpackScript].txt new file mode 100644 index 0000000..a4c82be --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/Backpack/ScriptRef[BackpackScript].txt @@ -0,0 +1 @@ +Client/Backpack \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/Chat/ScriptRef[ChatScript].txt b/DataModel/StarterGui/UI/RootFrame/Chat/ScriptRef[ChatScript].txt new file mode 100644 index 0000000..09237ac --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/Chat/ScriptRef[ChatScript].txt @@ -0,0 +1 @@ +Client/ChatScript \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[ClickToMove].txt b/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[ClickToMove].txt new file mode 100644 index 0000000..e26dc43 --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[ClickToMove].txt @@ -0,0 +1 @@ +Client/ClickToMove \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[Mouse].txt b/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[Mouse].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/ClassicMouse/ScriptRef[Mouse].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/Health/ScriptRef[HealthScript].txt b/DataModel/StarterGui/UI/RootFrame/Health/ScriptRef[HealthScript].txt new file mode 100644 index 0000000..ec49814 --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/Health/ScriptRef[HealthScript].txt @@ -0,0 +1 @@ +Client/Health \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/PlayerList/ScriptRef[PlayerList].txt b/DataModel/StarterGui/UI/RootFrame/PlayerList/ScriptRef[PlayerList].txt new file mode 100644 index 0000000..cdc323e --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/PlayerList/ScriptRef[PlayerList].txt @@ -0,0 +1 @@ +Client/PlayerList \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/SafeChat/ScriptRef[SafeChatScript].txt b/DataModel/StarterGui/UI/RootFrame/SafeChat/ScriptRef[SafeChatScript].txt new file mode 100644 index 0000000..670e36f --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/SafeChat/ScriptRef[SafeChatScript].txt @@ -0,0 +1 @@ +Client/Safechat \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/ScriptRef[ConsoleTweaks].txt b/DataModel/StarterGui/UI/RootFrame/ScriptRef[ConsoleTweaks].txt new file mode 100644 index 0000000..fc9aa75 --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/ScriptRef[ConsoleTweaks].txt @@ -0,0 +1 @@ +Client/ConsoleTweaks \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/ScriptRef[MessageScript].txt b/DataModel/StarterGui/UI/RootFrame/ScriptRef[MessageScript].txt new file mode 100644 index 0000000..ef6c229 --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/ScriptRef[MessageScript].txt @@ -0,0 +1 @@ +Client/Messages \ No newline at end of file diff --git a/DataModel/StarterGui/UI/RootFrame/ZoomControls/ScriptRef[ZoomControls].txt b/DataModel/StarterGui/UI/RootFrame/ZoomControls/ScriptRef[ZoomControls].txt new file mode 100644 index 0000000..535d78f --- /dev/null +++ b/DataModel/StarterGui/UI/RootFrame/ZoomControls/ScriptRef[ZoomControls].txt @@ -0,0 +1 @@ +Client/ZoomControls \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/PassCameraEvent.rbxmx b/DataModel/StarterPlayerScripts/PassCameraEvent.rbxmx new file mode 100644 index 0000000..aa15364 --- /dev/null +++ b/DataModel/StarterPlayerScripts/PassCameraEvent.rbxmx @@ -0,0 +1,10 @@ + + + + + PassCameraEvent + + true + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Animator].txt b/DataModel/StarterPlayerScripts/ScriptRef[Animator].txt new file mode 100644 index 0000000..fd12a68 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Animator].txt @@ -0,0 +1 @@ +Client/Animator \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[CharacterBevels].txt b/DataModel/StarterPlayerScripts/ScriptRef[CharacterBevels].txt new file mode 100644 index 0000000..3cd51b9 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[CharacterBevels].txt @@ -0,0 +1 @@ +Client/CharacterBevels \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Explosions].txt b/DataModel/StarterPlayerScripts/ScriptRef[Explosions].txt new file mode 100644 index 0000000..c44cc0b --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Explosions].txt @@ -0,0 +1 @@ +Client/Explosions \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[ForceFields].txt b/DataModel/StarterPlayerScripts/ScriptRef[ForceFields].txt new file mode 100644 index 0000000..9f61fe8 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[ForceFields].txt @@ -0,0 +1 @@ +Client/ForceFields \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[FpsCap].txt b/DataModel/StarterPlayerScripts/ScriptRef[FpsCap].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[FpsCap].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[GamepadPatch].txt b/DataModel/StarterPlayerScripts/ScriptRef[GamepadPatch].txt new file mode 100644 index 0000000..cb610e4 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[GamepadPatch].txt @@ -0,0 +1 @@ +Client/GamepadPatch \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[HumanoidLabels].txt b/DataModel/StarterPlayerScripts/ScriptRef[HumanoidLabels].txt new file mode 100644 index 0000000..d8fbc00 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[HumanoidLabels].txt @@ -0,0 +1 @@ +Client/HumanoidLabels \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[LensFlare].txt b/DataModel/StarterPlayerScripts/ScriptRef[LensFlare].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[LensFlare].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[LensFlare]/Moon.rbxmx b/DataModel/StarterPlayerScripts/ScriptRef[LensFlare]/Moon.rbxmx new file mode 100644 index 0000000..1bfd638 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[LensFlare]/Moon.rbxmx @@ -0,0 +1,194 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 511.7728 + 175.8011 + 482.2249 + 0.74845 + -0.2371427 + 0.6193432 + 1.490116E-08 + 0.9338833 + 0.3575782 + -0.6631912 + -0.2676294 + 0.698965 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Moon + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 100 + 100 + 1 + + true + + + + true + null + false + + true + + 800 + 800 + + false + true + 5 + 0 + MoonGui + 50 + true + null + 0 + + 0 + 0 + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + rbxassetid://599112257 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + MoonImage + null + null + null + null + + -0.5 + 0 + -0.5 + 0 + + null + 0 + 0 + false + null + + 2 + 0 + 2 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Moon].txt b/DataModel/StarterPlayerScripts/ScriptRef[Moon].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Moon].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Moon]/Moon.rbxmx b/DataModel/StarterPlayerScripts/ScriptRef[Moon]/Moon.rbxmx new file mode 100644 index 0000000..6540e52 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Moon]/Moon.rbxmx @@ -0,0 +1,194 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 511.7728 + 175.8011 + 482.2249 + 0.74845 + -0.2371427 + 0.6193432 + 1.490116E-08 + 0.9338833 + 0.3575782 + -0.6631912 + -0.2676294 + 0.698965 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Moon + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 80 + 80 + 1 + + true + + + + true + null + false + + true + + 800 + 800 + + false + true + 5 + 0 + MoonGui + 50 + true + null + 0 + + 0 + 0 + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + rbxassetid://599112257 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + MoonImage + null + null + null + null + + -0.5 + 0 + -0.5 + 0 + + null + 0 + 0 + false + null + + 2 + 0 + 2 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Music].txt b/DataModel/StarterPlayerScripts/ScriptRef[Music].txt new file mode 100644 index 0000000..bff4c2a --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Music].txt @@ -0,0 +1 @@ +Client/Music \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[RetroCam].txt b/DataModel/StarterPlayerScripts/ScriptRef[RetroCam].txt new file mode 100644 index 0000000..3f75c4b --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[RetroCam].txt @@ -0,0 +1 @@ +Client/Camera \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Sky].txt b/DataModel/StarterPlayerScripts/ScriptRef[Sky].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Sky].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Sky]/SkyAdorn.rbxmx b/DataModel/StarterPlayerScripts/ScriptRef[Sky]/SkyAdorn.rbxmx new file mode 100644 index 0000000..385533a --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Sky]/SkyAdorn.rbxmx @@ -0,0 +1,186 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 491.4301 + 0.025031 + 324.0601 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + SkyAdorn + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 0.05 + 0.05 + 0.05 + + true + + + + false + null + false + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 1 + INF + Night + null + true + null + + 0 + 3000 + 0 + 3000 + + + 0 + 0 + + + 0 + 0 + -3000 + + + 0 + 0 + 0 + + + 0 + true + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + NightFrame + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[Sky]/Star.rbxmx b/DataModel/StarterPlayerScripts/ScriptRef[Sky]/Star.rbxmx new file mode 100644 index 0000000..5adffc2 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[Sky]/Star.rbxmx @@ -0,0 +1,109 @@ + + + + false + null + false + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 0 + INF + Star + null + true + null + + 0 + 3 + 0 + 3 + + + 0 + 0 + + + 0 + 0 + 0 + + + 0 + 0 + 0 + + + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Frame + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[SunRays].txt b/DataModel/StarterPlayerScripts/ScriptRef[SunRays].txt new file mode 100644 index 0000000..39014e6 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[SunRays].txt @@ -0,0 +1 @@ +Client/UnivShared \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[SunRays]/Moon.rbxmx b/DataModel/StarterPlayerScripts/ScriptRef[SunRays]/Moon.rbxmx new file mode 100644 index 0000000..8ec2944 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[SunRays]/Moon.rbxmx @@ -0,0 +1,194 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 511.7728 + 175.8011 + 482.2249 + 0.74845 + -0.2371427 + 0.6193432 + 1.490116E-08 + 0.9338833 + 0.3575782 + -0.6631912 + -0.2676294 + 0.698965 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Moon + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 100 + 100 + 1 + + true + + + + true + null + false + + true + + 800 + 800 + + false + true + 5 + 0 + MoonGui + 50 + true + null + 0 + + 0 + 0 + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + rbxassetid://599112257 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + MoonImage + null + null + null + null + + -0.5 + 0 + -0.5 + 0 + + null + 0 + 0 + false + null + + 2 + 0 + 2 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/DataModel/StarterPlayerScripts/ScriptRef[ToolSoundGlitch].txt b/DataModel/StarterPlayerScripts/ScriptRef[ToolSoundGlitch].txt new file mode 100644 index 0000000..a9edc75 --- /dev/null +++ b/DataModel/StarterPlayerScripts/ScriptRef[ToolSoundGlitch].txt @@ -0,0 +1 @@ +Client/ToolSoundGlitch \ No newline at end of file diff --git a/Resources/BevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx b/Resources/BevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx new file mode 100644 index 0000000..65ffc6e --- /dev/null +++ b/Resources/BevelCache/1.00 ~ 0.40 ~ 1.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 1.800009 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + + 1 + 0.4 + 1 + + + -0.5 + 0.5 + 0 + 0 + false + false + 272 + + rbxassetid://3188648073 + + + rbxassetid://3188648073 + + 1.00 ~ 0.40 ~ 1.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1 + 0.4 + 1 + + 0 + true + + + + + + \ No newline at end of file diff --git a/Resources/BevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx b/Resources/BevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx new file mode 100644 index 0000000..e4dfcba --- /dev/null +++ b/Resources/BevelCache/1.00 ~ 1.00 ~ 4.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 3 + 0 + -0.5 + 0.5 + 3 + 0 + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 3 + 0 + + 1 + 1 + 4 + + + -0.5 + 0.5 + 3 + 0 + false + false + 272 + + rbxassetid://3188498185 + + + rbxassetid://3188498185 + + 1.00 ~ 1.00 ~ 4.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + + 1 + 1 + 4 + + 0 + true + + + + + + \ No newline at end of file diff --git a/Resources/BevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx b/Resources/BevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx new file mode 100644 index 0000000..6271c1c --- /dev/null +++ b/Resources/BevelCache/2.00 ~ 1.20 ~ 4.00.rbxmx @@ -0,0 +1,99 @@ + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 11.80001 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + + 2 + 1.2 + 4 + + + -0.5 + 0.5 + 0 + 0 + false + false + 272 + + rbxassetid://3188159241 + + + rbxassetid://3188159241 + + 2.00 ~ 1.20 ~ 4.00 + +KXn2PVkmG8K5+S8Au8qxA== + + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 2 + 1.2 + 4 + + 0 + true + + + + + + \ No newline at end of file diff --git a/Resources/CharacterAssets/BodyColors.rbxmx b/Resources/CharacterAssets/BodyColors.rbxmx new file mode 100644 index 0000000..1935aac --- /dev/null +++ b/Resources/CharacterAssets/BodyColors.rbxmx @@ -0,0 +1,40 @@ + + + + + + 0.9607844 + 0.8039216 + 0.1882353 + + + 0.9607844 + 0.8039216 + 0.1882353 + + + 0.6431373 + 0.7411765 + 0.2784314 + + BodyColors + + 0.9607844 + 0.8039216 + 0.1882353 + + + 0.6431373 + 0.7411765 + 0.2784314 + + + + 0.0509804 + 0.4117647 + 0.6745098 + + true + + + \ No newline at end of file diff --git a/Resources/CharacterAssets/Pants.rbxmx b/Resources/CharacterAssets/Pants.rbxmx new file mode 100644 index 0000000..9598336 --- /dev/null +++ b/Resources/CharacterAssets/Pants.rbxmx @@ -0,0 +1,18 @@ + + + + + + 1 + 1 + 1 + + Pants + + rbxassetid://1110695628 + + + true + + + \ No newline at end of file diff --git a/Resources/CharacterAssets/Shirt.rbxmx b/Resources/CharacterAssets/Shirt.rbxmx new file mode 100644 index 0000000..d002a2b --- /dev/null +++ b/Resources/CharacterAssets/Shirt.rbxmx @@ -0,0 +1,18 @@ + + + + + + 1 + 1 + 1 + + Shirt + + rbxassetid://1110695025 + + + true + + + \ No newline at end of file diff --git a/Resources/CharacterAssets/ShirtGraphic.rbxmx b/Resources/CharacterAssets/ShirtGraphic.rbxmx new file mode 100644 index 0000000..677d710 --- /dev/null +++ b/Resources/CharacterAssets/ShirtGraphic.rbxmx @@ -0,0 +1,18 @@ + + + + + + 1 + 1 + 1 + + + + + ShirtGraphic + + true + + + \ No newline at end of file diff --git a/Resources/GameJoin/GuiRoot.rbxmx b/Resources/GameJoin/GuiRoot.rbxmx new file mode 100644 index 0000000..60e1ad3 --- /dev/null +++ b/Resources/GameJoin/GuiRoot.rbxmx @@ -0,0 +1,1169 @@ + + + + + true + 0 + true + false + GuiRoot + false + null + + 0 + true + + + + false + + 0 + 0 + + + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Topbar + null + null + null + null + + 0 + 80 + 0 + -36 + + null + 0 + false + null + + 0 + 660 + 0 + 27 + + 0 + 0 + + true + 1 + true + + + + true + + 0 + 0 + + + false + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + false + Exit + null + null + null + null + + 0 + 528 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + Exit + + 0.4039216 + 0.4039216 + 0.4039216 + + true + 14 + + 0.4039216 + 0.4039216 + 0.4039216 + + 0.9 + 0.3 + 0 + true + 0 + 1 + true + 1 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + true + + 0 + 0 + + + false + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + false + Help + null + null + null + null + + 0 + 396 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + Help... + + 0.4039216 + 0.4039216 + 0.4039216 + + true + 14 + + 0.4039216 + 0.4039216 + 0.4039216 + + 0.9 + 0.3 + 0 + true + 0 + 1 + true + 1 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + true + + 0 + 0 + + + false + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + false + Fullscreen + null + null + null + null + + 0 + 264 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + Fullscreen + + 0.4039216 + 0.4039216 + 0.4039216 + + true + 14 + + 0.4039216 + 0.4039216 + 0.4039216 + + 0.9 + 0.3 + 0 + true + 0 + 1 + true + 1 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + false + + 0 + 0 + + + false + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + false + Insert + null + null + null + null + + 0 + 132 + 0 + 0 + + null + 0 + true + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + Insert + + 0.627451 + 0.627451 + 0.627451 + + true + 14 + + 0.627451 + 0.627451 + 0.627451 + + 0.9 + 0.3 + 0 + true + 0 + 1 + true + 1 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + false + + 0 + 0 + + + false + true + + 0.6980392 + 0.6980392 + 0.6980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + false + Tools + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + true + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + Tools + + 0.627451 + 0.627451 + 0.627451 + + true + 14 + + 0.627451 + 0.627451 + 0.627451 + + 0.9 + 0.3 + 0 + true + 0 + 1 + true + 1 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + + false + + 0.5 + 0.5 + + + true + + 0.7058824 + 0.7058824 + 0.7058824 + + 0.5 + + 1 + 1 + 1 + + 0 + 3 + false + false + 0 + MessageGui + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.6 + 0 + 1 + 0 + + 0 + 0 + + false + 1 + true + + + + false + + 0 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + Message + null + null + null + null + + 0 + 0 + 0.5 + 0 + + null + 0 + false + null + + 1 + 0 + 0.125 + 0 + + 0 + + Connecting to server... + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.75 + 0 + 0 + true + 2 + 1 + true + 1 + true + + + + + 3 + 0 + + 1 + UIAspectRatioConstraint + + true + + + + + false + + 0 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + ExitOverride + null + null + null + null + + 0 + 0 + 0.5 + 0 + + null + 0 + false + null + + 1 + 0 + 0.25 + 0 + + 0 + + + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.75 + 0 + 0 + true + 2 + 1 + false + 1 + true + + + + + + true + + 0.5 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + true + + rbxassetid://1041546985 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + HelpWindow + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + 1 + false + null + + 0.8 + 0 + 0.7 + 0 + + 0 + + + 4 + 30 + + + 304 + 130 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 1 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + rbxassetid://1041647615 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + Help + null + null + null + null + + 0 + 4 + 0 + 31 + + null + 0 + 0 + false + null + + 1 + -8 + 1 + -36 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + 2.75 + 0 + + 0 + UIAspectRatioConstraint + + true + + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 2 + 0 + 1 + Title + null + null + null + null + + 0 + 5 + 0 + 0 + + null + 0 + false + null + + 0.9 + -10 + 0 + 30 + + 0 + + ROBLOX Help + + 1 + 1 + 1 + + false + 14 + + 0.4980392 + 0.4980392 + 0.4980392 + + 0.6 + 0 + 0 + false + 0 + 1 + true + 2 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 2 + 0 + 1 + Stroke + null + null + null + null + + 0 + 1 + 0 + 1 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + ROBLOX Help + + 0 + 0 + 0 + + false + 14 + + 1 + 1 + 1 + + 1 + 0 + 0 + false + 0 + 1 + true + 1 + true + + + + + + true + + 1 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + + + + + rbxassetid://1041651899 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + true + Close + null + null + null + null + + 1 + -5 + 0 + 5 + + + + + null + 0 + 0 + true + false + null + + 0 + 22 + 0 + 22 + + 1 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + + 2.5 + 0 + + 0 + UIAspectRatioConstraint + + true + + + + + \ No newline at end of file diff --git a/Resources/GameJoin/GuiRoot/Topbar/Buttons.client.lua b/Resources/GameJoin/GuiRoot/Topbar/Buttons.client.lua new file mode 100644 index 0000000..c795091 --- /dev/null +++ b/Resources/GameJoin/GuiRoot/Topbar/Buttons.client.lua @@ -0,0 +1,22 @@ +local topbar = script.Parent + +local function registerButton(btn) + if btn:IsA("TextButton") and btn.Active then + local function onMouseEnter() + btn.BackgroundTransparency = 0 + end + + local function onMouseLeave() + btn.BackgroundTransparency = 0.5 + end + + btn.MouseEnter:Connect(onMouseEnter) + btn.MouseLeave:Connect(onMouseLeave) + end +end + +for _,v in pairs(topbar:GetChildren()) do + registerButton(v) +end + +topbar.ChildAdded:Connect(registerButton) \ No newline at end of file diff --git a/Resources/GameJoin/GuiRoot/Topbar/Exit/Exit.client.lua b/Resources/GameJoin/GuiRoot/Topbar/Exit/Exit.client.lua new file mode 100644 index 0000000..8d6ec06 --- /dev/null +++ b/Resources/GameJoin/GuiRoot/Topbar/Exit/Exit.client.lua @@ -0,0 +1,55 @@ +local TeleportService = game:GetService("TeleportService") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +GuiService.AutoSelectGuiEnabled = false + +local btn = script.Parent +local topbar = btn.Parent +local root = topbar.Parent +local messageGui = root:WaitForChild("MessageGui") +local message = messageGui:WaitForChild("Message") +local exitOverride = messageGui:WaitForChild("ExitOverride") + +local function onClicked() + local visibleSignal = messageGui:GetPropertyChangedSignal("Visible") + message.Visible = false + exitOverride.Visible = true + messageGui.Visible = true + TeleportService:Teleport(998374377) + visibleSignal:Connect(function () + if not messageGui.Visible then + messageGui.Visible = true + end + end) +end + +if not GuiService:IsTenFootInterface() then + btn.MouseButton1Down:Connect(onClicked) +end + +local exitBuffer = "Continue holding down 'Back' to return to the menu.\nExiting in...\n%.1f" + +local function onInputBegan(input) + if input.KeyCode == Enum.KeyCode.ButtonSelect and not exitOverride.Visible and not messageGui.Visible then + messageGui.Visible = true + message.Size = exitOverride.Size + + local success = true + for i = 3,0,-.1 do + if input.UserInputState ~= Enum.UserInputState.Begin then + success = false + break + end + message.Text = exitBuffer:format(i) + wait(.1) + end + + if success then + onClicked() + else + messageGui.Visible = false + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) \ No newline at end of file diff --git a/Resources/GameJoin/GuiRoot/Topbar/Fullscreen/Fullscreen.client.lua b/Resources/GameJoin/GuiRoot/Topbar/Fullscreen/Fullscreen.client.lua new file mode 100644 index 0000000..43c70fb --- /dev/null +++ b/Resources/GameJoin/GuiRoot/Topbar/Fullscreen/Fullscreen.client.lua @@ -0,0 +1,31 @@ +local UserInputService = game:GetService("UserInputService") + +local btn = script.Parent +local gameSettings = UserSettings():GetService("UserGameSettings") +local player = game.Players.LocalPlayer + +local function onClick() + if not player:FindFirstChild("FullscreenMsg") then + local m = Instance.new("Message") + m.Name = "FullscreenMsg" + m.Text = "This button is just here for legacy aesthetics, and has no functionality." + if UserInputService.MouseEnabled and UserInputService.KeyboardEnabled then + m.Text = m.Text .. "\nPress F11 to toggle fullscreen!" + end + m.Parent = player + wait(3) + m:Destroy() + end +end + +local function update() + if gameSettings:InFullScreen() then + btn.Text = "\t\tx Fullscreen" + else + btn.Text = "\t\tFullscreen" + end +end + +update() +gameSettings.FullscreenChanged:connect(update) +btn.MouseButton1Down:Connect(onClick) \ No newline at end of file diff --git a/Resources/GameJoin/GuiRoot/Topbar/Help/Help.client.lua b/Resources/GameJoin/GuiRoot/Topbar/Help/Help.client.lua new file mode 100644 index 0000000..7f90875 --- /dev/null +++ b/Resources/GameJoin/GuiRoot/Topbar/Help/Help.client.lua @@ -0,0 +1,16 @@ +local help = script.Parent +local topbar = help.Parent +local root = topbar.Parent +local window = root:WaitForChild("HelpWindow") +local close = window:WaitForChild("Close") + +local function onOpen() + window.Visible = true +end + +local function onClose() + window.Visible = false +end + +help.MouseButton1Down:Connect(onOpen) +close.MouseButton1Down:Connect(onClose) \ No newline at end of file diff --git a/Resources/GameJoin/init.client.lua b/Resources/GameJoin/init.client.lua new file mode 100644 index 0000000..6069745 --- /dev/null +++ b/Resources/GameJoin/init.client.lua @@ -0,0 +1,160 @@ +local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local TeleportService = game:GetService("TeleportService") +local ReplicatedFirst = script.Parent +local JointsService = game:GetService("JointsService") + +do + local StarterGui = game:GetService("StarterGui") + + local function setCoreSafe(method,...) + while not pcall(StarterGui.SetCore, StarterGui, method,...) do + wait() + end + end + + spawn(function () + setCoreSafe("ResetButtonCallback", false) + end) + + setCoreSafe("TopbarEnabled", false) +end + +local player = game.Players.LocalPlayer +local playerGui = player:WaitForChild("PlayerGui") +local mouse = player:GetMouse() + +if not UserInputService.TouchEnabled then + mouse.Icon = "rbxassetid://334630296" +end + +local guiRoot = script:WaitForChild("GuiRoot") +guiRoot.Parent = playerGui + +ReplicatedFirst:RemoveDefaultLoadingScreen() + +if playerGui:FindFirstChild("ConnectingGui") then + playerGui.ConnectingGui:Destroy() +end + +if RunService:IsStudio() then + return +end + +local c = workspace.CurrentCamera +local IS_PHONE = c.ViewportSize.Y < 600 + +local topbar = guiRoot:WaitForChild("Topbar") + +if IS_PHONE then + local uiScale = Instance.new("UIScale") + uiScale.Scale = 0.6 + uiScale.Parent = topbar +end + +local messageGui = guiRoot:WaitForChild("MessageGui") +local message = messageGui:WaitForChild("Message") + +local partWatch = nil +local partQueue = {} + +local bricks = 0 +local connectors = 0 +local messageFormat = "Bricks: %d Connectors: %d" + +--------------------------------------------------------------------- + +local fakeLoadTime = TeleportService:GetTeleportSetting("FakeLoadTime") + +local function onDescendantAdded(desc) + if desc:IsA("BasePart") and not desc:IsA("Terrain") then + if not CollectionService:HasTag(desc, "AxisPart") and desc.Name ~= "__negatepart" then + desc.LocalTransparencyModifier = 1 + partQueue[#partQueue + 1] = desc + end + elseif desc:IsA("Decal") then + desc.LocalTransparencyModifier = 1 + end +end + +if fakeLoadTime then + local descendants = workspace:GetDescendants() + + for _,desc in pairs(descendants) do + onDescendantAdded(desc) + end + + partWatch = workspace.DescendantAdded:Connect(onDescendantAdded) +end + +--------------------------------------------------------------------- + +local c = workspace.CurrentCamera +c.CameraType = "Follow" +c.CameraSubject = workspace + +messageGui.Visible = true + +local bricks = 0 +local connectors = 0 +local lastUpdate = 0 + +local done = false + +local function stepBrickConnectorStatus() + if fakeLoadTime then + wait(math.random() / 4) + + for i = 1, math.random(30, 50) do + local part = table.remove(partQueue) + + if part then + bricks = bricks + 1 + + connectors = connectors + #part:GetJoints() + part.LocalTransparencyModifier = 0 + + for _,v in pairs(part:GetDescendants()) do + if v:IsA("Decal") then + v.LocalTransparencyModifier = 0 + end + end + end + end + + done = (#partQueue == 0) + else + wait() + done = game:IsLoaded() + end +end + +while not done do + stepBrickConnectorStatus() + message.Text = messageFormat:format(bricks, connectors) +end + +if partWatch then + partWatch:Disconnect() + partWatch = nil +end + +c.CameraSubject = nil +message.Text = "Requesting character..." + +wait(1) + +local rep = game:GetService("ReplicatedStorage") +local requestCharacter = rep:WaitForChild("RequestCharacter") + +requestCharacter:FireServer() +message.Text = "Waiting for character..." + +while not player.Character do + player.CharacterAdded:Wait() + wait() +end + +messageGui.Visible = false +c.CameraType = "Custom" \ No newline at end of file diff --git a/Resources/SafeChat/RawTreeData.lua b/Resources/SafeChat/RawTreeData.lua new file mode 100644 index 0000000..df39095 --- /dev/null +++ b/Resources/SafeChat/RawTreeData.lua @@ -0,0 +1,447 @@ +return [==[ +Hello + Hi + Hi there! + Hi everyone + Howdy + Howdy partner! + Greetings + Greetings everyone + Greetings robloxians! + Seasons greetings! + Welcome + Welcome to my place + Welcome to our base + Welcome to my barbecque + Hey there! + What's up? + How are you doing? + How's it going? + What's new? + Good day + Good morning + Good afternoon + Good evening + Good night + Silly + Waaaaaaaz up?! + Hullo! + Behold greatness, mortals! + Holidays + Happy New Year! + Happy Valentine's Day! + Beware the Ides of March! + Happy Easter! + Happy 4th of July! + Happy Thanksgiving! + Happy Halloween! + Happy Hanukkah! + Merry Christmas! + Happy Holidays! +Goodbye + Good Night + Sweet dreams + Go to sleep! + Lights out! + Bedtime + Later + See ya later + Later gator! + See you tomorrow + Bye + Hasta la bye bye! + I'll be right back + I have to go + Farewell + Take care + Have a nice day + Goodluck! + Ta-ta for now! + Peace + Peace out! + Peace dudes! + Rest in pieces! + Silly + To the batcave! + Over and out! + Happy trails! + I've got to book it! + Tootles! + Smell you later! + GG! + My house is on fire! gtg. +Friend + Wanna be friends? + Follow me + Come to my place! + Come to my base! + Follow me, team! + Your place is cool + Your place is fun + Your place is awesome + Your place looks good + Thank you + Thanks for playing + Thanks for visiting + Thanks for everything + No thank you + No problem + Don't worry + That's ok + You are ... + You are great! + You are good! + You are cool! + You are funny! + You are silly! + You are awesome! + I like ... + I like your name + I like your shirt + I like your place + I like your style + Sorry + My bad! + I'm sorry + Whoops! + Please forgive me + I forgive you +Questions + Who? + Who wants to be my friend? + Who wants to be on my team? + Who made this brilliant game? + What? + What is your favorite animal? + What is your favorite game? + What is your favorite movie? + What is your favorite TV show? + What is your favorite music? + What are your hobbies? + When? + When are you online? + When is the new version coming out? + When can we play again? + When will your place be done? + Where? + Where do you want to go? + Where are you going? + Where am I?! + How? + How are you today? + How did you make this cool place? + Can I... + Can I have a tour? + Can I be on your team? + Can I be your friend? + Can I try something? +Answers + You need help? + Check out the news section + Check out the help section + Read the wiki! + All the answers are in the wiki! + Some people ... + Me + Not me + You + All of us + Everyone but you + Builderman! + Telamon! + Time ... + In the morning + In the afternoon + At night + Tomorrow + This week + This month + Sometime + Sometimes + Whenever you want + Never + Animals + Cats + Lion + Tiger + Leopard + Cheetah + Dogs + Wolves + Beagle + Collie + Dalmatian + Poodle + Spaniel + Shepherd + Terrier + Retriever + Horses + Ponies + Stallions + Reptiles + Dinosaurs + Lizards + Snakes + Turtles! + Hamster + Monkey + Bears + Fish + Goldfish + Sharks + Sea Bass + Halibut + Birds + Eagles + Penguins + Turkeys + Elephants + Mythical Beasts + Dragons + Unicorns + Sea Serpents + Sphinx + Cyclops + Minotaurs + Goblins + Honest Politicians + Ghosts + Scylla and Charybdis + Games + Roblox + BrickBattle + Community Building + Roblox Minigames + Action + Puzzle + Strategy + Racing + RPG + Board games + Chess + Checkers + Settlers of Catan + Tigris and Euphrates + El Grande + Stratego + Carcassonne + Sports + Hockey + Soccer + Football + Baseball + Basketball + Volleyball + Tennis + Watersports + Surfing + Swimming + Water Polo + Winter sports + Skiing + Snowboarding + Sledding + Skating + Adventure + Rock climbing + Hiking + Fishing + Wacky + Foosball + Calvinball + Croquet + Cricket + Dodgeball + Squash + Movies/TV + Science Fiction + Animated + Anime + Comedy + Romantic + Action + Fantasy + Music + Country + Jazz + Rap + Hip-hop + Techno + Classical + Pop + Rock + Hobbies + Computers + Building computers + Videogames + Coding + Hacking + The Internet + lol. teh internets! + Dance + Gynastics + Martial Arts + Karate + Judo + Taikwon Do + Wushu + Street fighting + Listening to music + Music lessons + Playing in my band + Playing piano + Playing guitar + Playing violin + Playing drums + Playing a weird instrument + Arts and crafts + Location + USA + West + Alaska + Arizona + California + Colorado + Hawaii + Idaho + Montana + Nevada + New Mexico + Oregon + Utah + Washington + Wyoming + Midwest + Illinois + Indiana + Iowa + Kansas + Michigan + Minnesota + Missouri + Nebraska + North Dakota + Ohio + South Dakota + Wisconsin + Northeast + Connecticut + Delaware + Maine + Maryland + Massachusetts + New Hampshire + New Jersey + New York + Pennsylvania + Rhode Island + Vermont + Virginia + West Virginia + South + Alabama + Arkansas + Florida + Georgia + Kentucky + Louisiana + Mississippi + North Carolina + Oklahoma + South Carolina + Tennessee + Texas + Canada + Alberta + British Columbia + Manitoba + New Brunswick + Newfoundland + Northwest Territories + Nova Scotia + Nunavut + Ontario + Prince Edward Island + Quebec + Saskatchewan + Yukon + Mexico + Central America + Europe + Great Britain + England + Scotland + Wales + Northern Ireland + France + Germany + Spain + Italy + Poland + Switzerland + Greece + Romania + Asia + China + India + Japan + Korea + South America + Argentina + Brazil + Africa + Eygpt + Swaziland + Australia + Middle East + Antarctica + Age + Rugrat + Kid + Teen + Twenties + Old + Ancient + Mesozoic + Mood + Good + Great! + Not bad + Sad + Hyper + Chill + Boy + Girl +Game + Let's build + Let's battle + Nice one! + So far so good! + Lucky shot! + Oh man! +Silly + Muahahahaha! + 1337 + i r teh pwnz0r! + w00t! + z0mg h4x! + ub3rR0xXorzage! + all your base are belong to me! +Yes + Absolutely! + Rock on! + Totally! + Juice! +No + Ummm. No. + ... +Ok + Well... ok + Sure +:-) + :-( + :D + :-O + lol +]==] \ No newline at end of file diff --git a/Resources/SafeChat/init.lua b/Resources/SafeChat/init.lua new file mode 100644 index 0000000..2c7a46a --- /dev/null +++ b/Resources/SafeChat/init.lua @@ -0,0 +1,35 @@ +local safeChatTree = +{ + Label = "ROOT"; + Branches = {}; +} + +do + local mTreeData = script:WaitForChild("RawTreeData") + local treeData = require(mTreeData) + + local stack = {} + stack[0] = safeChatTree + + for line in treeData:gmatch("[^\n]+") do + if #line > 0 then + local stackIndex = 0 + while line:sub(1,1) == "\t" do + stackIndex = stackIndex + 1 + line = line:sub(2) + end + + local tree = stack[stackIndex] + assert(tree,"Bad safechat tree setup at depth " .. stackIndex .. ": " .. line) + + local branch = {} + branch.Label = line + branch.Branches = {} + table.insert(tree.Branches,branch) + + stack[stackIndex+1] = branch + end + end +end + +return safeChatTree \ No newline at end of file diff --git a/Server/Badges.server.lua b/Server/Badges.server.lua new file mode 100644 index 0000000..d865dde --- /dev/null +++ b/Server/Badges.server.lua @@ -0,0 +1,224 @@ +local ServerStorage = game:GetService("ServerStorage") +local BadgeService = game:GetService("BadgeService") +local AssetService = game:GetService("AssetService") +local Players = game:GetService("Players") + +local usingLeaderboard = true + +if ServerStorage:FindFirstChild("TrackCombatBadges") then + usingLeaderboard = ServerStorage.TrackCombatBadges.Value +elseif ServerStorage:FindFirstChild("LoadLeaderboard") then + usingLeaderboard = ServerStorage.LoadLeaderboard.Value +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) + +if not playerDataGet.Success then + warn("Failed to load PlayerData, badges will not be awarded") + return +end + +local playerData = playerDataGet.DataStore + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local placeCount = 0 + +local function iterPageItems(pages) + return coroutine.wrap(function () + local pageNum = 1 + while true do + for _, item in ipairs(pages:GetCurrentPage()) do + coroutine.yield(item, pageNum) + end + + if pages.IsFinished then + break + end + + pages:AdvanceToNextPageAsync() + pageNum = pageNum + 1 + end + end) +end + +for place in iterPageItems(AssetService:GetGamePlacesAsync()) do + if not place.Name:lower():find("devtest") and not place.Name:find("Super Nostalgia Zone") then + placeCount = placeCount + 1 + end +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local badges = +{ + CombatInitiation = 1020931358; + Warrior = 1020932933; + Bloxxer = 1021012898; + Inviter = 1021010468; + Friendship = 1021024465; + Ambassador = 1021056315; +} + +local inviterBadgeStatus = {} +local lastWipeout = {} + +local function giveBadge(player,badge) + warn("AWARDING BADGE", badge, "TO", player) + if not BadgeService:UserHasBadge(player.UserId,badge) then + BadgeService:AwardBadge(player.UserId,badge) + end +end + +local function onHumanoidDied(humanoid, victim) + local player do + local char = humanoid.Parent + if char then + player = Players:GetPlayerFromCharacter(char) + end + end + + local myLastWipeout = lastWipeout[victim.Name] or 0 + local now = tick() + + if (now - myLastWipeout) > 5 then + local creator = humanoid:FindFirstChild("creator") + + if creator then + local killer = creator.Value + + if killer and killer.UserId > 0 and killer ~= player then + local killerData = playerData:GetSaveData(killer) + local knockOuts = killerData:Get("Knockouts") or 0 + + knockOuts = knockOuts + 1 + killerData:Set("Knockouts",knockOuts) + + if knockOuts > 250 then + local wipeOuts = killerData:Get("Wipeouts") or 0 + if wipeOuts < knockOuts then + giveBadge(killer,badges.Bloxxer) + end + elseif knockOuts > 100 then + giveBadge(killer,badges.Warrior) + elseif knockOuts > 10 then + giveBadge(killer,badges.CombatInitiation) + end + end + end + + local myData = playerData:GetSaveData(victim) + local wipeOuts = myData:Get("Wipeouts") or 0 + + myData:Set("Wipeouts", wipeOuts + 1) + lastWipeout[victim.Name] = now + end +end + +local function onCharacterAdded(char) + local player = game.Players:GetPlayerFromCharacter(char) + local humanoid = char:WaitForChild("Humanoid") + + humanoid.Died:Connect(function () + onHumanoidDied(humanoid,player) + end) +end + +local function handleSocialBadges(player) + -- Set up our inviter status from scratch. + inviterBadgeStatus[player.Name] = + { + Counted = 0; + Queried = {}; + } + + -- Check the status of other players, and see if we can give them the inviter badge. + local myData = playerData:GetSaveData(player) + + for _,otherPlayer in pairs(Players:GetPlayers()) do + if player ~= otherPlayer and player:IsFriendsWith(otherPlayer.UserId) then + local theirName = otherPlayer.Name + local theirStatus = inviterBadgeStatus[theirName] + + if theirStatus and not theirStatus.Queried[player.Name] then + theirStatus.Queried[player.Name] = true + theirStatus.Counted = theirStatus.Counted + 1 + if theirStatus.Counted >= 3 then + giveBadge(otherPlayer,badges.Inviter) + end + end + + -- Also increment the friendship encounters for these two. + + local myFrEncs = myData:Get("FriendEncounters") or 0 + myFrEncs = myFrEncs + 1 + + myData:Set("FriendEncounters",myFrEncs) + + if myFrEncs >= 10 then + giveBadge(player,badges.Friendship) + end + + local theirData = playerData:GetSaveData(otherPlayer) + local theirFrEncs = theirData:Get("FriendEncounters") or 0 + + theirFrEncs = theirFrEncs + 1 + theirData:Set("FriendEncounters",theirFrEncs) + + if theirFrEncs >= 10 then + giveBadge(otherPlayer,badges.Friendship) + end + end + end +end + +local function onPlayerAdded(player) + if player.UserId > 0 then + -- Hook up combat badge listeners + if usingLeaderboard then + if player.Character and player.Character:IsDescendantOf(workspace) then + onCharacterAdded(player.Character) + end + + player.CharacterAdded:Connect(onCharacterAdded) + end + + -- Handle social badges + handleSocialBadges(player) + + -- Handle ambassador badge + local myData = playerData:GetSaveData(player) + local myPlaceVisits = myData:Get("PlacesVisited") + + if myPlaceVisits == nil then + myPlaceVisits = + { + Count = 0; + Record = {}; + } + end + + local placeId = tostring(game.PlaceId) + + if not myPlaceVisits.Record[placeId] then + myPlaceVisits.Record[placeId] = true + myPlaceVisits.Count = myPlaceVisits.Count + 1 + end + + if myPlaceVisits.Count >= placeCount then + giveBadge(player, badges.Ambassador) + end + + myData:Set("PlacesVisited", myPlaceVisits) + end +end + +for _,v in pairs(Players:GetPlayers()) do + onPlayerAdded(v) +end + +Players.PlayerAdded:Connect(onPlayerAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Server/Bevels.server.lua b/Server/Bevels.server.lua new file mode 100644 index 0000000..485c5be --- /dev/null +++ b/Server/Bevels.server.lua @@ -0,0 +1,537 @@ +------------------------------------------------------------------------------------------------ +-- Initialization +------------------------------------------------------------------------------------------------ + +local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local ServerStorage = game:GetService("ServerStorage") + +local function getFlag(name) + local flag = ServerStorage:FindFirstChild(name) + return (flag and flag:IsA("BoolValue") and flag.Value) +end + +local enableBevels = getFlag("EnableBevels") +local debugMode = getFlag("DevTestMode") + +local bevelCache = ServerStorage:FindFirstChild("BevelCache") +local bevelsReady = bevelCache:FindFirstChild("BevelsReady") + +if not bevelCache then + bevelCache = Instance.new("Folder") + bevelCache.Name = "BevelCache" + bevelCache.Parent = ServerStorage +end + +if not bevelsReady then + bevelsReady = Instance.new("BoolValue") + bevelsReady.Name = "BevelsReady" + bevelsReady.Parent = bevelCache + bevelsReady.Archivable = false +end + +if not enableBevels then + bevelsReady.Value = true + return +end + +do + local coreBevelCache = ServerStorage:WaitForChild("CoreBevelCache") + + for _,bevel in pairs(coreBevelCache:GetChildren()) do + if not bevelCache:FindFirstChild(bevel.Name) then + bevel.Parent = bevelCache + bevel.Archivable = false + end + end + + coreBevelCache:Destroy() +end + +local regen = ServerStorage:FindFirstChild("Regeneration") + +if regen then + local ready = regen:WaitForChild("Ready") + + while not ready.Value do + ready.Changed:Wait() + end +end + +local loadBuildTools = ServerStorage:FindFirstChild("LoadBuildTools") +local hasBuildTools = (loadBuildTools ~= nil) + +------------------------------------------------------------------------------------------------ + +local edgeDepth = 1 / 15 +local cornerDepth = edgeDepth * math.sqrt(8 / 3) + +local mirrorProps = +{ + "Anchored", + "CanCollide", + "CastShadow", + "CFrame", + "CollisionGroupId", + "CustomPhysicalProperties", + "Color", + "Locked", + "Material", + "Name", + "Reflectance", + "RotVelocity", + "Transparency", + "Velocity", +} + +local surfaceProps = +{ + "ParamA", + "ParamB", + "Surface", + "SurfaceInput" +} + +local bevelHash = "%.2f ~ %.2f ~ %.2f" +local isStudio = RunService:IsStudio() + +local negateBase = Instance.new("Part") +negateBase.Name = "__negateplane" +negateBase.CanCollide = false +negateBase.BottomSurface = 0 +negateBase.Transparency = 1 +negateBase.Anchored = true +negateBase.TopSurface = 0 +negateBase.Locked = true + +CollectionService:AddTag(negateBase, "NoBevels") + +for _,normalId in pairs(Enum.NormalId:GetEnumItems()) do + local name = normalId.Name + for _,surfaceProp in pairs(surfaceProps) do + table.insert(mirrorProps, name .. surfaceProp) + end +end + +------------------------------------------------------------------------------------------------ + +local overload = 0 +local threshold = Vector3.new(30, 30, 30) + +if ServerStorage:FindFirstChild("BevelThreshold") then + threshold = ServerStorage.BevelThreshold.Value +end + +local function debugPrint(...) + if debugMode then + warn("[BEVELS DEBUG]:", ...) + end +end + +local function isPartOfHumanoid(object) + local model = object:FindFirstAncestorOfClass("Model") + + if model then + if model:FindFirstChildOfClass("Humanoid") then + return true + else + return isPartOfHumanoid(model) + end + end + + return false +end + +local function canGiveBevels(part) + if part.Parent and part:IsA("Part") and not CollectionService:HasTag(part, "NoBevels") then + if not isPartOfHumanoid(part) and not part:FindFirstChildWhichIsA("DataModelMesh") then + local inThreshold = false + local diff = threshold - part.Size + + if diff.X >= 0 and diff.Y >= 0 and diff.Z >= 0 then + inThreshold = true + end + + if inThreshold then + if CollectionService:HasTag(part, "ForceBevels") then + return true + else + return part.Shape.Name == "Block" and part.Transparency < 1 + end + end + end + end + + return false +end + +local function createProxyPart(part, name, tag, sizeChange) + local proxyPart = Instance.new("Part") + proxyPart.Name = name + proxyPart.Locked = true + proxyPart.TopSurface = 0 + proxyPart.Massless = true + proxyPart.Transparency = 1 + proxyPart.BottomSurface = 0 + proxyPart.CanCollide = false + proxyPart.CFrame = part.CFrame + + local size = part.Size + if sizeChange then + size = size + sizeChange + end + + local proxyWeld = Instance.new("Weld") + proxyWeld.Name = "ProxyWeld" + proxyWeld.Part1 = proxyPart + proxyWeld.Part0 = part + + if hasBuildTools then + local mesh = Instance.new("SpecialMesh") + mesh.Scale = size * 20 + mesh.MeshType = "Brick" + mesh.Offset = part.Size + mesh.Parent = proxyPart + + proxyPart.Size = Vector3.new(.05, .05, .05) + proxyWeld.C0 = CFrame.new(-mesh.Offset) + else + proxyPart.Size = part.Size + end + + CollectionService:AddTag(proxyPart, tag) + CollectionService:AddTag(proxyPart, "NoBevels") + CollectionService:AddTag(proxyWeld, "GorillaGlue") + + proxyWeld.Parent = proxyPart + proxyPart.Parent = part + + return proxyPart +end + +local function createBevels(part, initializing) + if not canGiveBevels(part) or isPartOfHumanoid(part) then + return + end + + local size = part.Size + local sx, sy, sz = size.X, size.Y, size.Z + local bevelKey = bevelHash:format(sx, sy, sz) + + local debugBox + + if debugMode then + debugBox = Instance.new("BoxHandleAdornment") + + debugBox.Color3 = Color3.new(0, 2, 2) + debugBox.AlwaysOnTop = true + debugBox.Name = "DebugBox" + debugBox.Size = size + debugBox.ZIndex = 0 + + debugBox.Adornee = part + debugBox.Parent = part + end + + if not bevelCache:FindFirstChild(bevelKey) then + local halfSize = size / 2 + + local planeScale = math.max(sx, sy, sz) + local planes = {} + + local solverPart = part:Clone() + solverPart.CFrame = CFrame.new() + solverPart.BrickColor = BrickColor.new(-1) + + debugPrint("Solving:", bevelKey) + + for x = -1, 1 do + local x0 = (x == 0) + + for y = -1, 1 do + local y0 = (y == 0) + + for z = -1, 1 do + local z0 = (z == 0) + + local isCenter = (x0 and y0 and z0) + local isFace = ((x0 and y0) or (y0 and z0) or (z0 and x0)) + + if not (isCenter or isFace) then + local isCorner = (not x0 and not y0 and not z0) + local depth = isCorner and cornerDepth or edgeDepth + + local offset = Vector3.new(x, y, z) + local cornerPos = (halfSize * offset) + + local plane = negateBase:Clone() + plane.CFrame = CFrame.new(cornerPos, cornerPos + offset) + plane.Size = Vector3.new(planeScale, planeScale, depth) + plane.Parent = part + + table.insert(planes, plane) + end + end + end + end + + local success, union = pcall(function () + return solverPart:SubtractAsync(planes, "Box") + end) + + if success then + union.Name = bevelKey + union.UsePartColor = true + union.Parent = bevelCache + + CollectionService:AddTag(union, "HasBevels") + + if debugBox then + debugBox.Color3 = Color3.new(0, 2, 0) + end + elseif debugBox then + debugBox.Color3 = Color3.new(2, 0, 0) + end + + for _,plane in pairs(planes) do + plane:Destroy() + end + + overload = 0 + else + if debugBox then + debugBox.Color3 = Color3.new(2, 0, 2) + end + + overload = overload + 1 + + if overload % 10 == 0 then + RunService.Heartbeat:Wait() + end + end + + local baseUnion = bevelCache:FindFirstChild(bevelKey) + + if baseUnion then + local archivable = baseUnion.Archivable + baseUnion.Archivable = true + + local union = baseUnion:Clone() + baseUnion.Archivable = archivable + + for _,prop in ipairs(mirrorProps) do + union[prop] = part[prop] + end + + for _,joint in pairs(part:GetJoints()) do + if joint:IsA("JointInstance") or joint:IsA("WeldConstraint") then + if joint.Part0 == part then + joint.Part0 = union + elseif joint.Part1 == part then + joint.Part1 = union + end + end + end + + for _,child in pairs(part:GetChildren()) do + if not child:IsA("TouchTransmitter") and not child:IsA("Texture") then + if child:IsA("BaseScript") then + child.Disabled = true + end + + child.Parent = union + + if child:IsA("BaseScript") then + child.Disabled = false + end + end + end + + if not initializing then + wait() + end + + if CollectionService:HasTag(part, "DoUnlock") then + union.Locked = false + end + + if part.ClassName ~= "Part" then + local holder = Instance.new("Weld") + holder.Part0 = part + holder.Part1 = union + holder.Parent = part + + union.Anchored = false + union.Massless = true + union.Parent = part + + part.Transparency = 1 + CollectionService:AddTag(holder, "GorillaGlue") + else + local parent = part.Parent + part:Destroy() + + union.Parent = parent + end + elseif debugBox then + debugBox.Color3 = Color3.new(2, 0, 0) + end + + if debugBox then + debugBox.Transparency = 0.5 + Debris:AddItem(debugBox, 2) + end +end + +------------------------------------------------------------------------------------------------ + +do + local waitForPlayer = getFlag("BevelsWaitForPlayer") + + if waitForPlayer then + -- Wait for a player to spawn + local playerSpawned = false + + while not playerSpawned do + for _,player in pairs(Players:GetPlayers()) do + if player.Character and player.Character:IsDescendantOf(workspace) then + playerSpawned = true + break + end + end + + workspace.ChildAdded:Wait() + end + end + + warn("Solving bevels...") + + -- Collect all blocks currently in the workspace. + local initialPass = {} + local debugHint + + for _,desc in pairs(workspace:GetDescendants()) do + if canGiveBevels(desc) then + if not desc.Locked then + CollectionService:AddTag(desc, "DoUnlock") + desc.Locked = true + end + + table.insert(initialPass, desc) + end + end + + if waitForPlayer then + -- Sort the blocks by the sum of their distances from players in the game. + local samplePoints = {} + + for _,player in pairs(Players:GetPlayers()) do + local char = player.Character + if char then + local root = char.PrimaryPart + if root then + local rootPos = root.Position + table.insert(samplePoints, rootPos) + end + end + end + + table.sort(initialPass, function (a, b) + local distSumA = 0 + local distSumB = 0 + + local posA = a.Position + local posB = b.Position + + for _,rootPos in pairs(samplePoints) do + local distA = (rootPos - posA).Magnitude + distSumA = distSumA + distA + + local distB = (rootPos - posB).Magnitude + distSumB = distSumB + distB + end + + if distSumA ~= distSumB then + return distSumA < distSumB + end + + if posA.Y ~= posB.Y then + return posA.Y < posB.Y + end + + if posA.X ~= posB.X then + return posA.X < posB.X + end + + if posA.Z ~= posB.Z then + return posA.Z < posB.Z + end + + return 0 + end) + end + + if debugMode then + debugHint = Instance.new("Hint") + debugHint.Text = "Generating Bevels..." + debugHint.Parent = workspace + end + + -- Run through the initial bevel creation phase. + for _,block in ipairs(initialPass) do + createBevels(block, true) + end + + if debugHint then + debugHint:Destroy() + end +end + +-- Listen for new parts being added. +workspace.DescendantAdded:Connect(createBevels) + +-- Allow regeneration to request bevel solving +local bevelSolver = bevelCache:FindFirstChild("RequestSolve") + +if not bevelSolver then + bevelSolver = Instance.new("BindableFunction") + bevelSolver.Name = "RequestSolve" + bevelSolver.Parent = bevelCache + bevelSolver.Archivable = false +end + +function bevelSolver.OnInvoke(inst) + for _,desc in pairs(inst:GetDescendants()) do + if desc:IsA("Part") then + createBevels(desc) + end + end +end + +if RunService:IsStudio() then + local exportBin = Instance.new("Folder") + exportBin.Name = "ExportBin" + exportBin.Parent = ServerStorage + + for _,v in pairs(bevelCache:GetChildren()) do + if v:IsA("TriangleMeshPart") and v.Archivable then + v:Clone().Parent = exportBin + end + end + + wait(.1) + + for _,v in pairs(exportBin:GetChildren()) do + if v:FindFirstChild("LOD") then + v.LOD:Destroy() + end + end +end + +-- Ready! +warn("Bevels ready!") +bevelsReady.Value = true + +------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/Server/BuildTools/Dragger.client.lua b/Server/BuildTools/Dragger.client.lua new file mode 100644 index 0000000..e57e6f9 --- /dev/null +++ b/Server/BuildTools/Dragger.client.lua @@ -0,0 +1,256 @@ +local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local SoundService = game:GetService("SoundService") +local Dragger = Instance.new("Dragger") + +local tool = script.Parent +local selection = Instance.new("SelectionBox") +selection.Parent = tool +selection.Transparency = 1 + +local icon = Instance.new("StringValue") +icon.Name = "IconOverride" +icon.Parent = tool + +local mode = tool.Name +local draggerService = ReplicatedStorage:WaitForChild("DraggerService") +local gateway = draggerService:WaitForChild("DraggerGateway") +local submitUpdate = draggerService:WaitForChild("SubmitUpdate") + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Connections +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local cons = {} + +local function addConnections(connections) + for event, func in pairs(connections) do + local con = event:Connect(func) + table.insert(cons, con) + end +end + +local function clearCons() + while #cons > 0 do + local connection = table.remove(cons) + connection:Disconnect() + end +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Keys +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local keyLocks = {} + +local function onInputEnded(input) + if keyLocks[input.KeyCode.Name] then + keyLocks[input.KeyCode.Name] = nil + end +end + +local function isKeyDown(key) + if UserInputService:IsKeyDown(key) and not keyLocks[key] then + keyLocks[key] = true + return true + end + return false +end + +UserInputService.InputEnded:Connect(onInputEnded) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Tool Style +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local style = +{ + GameTool = + { + Icon = "rbxassetid://1048129653"; + HoverColor = Color3.fromRGB(25,153,255); + Cursors = + { + Idle = ""; + Hover = "rbxasset://textures/DragCursor.png"; + Grab = "rbxasset://textures/GrabRotateCursor.png"; + }; + }; + Clone = + { + Icon = "rbxasset://textures/Clone.png"; + HoverColor = Color3.fromRGB(25,153,255); + Cursors = + { + Idle = "rbxasset://textures/CloneCursor.png"; + Hover = "rbxassetid://1048136830"; + Grab = "rbxasset://textures/GrabRotateCursor.png"; + } + }; + Delete = + { + Icon = "rbxasset://textures/Hammer.png"; + HoverColor = Color3.new(1,0.5,0); + CanShowWithHover = true; + Cursors = + { + Idle = "rbxasset://textures/HammerCursor.png"; + Hover = "rbxasset://textures/HammerOverCursor.png"; + } + } +} + +local function getIcon(iconType) + return style[mode].Cursors[iconType] +end + +tool.TextureId = style[mode].Icon +selection.Color3 = style[mode].HoverColor + +if style[mode].CanShowWithHover then + selection.Transparency = 0 +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Dragger +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mouse +local currentKey +local down = false +local debounce = false + +local function onIdle() + if not down and mouse then + local mousePart = mouse.Target + + if mousePart and not mousePart.Locked then + selection.Adornee = mousePart + icon.Value = getIcon("Hover") + return + end + + selection.Adornee = nil + icon.Value = getIcon("Idle") + end +end + +local function draggerRotate(axis) + if down then + Dragger:AxisRotate(axis) + end +end + +local function startDraggerAction(mPart) + if mode == "Delete" then + gateway:InvokeServer("RequestDelete",mPart) + return + end + + local pointOnMousePart = mPart.CFrame:ToObjectSpace(mouse.Hit).Position + local canDrag, dragKey, mousePart = gateway:InvokeServer("GetKey", mPart, mode == "Clone") + + if canDrag then + selection.Adornee = mousePart + selection.Transparency = 0 + + down = true + currentKey = dragKey + + icon.Value = getIcon("Grab") + Dragger:MouseDown(mousePart, pointOnMousePart, {mousePart}) + + local lastSubmit = 0 + + while down do + local now = tick() + local joints = {} + + for _,joint in pairs(mousePart:GetJoints()) do + if CollectionService:HasTag(joint, "GorillaGlue") then + joints[joint] = joint.Parent + joint.Parent = nil + end + end + + --local mousePart = selection.Adornee + if down then + Dragger:MouseMove(mouse.UnitRay) + end + + if mousePart and currentKey then + if isKeyDown("R") then + draggerRotate("Z") + elseif isKeyDown("T") then + draggerRotate("X") + end + + if now - lastSubmit > 0.03 then + submitUpdate:FireServer(currentKey, mousePart.CFrame) + lastSubmit = now + end + end + + for joint, parent in pairs(joints) do + joint.Parent = parent + end + + RunService.Heartbeat:Wait() + end + + selection.Transparency = 1 + gateway:InvokeServer("ClearKey", dragKey) + + currentKey = nil + end +end + +local function onButton1Down() + if not debounce then + debounce = true + + local mousePart = selection.Adornee + + if mousePart and not down then + startDraggerAction(mousePart) + end + + debounce = false + end +end + +local function onButton1Up() + if down then + down = false + Dragger:MouseUp() + end +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Tool +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function onEquipped(newMouse) + mouse = newMouse + addConnections + { + [mouse.Button1Down] = onButton1Down; + [mouse.Button1Up] = onButton1Up; + [mouse.Idle] = onIdle; + } +end + +local function onUnequipped() + onButton1Up() + clearCons() + + selection.Adornee = nil + mouse = nil +end + +tool.Equipped:Connect(onEquipped) +tool.Unequipped:Connect(onUnequipped) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Server/BuildTools/init.server.lua b/Server/BuildTools/init.server.lua new file mode 100644 index 0000000..17fac5c --- /dev/null +++ b/Server/BuildTools/init.server.lua @@ -0,0 +1,341 @@ +local CollectionService = game:GetService("CollectionService") +local HttpService = game:GetService("HttpService") +local Players = game:GetService("Players") +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local ServerStorage = game:GetService("ServerStorage") + +local loadBuildTools = ServerStorage:FindFirstChild("LoadBuildTools") +if not (loadBuildTools and loadBuildTools.Value) then + return +end + +local looseBranches = ServerStorage:FindFirstChild("LooseBranches") + +if looseBranches and looseBranches:IsA("BoolValue") then + looseBranches = looseBranches.Value +else + looseBranches = false +end + +local toolList = loadBuildTools.Value +if toolList == true then -- If it's a BoolValue, load all of them. + toolList = "GameTool;Clone;Delete" +end + +local DraggerService = Instance.new("Folder") +DraggerService.Name = "DraggerService" +DraggerService.Parent = ReplicatedStorage + +local draggerGateway = Instance.new("RemoteFunction") +draggerGateway.Name = "DraggerGateway" +draggerGateway.Parent = DraggerService + +local submitUpdate = Instance.new("RemoteEvent") +submitUpdate.Name = "SubmitUpdate" +submitUpdate.Parent = DraggerService + +local draggerScript = script:WaitForChild("Dragger") + +local activeKeys = {} +local playerToKey = {} +local partToKey = {} +local debounce = {} + +local SIMULATE_TAG = "SimulateAfterDrag" +local NO_BREAK_TAG = "GorillaGlue" + +local function assertClass(obj, class) + assert(obj) + assert(typeof(obj) == "Instance") + assert(obj:IsA(class)) +end + +local function canGiveKey(player, part) + if part.Locked then + return false + end + local playerHasKey = playerToKey[player] + if playerHasKey then + return false + end + local partHasKey = partToKey[part] + if partHasKey then + return false + end + return true +end + +local function claimAssembly(player, part) + if part:CanSetNetworkOwnership() then + part:SetNetworkOwner(player) + end +end + +local function validJointsOf(part) + return coroutine.wrap(function () + for _,joint in pairs(part:GetJoints()) do + if not CollectionService:HasTag(joint, NO_BREAK_TAG) then + coroutine.yield(joint) + end + end + end) +end + +local function breakJoints(part) + for joint in validJointsOf(part) do + if not CollectionService:HasTag(joint, NO_BREAK_TAG) then + joint:Destroy() + end + end +end + +local function makeJoints(part) + -- Connect this part to a nearby surface + workspace:JoinToOutsiders({part}, "Surface") +end + +local function removePartKey(key) + local data = activeKeys[key] + if data then + local player = data.Player + if player then + playerToKey[player] = nil + end + + local part = data.Part + + if part then + makeJoints(part) + + if CollectionService:HasTag(part, SIMULATE_TAG) then + data.Anchored = false + CollectionService:RemoveTag(part, SIMULATE_TAG) + end + + part.Anchored = data.Anchored + claimAssembly(player, part) + + partToKey[part] = nil + end + + activeKeys[key] = nil + end +end + +local function restoreJointUpstream(part) + local collectedParts = {} + + if part and CollectionService:HasTag(part, SIMULATE_TAG) then + CollectionService:RemoveTag(part, SIMULATE_TAG) + part.Anchored = false + + makeJoints(part) + + for joint in validJointsOf(part) do + local part0 = joint.Part0 + local part1 = joint.Part1 + + if part0 and part ~= part0 then + collectedParts[part0] = true + restoreJointUpstream(part0) + end + + if part1 and part ~= part1 then + collectedParts[part1] = true + restoreJointUpstream(part1) + end + end + end + + return collectedParts +end + +local function collapseJointUpstream(part) + if part and not (part.Locked or CollectionService:HasTag(part, SIMULATE_TAG)) then + CollectionService:AddTag(part, SIMULATE_TAG) + part.Anchored = true + + for joint in validJointsOf(part) do + local part0 = joint.Part0 + local part1 = joint.Part1 + + if part0 and part ~= part0 then + collapseJointUpstream(part0) + end + + if part1 and part ~= part1 then + collapseJointUpstream(part1) + end + end + + breakJoints(part) + end +end + +function draggerGateway.OnServerInvoke(player, request, ...) + if request == "GetKey" then + local part, asClone = ... + assertClass(part, "BasePart") + + if asClone then + local newPart = part:Clone() + newPart.Parent = workspace + + breakJoints(newPart) + newPart.CFrame = CFrame.new(part.Position + Vector3.new(0, part.Size.Y, 0)) + + local copySound = Instance.new("Sound") + copySound.SoundId = "rbxasset://sounds/electronicpingshort.wav" + copySound.PlayOnRemove = true + copySound.Parent = newPart + + wait() + + part = newPart + copySound:Destroy() + end + + if canGiveKey(player, part) then + local key = HttpService:GenerateGUID(false) + claimAssembly(player, part) + + playerToKey[player] = key + partToKey[part] = key + + local collected = restoreJointUpstream(part) + + local anchored = part.Anchored + part.Anchored = true + breakJoints(part) + + for otherPart in pairs(collected) do + if otherPart:IsGrounded() then + collapseJointUpstream(otherPart) + end + end + + activeKeys[key] = + { + Player = player; + Part = part; + Anchored = anchored; + } + + return true, key, part + else + return false + end + elseif request == "ClearKey" then + local key = ... + + if not key then + key = playerToKey[player] + end + + if key then + local data = activeKeys[key] + if data then + local owner = data.Player + if player == owner then + removePartKey(key) + end + end + end + elseif request == "RequestDelete" then + if not debounce[player] then + local part = ... + assertClass(part, "BasePart") + + debounce[player] = true + + if canGiveKey(player, part) then + local e = Instance.new("Explosion") + e.BlastPressure = 0 + e.Position = part.Position + e.Parent = workspace + + local s = Instance.new("Sound") + s.SoundId = "rbxasset://sounds/collide.wav" + s.Volume = 1 + s.PlayOnRemove = true + s.Parent = part + + local connectedParts = restoreJointUpstream(part) + part:Destroy() + + for otherPart in pairs(connectedParts) do + if otherPart:IsGrounded() then + collapseJointUpstream(otherPart) + end + end + end + + wait(.1) + debounce[player] = false + end + end +end + +local function onChildAdded(child) + if child:IsA("Backpack") then + for draggerTool in toolList:gmatch("[^;]+") do + local tool = Instance.new("Tool") + tool.Name = draggerTool + tool.RequiresHandle = false + + local newDragger = draggerScript:Clone() + newDragger.Parent = tool + newDragger.Disabled = false + + tool.Parent = child + end + end +end + +local function onPlayerAdded(player) + for _, v in pairs(player:GetChildren()) do + onChildAdded(v) + end + + player.ChildAdded:Connect(onChildAdded) +end + +local function onPlayerRemoved(player) + local key = playerToKey[player] + if key then + removePartKey(key) + end +end + +local function onSubmitUpdate(player, key, cframe) + local keyData = activeKeys[key] + if keyData then + local owner = keyData.Player + if owner == player then + local part = keyData.Part + if part and part:IsDescendantOf(workspace) then + breakJoints(part) + part.CFrame = cframe + end + end + end +end + +for _, player in pairs(game.Players:GetPlayers()) do + onPlayerAdded(player) +end + +submitUpdate.OnServerEvent:Connect(onSubmitUpdate) +Players.PlayerAdded:Connect(onPlayerAdded) +Players.PlayerRemoving:Connect(onPlayerRemoved) + +-- Garbage Collection + +while wait(5) do + for part, key in pairs(partToKey) do + if not part:IsDescendantOf(workspace) then + removePartKey(key) + end + end +end \ No newline at end of file diff --git a/Server/CaptureTheFlag.server.lua b/Server/CaptureTheFlag.server.lua new file mode 100644 index 0000000..c4351a4 --- /dev/null +++ b/Server/CaptureTheFlag.server.lua @@ -0,0 +1,295 @@ +local Players = game:GetService("Players") +local CollectionService = game:GetService("CollectionService") +local Teams = game:GetService("Teams") + +local FlagInstance = "FlagInstance" +local FlagStandInstance = "FlagStandInstance" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +-- Flags +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +local function restoreFlag(flag) + local owner = flag:FindFirstChild("FlagStand") + local flagStand = owner and owner.Part0 + + if owner and flagStand then + for _,joint in pairs(flag:GetJoints()) do + if joint.Name == "RightGrip" then + joint:Destroy() + end + end + + if flag.Name == "Handle" then + local tool = flag.Parent + if tool:IsA("Tool") then + flag.Name = tool.Name + tool.Parent = nil + end + end + + flag.CFrame = flagStand.CFrame + flag.Parent = flagStand.Parent + + wait() + + flag.Velocity = Vector3.new() + flag.RotVelocity = Vector3.new() + + owner.Part1 = flag + flag.Anchored = false + end +end + +local function mountFlagAsTool(flag, humanoid) + local owner = flag:FindFirstChild("FlagStand") + local teamColor = flag:FindFirstChild("TeamColor") + + if not (owner and teamColor) or flag.Name == "Handle" then + return + end + + local grip = CFrame.new(0.25, 0, 0) * CFrame.Angles(0, -math.pi / 2, 0) + + local tool = Instance.new("Tool") + tool.Name = flag.Name + tool.Grip = grip + + local deathCon + + local function onDied() + local char = humanoid.Parent + + if char and tool.Parent == char then + humanoid:UnequipTools() + end + + if deathCon then + deathCon:Disconnect() + deathCon = nil + end + end + + local function onUnequipped() + if deathCon then + deathCon:Disconnect() + deathCon = nil + end + + if humanoid then + local rootPart = humanoid.RootPart + + if rootPart then + local cf = rootPart.CFrame * CFrame.new(0, 4, -8) + flag.RotVelocity = Vector3.new(1, 1, 1) + flag.Position = cf.Position + end + end + + if flag.Parent == tool then + flag.Parent = workspace + end + + flag.Name = tool.Name + + spawn(function () + tool:Destroy() + end) + end + + tool.Unequipped:Connect(onUnequipped) + CollectionService:AddTag(tool, "Flag") + + tool.Parent = workspace + owner.Part1 = nil + + flag.Name = "Handle" + flag.Parent = tool + + humanoid:EquipTool(tool) + deathCon = humanoid.Died:Connect(onDied) +end + +local function onFlagAdded(flag) + if not flag:IsA("BasePart") then + return + end + + -- Mount TeamColor + local teamColor = flag:FindFirstChild("TeamColor") + + if not teamColor then + teamColor = Instance.new("BrickColorValue") + teamColor.Value = flag.BrickColor + teamColor.Name = "TeamColor" + teamColor.Parent = flag + end + + -- Mount FlagStand + local flagStand, owner + + for _,part in pairs(flag:GetConnectedParts()) do + if CollectionService:HasTag(part, FlagStandInstance) then + flagStand = part + break + end + end + + if flagStand then + owner = Instance.new("Weld") + owner.C0 = flagStand.CFrame:ToObjectSpace(flag.CFrame) + owner.Name = "FlagStand" + owner.Part0 = flagStand + owner.Parent = flag + + for _,joint in pairs(flag:GetJoints()) do + if joint ~= owner then + joint:Destroy() + end + end + + owner.Part1 = flag + CollectionService:AddTag(owner, "GorillaGlue") + end + + spawn(function () + -- Try to keep the flag from falling out of the world. + local deathPlane = workspace.FallenPartsDestroyHeight + + while flag:IsDescendantOf(workspace) do + if flag.Position.Y < deathPlane + 200 then + local tool = flag.Parent + + if tool:IsA("Tool") then + tool.Parent = workspace + wait() + end + + restoreFlag(flag) + end + + wait() + end + end) + + local function onTouched(hit) + local char = hit.Parent + if char then + local player = Players:GetPlayerFromCharacter(char) + local humanoid = char:FindFirstChildOfClass("Humanoid") + + if player and humanoid then + if player.Neutral then + return + end + + if player.TeamColor == teamColor.Value then + if owner.Part1 ~= flag then + restoreFlag(flag) + end + else + mountFlagAsTool(flag, humanoid) + end + end + end + end + + flag.Touched:Connect(onTouched) +end + +for _,flag in pairs(CollectionService:GetTagged(FlagInstance)) do + onFlagAdded(flag) +end + +local flagAdded = CollectionService:GetInstanceAddedSignal(FlagInstance) +flagAdded:Connect(onFlagAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +-- Flag Stands +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +local function onFlagStandAdded(flagStand) + if not flagStand:IsA("BasePart") then + return + end + + local debounce = false + local teamColor = flagStand:FindFirstChild("TeamColor") + local flagCaptured = flagStand:FindFirstChild("FlagCaptured") + + if not teamColor then + teamColor = Instance.new("BrickColorValue") + teamColor.Value = flagStand.BrickColor + teamColor.Name = "TeamColor" + teamColor.Parent = flagStand + end + + if not flagCaptured then + flagCaptured = Instance.new("BindableEvent") + flagCaptured.Name = "FlagCaptured" + flagCaptured.Parent = flagStand + end + + local function onTouched(hit) + if debounce then + return + end + + local char = hit.Parent + if char then + local player = Players:GetPlayerFromCharacter(char) + if player then + if player.Neutral then + return + end + + if player.TeamColor ~= teamColor.Value then + return + end + + local tool = char:FindFirstChildOfClass("Tool") + local handle = tool and tool:FindFirstChild("Handle") + + if handle and CollectionService:HasTag(handle, FlagInstance) then + debounce = true + print("flag captured!") + + flagCaptured:Fire(player) + restoreFlag(handle) + + tool:Destroy() + + wait(1) + debounce = false + end + end + end + end + + flagStand.Touched:Connect(onTouched) +end + +local function onFlagStandRemoved(flagStand) + local teamColor = flagStand:FindFirstChild("TeamColor") + local flagCaptured = flagStand:FindFirstChild("FlagCaptured") + + if teamColor then + teamColor:Destroy() + end + + if flagCaptured then + flagCaptured:Destroy() + end +end + +for _,flagStand in pairs(CollectionService:GetTagged(FlagStandInstance)) do + onFlagStandAdded(flagStand) +end + +local flagStandAdded = CollectionService:GetInstanceAddedSignal(FlagStandInstance) +flagStandAdded:Connect(onFlagStandAdded) + +local flagStandRemoved = CollectionService:GetInstanceRemovedSignal(FlagStandInstance) +flagStandRemoved:Connect(onFlagStandRemoved) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/Server/Characters.server.lua b/Server/Characters.server.lua new file mode 100644 index 0000000..5305e23 --- /dev/null +++ b/Server/Characters.server.lua @@ -0,0 +1,199 @@ +local CollectionService = game:GetService("CollectionService") +local Players = game:GetService("Players") +local InsertService = game:GetService("InsertService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local ServerStorage = game:GetService("ServerStorage") + +local hats = ServerStorage:WaitForChild("ServerHatCache") +local requestCharacter = ReplicatedStorage:WaitForChild("RequestCharacter") +local assetUtil = require(ReplicatedStorage:WaitForChild("AssetUtil")) +local itemData = ReplicatedStorage:WaitForChild("ItemData") +local hatData = require(itemData:WaitForChild("Hat")) + +local playerDataGet = { Success = false } +pcall(function () + playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) +end) + +if not playerDataGet.Success then + warn("Failed to get PlayerData. Avatars will not be loaded.") +end + +local playerDataStore = playerDataGet.DataStore + +local limbs = {"Head", "Torso", "LeftArm", "RightArm", "LeftLeg", "RightLeg"} + +local function preBufferHat(hatId) + local hat = hats:FindFirstChild(hatId) + + if not hat then + local success, import = assetUtil:SafeCall(InsertService, "LoadAsset", tonumber(hatId)) + + if success then + hat = import:FindFirstChildWhichIsA("Accoutrement") + if hat then + hat.Name = hatId + hat.Parent = hats + end + end + end + + return hat +end + +local function safeDestroy(obj) + spawn(function () + obj:Destroy() + end) +end + +local function onCharacterAdded(char) + local player = Players:GetPlayerFromCharacter(char) + + local bodyColors = script.BodyColors:Clone() + CollectionService:AddTag(bodyColors, "RespectCharacterAsset") + + local graphic = script.ShirtGraphic:Clone() + + local shirt = char:FindFirstChildWhichIsA("Shirt") + if not shirt then + shirt = script.Shirt:Clone() + end + + local pants = char:FindFirstChildWhichIsA("Pants") + if not pants then + pants = script.Pants:Clone() + end + + local faceId = 1104210678 + local tshirtId = 131792587 + + local humanoid = char:WaitForChild("Humanoid") + CollectionService:AddTag(humanoid, "Animator") + + local function onDied() + if char:FindFirstChild("HumanoidRootPart") then + char.HumanoidRootPart:Destroy() + end + + wait(5) + + local player = game.Players:GetPlayerFromCharacter(char) + if player then + player:LoadCharacter() + end + end + + local function onDescendantAdded(desc) + if desc:IsA("CharacterMesh") and not desc.Name:sub(1, 3) == "CL_" then + safeDestroy(desc) + elseif desc:IsA("Accoutrement") then + -- Safe way to deter non-game accessories, since I name them by their AssetId + if not tonumber(desc.Name) then + safeDestroy(desc) + end + elseif desc:IsA("SpecialMesh") and desc.Parent.Name == "Head" then + if desc.Name ~= "HeadMesh" then + wait() + + local override = Instance.new("SpecialMesh") + override.Name = "HeadMesh" + override.Scale = Vector3.new(1.25, 1.25, 1.25) + override.Parent = desc.Parent + + safeDestroy(desc) + end + elseif desc:IsA("BodyColors") and desc ~= bodyColors and not CollectionService:HasTag(bodyColors, "RespectCharacterAsset") then + safeDestroy(desc) + bodyColors.Parent = nil + wait() + bodyColors.Parent = char + end + end + + for _,v in pairs(char:GetDescendants()) do + onDescendantAdded(v) + end + + char.DescendantAdded:Connect(onDescendantAdded) + humanoid.Died:Connect(onDied) + + if player.UserId > 0 and playerDataStore then + local playerData = playerDataStore:GetSaveData(player) + local colorData = playerData:Get("BodyColors") + if colorData then + for _,limb in pairs(limbs) do + local num = colorData[limb] + if num then + bodyColors[limb.."Color"] = BrickColor.new(num) + end + end + end + + local loadout = playerData:Get("Loadout") + if loadout then + local shirtId = loadout.Shirt + if shirtId then + shirt.ShirtTemplate = "rbxassetid://" .. shirtId + end + local pantsId = loadout.Pants + if pantsId then + pants.PantsTemplate = "rbxassetid://" .. pantsId + end + + faceId = loadout.Face or faceId + spawn(function () + local hatId = loadout.Hat or 0 + if hatId > 0 then + local hatSrc = preBufferHat(hatId) + local hat = hatSrc:Clone() + hat.Parent = char + end + end) + end + + tshirtId = playerData:Get("TShirt") or tshirtId + end + + if tshirtId > 0 then + local success,img = assetUtil:RequestImage(tshirtId) + if success and img then + graphic.Graphic = img + graphic.Parent = char + end + end + + bodyColors.Parent = char + shirt.Parent = char + pants.Parent = char + + local head = char:WaitForChild("Head") + local face = head:WaitForChild("face") + face.Texture = "rbxhttp://Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&aid=" .. faceId +end + +local function onRequestCharacter(player) + if not player.Character then + player:LoadCharacter() + end +end + +local function onPlayerAdded(player) + player.CanLoadCharacterAppearance = false + player.CharacterAdded:connect(onCharacterAdded) + + if player.Character then + onCharacterAdded(player.Character) + end + + if game.JobId == "" then + player:LoadCharacter() + end +end + +for _,v in pairs(Players:GetPlayers()) do + onPlayerAdded(v) +end + +Players.PlayerAdded:connect(onPlayerAdded) +requestCharacter.OnServerEvent:Connect(onRequestCharacter) \ No newline at end of file diff --git a/Server/Chat.server.lua b/Server/Chat.server.lua new file mode 100644 index 0000000..da2f4c3 --- /dev/null +++ b/Server/Chat.server.lua @@ -0,0 +1,66 @@ +local Players = game:GetService("Players") +local TextService = game:GetService("TextService") +local Chat = game:GetService("Chat") +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") +local mSafeChatTree = ReplicatedStorage:WaitForChild("SafeChatTree") +local safeChatTree = require(mSafeChatTree) + +local filterCache = {} +local maxChatLength = 128 + +local function onServerEvent(player, message) + assert(typeof(message) == "string", "bad input passed") + assert(#message <= maxChatLength, "Chat message was too long!") + + if message:sub(1,3) == "/sc" then + local tree = safeChatTree + + for t in message:gmatch("%d+") do + local i = tonumber(t) + 1 + tree = tree.Branches[i] + + if not tree then + break + end + end + + message = tree and tree.Label or " " + end + + local asciiMessage = "" + + for p, c in utf8.codes(message) do + if c > 0x1F600 then + asciiMessage = asciiMessage .. "??" + else + asciiMessage = asciiMessage .. utf8.char(c) + end + end + + message = asciiMessage + + local userId = player.UserId + if not filterCache[userId] then + filterCache[userId] = {} + end + + local filterResult = filterCache[userId][message] + + if not filterResult then + filterResult = TextService:FilterStringAsync(message,userId) + filterCache[userId][message] = filterResult + end + + for _,receiver in pairs(Players:GetPlayers()) do + spawn(function () + pcall(function () + local filtered = filterResult:GetChatForUserAsync(receiver.UserId) + chatRemote:FireClient(receiver, player, filtered, filtered ~= message) + end) + end) + end +end + +chatRemote.OnServerEvent:Connect(onServerEvent) \ No newline at end of file diff --git a/Server/Cylinders/CylinderSurface.rbxmx b/Server/Cylinders/CylinderSurface.rbxmx new file mode 100644 index 0000000..3238910 --- /dev/null +++ b/Server/Cylinders/CylinderSurface.rbxmx @@ -0,0 +1,137 @@ + + + + true + null + false + + true + + 100 + 100 + + false + true + 1 + 0 + CylinderSurface + 50 + true + null + 0 + + 0 + 0 + 0 + true + + + + false + + 0.5 + 0.5 + + + true + + 0.3254902 + 0.3254902 + 0.3254902 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Frame + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0 + 20 + 0.7 + 0 + + 0 + 0 + + true + 1 + true + + + + + false + + 0.5 + 0.5 + + + true + + 0.3254902 + 0.3254902 + 0.3254902 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Frame + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.7 + 0 + 0 + 20 + + 0 + 0 + + true + 1 + true + + + + \ No newline at end of file diff --git a/Server/Cylinders/init.server.lua b/Server/Cylinders/init.server.lua new file mode 100644 index 0000000..5452f2c --- /dev/null +++ b/Server/Cylinders/init.server.lua @@ -0,0 +1,76 @@ +local CollectionService = game:GetService("CollectionService") + +local cylinderSurface = script:WaitForChild("CylinderSurface") +local cylinderListener = CollectionService:GetInstanceAddedSignal("Cylinder") + +local min, max = math.min, math.max + +local function makeCylinderSurface(part, sizeUpdated) + local surface = cylinderSurface:Clone() + surface.Parent = part + surface.Adornee = part + surface.Archivable = false + + local lastSize = Vector3.new() + + local function onSizeUpdated() + local size = part.Size + if size ~= lastSize then + local scale = min(size.Y, size.Z) + surface.CanvasSize = Vector2.new(max(100, scale * 100), max(100, scale * 100)) + lastSize = size + end + end + + onSizeUpdated() + sizeUpdated:Connect(onSizeUpdated) + + return surface +end + +local function bindCylinder(part) + if not part:IsA("Part") then + return + end + + local sizeUpdated = part:GetPropertyChangedSignal("Size") + part.Shape = "Ball" + part:MakeJoints() + + local mesh = Instance.new("SpecialMesh") + mesh.MeshId = "rbxassetid://1009010722" + mesh.Archivable = false + mesh.Parent = part + + local leftSurface = makeCylinderSurface(part, sizeUpdated) + leftSurface.Face = "Left" + + local rightSurface = makeCylinderSurface(part, sizeUpdated) + rightSurface.Face = "Right" + + local function onSizeUpdated() + local size = part.Size + local scale = math.min(size.Y,size.Z) + mesh.Scale = Vector3.new(scale,scale,scale) + end + + onSizeUpdated() + sizeUpdated:Connect(onSizeUpdated) +end + +local function findCylinder(obj) + if obj:IsA("Part") and obj.Shape == Enum.PartType.Cylinder then + CollectionService:AddTag(obj, "Cylinder") + end +end + +for _, obj in pairs(workspace:GetDescendants()) do + findCylinder(obj) +end + +for _, cylinder in pairs(CollectionService:GetTagged("Cylinder")) do + bindCylinder(cylinder) +end + +workspace.DescendantAdded:Connect(findCylinder) +cylinderListener:Connect(bindCylinder) diff --git a/Server/Explosions.server.lua b/Server/Explosions.server.lua new file mode 100644 index 0000000..262d41d --- /dev/null +++ b/Server/Explosions.server.lua @@ -0,0 +1,185 @@ +local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") +local ServerStorage = game:GetService("ServerStorage") + +local FORCE_GRANULARITY = 2 +local allowTeamDamage = false + +local teamDamage = ServerStorage:FindFirstChild("TeamDamage") +if teamDamage then + allowTeamDamage = teamDamage.Value +end + +local function processExplosion(explosion) + local BLAST_RADIUS = explosion.BlastRadius + local BLAST_PRESSURE = explosion.BlastPressure + + if explosion:FindFirstChild("BLAST_PRESSURE") then + BLAST_PRESSURE = explosion.BLAST_PRESSURE.Value + end + + if BLAST_PRESSURE > 0 then + local damagedPlayerSet = {} + local blastCenter = explosion.Position + + local function onExplosionHit(p, dist) + if explosion:FindFirstChild("Owner") then + local player = explosion.Owner.Value + if player then + local char = player.Character + if char and p:IsDescendantOf(char) then + return + end + end + end + + local isInCharacter = false + + if p.Size.Magnitude / 2 < 20 then + --world->ticklePrimitive(p, true); + + local doBreakjoints = true + local hitCharacter = p:FindFirstAncestorWhichIsA("Model") + local hitHumanoid = hitCharacter:FindFirstChild("Humanoid") + + if hitCharacter and hitHumanoid then + -- flag as character + isInCharacter = true + + -- don't breakjoints characters + doBreakjoints = false + + -- work out what damage to do + local hitPlayer = game.Players:GetPlayerFromCharacter(hitCharacter) + local creatorTag = explosion:FindFirstChild("creator") + local myPlayer + + if creatorTag then + myPlayer = creatorTag.Value + end + + if hitPlayer and not damagedPlayerSet[hitPlayer] then + local doDamage = true + + if not allowTeamDamage then + if myPlayer and hitPlayer ~= myPlayer then + if hitPlayer.Team and myPlayer.Team and hitPlayer.Team == myPlayer.Team then + doDamage = false + end + end + end + + if doDamage then + -- flag as damaged + damagedPlayerSet[hitPlayer] = true + + -- assume the torso is a massless frictionless unit ball in a perfect vaccum + dist = math.min(math.max(dist - 0.8, 0), 1) + + -- damage to do + local frac = (dist / BLAST_RADIUS) + + -- do damage. See how much damage to do + if myPlayer == hitPlayer then + hitHumanoid:TakeDamage((BLAST_RADIUS * 20) - (frac * 38)) + hitHumanoid:ChangeState("Ragdoll") + else + hitHumanoid:TakeDamage(100) + end + end + end + end + + -- breakjoints stuff + if doBreakjoints then + if not hitHumanoid and p:CanSetNetworkOwnership() then + p:SetNetworkOwner(nil) + end + + for _,joint in pairs(p:GetJoints()) do + if not CollectionService:HasTag(joint, "GorillaGlue") then + joint:Destroy() + end + end + end + + --Vector3 delta = (p->getCoordinateFrame().translation - position); + local delta = (p.Position - blastCenter) + + --Vector3 normal = + -- (delta == Vector3::zero()) + -- ? Vector3::unitY() + -- : delta.direction(); + local normal = (delta == Vector3.new(0, 0, 0)) + and Vector3.new(0, 1, 0) + or delta.unit + + --float radius = p->getRadius(); + local radius = p.Size.magnitude / 2 + + --float surfaceArea = radius * radius; + local surfaceArea = radius * radius + + --Vector3 impulse = normal * blastPressure * surfaceArea * (1.0f / 4560.0f); // normalizing factor + local impulse = normal * BLAST_PRESSURE * surfaceArea * (1.0 / 4560.0) + + -- How much force to apply (for characters, ramp it down towards the edge) + local frac; + + if isInCharacter then + frac = 1 - math.max(0, math.min(1, (dist - 2) / BLAST_RADIUS)) + else + frac = 1 + end + + --p->getBody()->accumulateLinearImpulse(impulse, p->getCoordinateFrame().translation); + local currentVelocity = p.Velocity + local deltaVelocity = impulse / p:GetMass() -- m * del-v = F * del-t = Impulse + local forceNeeded = workspace.Gravity * p:GetMass() -- F = ma + + local bodyV = Instance.new('BodyVelocity') + bodyV.Velocity = currentVelocity + deltaVelocity + bodyV.MaxForce = Vector3.new(forceNeeded, forceNeeded, forceNeeded) * 10 * frac + bodyV.Parent = p + + Debris:AddItem(bodyV, 0.2 / FORCE_GRANULARITY) + + --p->getBody()->accumulateRotationalImpulse(impulse * 0.5 * radius); // a somewhat arbitrary, but nice torque + local rotImpulse = impulse * 0.5 * radius + local currentRotVelocity = p.RotVelocity + + local momentOfInertia = (2 * p:GetMass() * radius * radius / 5) -- moment of inertia = 2/5*m*r^2 (assuming roughly spherical) + local deltaRotVelocity = rotImpulse / momentOfInertia + local torqueNeeded = 20 * momentOfInertia -- torque = r x F, want about alpha = 20 rad/s^2, alpha * P = torque + + local rot = Instance.new('BodyAngularVelocity') + rot.MaxTorque = Vector3.new(torqueNeeded, torqueNeeded, torqueNeeded) * 10 * frac + rot.AngularVelocity = currentRotVelocity + deltaRotVelocity + rot.Parent = p + + Debris:AddItem(rot, 0.2 / FORCE_GRANULARITY) + end + end + + explosion.Hit:Connect(onExplosionHit) + end +end + +local function onDescendantAdded(desc) + if desc:IsA("Explosion") then + local pressure = desc.BlastPressure + + if pressure > 0 then + local blastPressure = Instance.new("NumberValue") + blastPressure.Name = "BLAST_PRESSURE" + blastPressure.Value = pressure + blastPressure.Parent = desc + + desc.BlastPressure = 0 + end + + processExplosion(desc) + end +end + +workspace.DescendantAdded:Connect(onDescendantAdded) \ No newline at end of file diff --git a/Server/ForceFields.server.lua b/Server/ForceFields.server.lua new file mode 100644 index 0000000..94dde20 --- /dev/null +++ b/Server/ForceFields.server.lua @@ -0,0 +1,60 @@ +local ffAdorns = Instance.new("Folder") +ffAdorns.Name = "_ForceFieldAdorns" +ffAdorns.Parent = workspace + +local hide = false +if game.ServerStorage:FindFirstChild("HideForceFields") then + hide = true +end + +local ignoreNames = +{ + HumanoidRootPart = true; + DebugAdorn = true; + NoForceField = true; +} + +local function onDescendantAdded(desc) + if desc:IsA("ForceField") then + desc.Visible = false + if hide then return end + + local adorns = {} + local char = desc.Parent + + local function registerAdorn(child) + if child:IsA("BasePart") and not ignoreNames[child.Name] then + local adorn = Instance.new("SelectionBox") + adorn.Transparency = 1 + adorn.Adornee = child + adorn.Parent = ffAdorns + table.insert(adorns,adorn) + end + end + + for _,part in pairs(char:GetDescendants()) do + registerAdorn(part) + end + + local regSignal = char.DescendantAdded:Connect(registerAdorn) + + + while desc:IsDescendantOf(workspace) do + desc.AncestryChanged:Wait() + end + + for _,adorn in pairs(adorns) do + adorn:Destroy() + end + + adorns = nil + regSignal:Disconnect() + + end +end + +for _,v in pairs(workspace:GetDescendants()) do + onDescendantAdded(v) +end + +workspace.DescendantAdded:Connect(onDescendantAdded) \ No newline at end of file diff --git a/Server/HatGranter.server.lua b/Server/HatGranter.server.lua new file mode 100644 index 0000000..bb99c84 --- /dev/null +++ b/Server/HatGranter.server.lua @@ -0,0 +1,64 @@ +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local itemData = ReplicatedStorage:WaitForChild("ItemData") +local hatData = require(itemData:WaitForChild("Hat")) + +local ServerStorage = game:GetService("ServerStorage") +local grantHatToUser = ServerStorage:WaitForChild("GrantHatToUser") + +local authTable = +{ + ["1073469644"] = { ["96"] = true }; + + ["1081616136"] = { ["97"] = true, + ["98"] = true }; + + ["2421080323"] = { ["100"] = true }; + + ["2471146032"] = { ["101"] = true, + ["102"] = true }; +} + +local playerDataGet = { Success = false } + +pcall(function () + playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) +end) + +if not playerDataGet.Success then + warn("Failed to load PlayerData. HatGranter will not work.") +end + +local playerData = playerDataGet.DataStore + +local function onGrantHat(player,hatId) + local userId = player.UserId + + if userId > 0 then + local auth = authTable[tostring(game.PlaceId)] + + if auth then + local canGiveHat = auth[tostring(hatId)] + + if canGiveHat and playerData then + local hatInfo = hatData[hatId] + local hatAsset = hatInfo.AssetId + + local myData = playerData:GetSaveData(player) + local items = myData:Get("Items") + local loadout = myData:Get("Loadout") + + local id = tostring(hatAsset) + + if not items.Hat[id] then + items.Hat[id] = true + myData:Set("Items", items) + end + + loadout.Hat = hatAsset + myData:Set("Loadout", loadout) + end + end + end +end + +grantHatToUser.Event:Connect(onGrantHat) \ No newline at end of file diff --git a/Server/Heads.server.lua b/Server/Heads.server.lua new file mode 100644 index 0000000..3ab94fa --- /dev/null +++ b/Server/Heads.server.lua @@ -0,0 +1,27 @@ +local function processObject(obj) + if obj:IsA("SpecialMesh") and obj.MeshType == Enum.MeshType.Head then + local head = obj.Parent + + local col = math.min(head.Size.X,head.Size.Z) + local thickness = head.Size.Y/col + + if math.abs(thickness-1) <= 0.01 then + local face = head:FindFirstChild("face") + if face and face.Texture:lower() == "rbxasset://textures/face.png" then + face.Texture = "rbxassetid://1104210678" + end + obj.Name = "MeshHead" + obj.MeshId = "rbxassetid://1104623876" + obj.Scale = obj.Scale * head.Size.Y + for _,surface in pairs(Enum.NormalId:GetEnumItems()) do + head[surface.Name .. "Surface"] = 0 + end + end + end +end + +for _,desc in pairs(workspace:GetDescendants()) do + processObject(desc) +end + +workspace.DescendantAdded:Connect(processObject) \ No newline at end of file diff --git a/Server/InputGateway.server.lua b/Server/InputGateway.server.lua new file mode 100644 index 0000000..0dfbbc8 --- /dev/null +++ b/Server/InputGateway.server.lua @@ -0,0 +1,48 @@ +local self = script.Parent +local remote = self:WaitForChild("Gateway") + +local tool = self.Parent +tool.ManualActivationOnly = true + +local keyEvent = Instance.new("BindableEvent") +keyEvent.Name = "KeyEvent" +keyEvent.Parent = tool + +local function onGatewayReceive(sendingPlayer, request, ...) + local char = tool.Parent + + if char and char:IsA("Model") then + local humanoid = char:FindFirstChild("Humanoid") + + if humanoid then + local player = game.Players:GetPlayerFromCharacter(char) + assert(sendingPlayer == player) + + if request == "SetActive" then + local down, target = ... + assert(typeof(target) == "CFrame","Expected CFrame") + + humanoid.TargetPoint = target.p + + if humanoid.Health > 0 and tool:IsDescendantOf(char) then + if down then + tool:Activate() + else + tool:Deactivate() + end + end + elseif request == "SetTarget" then + local target = ... + assert(typeof(target) == "CFrame","Expected CFrame") + humanoid.TargetPoint = target.p + elseif request == "KeyEvent" then + local key, down = ... + assert(typeof(key) == "string","bad key cast") + assert(typeof(down) == "boolean","bad down state cast") + keyEvent:Fire(key, down) + end + end + end +end + +remote.OnServerEvent:Connect(onGatewayReceive) \ No newline at end of file diff --git a/Server/Leaderboard.server.lua b/Server/Leaderboard.server.lua new file mode 100644 index 0000000..8cbdcd0 --- /dev/null +++ b/Server/Leaderboard.server.lua @@ -0,0 +1,194 @@ +print("LinkedLeaderboard script version 5.00 loaded") + +local ServerStorage = game:GetService("ServerStorage") +local loadConfig = ServerStorage:FindFirstChild("LoadLeaderboard") +local hasLoadConfig = (loadConfig ~= nil) + +if hasLoadConfig and not loadConfig.Value then + return +end + +if not (ServerStorage:FindFirstChild("LoadTools") or (hasLoadConfig and loadConfig.Value)) then -- Infer we aren't in a brickbattle. + return +end + +stands = {} +CTF_mode = false + +function onHumanoidDied(humanoid, player) + local stats = player:findFirstChild("leaderstats") + if stats ~= nil then + local deaths = stats:findFirstChild("Wipeouts") + deaths.Value = deaths.Value + 1 + + -- do short dance to try and find the killer + + local killer = getKillerOfHumanoidIfStillInGame(humanoid) + + handleKillCount(humanoid, player) + end +end + +function onPlayerRespawn(property, player) + -- need to connect to new humanoid + + if property == "Character" and player.Character ~= nil then + local humanoid = player.Character.Humanoid + local deathCon + local p = player + local h = humanoid + deathCon = humanoid.Died:connect(function () + deathCon:Disconnect() + onHumanoidDied(h, p) + end) + end +end + +function getKillerOfHumanoidIfStillInGame(humanoid) + -- returns the player object that killed this humanoid + -- returns nil if the killer is no longer in the game + + -- check for kill tag on humanoid - may be more than one - todo: deal with this + local tag = humanoid:findFirstChild("creator") + + -- find player with name on tag + if tag ~= nil then + + local killer = tag.Value + if killer.Parent ~= nil then -- killer still in game + return killer + end + end + + return nil +end + +function handleKillCount(humanoid, player) + local killer = getKillerOfHumanoidIfStillInGame(humanoid) + if killer ~= nil then + local stats = killer:findFirstChild("leaderstats") + if stats ~= nil then + local kills = stats:findFirstChild("KOs") + if killer ~= player then + kills.Value = kills.Value + 1 + + else + kills.Value = kills.Value - 1 + + end + end + end +end + + +----------------------------------------------- + + + +function findAllFlagStands(root) + local c = root:children() + for i=1,#c do + if (c[i].className == "Model" or c[i].className == "Part") then + findAllFlagStands(c[i]) + end + if (c[i].className == "FlagStand") then + table.insert(stands, c[i]) + end + end +end + +function hookUpListeners() + for i=1,#stands do + stands[i].FlagCaptured:connect(onCaptureScored) + end +end + +function onPlayerEntered(newPlayer) + + if CTF_mode == true then + + local stats = Instance.new("IntValue") + stats.Name = "leaderstats" + + local captures = Instance.new("IntValue") + captures.Name = "Captures" + captures.Value = 0 + + + captures.Parent = stats + + -- VERY UGLY HACK + -- Will this leak threads? + -- Is the problem even what I think it is (player arrived before character)? + while true do + if newPlayer.Character ~= nil then break end + wait(5) + end + + stats.Parent = newPlayer + + else + + local stats = Instance.new("IntValue") + stats.Name = "leaderstats" + + local kills = Instance.new("IntValue") + kills.Name = "KOs" + kills.Value = 0 + + local deaths = Instance.new("IntValue") + deaths.Name = "Wipeouts" + deaths.Value = 0 + + kills.Parent = stats + deaths.Parent = stats + + -- VERY UGLY HACK + -- Will this leak threads? + -- Is the problem even what I think it is (player arrived before character)? + while true do + if newPlayer.Character ~= nil then break end + wait(0.5) + end + + local deathCon + local humanoid = newPlayer.Character.Humanoid + + deathCon = humanoid.Died:connect(function() + deathCon:Disconnect() + onHumanoidDied(humanoid, newPlayer) + end ) + + -- start to listen for new humanoid + newPlayer.Changed:connect(function(property) onPlayerRespawn(property, newPlayer) end ) + + + stats.Parent = newPlayer + + end + +end + + +function onCaptureScored(player) + + local ls = player:findFirstChild("leaderstats") + if ls == nil then return end + local caps = ls:findFirstChild("Captures") + if caps == nil then return end + caps.Value = caps.Value + 1 + +end + + +findAllFlagStands(game.Workspace) +hookUpListeners() +if (#stands > 0) then CTF_mode = true end + +for _,v in pairs(game.Players:GetPlayers()) do + onPlayerEntered(v) +end + +game.Players.ChildAdded:connect(onPlayerEntered) + + diff --git a/Server/LoadTools.server.lua b/Server/LoadTools.server.lua new file mode 100644 index 0000000..90b84f1 --- /dev/null +++ b/Server/LoadTools.server.lua @@ -0,0 +1,19 @@ +local ServerStorage = game:GetService("ServerStorage") +local StarterPack = game:GetService("StarterPack") +local Players = game:GetService("Players") + +local standardTools = ServerStorage:WaitForChild("StandardTools") +local loadTools = ServerStorage:FindFirstChild("LoadTools") + +if loadTools then + for toolName in loadTools.Value:gmatch("[^;]+") do + local tool = standardTools:WaitForChild(toolName) + tool:Clone().Parent = StarterPack + + for _,v in pairs(Players:GetPlayers()) do + if v:FindFirstChild("Backpack") and not v:FindFirstChild(tool.Name) then + tool:Clone().Parent = v.Backpack + end + end + end +end \ No newline at end of file diff --git a/Server/Parts.server.lua b/Server/Parts.server.lua new file mode 100644 index 0000000..2f0c951 --- /dev/null +++ b/Server/Parts.server.lua @@ -0,0 +1,295 @@ +local CollectionService = game:GetService("CollectionService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local ServerStorage = game:GetService("ServerStorage") +local Players = game:GetService("Players") + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local brickColors = require(ReplicatedStorage:WaitForChild("BrickColors")) +local oldColors = {} + +for _,v in ipairs(brickColors) do + oldColors[v] = true +end + +local textureCaches = {} +local colorCaches = {} + +local char = string.char +local floor = math.floor +local clamp = math.clamp + +local function serializeColor3(color) + local r = clamp(floor(color.r * 256), 0, 255) + local g = clamp(floor(color.g * 256), 0, 255) + local b = clamp(floor(color.b * 256), 0, 255) + return r .. g .. b +end + +local function computeEpsilon(bc, color) + local bColor = bc.Color + + local v0 = Vector3.new(bColor.r, bColor.g, bColor.b) + local v1 = Vector3.new(color.r, color.g, color.b) + + return (v1-v0).Magnitude +end + +local function toNearestOldBrickColor(color) + local colorKey = serializeColor3(color) + + if not colorCaches[colorKey] then + local bestColor, bestEpsilon = nil, math.huge + + for bcName in pairs(oldColors) do + local bc = BrickColor.new(bcName) + local epsilon = computeEpsilon(bc, color) + + if epsilon < bestEpsilon then + bestEpsilon = epsilon + bestColor = bc + end + end + + colorCaches[colorKey] = bestColor + end + + return colorCaches[colorKey] +end + +local function onBrickColorUpdated(part) + part.BrickColor = toNearestOldBrickColor(part.Color) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local scale = 1 + +if ServerStorage:FindFirstChild("StudScale") then + scale = ServerStorage.StudScale.Value +end + +local surfaces = +{ + TopSurface = "Top"; + BottomSurface = "Bottom"; + LeftSurface = "Left"; + RightSurface = "Right"; + FrontSurface = "Front"; + BackSurface = "Back"; +} + +local textures = +{ + Studs = 3309082834; + Inlet = 3307955447; + Glue = 3308133326; + Weld = 3308005654; +} + +local normalIdToAxis = +{ + Left = 'X'; + Right = 'X'; + Top = 'Y'; + Bottom = 'Y'; + Front = 'Z'; + Back = 'Z'; +} + +local function selectUVSize(part, normalId) + if typeof(normalId) == "EnumItem" then + normalId = normalId.Name + end + + local axis = normalIdToAxis[normalId] + local size = part.Size + + if axis == 'X' then + return size.Z, size.Y + elseif axis == 'Z' then + return size.X, size.Y + elseif axis == 'Y' then + return size.X, size.Z + end +end + +local function onSurfaceChanged(part, surface) + local surfaceId = part[surface].Name + + if surfaceId ~= "SmoothNoOutlines" then + local normalId = surfaces[surface] + local textureId = textures[surfaceId] + + local cache = textureCaches[part] + local texture = cache[surface] + + if not textureId then + if texture then + texture.Texture = "" + end + + return + end + + if not (texture and texture:IsA("Texture")) then + texture = Instance.new("Texture") + cache[surface] = texture + + texture.StudsPerTileU = 2; + texture.StudsPerTileV = 4; + + texture.Face = normalId + texture.Name = surface + + texture.Parent = part + end + + -- Select the texture id based on the even/odd dimensions of the UV map. + local mapId = "AA" + + if part:IsA("MeshPart") then + local texU, texV = selectUVSize(part, normalId) + + local alignU = string.format("%i", (texU % 2) + .5) + local alignV = string.format("%i", (texV % 2) + .5) + + if alignU == '1' then + texture.OffsetStudsU = 0.5 + end + + if alignV == '1' then + texture.OffsetStudsV = 0.5 + end + end + + texture.Texture = "rbxassetid://" .. textureId + end +end + +local function onTransparencyChanged(part) + local textureCache = textureCaches[part] + + for _,texture in pairs(textureCache) do + texture.Transparency = 0.25 + (part.Transparency * 0.75) + end +end + +local function onParentChanged(part) + local texureCache = textureCaches[part] + + if not part:IsDescendantOf(workspace) then + for _,tex in pairs(texureCache) do + tex:Destroy() + end + + texureCache[part] = nil + end +end + +local function registerPartSurfaces(part) + local textureCache = {} + textureCaches[part] = textureCache + + for surface in pairs(surfaces) do + onSurfaceChanged(part, surface) + end + + onBrickColorUpdated(part) + onTransparencyChanged(part) + + part.Material = "SmoothPlastic" +end + +local function applyCharacter(humanoid) + local model = humanoid.Parent + + if not CollectionService:HasTag(humanoid, "Classified") then + CollectionService:AddTag(humanoid, "Classified") + + for _,v in pairs(model:GetDescendants()) do + if v:IsA("SpecialMesh") and v.MeshType == Enum.MeshType.Brick then + v:Destroy() + end + end + + for _,v in pairs(script:GetChildren()) do + if v:IsA("CharacterMesh") then + local copy = v:Clone() + copy.Parent = model + CollectionService:AddTag(copy, "NoCharacterBevels") + end + end + + delay(1, function () + if not model:FindFirstChildWhichIsA("Shirt") then + script.Shirt:Clone().Parent = model + end + + if not model:FindFirstChildWhichIsA("Pants") then + script.Pants:Clone().Parent = model + end + end) + end +end + +local function onDescendantAdded(desc) + if desc:IsA("BasePart") then + local model = desc:FindFirstAncestorWhichIsA("Model") + + if model then + local humanoid = model:FindFirstChildWhichIsA("Humanoid") + + if humanoid then + applyCharacter(humanoid) + return + end + + local fileMesh = desc:FindFirstChildWhichIsA("FileMesh") + + if fileMesh then + local meshType = fileMesh.MeshType.Name + if meshType == "Head" or meshType == "FileMesh" then + desc.Material = "SmoothPlastic" + return + end + end + + if desc:IsA("VehicleSeat") then + desc.HeadsUpDisplay = false + end + + if not CollectionService:HasTag(desc, "NoBevels") then + registerPartSurfaces(desc) + end + end + elseif desc:IsA("Decal") and desc.Texture:lower() == "rbxasset://textures/spawnlocation.png" then + desc.Texture = "rbxassetid://989514407" + elseif desc:IsA("Humanoid") then + applyCharacter(desc) + end +end + +local function onItemChanged(object, descriptor) + if textureCaches[object] then + if surfaces[descriptor] then + onSurfaceChanged(object, descriptor) + elseif descriptor == "Transparency" then + onTransparencyChanged(object) + elseif descriptor == "BrickColor" then + onBrickColorUpdated(object) + elseif descriptor == "Parent" then + onParentChanged(object) + end + end +end + +for _,desc in pairs(workspace:GetDescendants()) do + onDescendantAdded(desc) +end + +workspace.DescendantAdded:Connect(onDescendantAdded) +game.ItemChanged:Connect(onItemChanged) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + diff --git a/Server/Regeneration.server.lua b/Server/Regeneration.server.lua new file mode 100644 index 0000000..e3edb83 --- /dev/null +++ b/Server/Regeneration.server.lua @@ -0,0 +1,98 @@ +local CollectionService = game:GetService("CollectionService") +local ServerStorage = game:GetService("ServerStorage") + +local regen = ServerStorage:FindFirstChild("Regeneration") + +if regen then + local REGEN_TIME = 800 + local REGEN_DELAY = 4 + + if regen:FindFirstChild("RegenTime") then + REGEN_TIME = regen.RegenTime.Value + end + + if regen:FindFirstChild("RegenDelay") then + REGEN_DELAY = regen.RegenDelay.Value + end + + local ready = Instance.new("BoolValue") + ready.Name = "Ready" + ready.Parent = regen + + local bevelCache = ServerStorage:WaitForChild("BevelCache") + local bevelsReady = bevelCache:WaitForChild("BevelsReady") + + local function isLodPart(part) + return part and CollectionService:HasTag(part, "PartLOD") + end + + local function setupModelRegen(model, title) + local title = title or model.Name + + local parent = model.Parent + local backup = model:Clone() + + local message, text + + if typeof(title) == "string" then + message = Instance.new("Message") + text = "Regenerating " .. title .. "..." + end + + spawn(function () + while not bevelsReady.Value do + bevelsReady.Changed:Wait() + end + + local requestSolve = bevelCache:FindFirstChild("RequestSolve") + if requestSolve then + requestSolve:Invoke(backup) + end + + while wait(REGEN_TIME * (1 - (math.random() * .8))) do + local cooldown = 0 + + if message then + message.Text = text + message.Parent = workspace + end + + model:Destroy() + wait(REGEN_DELAY) + + model = backup:Clone() + model.Parent = parent + + for _,inst in pairs(model:GetDescendants()) do + if inst:IsA("BasePart") then + workspace:JoinToOutsiders({inst}, Enum.JointCreationMode.All) + end + end + + for _,joint in pairs(model:GetDescendants()) do + if joint:IsA("JointInstance") and joint.Name:sub(-12) == "Strong Joint" then + if isLodPart(joint.Part0) or isLodPart(joint.Part1) then + joint:Destroy() + end + end + end + + if message then + message.Parent = nil + end + end + end) + end + + for _,v in pairs(regen:GetChildren()) do + if v:IsA("ObjectValue") then + if v.Name == "" then + setupModelRegen(v.Value, true) + else + setupModelRegen(v.Value, v.Name) + end + end + end + + ready.Value = true +end \ No newline at end of file diff --git a/Server/SessionTracker.server.lua b/Server/SessionTracker.server.lua new file mode 100644 index 0000000..ab71524 --- /dev/null +++ b/Server/SessionTracker.server.lua @@ -0,0 +1,52 @@ +local MessagingService = game:GetService("MessagingService") +local Players = game:GetService("Players") + +local jobId = game.JobId +local placeId = game.PlaceId + +if jobId == "" then + return +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local closed = false + +local function publishUpdate() + local playerCount = #Players:GetPlayers() + + local serverInfo = + { + JobId = jobId; + PlaceId = placeId; + Players = playerCount; + } + + if closed then + serverInfo.Closed = true; + end + + pcall(function () + MessagingService:PublishAsync("ServerData", serverInfo) + end) +end + +local function onGameClosing() + closed = true + publishUpdate() +end + +game:BindToClose(onGameClosing) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +while #Players:GetPlayers() < 1 do + wait(1) +end + +while not closed do + publishUpdate() + wait(5) +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Server/Time.server.lua b/Server/Time.server.lua new file mode 100644 index 0000000..e8c1e5a --- /dev/null +++ b/Server/Time.server.lua @@ -0,0 +1,10 @@ +local Lighting = game:GetService("Lighting") +local ServerStorage = game:GetService("ServerStorage") +local loadTime = ServerStorage:FindFirstChild("LoadTime") + +if loadTime and loadTime.Value then + while wait() do + Lighting:SetMinutesAfterMidnight((tick()*5)%1440) + end +end + diff --git a/Shared/ReplicatedStorage/AssetUtil.lua b/Shared/ReplicatedStorage/AssetUtil.lua new file mode 100644 index 0000000..b8cae5e --- /dev/null +++ b/Shared/ReplicatedStorage/AssetUtil.lua @@ -0,0 +1,78 @@ +local MarketplaceService = game:GetService("MarketplaceService") +local InsertService = game:GetService("InsertService") + +local AssetUtil = +{ + TextureCache = {}; + NUM_FETCH_RETRIES = 4; +} + +local assetTypes = {} +for _,assetType in pairs(Enum.AssetType:GetEnumItems()) do + assetTypes[assetType.Value] = assetType.Name +end + +function AssetUtil:SafeCall(class,method,...) + local success,response + local tries = 0 + while not success do + success,response = pcall(class[method],class,...) + if not success then + if response:find("400") then + success = true + response = false + else + tries = tries + 1 + if tries > self.NUM_FETCH_RETRIES then + return false + end + end + end + end + return success,response +end + +function AssetUtil:Import(assetId) + local success,model = self:SafeCall(InsertService,"LoadAsset",assetId) + if success then + local objects = model:GetChildren() + return true,unpack(objects) + end + return false +end + +function AssetUtil:RequestImage(assetId) + assert(typeof(assetId) == "number") + assert(assetId == math.floor(assetId)) + assert(assetId > 0) + + if self.TextureCache[assetId] == nil then + local success,response = self:SafeCall(MarketplaceService,"GetProductInfo",assetId) + if success then + local result + if response then + local assetType = assetTypes[response.AssetTypeId] + if assetType == "Image" then -- No transformation needed! + result = "rbxassetid://" .. assetId + elseif assetType == "TeeShirt" then + local imported,shirtGraphic = self:Import(assetId) + if imported then + result = shirtGraphic.Graphic + end + elseif assetType == "Decal" or assetType == "Face" then + local imported,decal = self:Import(assetId) + if imported then + result = decal.Texture + end + end + else + result = "" + end + self.TextureCache[assetId] = result + end + end + + return true,self.TextureCache[assetId] +end + +return AssetUtil \ No newline at end of file diff --git a/Shared/ReplicatedStorage/BrickColors.lua b/Shared/ReplicatedStorage/BrickColors.lua new file mode 100644 index 0000000..76dc402 --- /dev/null +++ b/Shared/ReplicatedStorage/BrickColors.lua @@ -0,0 +1,35 @@ +return +{ + "White"; + "Light stone grey"; + "Medium stone grey"; + "Dark stone grey"; + "Black"; + "Bright red"; + "Bright yellow"; + "Cool yellow"; + "Bright blue"; + "Bright bluish green"; + "Medium blue"; + "Pastel Blue"; + "Light blue"; + "Sand blue"; + "Bright orange"; + "Br. yellowish orange"; + "Earth green"; + "Dark green"; + "Bright green"; + "Br. yellowish green"; + "Medium green"; + "Sand green"; + "Dark orange"; + "Reddish brown"; + "Bright violet"; + "Light reddish violet"; + "Medium red"; + "Brick yellow"; + "Sand red"; + "Brown"; + "Nougat"; + "Light orange"; +} \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/FpsCap.lua b/Shared/ReplicatedStorage/Client/FpsCap.lua new file mode 100644 index 0000000..00efa60 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/FpsCap.lua @@ -0,0 +1,17 @@ +return function (script) + local RunService = game:GetService("RunService") + local TeleportService = game:GetService("TeleportService") + + spawn(function () + while RunService.RenderStepped:Wait() do + if TeleportService:GetTeleportSetting("FPSCapTo30") then + local t0 = tick() + RunService.Heartbeat:Wait() + debug.profilebegin("30 FPS Cap") + repeat until (t0+0.0325) < tick() + debug.profileend() + end + end + end) + +end \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/LensFlare.lua b/Shared/ReplicatedStorage/Client/LensFlare.lua new file mode 100644 index 0000000..a1989b6 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/LensFlare.lua @@ -0,0 +1,134 @@ +local RunService = game:GetService("RunService") +local Lighting = game:GetService("Lighting") +local TeleportService = game:GetService("TeleportService") + +local c = workspace.CurrentCamera + +local lensFlareNode = c:FindFirstChild("LensFlareNode") +if not lensFlareNode then + lensFlareNode = Instance.new("Part") + lensFlareNode.Name = "LensFlareNode" + lensFlareNode.Transparency = 1 + lensFlareNode.Anchored = true + lensFlareNode.CanCollide = false + lensFlareNode.Locked = true + lensFlareNode.Parent = c +end + +local lenses = +{ + { Color = Color3.fromRGB(200, 255, 200), Radius = 1.20, Distance = 0.100 }; + { Color = Color3.fromRGB( 0, 255, 0), Radius = 0.50, Distance = 0.200 }; + { Color = Color3.fromRGB(255, 0, 0), Radius = 0.30, Distance = 0.225 }; + { Color = Color3.fromRGB(255, 170, 0), Radius = 1.50, Distance = 0.250 }; + { Color = Color3.fromRGB(255, 170, 0), Radius = 3.00, Distance = 0.250 }; + { Color = Color3.fromRGB( 0, 255, 0), Radius = 0.50, Distance = 0.300 }; + { Color = Color3.fromRGB( 0, 255, 0), Radius = 0.20, Distance = 0.600 }; + { Color = Color3.fromRGB( 0, 255, 0), Radius = 0.40, Distance = 0.650 }; + { Color = Color3.fromRGB(255, 0, 0), Radius = 0.20, Distance = 0.780 }; + { Color = Color3.fromRGB( 0, 255, 0), Radius = 0.25, Distance = 0.900 }; + { Color = Color3.fromRGB( 23, 17, 0), Radius = 0.15, Distance = 1.200 }; + { Color = Color3.fromRGB( 23, 17, 0), Radius = 0.15, Distance = 1.500 }; +} + +local function projectRay(ray,length) + local origin = ray.Origin + local direction = ray.Direction + return Ray.new(origin,direction.Unit * length) +end + +local function computeSunOcclusion() + local sunPos = Lighting:GetSunDirection() + local cf = c.CFrame + + if sunPos:Dot(cf.lookVector) > 0 then + local sunView = c:WorldToViewportPoint(cf.p + sunPos) + local visibility = 0 + local total = 0 + + for dx = -1,1 do + for dy = -1,1 do + local posX = math.floor(sunView.X + dx * 15) + local posY = math.floor(sunView.Y + dy * 15) + + local sunRay = c:ViewportPointToRay(posX, posY) + sunRay = projectRay(sunRay,5000) + + local hit,pos = workspace:FindPartOnRay(sunRay,c) + if not hit then + visibility = visibility + 1 + end + total = total + 1 + end + end + + visibility = visibility / total + return (1-visibility),sunView + end + + return 0 +end + +local function asVector2(v3,...) + return Vector2.new(v3.X,v3.Y),... +end + +local function update() + if TeleportService:GetTeleportSetting("ClassicSky") then + local vpSize = c.ViewportSize + local sunDir = Lighting:GetSunDirection() + local sunWP = sunDir * 10e6 + local sunSP,inView = asVector2(c:WorldToViewportPoint(sunWP)) + local occlusion = inView and computeSunOcclusion() or 1 + if occlusion < 1 then + local invSunSP = vpSize - sunSP + local enabled = (inView and occlusion < 1) + local flareBrightness = math.sqrt(math.max(0,sunDir.y*4)) + + for i,lense in ipairs(lenses) do + local radius = lense.Radius / 12 + if not lense.Beam then + local a0 = Instance.new("Attachment") + lense.A0 = a0 + a0.Name = i .. "_A0" + a0.Parent = lensFlareNode + + local a1 = Instance.new("Attachment") + lense.A1 = a1 + a1.Name = i .. "_A1" + a1.Parent = lensFlareNode + + local beam = Instance.new("Beam") + lense.Beam = beam + + beam.Name = i + beam.Color = ColorSequence.new(lense.Color) + beam.Width0 = radius + beam.Width1 = radius + beam.TextureSpeed = 0 + beam.Transparency = NumberSequence.new(0.9) + beam.LightEmission = 1 + beam.Texture = "rbxasset://sky/lensflare.jpg" + beam.Attachment0 = a0 + beam.Attachment1 = a1 + beam.Parent = lensFlareNode + end + + local lenseSP = invSunSP:lerp(sunSP,lense.Distance) + local lenseWP = c:ViewportPointToRay(lenseSP.X,lenseSP.Y,1).Origin + local lenseCF = CFrame.new(lenseWP,lenseWP - sunDir) + lense.A0.CFrame = lenseCF * CFrame.new(-radius/2,0,0) + lense.A1.CFrame = lenseCF * CFrame.new(radius/2,0,0) + end + + lensFlareNode.Parent = c + return + end + end + + lensFlareNode.Parent = nil +end + +return function (script) + RunService:BindToRenderStep("LensFlareUpdate",201,update) +end \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Moon.lua b/Shared/ReplicatedStorage/Client/Moon.lua new file mode 100644 index 0000000..b40a7f1 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Moon.lua @@ -0,0 +1,24 @@ +return function (script) + local RunService = game:GetService("RunService") + local Lighting = game:GetService("Lighting") + local TeleportService = game:GetService("TeleportService") + + local c = workspace.CurrentCamera + local moon = script:WaitForChild("Moon") + moon.Locked = true + moon.Size = Vector3.new(50,50,1) + + local function moonUpdate() + if TeleportService:GetTeleportSetting("ClassicSky") then + local pos = Lighting:GetMoonDirection() * 900 + local origin = c.CFrame.p + moon.Parent = c + moon.CFrame = CFrame.new(origin+pos, origin) + else + moon.Parent = nil + end + end + + RunService:BindToRenderStep("MoonUpdate",201,moonUpdate) + return 1 +end \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Moon/Moon.rbxmx b/Shared/ReplicatedStorage/Client/Moon/Moon.rbxmx new file mode 100644 index 0000000..7d5a855 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Moon/Moon.rbxmx @@ -0,0 +1,194 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 175.2431 + 225.3089 + -54.92519 + 0.74845 + -0.2371427 + 0.6193432 + 1.490116E-08 + 0.9338833 + 0.3575782 + -0.6631912 + -0.2676294 + 0.698965 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + false + 256 + Moon + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 80 + 80 + 1 + + true + + + + true + null + false + + true + + 800 + 800 + + false + true + 5 + 0 + MoonGui + 50 + true + null + 0 + + 0 + 0 + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + rbxassetid://599112257 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + MoonImage + null + null + null + null + + -0.5 + 0 + -0.5 + 0 + + null + 0 + 0 + false + null + + 2 + 0 + 2 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Mouse.lua b/Shared/ReplicatedStorage/Client/Mouse.lua new file mode 100644 index 0000000..975b019 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Mouse.lua @@ -0,0 +1,133 @@ +local UserInputService = game:GetService("UserInputService") +local RunService = game:GetService("RunService") +local GuiService = game:GetService("GuiService") +local Players = game:GetService("Players") + +----------------------------------------------------------------- + +local inGuiFocus = false +local inputQueue = {} + +local function checkGuiFocus() + inGuiFocus = (next(inputQueue) ~= nil) +end + +local function onInputChanged(input,gameProcessed) + if input.UserInputType == Enum.UserInputType.MouseMovement then + inputQueue[input] = gameProcessed or nil + checkGuiFocus() + end +end + +UserInputService.InputChanged:Connect(onInputChanged) + +----------------------------------------------------------------- + +local activated = false +local player = Players.LocalPlayer +local mouseGui + +local function onInputBegan(input,gameProcessed) + if mouseGui then + if input.UserInputType == Enum.UserInputType.Touch and not gameProcessed then + wait(.1) + if input.UserInputState == Enum.UserInputState.End then + activated = true + else + mouseGui.ImageTransparency = 1 + end + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + +----------------------------------------------------------------- + +local GUN_WAIT_CURSOR = "rbxasset://textures/GunWaitCursor.png" +local GUN_CURSOR = "rbxasset://textures/GunCursor.png" +local IS_TOUCH = UserInputService.TouchEnabled + +return function (script) + mouseGui = script.Parent + + local hasTool = mouseGui:WaitForChild("HasTool") + UserInputService.MouseIconEnabled = false + + local canActivate = true + + if UserInputService.TouchEnabled then + local c = workspace.CurrentCamera + local playerGui = player:WaitForChild("PlayerGui") + local touchGui = playerGui:WaitForChild("TouchGui") + local touchFrame = touchGui:WaitForChild("TouchControlFrame") + if c.ViewportSize.Y < 600 then + touchFrame.Size = UDim2.new(0.85,0,0.8,0) + else + touchFrame.Size = UDim2.new(0.9,0,0.9,0) + end + touchFrame.Position = UDim2.new(0.05,0,0,0) + end + + local function updateMouse() + local char = player.Character + local tool + local override = false + if char then + tool = char:FindFirstChildWhichIsA("Tool") + hasTool.Value = (tool ~= nil) + if tool then + if tool:FindFirstChild("IconOverride") then + if tool.IconOverride.Value ~= "" then + mouseGui.Image = tool.IconOverride.Value + else + mouseGui.Image = "rbxassetid://1000000" + end + elseif tool.Enabled then + mouseGui.Image = GUN_CURSOR + if IS_TOUCH then + canActivate = true + mouseGui.ImageTransparency = 1 + end + else + mouseGui.Image = GUN_WAIT_CURSOR + end + end + else + hasTool.Value = false + end + if inGuiFocus then + mouseGui.Image = "rbxassetid://1000000" + end + + local guiInset = GuiService:GetGuiInset() + local pos = UserInputService:GetMouseLocation() - guiInset + local upos = UDim2.new(0,pos.X,0,pos.Y) + + if IS_TOUCH then + if hasTool.Value then + mouseGui.Visible = true + if activated and mouseGui.Image == GUN_WAIT_CURSOR then + if canActivate then + canActivate = false + mouseGui.Position = upos + mouseGui.ImageTransparency = -1 + end + activated = false + else + mouseGui.ImageTransparency = math.min(1,mouseGui.ImageTransparency + 0.01) + end + else + mouseGui.Visible = false + end + else + mouseGui.Position = upos + end + + if UserInputService.MouseIconEnabled then + UserInputService.MouseIconEnabled = false + end + end + + RunService:BindToRenderStep("UpdateMouse",1000,updateMouse) +end \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Sky.lua b/Shared/ReplicatedStorage/Client/Sky.lua new file mode 100644 index 0000000..a423fce --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Sky.lua @@ -0,0 +1,146 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Services + +local Lighting = game:GetService("Lighting") +local RunService = game:GetService("RunService") +local TeleportService = game:GetService("TeleportService") +local UserInputService = game:GetService("UserInputService") + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Sky Colors + +local midnight = 0 +local day = 86400 +local hour = day/24 + +local sunRise = day * .25 +local sunSet = day * .75 +local riseAndSetTime = hour/2 + +local times = +{ + midnight; + sunRise - hour; + sunRise - riseAndSetTime; + sunRise; + sunRise + riseAndSetTime; + sunSet - riseAndSetTime; + sunSet; + sunSet + (hour/3); + day; +} + +local colors = +{ + Color3.new(); + Color3.new(); + Color3.new(.2, .15, .01); + Color3.new(.2, .15, .01); + Color3.new(1, 1, 1); + Color3.new(1, 1, 1); + Color3.new(.4, .2, .05); + Color3.new(); + Color3.new(); +} + +local function linearSpline(x,times,values) + assert(#times == #values) + if #values == 1 or x < times[1] then + return values[1] + end + + for i = 2, #times do + if x < times[i] then + local alpha = (times[i] - x) / (times[i] - times[i-1]) + return values[i-1]:lerp(values[i], 1-alpha) + end + end + + return values[#values] +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local lastTime = 0 +local c = workspace.CurrentCamera + +local function r() + return -1 + (math.random()*2) +end + +local skyAdorn = script:WaitForChild("SkyAdorn") +local night = skyAdorn:WaitForChild("Night") +local nightFrame = night:WaitForChild("NightFrame") +local star = script:WaitForChild("Star") + +if UserInputService.TouchEnabled then + -- TODO: Get rid of this when shadow-mapping is available + -- on mobile or the tone mapping is corrected. + + spawn(function () + local legacyToneMap = Lighting:WaitForChild("LegacyToneMap") + legacyToneMap:Destroy() + end) +end + +return function (script) + local shadowsOn = true + + for i = 1,500 do + local bb = star:Clone() + bb.StudsOffsetWorldSpace = Vector3.new(r(), r(), r()).Unit * 2500 + bb.Size = UDim2.new(0, math.random(2, 5), 0, math.random(2, 5)) + bb.Adornee = skyAdorn + bb.Parent = skyAdorn + end + + local function updateSky() + local shadowState = TeleportService:GetTeleportSetting("StencilShadows") + + if shadowState == nil then + TeleportService:SetTeleportSetting("StencilShadows", true) + shadowState = true + end + + if shadowState ~= shadowsOn then + shadowsOn = shadowState + + if shadowsOn then + local black = Color3.new() + Lighting.GlobalShadows = true + Lighting.Ambient = black:Lerp(Lighting.OutdoorAmbient, 0.5) + else + Lighting.GlobalShadows = false + Lighting.Ambient = Lighting.OutdoorAmbient + end + end + + + + if TeleportService:GetTeleportSetting("ClassicSky") then + local seconds = Lighting:GetMinutesAfterMidnight() * 60 + + if seconds < 0 then + seconds = day + seconds + end + + if seconds ~= lastTime then + local sunDir = game.Lighting:GetSunDirection() + local skyColor = linearSpline(seconds, times, colors) + nightFrame.BackgroundColor3 = skyColor + nightFrame.BackgroundTransparency = math.clamp((sunDir.Y + .033) * 10, 0, 1) + lastTime = seconds + end + + local sunDir = Lighting:GetSunDirection() + skyAdorn.CFrame = CFrame.new(c.CFrame.p) * CFrame.new(Vector3.new(), sunDir) + skyAdorn.Parent = (nightFrame.BackgroundTransparency < 1 and c or nil) + else + skyAdorn.Parent = nil + end + end + + RunService:BindToRenderStep("UpdateSky", 201, updateSky) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Sky/SkyAdorn.rbxmx b/Shared/ReplicatedStorage/Client/Sky/SkyAdorn.rbxmx new file mode 100644 index 0000000..a7866db --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Sky/SkyAdorn.rbxmx @@ -0,0 +1,186 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 154.9001 + 49.55002 + -213.09 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + SkyAdorn + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 0.05 + 0.05 + 0.05 + + true + + + + false + null + false + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 1 + INF + Night + null + true + null + + 0 + 3000 + 0 + 3000 + + + 0 + 0 + + + 0 + 0 + -3000 + + + 0 + 0 + 0 + + + 0 + true + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + NightFrame + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + + \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/Sky/Star.rbxmx b/Shared/ReplicatedStorage/Client/Sky/Star.rbxmx new file mode 100644 index 0000000..3ef3671 --- /dev/null +++ b/Shared/ReplicatedStorage/Client/Sky/Star.rbxmx @@ -0,0 +1,109 @@ + + + + false + null + false + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 0 + INF + Star + null + true + null + + 0 + 3 + 0 + 3 + + + 0 + 0 + + + 0 + 0 + 0 + + + 0 + 0 + 0 + + + 0 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Frame + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/SunRays.lua b/Shared/ReplicatedStorage/Client/SunRays.lua new file mode 100644 index 0000000..32e763b --- /dev/null +++ b/Shared/ReplicatedStorage/Client/SunRays.lua @@ -0,0 +1,79 @@ +local Lighting = game:GetService("Lighting") +local RunService = game:GetService("RunService") +local TeleportService = game:GetService("TeleportService") + +local adorn = script:WaitForChild("Rays") +local sunRays = adorn:WaitForChild("SunRays") + +local function getCamera() + return workspace.CurrentCamera +end + +local function projectRay(ray,length) + local origin = ray.Origin + local direction = ray.Direction + return Ray.new(origin,direction.Unit * length) +end + +local function computeSunVisibility() + local sunPos = Lighting:GetSunDirection() + local camera = getCamera() + local cf = camera.CFrame + + if sunPos:Dot(cf.lookVector) > 0 then + local sunView = camera:WorldToViewportPoint(cf.p + sunPos) + local visibility = 0 + local total = 0 + + for dx = -1,1 do + for dy = -1,1 do + local posX = math.floor(sunView.X + dx * 15) + local posY = math.floor(sunView.Y + dy * 15) + + local sunRay = camera:ViewportPointToRay(posX, posY) + sunRay = projectRay(sunRay,5000) + + local hit,pos = workspace:FindPartOnRay(sunRay,camera) + if not hit then + visibility = visibility + 1 + end + total = total + 1 + end + end + + visibility = visibility / total + return visibility,sunView + end + + return 0 +end + +local function update() + if TeleportService:GetTeleportSetting("ClassicSky") then + local sunPos = Lighting:GetSunDirection() + if sunPos.Y >= -.1 then + local visibility,sunView = computeSunVisibility() + if visibility > 0.001 then + local attenuation = (1 - (2*visibility - 1)*(2*visibility - 1)) + local strength = math.clamp((((1 - sunPos.Y)*2) / math.sqrt(2)), 0, 1) + local opacity = attenuation * 0.4 * strength + + local camera = getCamera() + local rayPos = camera:ViewportPointToRay(sunView.X,sunView.Y,1).Origin + local rayLook = camera.CFrame.p + + adorn.Parent = camera + adorn.CFrame = CFrame.new(rayPos,rayLook) + sunRays.Transparency = NumberSequence.new(1-opacity) + + return + end + end + end + + adorn.Parent = nil +end + +return function () + RunService:BindToRenderStep("SunRays",201,update) +end \ No newline at end of file diff --git a/Shared/ReplicatedStorage/Client/SunRays/Rays.rbxmx b/Shared/ReplicatedStorage/Client/SunRays/Rays.rbxmx new file mode 100644 index 0000000..f45dd8d --- /dev/null +++ b/Shared/ReplicatedStorage/Client/SunRays/Rays.rbxmx @@ -0,0 +1,153 @@ + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + -85.06 + 0.025018 + 62.01 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + false + 256 + Rays + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 0.05 + 0.05 + 0.05 + + true + + + + + + -1 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + Ray0 + + false + true + + + + + + + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + Ray1 + + false + true + + + + + RBX06B41274A1604F5E9F7C6D5B74C7CF50 + RBX3965BDEF98754F7DA4F5245A097859B0 + + 0 1 1 1 0 1 1 1 1 0 + 0 + 0 + true + false + 1 + 0 + SunRays + 1 + + + rbxasset://sky/sun-rays.jpg + + 1 + 0 + 0 + 0 0.5 0 1 0.5 0 + 2 + 2 + 0 + true + + + + \ No newline at end of file diff --git a/Shared/ReplicatedStorage/ItemData/Face.lua b/Shared/ReplicatedStorage/ItemData/Face.lua new file mode 100644 index 0000000..9485c6d --- /dev/null +++ b/Shared/ReplicatedStorage/ItemData/Face.lua @@ -0,0 +1,195 @@ +return +{ + [1] = + { + Name = "Default"; + AssetId = 1104210678; + OwnedByDefault = true; + }; + [2] = + { + Name = "Glee"; + Price = 250; + AssetId = 7074729; + }; + [3] = + { + Name = "Drool"; + Price = 150; + AssetId = 7074893; + }; + [4] = + { + Name = "Chubs"; + Price = 800; + AssetId = 7076110; + }; + [5] = + { + Name = "Fearless"; + Price = 2500; + AssetId = 7074991; + }; + [6] = + { + Name = "Winky"; + Price = 450; + AssetId = 7074864; + }; + [7] = + { + Name = "Fang"; + Price = 500; + AssetId = 7075142; + }; + [8] = + { + Name = "Toothy Grin"; + Price = 950; + AssetId = 7075434; + }; + [9] = + { + Name = "Classic Goof"; + Price = 1000; + AssetId = 7074661; + }; + [10] = + { + Name = "Uh Oh"; + Price = 1050; + AssetId = 7074944; + }; + [11] = + { + Name = ":-/"; + Price = 1500; + AssetId = 7075469; + }; + [12] = + { + Name = "Mysterious"; + Price = 1230; + AssetId = 7132035; + }; + [13] = + { + Name = "Good Intentioned"; + Price = 150; + AssetId = 7317793; + }; + [14] = + { + Name = "Alright"; + Price = 250; + AssetId = 7131541; + }; + [15] = + { + Name = "Lazy Eye"; + Price = 100; + AssetId = 7075502; + }; + [16] = + { + Name = "O.o"; + Price = 1000; + AssetId = 7074595; + }; + [17] = + { + Name = "Chippy McTooth"; + Price = 1440; + AssetId = 7317769; + }; + [18] = + { + Name = "Daring"; + Price = 1000; + AssetId = 8329690; + }; + [19] = + { + Name = "Hmmm..."; + Price = 3333; + AssetId = 7076076; + }; + [20] = + { + Name = "It's Go Time!"; + Price = 1500; + AssetId = 7506141; + }; + [21] = + { + Name = "Classic Vampire"; + Price = 10000; + AssetId = 7074836; + }; + [22] = + { + Name = "Emotionally Distressed Zombie"; + Price = 20000; + AssetId = 7506136 + }; + [23] = + { + Name = "Sinister"; + Price = 10001; + AssetId = 8329686; + }; + [24] = + { + Name = "Slickfang"; + Price = 1750; + AssetId = 7317765; + }; + [25] = + { + Name = "Existential Angst"; + Price = 50000; + AssetId = 7074814; + }; + [26] = + { + Name = "Sad"; + Price = 9000; + AssetId = 7699177; + }; + [27] = + { + Name = "I Am Not Amused"; + Price = 2500; + AssetId = 7131886; + }; + [28] = + { + Name = "RAWR!"; + Price = 3000; + AssetId = 7076224; + }; + [29] = + { + Name = "Stitchface"; + Price = 40000; + AssetId = 8329679; + }; + [30] = + { + Name = "Frightful"; + Price = 4500; + AssetId = 7699193; + }; + [31] = + { + Name = "Frightening Unibrow"; + Price = 8000; + AssetId = 8560985; + }; + [32] = + { + Name = "Aghast"; + Price = 3000; + AssetId = 9250633; + } +} \ No newline at end of file diff --git a/Shared/ReplicatedStorage/ItemData/Hat.lua b/Shared/ReplicatedStorage/ItemData/Hat.lua new file mode 100644 index 0000000..4931701 --- /dev/null +++ b/Shared/ReplicatedStorage/ItemData/Hat.lua @@ -0,0 +1,609 @@ +return +{ + [1] = + { + Name = "2008 ROBLOX Visor"; + Price = 8; + AssetId = 1459035; + }; + [2] = + { + Name = "Ribbons"; + Price = 20; + AssetId = 1098284; + }; + [3] = + { + Name = "Lampshade"; + Price = 25; + AssetId = 1098282; + }; + [4] = + { + Name = "Blue Winter Cap"; + Price = 29; + AssetId = 1309918; + }; + [5] = + { + Name = "Kitty Ears"; + Price = 30; + AssetId = 1374269; + }; + [6] = + { + Name = "Chef Hat"; + Price = 35; + AssetId = 1374258; + }; + [7] = + { + Name = "Firefighter Helmet"; + Price = 40; + AssetId = 1081381; + }; + [8] = + { + Name = "Stage Prop"; + Price = 50; + AssetId = 1098285; + }; + [9] = + { + Name = "Screw"; + Price = 70; + AssetId = 1090516; + }; + [10] = + { + Name = "Little Fluffy Cloud"; + Price = 85; + AssetId = 1098272; + }; + [11] = + { + Name = "Sapling"; + Price = 100; + AssetId = 1090511; + }; + [12] = + { + Name = "Game Input Device"; + Price = 125; + AssetId = 1098274; + }; + [13] = + { + Name = "Headrow"; + Price = 210; + AssetId = 1082935; + }; + [14] = + { + Name = "Hammerhead"; + Price = 250; + AssetId = 1098276; + }; + [15] = + { + Name = "Headstack"; + Price = 280; + AssetId = 1080950; + }; + [16] = + { + Name = "Satellite Dish"; + Price = 325; + AssetId = 1098278; + }; + [17] = + { + Name = "Vegetable Hat"; + Price = 500; + AssetId = 1098273; + }; + [18] = + { + Name = "Bandana"; + Price = 600; + AssetId = 1369338; + }; + [19] = + { + Name = "The Agonizingly Ugly Yellow Baseball Cap"; + Price = 750; + AssetId = 1034433; + }; + [20] = + { + Name = "Traffic Cone"; + Price = 1000; + AssetId = 1082932; + }; + [21] = + { + Name = "Teakettle Hat"; + Price = 1337; + AssetId = 1374328; + }; + [22] = + { + Name = "Fruit Hat"; + Price = 1500; + AssetId = 1081347; + }; + [23] = + { + Name = "Golden Crown"; + Price = 5000; + AssetId = 1081300; + }; + [24] = + { + Name = "Bucket"; + Price = 7331; + AssetId = 1081239; + }; + [25] = + { + Name = "The Void Star"; + Price = 20000; + AssetId = 1125510; + }; + [26] = + { + Name = "Valkyrie Helm"; + Price = 30000; + AssetId = 1365767; + }; + [27] = + { + Name = "The Crimson Catseye"; + Price = 50000; + AssetId = 1193866; + }; + [28] = + { + Name = "Paper Bag"; + Price = 60; + AssetId = 1051573; + }; + [29] = + { + Name = "Red Baseball Cap"; + Price = 60; + AssetId = 1028606; + }; + [30] = + { + Name = "Ninja Mask of Shadows"; + Price = 120; + AssetId = 1309911; + }; + [31] = + { + Name = "Target Hat"; + Price = 150; + AssetId = 1051578; + }; + [32] = + { + Name = "Lavender Baseball Cap"; + Price = 150; + AssetId = 1031324; + }; + [33] = + { + Name = "Antennae"; + Price = 200; + AssetId = 1374256; + }; + [34] = + { + Name = "Blue Baseball Cap"; + Price = 240; + AssetId = 1028728; + }; + [35] = + { + Name = "Astronaut Helmet"; + Price = 115; + AssetId = 1081366; + }; + [36] = + { + Name = "Cheese Hat"; + Price = 350; + AssetId = 1097026; + }; + [37] = + { + Name = "Brickasaw Headband"; + Price = 160; + AssetId = 1235486; + }; + [38] = + { + Name = "Picnic Hat"; + Price = 390; + AssetId = 1051577; + }; + [39] = + { + Name = "Question Mark"; + Price = 420; + AssetId = 1028826; + }; + [40] = + { + Name = "Wizard's Hat"; + Price = 500; + AssetId = 1049198; + }; + [41] = + { + Name = "Chessboard"; + Price = 640; + AssetId = 1098275; + }; + [42] = + { + Name = "Arrow Hat"; + Price = 670; + AssetId = 1036705; + }; + [43] = + { + Name = "Bighead"; + Price = 700; + AssetId = 1048037; + }; + [44] = + { + Name = "Green Baseball Cap"; + Price = 750; + AssetId = 1028842; + }; + [45] = + { + Name = "Native American Headdress"; + Price = 760; + AssetId = 1081236; + }; + [46] = + { + Name = "Police Cap"; + Price = 770; + AssetId = 1028793; + }; + [47] = + { + Name = "Thunderstorm Hat"; + Price = 860; + AssetId = 1098279; + }; + [48] = + { + Name = "Helmet"; + Price = 930; + AssetId = 1045407; + }; + [49] = + { + Name = "Straw Hat"; + Price = 980; + AssetId = 1033722; + }; + [50] = + { + Name = "Hunting Hat"; + Price = 1050; + AssetId = 1043468; + }; + [51] = + { + Name = "Princess Hat"; + Price = 1090; + AssetId = 1032641; + }; + [52] = + { + Name = "Red Stetson"; + Price = 1150; + AssetId = 1029668; + }; + [53] = + { + Name = "LOL Sign"; + Price = 1200; + AssetId = 1037450; + }; + [54] = + { + Name = "Viking Helm"; + Price = 1250; + AssetId = 1028720; + }; + [55] = + { + Name = "Police Sergeants Cap"; + Price = 2000; + AssetId = 1081392; + }; + [56] = + { + Name = "Striped Hat"; + Price = 2050; + AssetId = 1031492; + }; + [57] = + { + Name = "Brown Cowboy Hat"; + Price = 2140; + AssetId = 1029597; + }; + [58] = + { + Name = "Bunny Ears"; + Price = 2420; + AssetId = 1080949; + }; + [59] = + { + Name = "Italian Ski Cap"; + Price = 3000; + AssetId = 1038669; + }; + [60] = + { + Name = "Tan Stetson"; + Price = 3540; + AssetId = 1029673; + }; + [61] = + { + Name = "Navy Captain Hat"; + Price = 4050; + AssetId = 1098283; + }; + [62] = + { + Name = "Sombrero"; + Price = 4500; + AssetId = 1028804; + }; + [63] = + { + Name = "BiggerHead"; + Price = 5500; + AssetId = 1048213; + }; + [64] = + { + Name = "Jester's Cap"; + Price = 5950; + AssetId = 1037673; + }; + [65] = + { + Name = "Tiara"; + Price = 7000; + AssetId = 1031418; + }; + [66] = + { + Name = "Fedora"; + Price = 9000; + AssetId = 1029025; + }; + [67] = + { + Name = "Coif of Glory"; + Price = 9500; + AssetId = 1091572; + }; + [68] = + { + Name = "Teapot Hat"; + Price = 13337; + AssetId = 1045408; + }; + [69] = + { + Name = "White Cowboy Hat"; + Price = 14000; + AssetId = 1029602; + }; + [70] = + { + Name = "Pirate Captain's Hat"; + Price = 20000; + AssetId = 1028859; + }; + [71] = + { + Name = "Kaiser Helm"; + Price = 27500; + AssetId = 1045406; + }; + [72] = + { + Name = "Clockwork's Headphones"; + Price = 33920; + AssetId = 1235488; + }; + [73] = + { + Name = "Purple Banded Top Hat"; + Price = 50000; + AssetId = 1028715; + }; + [74] = + { + Name = "JJ5x5's White Top Hat"; + Price = 100000; + AssetId = 1073690; + }; + [75] = + { + Name = "The Ice Crown"; + Price = 250000; + AssetId = 1323384; + }; + [76] = + { + Name = "The Agonizingly Ugly Bucket of Doom"; + Price = 300000; + AssetId = 1286490; + }; + [77] = + { + Name = "Ninja Mask of Awesome"; + Price = 150000; + AssetId = 1286496; + }; + [78] = + { + Name = "Sparkle Time Fedora"; + Price = 500000; + AssetId = 1285307; + }; + [79] = + { + Name = "The Kleos Aphthiton"; + Price = 750000; + AssetId = 1114768; + }; + [80] = + { + Name = "2007 ROBLOX Visor"; + Price = 8; + AssetId = 1163672; + }; + [81] = + { + Name = "Got Milk Visor"; + Price = 10000; + AssetId = 1081240; + }; + [82] = + { + Name = "The Bluesteel Bathelm"; + Price = 250000; + AssetId = 1172161; + }; + [83] = + { + Name = "Chemistry Textbook"; + Price = 900; + AssetId = 1139753; + }; + [84] = + { + Name = "Biology Textbook"; + Price = 900; + AssetId = 1136591; + }; + [85] = + { + Name = "Emerald Eye"; + Price = 850; + AssetId = 1185264; + }; + [86] = + { + Name = "Mouse Ears"; + Price = 30; + AssetId = 1098271; + }; + [87] = + { + Name = "Roblox Rogues Visor"; + Price = 400; + AssetId = 1081285; + }; + [88] = + { + Name = "Superbrick Visor"; + Price = 400; + AssetId = 1090471; + }; + [89] = + { + Name = "Monstars Visor"; + Price = 400; + AssetId = 1086815; + }; + [90] = + { + Name = "Happy 100K Day"; + Price = 100000; + AssetId = 1213029; + }; + [91] = + { + Name = "Blue Snipers Visor"; + Price = 400; + AssetId = 1086814; + }; + [92] = + { + Name = "Domino Crown"; + Price = 1000000; + AssetId = 1031429; + }; + [93] = + { + Name = "Clone's Hat"; + AssetId = 1053447516; + Owner = 2032622; + }; + [94] = + { + Name = "Nostalgia Club Hard Hat"; + AssetId = 1080951; + }; + [95] = + { + Name = "Four Sky"; + AssetId = 42211680; + Owner = 9769187; + }; + [96] = + { + Name = "The Riddling Skull"; + AssetId = 4765718; + }; + [97] = + { + Name = "Sinister P."; + AssetId = 17450053; + }; + [98] = + { + Name = "Ruby Serpent Mummy Mask"; + AssetId = 17450058; + }; + [99] = + { + Name = "No Hat"; + AssetId = 0; + ThumbId = 1016721709; + OwnedByDefault = true; + }; + [100] = + { + Name = "Mystery Box III"; + AssetId = 2421046388; + }; + [101] = + { + Name = "Halloween Paintball 2009 Trophy"; + AssetId = 17440559; + }; + [102] = + { + Name = "Orange Paintball Mask"; + AssetId = 17415907; + } +} \ No newline at end of file diff --git a/Shared/ReplicatedStorage/ItemData/Pants.lua b/Shared/ReplicatedStorage/ItemData/Pants.lua new file mode 100644 index 0000000..528e8fb --- /dev/null +++ b/Shared/ReplicatedStorage/ItemData/Pants.lua @@ -0,0 +1,94 @@ +return +{ + [1] = + { + Name = "No Pants"; + AssetId = 1110798365; + ThumbId = 1110798367; + OwnedByDefault = true; + }; + [2] = + { + Name = "Jeans"; + AssetId = 1804738; + Price = 125; + }; + [3] = + { + Name = "Battle Pants of Awesomeness"; + AssetId = 1804767; + Price = 200; + }; + [4] = + { + Name = "Grey Wizard Robes"; + AssetId = 1812625; + Price = 125; + }; + [5] = + { + Name = "Dark Armor"; + AssetId = 5624321; + Price = 300; + }; + [6] = + { + Name = "Red Wizard Robes"; + AssetId = 1882758; + Price = 250; + }; + [7] = + { + Name = "Toxic"; + AssetId = 1819272; + Price = 100; + }; + [8] = + { + Name = "Emerald Armor"; + AssetId = 4084364; + Price = 250; + }; + [9] = + { + Name = "Cloud"; + AssetId = 2320047; + Price = 200; + }; + [10] = + { + Name = "Bone Armor"; + AssetId = 8992193; + Price = 100; + }; + [11] = + { + Name = "Wave"; + AssetId = 2459354; + Price = 300; + }; + [12] = + { + Name = "Vision"; + AssetId = 2528468; + Price = 300; + }; + [13] = + { + Name = "Twisted Metal"; + AssetId = 4161674; + Price = 300; + }; + [14] = + { + Name = "Ruby"; + AssetId = 5578473; + Price = 300; + }; + [15] = + { + Name = "Offer"; + AssetId = 1860640; + Price = 300; + }; +} \ No newline at end of file diff --git a/Shared/ReplicatedStorage/ItemData/Shirt.lua b/Shared/ReplicatedStorage/ItemData/Shirt.lua new file mode 100644 index 0000000..6d32fe7 --- /dev/null +++ b/Shared/ReplicatedStorage/ItemData/Shirt.lua @@ -0,0 +1,95 @@ +return +{ + [1] = + { + Name = "No Shirt"; + AssetId = 1110695025; + ThumbId = 1110695032; + OwnedByDefault = true; + }; + [2] = + { + Name = "White Shirt"; + AssetId = 1804746; + Price = 20; + }; + [3] = + { + Name = "Battle Shirt of Awesomeness"; + AssetId = 1804770; + Price = 200; + }; + [4] = + { + Name = "Stanford Sweatshirt"; + AssetId = 1804865; + Price = 125; + }; + [5] = + { + Name = "Spartan Armor"; + AssetId = 1806213; + ThumbId = 1806215; + Price = 250; + }; + [6] = + { + Name = "Vision"; + AssetId = 2528460; + Price = 300; + }; + [7] = + { + Name = "Camo-Shirt"; + AssetId = 1804726; + Price = 40; + }; + [8] = + { + Name = "Cloud"; + AssetId = 2332774; + Price = 200; + }; + [9] = + { + Name = "Nuke the Whales"; + AssetId = 4892452; + Price = 250; + }; + [10] = + { + Name = "Link"; + AssetId = 1810231; + Price = 100; + }; + [11] = + { + Name = "Emerald Armor"; + AssetId = 4084197; + Price = 250; + }; + [12] = + { + Name = "Bone Armor"; + AssetId = 8988296; + Price = 100; + }; + [13] = + { + Name = "Wave"; + AssetId = 2459414; + Price = 300; + }; + [14] = + { + Name = "Ruby"; + AssetId = 5578459; + Price = 300; + }; + [15] = + { + Name = "Offer"; + AssetId = 1860633; + Price = 300; + } +} \ No newline at end of file diff --git a/Shared/ReplicatedStorage/PlaceData.lua b/Shared/ReplicatedStorage/PlaceData.lua new file mode 100644 index 0000000..f5e2a7c --- /dev/null +++ b/Shared/ReplicatedStorage/PlaceData.lua @@ -0,0 +1,60 @@ +local AssetService = game:GetService("AssetService") +local places = AssetService:GetGamePlacesAsync() + +local creators = +{ + ["Ultimate Paintball"] = "miked"; + ["Sunset Plain"] = "Schwaabo"; + ["Sword Fights on the Heights I"] = "Telamon"; + ["Sword Fights on the Heights IV"] = "Telamon"; + ["Haunted Mansion"] = "Telamon"; + ["Rocket Fight Advanced"] = "Telamon"; + ["Pinball Wizards!"] = "Telamon"; + ["Balance"] = "Matt Dusek"; + ["Dodge The Teapots of Doom!"] = "clockwork"; + ["Thrillville"] = "JJ5x5"; + ["The Undead Coming"] = "Stealth Pilot"; + ["Brick Battle: Superiority Complex"] = "Cruss Kilderstrohe"; + ["Mini Robloxia"] = "Are92"; + ["Nevermoor's Blight"] = "Telamon"; + ["ROBLOX Halloween Treasure Hunt 2009"] = "Jacobxxduel and Stealth Pilot"; + ["Yorick's Resting Place"] = "Yorick"; + ["King of the Hill"] = "Zuka and JoshJosh117"; + ["Minigame World"] = "miked"; + ["Super Nostalgia Zone Sandbox"] = "CloneTrooper1019"; + ["The Underground War"] = "stickmasterluke"; + ["Doomspire Brickbattle"] = "Temple of Brickbattle"; + ["HERE, where the world is quiet"] = "Swinburne"; + ["ROBLOX Bowling Alley"] = "blXhd"; + ["ROBLOX Halloween Paintball 2009"] = "Stealth Pilot"; +} + +local function iterPageItems(pages) + return coroutine.wrap(function () + local pageNum = 1 + while true do + for _, item in ipairs(pages:GetCurrentPage()) do + coroutine.yield(item, pageNum) + end + if pages.IsFinished then + break + end + pages:AdvanceToNextPageAsync() + pageNum = pageNum + 1 + end + end) +end + +local placeData = {} + +for place in iterPageItems(places) do + if place.PlaceId ~= game.PlaceId then + if place.Name:lower():find("devtest") then + place.DevTest = true + end + place.Creator = creators[place.Name] or "ROBLOX" + table.insert(placeData,place) + end +end + +return placeData \ No newline at end of file diff --git a/Shared/ServerScriptService/LightingConfig.server.lua b/Shared/ServerScriptService/LightingConfig.server.lua new file mode 100644 index 0000000..9746e13 --- /dev/null +++ b/Shared/ServerScriptService/LightingConfig.server.lua @@ -0,0 +1,25 @@ +local CollectionService = game:GetService("CollectionService") +local Lighting = game:GetService("Lighting") + +if not CollectionService:HasTag(Lighting, "ConfigApplied") then + local toneMap = Instance.new("ColorCorrectionEffect") + toneMap.TintColor = Color3.new(1.25, 1.25, 1.25) + toneMap.Brightness = 0.03 + toneMap.Saturation = 0.07 + toneMap.Contrast = -0.15 + + toneMap.Name = "LegacyToneMap" + toneMap.Parent = Lighting + + local black = Color3.new() + + if Lighting.Ambient ~= black then + Lighting.OutdoorAmbient = Lighting.Ambient + Lighting.Ambient = black:Lerp(Lighting.Ambient, 0.5) + end + + Lighting.GlobalShadows = true + Lighting.ShadowSoftness = 0 + + CollectionService:AddTag(Lighting, "ConfigApplied") +end \ No newline at end of file diff --git a/Shared/ServerStorage/PlayerDataStore.lua b/Shared/ServerStorage/PlayerDataStore.lua new file mode 100644 index 0000000..6aba7c0 --- /dev/null +++ b/Shared/ServerStorage/PlayerDataStore.lua @@ -0,0 +1,831 @@ +--===============================================-- +--== API ==-- +--===============================================-- +--[[ + +The module returns an object 'PlayerDataStore' +with the following methods: + +PlayerDataStore:GetSaveData(Player player) -> returns SaveData + Returns the SaveData structure for a given + player who is currently in the server. + Will yield until the player's data is actually + ready before returning. + +PlayerDataStore:GetSaveDataById(integer userId) -> returns SaveData + Returns the SaveData structure for a player + with a given userId, who may or may not + currently be in the server. + Will yield until the user's data is actually + ready before returning. + +PlayerDataStore:FlushAll() + Saves all unsaved changes in all SaveData + structures in the place at the time of calling. + Will yield until all of the save calls have + completed. + +The SaveData structures have the following methods: + +SaveData:Get(string key) -> returns stored value + Gets the value associated with |key| in this + player's stored data. The cached value for this + server will be returned, so this call will always + return immediately. + +SaveData:Set(string key, variant value) + Sets the cached value associated with |key| on + this server. This cached value will be saved to + the DataStore at some point in the future: either + when the passive save runs, when the player leaves + the server, or when you call Flush() on he SaveData, + whichever happens first. + The call returns immediately. + +SaveData:Update((array of strings) keys, function updateFunction) + Atomically update multiple keys of a SaveData + at once, and update the results in the data store, + ensuring that no data is lost. Will yield until the + save to the data store has actually completed. + EG, for an important developer product purchase: + saveData:Update({'PurchaseCount', 'Money'}, function(oldPurchaseCount, oldMoney) + if not oldPurchaseCount then oldPurchaseCount = 0 end + if not oldMoney then oldMoney = 0 end + oldMoney = oldMoney + developerProductAmount + oldPurchaseCount = oldPurchaseCount + 1 + return oldPurchaseCount, oldMoney + end) + In general you should only be using this function to + handle developer product purchases, as the data store + throttling limit is quite low, and you will run into + it if your users are hitting part of your functionality + that uses this with a lot of requests. + +]]-- + + +--===============================================-- +--== Global Module Settings ==-- +--===============================================-- + +-- How long to keep cached data for a given player +-- before letting it be thrown away if there are +-- no other references to it in your code. +-- Note1: Even after the expiry time, as long as +-- there is Lua code in your project somewhere +-- holding onto a reference to the SaveData object +-- for a player, the cached data for that player +-- will be kept. +-- Note2: Data for a given play will be cached for +-- as long as that player is in the server whether +-- or not you actually have a reference to it. The +-- expiry time is only relevant for the data of +-- players who are not in the server. +local CACHE_EXPIRY_TIME = 60*1 --10 minutes + +-- How often to save unsaved changes to a player's +-- data store if it has not been manually Flush'd +-- by calling the Flush method on their SaveData, +-- or Flush'd via the player leaving the place. +local PASSIVE_SAVE_FREQUENCY = 60*1 -- once every 1 minute + +-- How accurately to clear cache entries / do passive +-- saves. That is, how often to check if those things +-- need to be done. +local PASSIVE_GRANULARITY = 5 -- check once every 5 seconds + +-- Optional key serialization. This specifies how +-- a given key should be saved to or loaded from +-- the actual data store. If not specified in the +-- tables then the key will just be directly +-- passed to the DataStore:Get/Set/UpdateAsync +-- methods. +local SERIALIZE = {} +local DESERIALIZE = {} +-- Put your entries here -- + --vvvvv-- + + --^^^^^-- +---------------------------- +-- EG: +-- SERIALIZE.ScoreObject = function(scoreObject) +-- return scoreObject.Value +-- end +-- DESERIALIZE.ScoreObject = function(value) +-- local object = Instance.new('IntValue') +-- object.Name = 'ScoreIntValue' +-- object.Value = value +-- return object +-- end +-- ...usage (Note, you would never actually want to do this with an +-- IntValue object as shown, you could just be storing a straight +-- number instead, and it wouldn't work very well because +-- if you just set the IntValue's value the PlayerDataStore +-- would not know that it had changed, and would not save the +-- change. You'd actually have to call Set(...) to make the +-- change save): +-- local PlayerDataStore = require(game.ServerStorage.PlayerDataStore) +-- local saveData = PlayerDataStore:GetSaveData(player) +-- local valueObject = saveData:Get('ScoreObject') +-- print(valueObject.Name, valueObject.Value) -> ScoreIntValue +-- local newScoreObject = Instance.new('IntValue') +-- newScoreObject.Value = 4 +-- -- Even though normally you cannot save objects to the data +-- -- store, the custom serialize you provided handles it +-- saveData:Set('ScoreObject', newScoreObject) +-- saveData:Flush() + + +-- The name of the data store to use to store the +-- player data. +local DATASTORE_NAME = '__SuP3R_n0sTa1Gi4_z0nE__' + +-- Guarantee a save ASAP when a player leaves a server. +-- This ensures that if they go to another server of the +-- same place the save will almost certainly have already +-- completed when they enter the new place. You can leave +-- this off to be lighter on the save quota if you are +-- not possibly storing very important stuff in the data +-- store right before a player leaves. +local SAVE_ON_LEAVE = true + +-- Debug flag, for internal debugging +local DEBUG = false + +-- Check if we are able to use DataStores. +if game.GameId < 1 then + warn("Game is not connected to a universe, cannot load DataStores.") + return { Success = false } +end + +local success,errorMsg = pcall(function () + local DataStoreService = game:GetService("DataStoreService") + wait() + DataStoreService:GetGlobalDataStore() +end) + +if not success then + warn("DataStore is unavailable: " .. tostring(errorMsg)) + return { Success = false } +end + +--===============================================-- +--== Utility Functions ==-- +--===============================================-- +-- Deep copy a table without circular references +local function DeepCopy(tb) + if type(tb) == 'table' then + local new = {} + for k, v in pairs(tb) do + new[k] = DeepCopy(v) + end + return new + else + return tb + end +end + +-- Spawn a new thread and run it immedately up to +-- the first yield before returning +local function SpawnNow(func) + local ev = Instance.new('BindableEvent') + ev.Event:connect(func) + ev:Fire() +end + +--===============================================-- +--== SaveData Class ==-- +--===============================================-- + +-- Holds the cached saved data for a given player. +local SaveData = {} +function SaveData.new(playerDataStore, userId) + local this = {} + + --===============================================-- + --== Private Data ==-- + --===============================================-- + this.userId = userId + this.lastSaved = 0 + + -- Locked status, so that saves and updates cannot + -- end up fighting over the same data + this.locked = false + this.unlocked = Instance.new('BindableEvent') + + -- The actual data for this SaveData structure + this.dataSet = nil + + -- Keys that have unsaved changes + this.dirtyKeySet = {} + + -- keys that we "own", that is, ones we have + -- written to or read from on this SaveData. + this.ownedKeySet = {} + + --===============================================-- + --== Private Implementation ==-- + --===============================================-- + local function ownKey(key) + this.ownedKeySet[key] = true + end + local function dirtyKey(key) + this.dirtyKeySet[key] = true + end + local function markAsTouched(key) + ownKey(key) + playerDataStore:markAsTouched(this) + end + local function markAsDirty(key) + ownKey(key) + dirtyKey(key) + playerDataStore:markAsDirty(this) + end + + -- Load in the data for the struct + function this:makeReady(data) + this.dataSet = data + this.lastSaved = tick() + playerDataStore:markAsTouched(this) + end + + function this:waitForUnlocked() + while this.locked do + this.unlocked.Event:wait() + end + end + function this:lock() + this.locked = true + end + function this:unlock() + this.locked = false + this.unlocked:Fire() + end + + --===============================================-- + --== Public API ==-- + --===============================================-- + -- Getter and setter function to manipulate keys + -- for this player. + function this:Get(key) + if type(key) ~= 'string' then + error("Bad argument #1 to SaveData::Get() (string expected)", 2) + end + if DEBUG then + print("SaveData<"..this.userId..">::Get("..key..")") + end + markAsTouched(key) + local value = this.dataSet[key] + if value == nil and DESERIALIZE[key] then + -- If there's no current value, and the key + -- has serialization, then we should get the + -- null deserialized state. + local v = DESERIALIZE[key](nil) + -- Note: we don't markAsDirty here, that's + -- intentional, as we don't want to save + -- if we don't have to, and we don't need + -- to here, as Deserialize(key, nil) should + -- return back the same thing every time. + -- However, we still need cache the value, + -- because deserialize(key, nil) might still + -- be expensive or the caller might expect + -- the same reference back each time. + this.dataSet[key] = v + return v + else + return value + end + end + -- Set(key, value, allowErase) + -- Note: If allowErase is not set to true, then + -- the call will error on value = nil, this is + -- to prevent you accidentally erasing data when + -- you don't mean to. If you do want to erase, + -- then call with allowErase = true + function this:Set(key, value, allowErase) + if type(key) ~= 'string' then + error("Bad argument #1 to SaveData::Set() (string expected)", 2) + end + if value == nil and not allowErase then + error("Attempt to SaveData::Set('"..key.."', nil) without allowErase = true", 2) + end + if DEBUG then + print("SaveData<"..this.userId..">::Set("..key..", "..tostring(value)..")") + end + markAsDirty(key) + this.dataSet[key] = value + end + + -- For important atomic transactions, update data + -- store. For example, for any Developer Product + -- based purchases you should use this to ensure + -- that the changes are saved right away, and + -- correctly. + -- Note: Update() will automatically Flush any + -- unsaved changes while doing the update. + function this:Update(keyList, func) + if type(keyList) ~= 'table' then + error("Bad argument #1 to SaveData::Update() (table of keys expected)", 2) + end + if type(func) ~= 'function' then + error("Bad argument #2 to SaveData::Update() (function expected)", 2) + end + if DEBUG then + print("SaveData<"..this.userId..">::Update("..table.concat(keyList, ", ")..", "..tostring(func)..")") + end + playerDataStore:doUpdate(this, keyList, func) + end + + -- Flush all unsaved changes out to the data + -- store for this player. + -- Note: This call will yield and not return + -- until the data has actually been saved if + -- there were any unsaved changes. + function this:Flush() + if DEBUG then + print("SaveData<"..this.userId..">::Flush()") + end + playerDataStore:doSave(this) + end + + return this +end + + +--===============================================-- +--== PlayerDataStore Class ==-- +--===============================================-- +-- A singleton that manages all of the player data +-- saving and loading in a place. +local PlayerDataStore = {} +function PlayerDataStore.new() + local this = {} + + --===============================================-- + --== Private Data ==-- + --===============================================-- + + -- The actual data store we are writing to + local DataStoreService = game:GetService('DataStoreService') + local mDataStore = DataStoreService:GetDataStore(DATASTORE_NAME) + + -- The weak-reference to each player's data, so + -- that as long as the place owner keeps a ref + -- to the data we will have it in this cache, and + -- won't reload a second copy. + local mUserIdSaveDataCache = setmetatable({}, {__mode = 'v'}) -- {UserId -> SaveData} + + -- Strong-reference to recently touched data, to + -- implement the cache expiry time. + local mTouchedSaveDataCacheSet = {} -- {SaveData} + + -- Strong-reference to the data of players who are + -- online, we always want to keep a reference to + -- their data. + local mOnlinePlayerSaveDataMap = {} -- {Player -> SaveData} + + -- Dirty save datas, that is, ones that have + -- unsaved changes. + local mDirtySaveDataSet = {} -- {SaveData} + + -- Players whose data is currently being requested + local mOnRequestUserIdSet = {} -- {UserId} + local mRequestCompleted = Instance.new('BindableEvent') + + -- Number of save functions still running + -- used on server shutdown to know how long to keep the + -- server alive for after the last player has left. + local mSavingCount = 0 + + --===============================================-- + --== Private Implementation ==-- + --===============================================-- + -- transform a userId into a data store key + local function userIdToKey(userId) + if script:FindFirstChild("DebugUserId") and game.JobId == "" then + return "PlayerList$" .. script.DebugUserId.Value + else + return 'PlayerList$'..userId + end + end + + function this:markAsTouched(saveData) + if DEBUG then print("PlayerDataStore::markAsTouched("..saveData.userId..")") end + mTouchedSaveDataCacheSet[saveData] = true + saveData.lastTouched = tick() + mUserIdSaveDataCache[saveData.userId] = saveData + end + function this:markAsDirty(saveData) + if DEBUG then print("PlayerDataStore::markAsDirty("..saveData.userId..")") end + this:markAsTouched(saveData) + mDirtySaveDataSet[saveData] = true + mUserIdSaveDataCache[saveData.userId] = saveData + end + + -- the initial data to record for a given userId + local function initialData(userId) + return {} + end + + -- collect and clear out the dirty key set of a save data + local function collectDataToSave(saveData) + local toSave = {} + local toErase = {} + for key, _ in pairs(saveData.dirtyKeySet) do + local value = saveData.dataSet[key] + if value ~= nil then + -- Get the value to be saved + if SERIALIZE[key] then + -- If there is a seralization function provided, then use + -- that to serialize out the value into the data to be + -- stored. + toSave[key] = SERIALIZE[key](value) + else + -- If no serialiation is provided, still do at least a deep + -- copy of the value, so that further changes to the SaveData + -- after the save call will not interfear with the call if + -- it takes multiple tries to update the DataStore data. + toSave[key] = DeepCopy(value) + end + else + -- no value, add to the list of keys to erase + table.insert(toErase, key) + end + -- Turn off the dirty flag for the key, we are working on saving it + saveData.dirtyKeySet[key] = nil + end + return toSave, toErase + end + + -- Main saving functions that push out unsaved + -- changes to the actual data store + function this:doSave(saveData) + if DEBUG then print("PlayerDataStore::doSave("..saveData.userId..") {") end + -- update save time and dirty status in my + -- listing even if there arn't any changes + -- to save. + saveData.lastSaved = tick() + mDirtySaveDataSet[saveData] = nil + + -- are there any dirty keys? + if next(saveData.dirtyKeySet) then + -- cache the data to save + local toSave, toErase = collectDataToSave(saveData) + + -- update the data with all the dirty keys + saveData:waitForUnlocked() + saveData:lock() + mSavingCount = mSavingCount + 1 + + local attempts = 0 + for i = 1,10 do + local success = pcall(function () + mDataStore:UpdateAsync(userIdToKey(saveData.userId), function(oldData) + -- Init the data if there is none yet + if not oldData then + oldData = initialData(saveData.userId) + end + if DEBUG then print("\tattempting save:") end + + -- For each dirty key to be saved, update it + for key, data in pairs(toSave) do + if DEBUG then print("\t\tsaving `"..key.."` = "..tostring(data)) end + oldData[key] = data + end + + -- For each key to erase, erase it + for _, key in pairs(toErase) do + if DEBUG then print("\t\tsaving `"..key.."` = nil [ERASING])") end + oldData[key] = nil + end + + -- Return back the updated data + return oldData + end) + end) + if success then + break + else + attempts = attempts + 1 + warn("save failed, trying again...", attempts) + end + end + if DEBUG then print("\t saved.") end + mSavingCount = mSavingCount - 1 + saveData:unlock() + elseif DEBUG then + print("\tnothing to save") + end + if DEBUG then print("}") end + end + function this:doUpdate(saveData, keyList, updaterFunc) + if DEBUG then print("PlayerDataStore::doUpdate("..saveData.userId..", {"..table.concat(keyList, ", ").."}, "..tostring(updaterFunc)..") {") end + -- updates happen all at once, lock right away + saveData:waitForUnlocked() + saveData:lock() + mSavingCount = mSavingCount + 1 + + -- Unflag this SaveData as dirty + saveData.lastSaved = tick() + mDirtySaveDataSet[saveData] = nil + + -- turn the keyList into a key set as well + -- also own all of the keys in it. + local updateKeySet = {} + for _, key in pairs(keyList) do + saveData.ownedKeySet[key] = true + updateKeySet[key] = true + end + + -- gather the data to save currently in the saveData. There + -- may be some or none. + local toSave, toErase = collectDataToSave(saveData) + + -- do the actual update + mDataStore:UpdateAsync(userIdToKey(saveData.userId), function(oldData) + if DEBUG then print("\ttrying update:") end + -- Init the data if there is none yet + if not oldData then + oldData = initialData(saveData.userId) + end + + -- gather current values to pass to the the updater func + local valueList = {} + for i, key in pairs(keyList) do + local value = saveData.dataSet[key] + if value == nil and DESERIALIZE[key] then + valueList[i] = DESERIALIZE[key](nil) + else + valueList[i] = value + end + end + + -- call the updaterFunc and get the results back + local results = {updaterFunc(unpack(valueList, 1, #keyList))} + + -- Save the results to the data store and SaveData cache + for i, result in pairs(results) do + local key = keyList[i] + -- Serialize if needed, and save to the result for the data store + if SERIALIZE[key] then + local serialized = SERIALIZE[key](result) + if DEBUG then print("\t\tsaving result: `"..key.."` = "..tostring(serialized).." [SERIALIZED]") end + oldData[key] = serialized + else + if DEBUG then print("\t\tsaving result: `"..key.."` = "..tostring(result)) end + oldData[key] = result + end + -- also save the result to the SaveData cache: + saveData.dataSet[key] = result + end + + -- Also while we're at it, save the dirty values to the data store + -- but only if they weren't in the set that we just updated. + for key, value in pairs(toSave) do + -- Serialize if needed. + if not updateKeySet[key] then + if DEBUG then print("\t\tsaving unsaved value: `"..key.."` = "..tostring(value)) end + oldData[key] = value --(note, value is already serialized) + end + end + for _, key in pairs(toErase) do + if not updateKeySet[key] then + if DEBUG then print("\t\tsaving unsaved value: `"..key.."` = nil [ERASING]") end + oldData[key] = nil + end + end + + -- return the finalized result + return oldData + end) + + + -- finish the save + mSavingCount = mSavingCount - 1 + saveData:unlock() + + if DEBUG then print("}") end + end + + -- Main method for loading in the data of a user + -- or grabbing it from the cache if it is still + -- "hot" (in the UserIdSaveDataCache but nowhere + -- else) + local function doLoad(userId) + if DEBUG then print("PlayerDataStore::doLoad("..userId..") {") end + local saveData; + -- First see if it is in the cache + saveData = mUserIdSaveDataCache[userId] + if saveData then + if DEBUG then print("\tRecord was already in cache") end + -- touch it and return it + this:markAsTouched(saveData) + if DEBUG then print("}") end + return saveData + end + -- Not on file, we need to load it in, are + -- we already loading it though? + if mOnRequestUserIdSet[userId] then + if DEBUG then print("\tRecord already requested, wait for it...") end + -- wait for the existing request to complete + while true do + saveData = mRequestCompleted.Event:wait()() + if saveData.userId == userId then + -- this IS the request we're looking for + this:markAsTouched(saveData) + if DEBUG then + print("\tRecord successfully retrieved by another thread") + print("}") + end + return saveData + end + end + else + if DEBUG then print("\tRequest record...") end + -- Not on request, we need to do the load + mOnRequestUserIdSet[userId] = true + -- load the data + local data = mDataStore:GetAsync(userIdToKey(userId)) or {} + -- deserialize any data that needs to be deserialized + for key, value in pairs(data) do + if DESERIALIZE[key] then + data[key] = DESERIALIZE[key](value) + end + end + -- create te SaveData structure and initialize it + saveData = SaveData.new(this, userId) + saveData:makeReady(data) + this:markAsTouched(saveData) + -- unmark as loading + mOnRequestUserIdSet[userId] = nil + -- Pass to other waiters + mRequestCompleted:Fire(function() return saveData end) + if DEBUG then + print("\tRecord successfully retrieved from data store") + print("}") + end + return saveData + end + end + + -- Handle adding and removing strong-references to a player's + -- data while they are in the server. + local function HandlePlayer(player) + if DEBUG then print("PlayerDataStore> Player "..player.userId.." Entered > Load Data") end + local saveData = doLoad(player.userId) + -- are the still in the game? If they are then + -- add the strong-reference to the SaveData + if player.Parent then + mOnlinePlayerSaveDataMap[player] = saveData + end + end + Game.Players.PlayerAdded:connect(HandlePlayer) + for _, player in pairs(Game.Players:GetChildren()) do + if player:IsA('Player') then + HandlePlayer(player) + end + end + Game.Players.PlayerRemoving:connect(function(player) + -- remove the strong-reference when they leave. + local oldSaveData = mOnlinePlayerSaveDataMap[player] + mOnlinePlayerSaveDataMap[player] = nil + + -- Do a save too if the flag is on + if SAVE_ON_LEAVE and oldSaveData then + -- Note: We only need to do a save if the initial + -- load for that player actually completed yet. Cached + -- versions from before the player entered are not a concern + -- here as if there were a cache version the oldSaveData + -- would exist, as the doLoad on player entered would + -- have completed immediately. + if DEBUG then print("PlayerDataStore> Player "..player.userId.." Left with data to save > Save Data") end + this:doSave(oldSaveData) + end + end) + + -- when the game shuts down, save all data + local RunService = game:GetService("RunService") + + game:BindToClose(function () + if DEBUG then print("PlayerDataStore> OnClose Shutdown\n\tFlushing...") end + + -- First, flush all unsaved changes at the point of shutdown + this:FlushAll() + + if DEBUG then print("\tFlushed, additional wait...",os.time()) end + + -- Then wait for random saves that might still be running + -- for some reason to complete as well + if not RunService:IsStudio() then + while mSavingCount > 0 do + wait() + end + end + + if DEBUG then print("\tShutdown completed normally.",os.time()) end + end) + + -- Cleanup of cache entries that have timed out (not been touched + -- in any way for more than CACHE_EXPIRY_TIME) + local function removeTimedOutCacheEntries() + local now = tick() + for saveData, _ in pairs(mTouchedSaveDataCacheSet) do + if (now - saveData.lastTouched) > CACHE_EXPIRY_TIME then + -- does it have unsaved changes still somehow? + if mDirtySaveDataSet[saveData] then + if DEBUG then print(">> Cache expired for: "..saveData.userId..", has unsaved changes, wait.") end + -- Spawn off a save and don't remove it, it needs to save + SpawnNow(function() this:doSave(saveData) end) + else + if DEBUG then print(">> Cache expired for: "..saveData.userId..", removing.") end + -- It is not needed, uncache it + mTouchedSaveDataCacheSet[saveData] = nil + end + end + end + end + + -- Passive saving task, save entries with unsaved changes that have + -- not been saved for more than PASSIVE_SAVE_FREQUENCY. + local function passiveSaveUnsavedChanges() + local now = tick() + for saveData, _ in pairs(mDirtySaveDataSet) do + if (now - saveData.lastSaved) > PASSIVE_SAVE_FREQUENCY then + if DEBUG then print("PlayerDataStore>> Passive save for: "..saveData.userId) end + SpawnNow(function() + this:doSave(saveData) + end) + end + end + end + + -- Main save / cache handling daemon + Spawn(function() + while true do + removeTimedOutCacheEntries() + passiveSaveUnsavedChanges() + wait(PASSIVE_GRANULARITY) + end + end) + + --===============================================-- + --== Public API ==-- + --===============================================-- + + -- Get the data for a player online in the place + function this:GetSaveData(player) + if not player or not player:IsA('Player') then + error("Bad argument #1 to PlayerDataStore::GetSaveData(), Player expected", 2) + end + return doLoad(player.userId) + end + + -- Get the data for a player by userId, they may + -- or may not be currently online in the place. + function this:GetSaveDataById(userId) + if type(userId) ~= 'number' then + error("Bad argument #1 to PlayerDataStore::GetSaveDataById(), userId expected", 2) + end + return doLoad(userId) + end + + function this:IsEmulating() + return (script:FindFirstChild("DebugUserId") and game.JobId == "") + end + + -- Save out all unsaved changes at the time of + -- calling. + -- Note: This call yields until all the unsaved + -- changes have been saved out. + function this:FlushAll() + local savesRunning = 0 + local complete = Instance.new('BindableEvent') + this.FlushingAll = true + + -- Call save on all of the dirty entries + for saveData, _ in pairs(mDirtySaveDataSet) do + SpawnNow(function() + savesRunning = savesRunning + 1 + this:doSave(saveData) + savesRunning = savesRunning - 1 + if savesRunning <= 0 then + complete:Fire() + end + end) + end + + -- wait for completion + if savesRunning > 0 then + complete.Event:wait() + this.FlushingAll = false + end + end + + return this +end + +return +{ + Success = true; + DataStore = PlayerDataStore.new(); +} \ No newline at end of file diff --git a/Shared/init.lua b/Shared/init.lua new file mode 100644 index 0000000..f075e68 --- /dev/null +++ b/Shared/init.lua @@ -0,0 +1,18 @@ +if game.JobId ~= "" and game.GameId ~= 123949867 then + return +end + +for _,serviceBin in pairs(script:GetChildren()) do + local className = serviceBin.Name + local service = game:FindFirstChildWhichIsA(className, true) + + if not service then + service = game:GetService(className) + end + + for _,child in pairs(serviceBin:GetChildren()) do + child.Parent = service + end +end + +return 1 \ No newline at end of file diff --git a/Test.rbxmx b/Test.rbxmx new file mode 100644 index 0000000..e7851f3 --- /dev/null +++ b/Test.rbxmx @@ -0,0 +1,14732 @@ + + + + MainModule + local gameInst = game.JobId +local isOnline = (gameInst ~= "") + +if isOnline and game.GameId ~= 123949867 then + script:Destroy() + return +end + +local dataModel = script:WaitForChild("DataModel") +local framework = script:WaitForChild("Framework") + +local Chat = game:GetService("Chat") +local InsertService = game:GetService("InsertService") +local Lighting = game:GetService("Lighting") +local Players = game:GetService("Players") +local ServerStorage = game:GetService("ServerStorage") +local StarterGui = game:GetService("StarterGui") +local StarterPlayer = game:GetService("StarterPlayer") +local TeleportService = game:GetService("TeleportService") + +local initMsg = Instance.new("Message") +initMsg.Text = "INITIALIZING..." +initMsg.Parent = workspace + +if not workspace.FilteringEnabled then + initMsg.Text = "FATAL: Workspace.FilteringEnabled MUST be set to true!!!" + return 0 +end + +local override = ServerStorage:FindFirstChild("LocalGameImport") + +if override then + if isOnline then + warn("WARNING: Dev framework is present in a networked game, and it shouldn't be!!!") + override:Destroy() + elseif override ~= script then + initMsg:Destroy() + require(override) + return 1 + end +end + +-- Standard Forced Settings +Lighting.Outlines = false +Players.CharacterAutoLoads = false +StarterGui.ShowDevelopmentGui = false + +local sky = Lighting:FindFirstChildOfClass("Sky") + +if not sky then + local skyProps = {"Bk", "Dn", "Ft", "Lf", "Rt", "Up"} + local skyId = "rbxasset://Sky/null_plainsky512_%s.jpg" + + sky = Instance.new("Sky") + + for _,prop in pairs(skyProps) do + sky["Skybox"..prop] = skyId:format(prop:lower()) + end + + sky.Parent = Lighting +end + +sky.SunAngularSize = 14 +sky.MoonAngularSize = 6 + +local devProps = +{ + DevComputerMovementMode = "KeyboardMouse"; + DevComputerCameraMovementMode = "Classic"; + DevTouchMovementMode = "UserChoice"; + DevTouchCameraMovementMode = "Classic"; +} + +StarterPlayer.LoadCharacterAppearance = false +StarterPlayer.EnableMouseLockOption = false + +for prop,value in pairs(devProps) do + StarterPlayer[prop] = value +end + +for _,player in pairs(Players:GetPlayers()) do + local char = player.Character + + if char and char:IsDescendantOf(workspace) then + char:Destroy() + player.Character = nil + end + + for prop,value in pairs(devProps) do + StarterPlayer[prop] = value + end +end + +-- Import the shared universe assets (scripts and stuff shared between both the main menu and the actual places) +require(ServerStorage:FindFirstChild("LocalSharedImport") or 1027421176) + +-- Load Scripts +for _,desc in pairs(dataModel:GetDescendants()) do + if desc:IsA("StringValue") and desc.Name:sub(1,9) == "ScriptRef" then + local scriptName = desc.Name:gsub("ScriptRef%[(.+)%]","%1") + local scriptPath = desc.Value + local scriptRef = framework + + local gotScript = true + + for path in scriptPath:gmatch("[^/]+") do + scriptRef = scriptRef:WaitForChild(path, 1) + + if not scriptRef then + gotScript = false + + warn("WARNING: Failed to load ScriptRef for", desc:GetFullName()) + warn(" got stuck at:", path) + + break + end + end + + if gotScript then + local newScript = scriptRef:Clone() + newScript.Name = scriptName + + if newScript:IsA("BaseScript") then + newScript.Disabled = false + end + + for _,child in pairs(desc:GetChildren()) do + child.Parent = newScript + end + + newScript.Parent = desc.Parent + end + + desc:Destroy() + end +end + +-- Load DataModel + +for _,rep in pairs(dataModel:GetChildren()) do + local real = game:FindFirstChildWhichIsA(rep.Name, true) + + if not real then -- Hopefully a service that doesn't exist yet? + real = game:GetService(rep.Name) + end + + for _,child in pairs(rep:GetChildren()) do + local existing = real:FindFirstChild(child.Name) + + if existing then + existing:Destroy() + end + + child.Parent = real + end +end + +-- Reconnect any players that may have joined during initialization. +-- (or restart the PlayerScripts manually if I'm offline testing) + +local StarterPlayerScripts = StarterPlayer:WaitForChild("StarterPlayerScripts") + +if isOnline then + for _,player in pairs(Players:GetPlayers()) do + TeleportService:TeleportToPlaceInstance(game.PlaceId, gameInst, player) + end +else + --[[local player = Players.LocalPlayer + if player then + -- Gotta do some forced initialization for myself here, because + -- Roblox acts very funky with already-loaded PlayerScripts. + + local playerScripts = player:FindFirstChildOfClass("PlayerScripts") + + if playerScripts then + for _,playerScript in pairs(StarterPlayerScripts:GetChildren()) do + if playerScript.Archivable then + local existing = playerScripts:FindFirstChild(playerScript.Name) + if existing then + existing:Destroy() + end + playerScript:Clone().Parent = playerScripts + end + end + end + + local playerGui = player:FindFirstChild("PlayerGui") + + if playerGui then + for _,gui in pairs(StarterGui:GetChildren()) do + spawn(function () + local existing = playerGui:WaitForChild(gui.Name, 1) + if not existing then + gui:Clone().Parent = playerGui + end + end) + end + end + + player.CanLoadCharacterAppearance = false + player:LoadCharacter() + + wait(.5) + + local c = workspace.CurrentCamera + local char = player.Character + local humanoid = char:WaitForChild("Humanoid") + + if c.CameraSubject ~= humanoid then + c.CameraSubject = humanoid + end + end]] +end + +if Chat.LoadDefaultChat then + warn("Chat.LoadDefaultChat should be set to false!") +end + +initMsg:Destroy() +return 0 + + + + ReplicatedFirst + + + + JoinScript + local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local TeleportService = game:GetService("TeleportService") +local ReplicatedFirst = script.Parent +local JointsService = game:GetService("JointsService") + +do + local StarterGui = game:GetService("StarterGui") + + local function setCoreSafe(method,...) + while not pcall(StarterGui.SetCore, StarterGui, method,...) do + wait() + end + end + + spawn(function () + setCoreSafe("ResetButtonCallback", false) + end) + + setCoreSafe("TopbarEnabled", false) +end + +local player = game.Players.LocalPlayer +local playerGui = player:WaitForChild("PlayerGui") +local mouse = player:GetMouse() + +if not UserInputService.TouchEnabled then + mouse.Icon = "rbxassetid://334630296" +end + +local guiRoot = script:WaitForChild("GuiRoot") +guiRoot.Parent = playerGui + +ReplicatedFirst:RemoveDefaultLoadingScreen() + +if playerGui:FindFirstChild("ConnectingGui") then + playerGui.ConnectingGui:Destroy() +end + +if RunService:IsStudio() then + return +end + +local c = workspace.CurrentCamera +local IS_PHONE = c.ViewportSize.Y < 600 + +local topbar = guiRoot:WaitForChild("Topbar") + +if IS_PHONE then + local uiScale = Instance.new("UIScale") + uiScale.Scale = 0.6 + uiScale.Parent = topbar +end + +local messageGui = guiRoot:WaitForChild("MessageGui") +local message = messageGui:WaitForChild("Message") + +local partWatch = nil +local partQueue = {} + +local bricks = 0 +local connectors = 0 +local messageFormat = "Bricks: %d Connectors: %d" + +--------------------------------------------------------------------- + +local fakeLoadTime = TeleportService:GetTeleportSetting("FakeLoadTime") + +local function onDescendantAdded(desc) + if desc:IsA("BasePart") and not desc:IsA("Terrain") then + if not CollectionService:HasTag(desc, "AxisPart") and desc.Name ~= "__negatepart" then + desc.LocalTransparencyModifier = 1 + partQueue[#partQueue + 1] = desc + end + elseif desc:IsA("Decal") then + desc.LocalTransparencyModifier = 1 + end +end + +if fakeLoadTime then + local descendants = workspace:GetDescendants() + + for _,desc in pairs(descendants) do + onDescendantAdded(desc) + end + + partWatch = workspace.DescendantAdded:Connect(onDescendantAdded) +end + +--------------------------------------------------------------------- + +local c = workspace.CurrentCamera +c.CameraType = "Follow" +c.CameraSubject = workspace + +messageGui.Visible = true + +local bricks = 0 +local connectors = 0 +local lastUpdate = 0 + +local done = false + +local function stepBrickConnectorStatus() + if fakeLoadTime then + wait(math.random() / 4) + + for i = 1, math.random(30, 50) do + local part = table.remove(partQueue) + + if part then + bricks = bricks + 1 + + connectors = connectors + #part:GetJoints() + part.LocalTransparencyModifier = 0 + + for _,v in pairs(part:GetDescendants()) do + if v:IsA("Decal") then + v.LocalTransparencyModifier = 0 + end + end + end + end + + done = (#partQueue == 0) + else + wait() + done = game:IsLoaded() + end +end + +while not done do + stepBrickConnectorStatus() + message.Text = messageFormat:format(bricks, connectors) +end + +if partWatch then + partWatch:Disconnect() + partWatch = nil +end + +c.CameraSubject = nil +message.Text = "Requesting character..." + +wait(1) + +local rep = game:GetService("ReplicatedStorage") +local requestCharacter = rep:WaitForChild("RequestCharacter") + +requestCharacter:FireServer() +message.Text = "Waiting for character..." + +while not player.Character do + player.CharacterAdded:Wait() + wait() +end + +messageGui.Visible = false +c.CameraType = "Custom" + + + + GuiRoot + + + + Topbar + + + + Buttons + local topbar = script.Parent + +local function registerButton(btn) + if btn:IsA("TextButton") and btn.Active then + local function onMouseEnter() + btn.BackgroundTransparency = 0 + end + + local function onMouseLeave() + btn.BackgroundTransparency = 0.5 + end + + btn.MouseEnter:Connect(onMouseEnter) + btn.MouseLeave:Connect(onMouseLeave) + end +end + +for _,v in pairs(topbar:GetChildren()) do + registerButton(v) +end + +topbar.ChildAdded:Connect(registerButton) + + + + + Exit + + + + Exit + local TeleportService = game:GetService("TeleportService") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +GuiService.AutoSelectGuiEnabled = false + +local btn = script.Parent +local topbar = btn.Parent +local root = topbar.Parent +local messageGui = root:WaitForChild("MessageGui") +local message = messageGui:WaitForChild("Message") +local exitOverride = messageGui:WaitForChild("ExitOverride") + +local function onClicked() + local visibleSignal = messageGui:GetPropertyChangedSignal("Visible") + message.Visible = false + exitOverride.Visible = true + messageGui.Visible = true + TeleportService:Teleport(998374377) + visibleSignal:Connect(function () + if not messageGui.Visible then + messageGui.Visible = true + end + end) +end + +if not GuiService:IsTenFootInterface() then + btn.MouseButton1Down:Connect(onClicked) +end + +local exitBuffer = "Continue holding down 'Back' to return to the menu.\nExiting in...\n%.1f" + +local function onInputBegan(input) + if input.KeyCode == Enum.KeyCode.ButtonSelect and not exitOverride.Visible and not messageGui.Visible then + messageGui.Visible = true + message.Size = exitOverride.Size + + local success = true + for i = 3,0,-.1 do + if input.UserInputState ~= Enum.UserInputState.Begin then + success = false + break + end + message.Text = exitBuffer:format(i) + wait(.1) + end + + if success then + onClicked() + else + messageGui.Visible = false + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + + + + + + Fullscreen + + + + Fullscreen + local UserInputService = game:GetService("UserInputService") + +local btn = script.Parent +local gameSettings = UserSettings():GetService("UserGameSettings") +local player = game.Players.LocalPlayer + +local function onClick() + if not player:FindFirstChild("FullscreenMsg") then + local m = Instance.new("Message") + m.Name = "FullscreenMsg" + m.Text = "This button is just here for legacy aesthetics, and has no functionality." + if UserInputService.MouseEnabled and UserInputService.KeyboardEnabled then + m.Text = m.Text .. "\nPress F11 to toggle fullscreen!" + end + m.Parent = player + wait(3) + m:Destroy() + end +end + +local function update() + if gameSettings:InFullScreen() then + btn.Text = "\t\tx Fullscreen" + else + btn.Text = "\t\tFullscreen" + end +end + +update() +gameSettings.FullscreenChanged:connect(update) +btn.MouseButton1Down:Connect(onClick) + + + + + + Help + + + + Help + local help = script.Parent +local topbar = help.Parent +local root = topbar.Parent +local window = root:WaitForChild("HelpWindow") +local close = window:WaitForChild("Close") + +local function onOpen() + window.Visible = true +end + +local function onClose() + window.Visible = false +end + +help.MouseButton1Down:Connect(onOpen) +close.MouseButton1Down:Connect(onClose) + + + + + + + + GuiRoot + true + + true + 0 + true + false + false + null + + 0 + + + + Topbar + false + + 0 + 0 + + true + + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 80 + 0 + -36 + + null + 0 + false + null + + 0 + 660 + 0 + 27 + + 0 + 0 + + true + 1 + + + + Exit + true + + 0 + 0 + + true + + false + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 528 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + true + 14 + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + 0.8999999761581421 + 0.30000001192092896 + 0 + true + 0 + 1 + true + 1 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + Help + true + + 0 + 0 + + true + + false + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 396 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + true + 14 + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + 0.8999999761581421 + 0.30000001192092896 + 0 + true + 0 + 1 + true + 1 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + Fullscreen + true + + 0 + 0 + + true + + false + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 264 + 0 + 0 + + null + 0 + false + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + true + 14 + + 0.40392160415649414 + 0.40392160415649414 + 0.40392160415649414 + + 0.8999999761581421 + 0.30000001192092896 + 0 + true + 0 + 1 + true + 1 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + Insert + false + + 0 + 0 + + true + + false + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 132 + 0 + 0 + + null + 0 + true + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + + + 0.6274510025978088 + 0.6274510025978088 + 0.6274510025978088 + + true + 14 + + 0.6274510025978088 + 0.6274510025978088 + 0.6274510025978088 + + 0.8999999761581421 + 0.30000001192092896 + 0 + true + 0 + 1 + true + 1 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + Tools + false + + 0 + 0 + + true + + false + true + + 0.698039174079895 + 0.698039174079895 + 0.698039174079895 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + true + false + null + + 0 + 132 + 1 + 0 + + 0 + 0 + + + + 0.6274510025978088 + 0.6274510025978088 + 0.6274510025978088 + + true + 14 + + 0.6274510025978088 + 0.6274510025978088 + 0.6274510025978088 + + 0.8999999761581421 + 0.30000001192092896 + 0 + true + 0 + 1 + true + 1 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + + MessageGui + false + + 0.5 + 0.5 + + true + + true + + 0.7058823704719543 + 0.7058823704719543 + 0.7058823704719543 + + 0.5 + + 1 + 1 + 1 + + 0 + 3 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.6000000238418579 + 0 + 1 + 0 + + 0 + 0 + + false + 1 + + + + Message + false + + 0 + 0.5 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0.5 + 0 + + null + 0 + false + null + + 1 + 0 + 0.125 + 0 + + 0 + + Connecting to server... + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.75 + 0 + 0 + true + 2 + 1 + true + 1 + + + + + UIAspectRatioConstraint + true + 3 + 0 + + 1 + + + + + + ExitOverride + false + + 0 + 0.5 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0.5 + 0 + + null + 0 + false + null + + 1 + 0 + 0.25 + 0 + + 0 + + You are now being returned to the main menu. +Please hold... + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.75 + 0 + 0 + true + 2 + 1 + false + 1 + + + + + + HelpWindow + true + + 0.5 + 0.5 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + true + + rbxassetid://1041546985 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + 1 + false + null + + 0.800000011920929 + 0 + 0.699999988079071 + 0 + + 0 + + + 4 + 30 + + + 304 + 130 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 1 + + + + Help + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + rbxassetid://1041647615 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 0 + 4 + 0 + 31 + + null + 0 + 0 + false + null + + 1 + -8 + 1 + -36 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 1 + + + + UIAspectRatioConstraint + true + 2.75 + 0 + + 0 + + + + + + + Title + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 2 + 0 + 1 + null + null + null + null + + 0 + 5 + 0 + 0 + + null + 0 + false + null + + 0.8999999761581421 + -10 + 0 + 30 + + 0 + + ROBLOX Help + + 1 + 1 + 1 + + false + 14 + + 0.498039186000824 + 0.498039186000824 + 0.498039186000824 + + 0.6000000238418579 + 0 + 0 + false + 0 + 1 + true + 2 + + + + Stroke + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 2 + 0 + 1 + null + null + null + null + + 0 + 1 + 0 + 1 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + ROBLOX Help + + 0 + 0 + 0 + + false + 14 + + 1 + 1 + 1 + + 1 + 0 + 0 + false + 0 + 1 + true + 1 + + + + + + Close + true + + 1 + 0 + + true + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + + + + + + rbxassetid://1041651899 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + true + null + null + null + null + + 1 + -5 + 0 + 5 + + + + + + null + 0 + 0 + true + false + null + + 0 + 22 + 0 + 22 + + 1 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 1 + + + + + UIAspectRatioConstraint + true + 2.5 + 0 + + 0 + + + + + + + + + + ReplicatedStorage + + + + SafeChatTree + local safeChatTree = +{ + Label = "ROOT"; + Branches = {}; +} + +do + local mTreeData = script:WaitForChild("RawTreeData") + local treeData = require(mTreeData) + + local stack = {} + stack[0] = safeChatTree + + for line in treeData:gmatch("[^\n]+") do + if #line > 0 then + local stackIndex = 0 + while line:sub(1,1) == "\t" do + stackIndex = stackIndex + 1 + line = line:sub(2) + end + + local tree = stack[stackIndex] + assert(tree,"Bad safechat tree setup at depth " .. stackIndex .. ": " .. line) + + local branch = {} + branch.Label = line + branch.Branches = {} + table.insert(tree.Branches,branch) + + stack[stackIndex+1] = branch + end + end +end + +return safeChatTree + + + + RawTreeData + return [==[ +Hello + Hi + Hi there! + Hi everyone + Howdy + Howdy partner! + Greetings + Greetings everyone + Greetings robloxians! + Seasons greetings! + Welcome + Welcome to my place + Welcome to our base + Welcome to my barbecque + Hey there! + What's up? + How are you doing? + How's it going? + What's new? + Good day + Good morning + Good afternoon + Good evening + Good night + Silly + Waaaaaaaz up?! + Hullo! + Behold greatness, mortals! + Holidays + Happy New Year! + Happy Valentine's Day! + Beware the Ides of March! + Happy Easter! + Happy 4th of July! + Happy Thanksgiving! + Happy Halloween! + Happy Hanukkah! + Merry Christmas! + Happy Holidays! +Goodbye + Good Night + Sweet dreams + Go to sleep! + Lights out! + Bedtime + Later + See ya later + Later gator! + See you tomorrow + Bye + Hasta la bye bye! + I'll be right back + I have to go + Farewell + Take care + Have a nice day + Goodluck! + Ta-ta for now! + Peace + Peace out! + Peace dudes! + Rest in pieces! + Silly + To the batcave! + Over and out! + Happy trails! + I've got to book it! + Tootles! + Smell you later! + GG! + My house is on fire! gtg. +Friend + Wanna be friends? + Follow me + Come to my place! + Come to my base! + Follow me, team! + Your place is cool + Your place is fun + Your place is awesome + Your place looks good + Thank you + Thanks for playing + Thanks for visiting + Thanks for everything + No thank you + No problem + Don't worry + That's ok + You are ... + You are great! + You are good! + You are cool! + You are funny! + You are silly! + You are awesome! + I like ... + I like your name + I like your shirt + I like your place + I like your style + Sorry + My bad! + I'm sorry + Whoops! + Please forgive me + I forgive you +Questions + Who? + Who wants to be my friend? + Who wants to be on my team? + Who made this brilliant game? + What? + What is your favorite animal? + What is your favorite game? + What is your favorite movie? + What is your favorite TV show? + What is your favorite music? + What are your hobbies? + When? + When are you online? + When is the new version coming out? + When can we play again? + When will your place be done? + Where? + Where do you want to go? + Where are you going? + Where am I?! + How? + How are you today? + How did you make this cool place? + Can I... + Can I have a tour? + Can I be on your team? + Can I be your friend? + Can I try something? +Answers + You need help? + Check out the news section + Check out the help section + Read the wiki! + All the answers are in the wiki! + Some people ... + Me + Not me + You + All of us + Everyone but you + Builderman! + Telamon! + Time ... + In the morning + In the afternoon + At night + Tomorrow + This week + This month + Sometime + Sometimes + Whenever you want + Never + Animals + Cats + Lion + Tiger + Leopard + Cheetah + Dogs + Wolves + Beagle + Collie + Dalmatian + Poodle + Spaniel + Shepherd + Terrier + Retriever + Horses + Ponies + Stallions + Reptiles + Dinosaurs + Lizards + Snakes + Turtles! + Hamster + Monkey + Bears + Fish + Goldfish + Sharks + Sea Bass + Halibut + Birds + Eagles + Penguins + Turkeys + Elephants + Mythical Beasts + Dragons + Unicorns + Sea Serpents + Sphinx + Cyclops + Minotaurs + Goblins + Honest Politicians + Ghosts + Scylla and Charybdis + Games + Roblox + BrickBattle + Community Building + Roblox Minigames + Action + Puzzle + Strategy + Racing + RPG + Board games + Chess + Checkers + Settlers of Catan + Tigris and Euphrates + El Grande + Stratego + Carcassonne + Sports + Hockey + Soccer + Football + Baseball + Basketball + Volleyball + Tennis + Watersports + Surfing + Swimming + Water Polo + Winter sports + Skiing + Snowboarding + Sledding + Skating + Adventure + Rock climbing + Hiking + Fishing + Wacky + Foosball + Calvinball + Croquet + Cricket + Dodgeball + Squash + Movies/TV + Science Fiction + Animated + Anime + Comedy + Romantic + Action + Fantasy + Music + Country + Jazz + Rap + Hip-hop + Techno + Classical + Pop + Rock + Hobbies + Computers + Building computers + Videogames + Coding + Hacking + The Internet + lol. teh internets! + Dance + Gynastics + Martial Arts + Karate + Judo + Taikwon Do + Wushu + Street fighting + Listening to music + Music lessons + Playing in my band + Playing piano + Playing guitar + Playing violin + Playing drums + Playing a weird instrument + Arts and crafts + Location + USA + West + Alaska + Arizona + California + Colorado + Hawaii + Idaho + Montana + Nevada + New Mexico + Oregon + Utah + Washington + Wyoming + Midwest + Illinois + Indiana + Iowa + Kansas + Michigan + Minnesota + Missouri + Nebraska + North Dakota + Ohio + South Dakota + Wisconsin + Northeast + Connecticut + Delaware + Maine + Maryland + Massachusetts + New Hampshire + New Jersey + New York + Pennsylvania + Rhode Island + Vermont + Virginia + West Virginia + South + Alabama + Arkansas + Florida + Georgia + Kentucky + Louisiana + Mississippi + North Carolina + Oklahoma + South Carolina + Tennessee + Texas + Canada + Alberta + British Columbia + Manitoba + New Brunswick + Newfoundland + Northwest Territories + Nova Scotia + Nunavut + Ontario + Prince Edward Island + Quebec + Saskatchewan + Yukon + Mexico + Central America + Europe + Great Britain + England + Scotland + Wales + Northern Ireland + France + Germany + Spain + Italy + Poland + Switzerland + Greece + Romania + Asia + China + India + Japan + Korea + South America + Argentina + Brazil + Africa + Eygpt + Swaziland + Australia + Middle East + Antarctica + Age + Rugrat + Kid + Teen + Twenties + Old + Ancient + Mesozoic + Mood + Good + Great! + Not bad + Sad + Hyper + Chill + Boy + Girl +Game + Let's build + Let's battle + Nice one! + So far so good! + Lucky shot! + Oh man! +Silly + Muahahahaha! + 1337 + i r teh pwnz0r! + w00t! + z0mg h4x! + ub3rR0xXorzage! + all your base are belong to me! +Yes + Absolutely! + Rock on! + Totally! + Juice! +No + Ummm. No. + ... +Ok + Well... ok + Sure +:-) + :-( + :D + :-O + lol +]==] + + + + + + + ServerScriptService + + + + Badges + local ServerStorage = game:GetService("ServerStorage") +local BadgeService = game:GetService("BadgeService") +local AssetService = game:GetService("AssetService") +local Players = game:GetService("Players") + +local usingLeaderboard = true + +if ServerStorage:FindFirstChild("TrackCombatBadges") then + usingLeaderboard = ServerStorage.TrackCombatBadges.Value +elseif ServerStorage:FindFirstChild("LoadLeaderboard") then + usingLeaderboard = ServerStorage.LoadLeaderboard.Value +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) + +if not playerDataGet.Success then + warn("Failed to load PlayerData, badges will not be awarded") + return +end + +local playerData = playerDataGet.DataStore + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local placeCount = 0 + +local function iterPageItems(pages) + return coroutine.wrap(function () + local pageNum = 1 + while true do + for _, item in ipairs(pages:GetCurrentPage()) do + coroutine.yield(item, pageNum) + end + + if pages.IsFinished then + break + end + + pages:AdvanceToNextPageAsync() + pageNum = pageNum + 1 + end + end) +end + +for place in iterPageItems(AssetService:GetGamePlacesAsync()) do + if not place.Name:lower():find("devtest") and not place.Name:find("Super Nostalgia Zone") then + placeCount = placeCount + 1 + end +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local badges = +{ + CombatInitiation = 1020931358; + Warrior = 1020932933; + Bloxxer = 1021012898; + Inviter = 1021010468; + Friendship = 1021024465; + Ambassador = 1021056315; +} + +local inviterBadgeStatus = {} +local lastWipeout = {} + +local function giveBadge(player,badge) + warn("AWARDING BADGE", badge, "TO", player) + if not BadgeService:UserHasBadge(player.UserId,badge) then + BadgeService:AwardBadge(player.UserId,badge) + end +end + +local function onHumanoidDied(humanoid, victim) + local player do + local char = humanoid.Parent + if char then + player = Players:GetPlayerFromCharacter(char) + end + end + + local myLastWipeout = lastWipeout[victim.Name] or 0 + local now = tick() + + if (now - myLastWipeout) > 5 then + local creator = humanoid:FindFirstChild("creator") + + if creator then + local killer = creator.Value + + if killer and killer.UserId > 0 and killer ~= player then + local killerData = playerData:GetSaveData(killer) + local knockOuts = killerData:Get("Knockouts") or 0 + + knockOuts = knockOuts + 1 + killerData:Set("Knockouts",knockOuts) + + if knockOuts > 250 then + local wipeOuts = killerData:Get("Wipeouts") or 0 + if wipeOuts < knockOuts then + giveBadge(killer,badges.Bloxxer) + end + elseif knockOuts > 100 then + giveBadge(killer,badges.Warrior) + elseif knockOuts > 10 then + giveBadge(killer,badges.CombatInitiation) + end + end + end + + local myData = playerData:GetSaveData(victim) + local wipeOuts = myData:Get("Wipeouts") or 0 + + myData:Set("Wipeouts", wipeOuts + 1) + lastWipeout[victim.Name] = now + end +end + +local function onCharacterAdded(char) + local player = game.Players:GetPlayerFromCharacter(char) + local humanoid = char:WaitForChild("Humanoid") + + humanoid.Died:Connect(function () + onHumanoidDied(humanoid,player) + end) +end + +local function handleSocialBadges(player) + -- Set up our inviter status from scratch. + inviterBadgeStatus[player.Name] = + { + Counted = 0; + Queried = {}; + } + + -- Check the status of other players, and see if we can give them the inviter badge. + local myData = playerData:GetSaveData(player) + + for _,otherPlayer in pairs(Players:GetPlayers()) do + if player ~= otherPlayer and player:IsFriendsWith(otherPlayer.UserId) then + local theirName = otherPlayer.Name + local theirStatus = inviterBadgeStatus[theirName] + + if theirStatus and not theirStatus.Queried[player.Name] then + theirStatus.Queried[player.Name] = true + theirStatus.Counted = theirStatus.Counted + 1 + if theirStatus.Counted >= 3 then + giveBadge(otherPlayer,badges.Inviter) + end + end + + -- Also increment the friendship encounters for these two. + + local myFrEncs = myData:Get("FriendEncounters") or 0 + myFrEncs = myFrEncs + 1 + + myData:Set("FriendEncounters",myFrEncs) + + if myFrEncs >= 10 then + giveBadge(player,badges.Friendship) + end + + local theirData = playerData:GetSaveData(otherPlayer) + local theirFrEncs = theirData:Get("FriendEncounters") or 0 + + theirFrEncs = theirFrEncs + 1 + theirData:Set("FriendEncounters",theirFrEncs) + + if theirFrEncs >= 10 then + giveBadge(otherPlayer,badges.Friendship) + end + end + end +end + +local function onPlayerAdded(player) + if player.UserId > 0 then + -- Hook up combat badge listeners + if usingLeaderboard then + if player.Character and player.Character:IsDescendantOf(workspace) then + onCharacterAdded(player.Character) + end + + player.CharacterAdded:Connect(onCharacterAdded) + end + + -- Handle social badges + handleSocialBadges(player) + + -- Handle ambassador badge + local myData = playerData:GetSaveData(player) + local myPlaceVisits = myData:Get("PlacesVisited") + + if myPlaceVisits == nil then + myPlaceVisits = + { + Count = 0; + Record = {}; + } + end + + local placeId = tostring(game.PlaceId) + + if not myPlaceVisits.Record[placeId] then + myPlaceVisits.Record[placeId] = true + myPlaceVisits.Count = myPlaceVisits.Count + 1 + end + + if myPlaceVisits.Count >= placeCount then + giveBadge(player, badges.Ambassador) + end + + myData:Set("PlacesVisited", myPlaceVisits) + end +end + +for _,v in pairs(Players:GetPlayers()) do + onPlayerAdded(v) +end + +Players.PlayerAdded:Connect(onPlayerAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + Bevels + ------------------------------------------------------------------------------------------------ +-- Initialization +------------------------------------------------------------------------------------------------ + +local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local ServerStorage = game:GetService("ServerStorage") + +local function getFlag(name) + local flag = ServerStorage:FindFirstChild(name) + return (flag and flag:IsA("BoolValue") and flag.Value) +end + +local enableBevels = getFlag("EnableBevels") +local debugMode = getFlag("DevTestMode") + +local bevelCache = ServerStorage:FindFirstChild("BevelCache") +local bevelsReady = bevelCache:FindFirstChild("BevelsReady") + +if not bevelCache then + bevelCache = Instance.new("Folder") + bevelCache.Name = "BevelCache" + bevelCache.Parent = ServerStorage +end + +if not bevelsReady then + bevelsReady = Instance.new("BoolValue") + bevelsReady.Name = "BevelsReady" + bevelsReady.Parent = bevelCache + bevelsReady.Archivable = false +end + +if not enableBevels then + bevelsReady.Value = true + return +end + +do + local coreBevelCache = ServerStorage:WaitForChild("CoreBevelCache") + + for _,bevel in pairs(coreBevelCache:GetChildren()) do + if not bevelCache:FindFirstChild(bevel.Name) then + bevel.Parent = bevelCache + bevel.Archivable = false + end + end + + coreBevelCache:Destroy() +end + +local regen = ServerStorage:FindFirstChild("Regeneration") + +if regen then + local ready = regen:WaitForChild("Ready") + + while not ready.Value do + ready.Changed:Wait() + end +end + +local loadBuildTools = ServerStorage:FindFirstChild("LoadBuildTools") +local hasBuildTools = (loadBuildTools ~= nil) + +------------------------------------------------------------------------------------------------ + +local edgeDepth = 1 / 15 +local cornerDepth = edgeDepth * math.sqrt(8 / 3) + +local mirrorProps = +{ + "Anchored", + "CanCollide", + "CastShadow", + "CFrame", + "CollisionGroupId", + "CustomPhysicalProperties", + "Color", + "Locked", + "Material", + "Name", + "Reflectance", + "RotVelocity", + "Transparency", + "Velocity", +} + +local surfaceProps = +{ + "ParamA", + "ParamB", + "Surface", + "SurfaceInput" +} + +local bevelHash = "%.2f ~ %.2f ~ %.2f" +local isStudio = RunService:IsStudio() + +local negateBase = Instance.new("Part") +negateBase.Name = "__negateplane" +negateBase.CanCollide = false +negateBase.BottomSurface = 0 +negateBase.Transparency = 1 +negateBase.Anchored = true +negateBase.TopSurface = 0 +negateBase.Locked = true + +CollectionService:AddTag(negateBase, "NoBevels") + +for _,normalId in pairs(Enum.NormalId:GetEnumItems()) do + local name = normalId.Name + for _,surfaceProp in pairs(surfaceProps) do + table.insert(mirrorProps, name .. surfaceProp) + end +end + +------------------------------------------------------------------------------------------------ + +local overload = 0 +local threshold = Vector3.new(30, 30, 30) + +if ServerStorage:FindFirstChild("BevelThreshold") then + threshold = ServerStorage.BevelThreshold.Value +end + +local function debugPrint(...) + if debugMode then + warn("[BEVELS DEBUG]:", ...) + end +end + +local function isPartOfHumanoid(object) + local model = object:FindFirstAncestorOfClass("Model") + + if model then + if model:FindFirstChildOfClass("Humanoid") then + return true + else + return isPartOfHumanoid(model) + end + end + + return false +end + +local function canGiveBevels(part) + if part.Parent and part:IsA("Part") and not CollectionService:HasTag(part, "NoBevels") then + if not isPartOfHumanoid(part) and not part:FindFirstChildWhichIsA("DataModelMesh") then + local inThreshold = false + local diff = threshold - part.Size + + if diff.X >= 0 and diff.Y >= 0 and diff.Z >= 0 then + inThreshold = true + end + + if inThreshold then + if CollectionService:HasTag(part, "ForceBevels") then + return true + else + return part.Shape.Name == "Block" and part.Transparency < 1 + end + end + end + end + + return false +end + +local function createProxyPart(part, name, tag, sizeChange) + local proxyPart = Instance.new("Part") + proxyPart.Name = name + proxyPart.Locked = true + proxyPart.TopSurface = 0 + proxyPart.Massless = true + proxyPart.Transparency = 1 + proxyPart.BottomSurface = 0 + proxyPart.CanCollide = false + proxyPart.CFrame = part.CFrame + + local size = part.Size + if sizeChange then + size = size + sizeChange + end + + local proxyWeld = Instance.new("Weld") + proxyWeld.Name = "ProxyWeld" + proxyWeld.Part1 = proxyPart + proxyWeld.Part0 = part + + if hasBuildTools then + local mesh = Instance.new("SpecialMesh") + mesh.Scale = size * 20 + mesh.MeshType = "Brick" + mesh.Offset = part.Size + mesh.Parent = proxyPart + + proxyPart.Size = Vector3.new(.05, .05, .05) + proxyWeld.C0 = CFrame.new(-mesh.Offset) + else + proxyPart.Size = part.Size + end + + CollectionService:AddTag(proxyPart, tag) + CollectionService:AddTag(proxyPart, "NoBevels") + CollectionService:AddTag(proxyWeld, "GorillaGlue") + + proxyWeld.Parent = proxyPart + proxyPart.Parent = part + + return proxyPart +end + +local function createBevels(part, initializing) + if not canGiveBevels(part) or isPartOfHumanoid(part) then + return + end + + local size = part.Size + local sx, sy, sz = size.X, size.Y, size.Z + local bevelKey = bevelHash:format(sx, sy, sz) + + local debugBox + + if debugMode then + debugBox = Instance.new("BoxHandleAdornment") + + debugBox.Color3 = Color3.new(0, 2, 2) + debugBox.AlwaysOnTop = true + debugBox.Name = "DebugBox" + debugBox.Size = size + debugBox.ZIndex = 0 + + debugBox.Adornee = part + debugBox.Parent = part + end + + if not bevelCache:FindFirstChild(bevelKey) then + local halfSize = size / 2 + + local planeScale = math.max(sx, sy, sz) + local planes = {} + + local solverPart = part:Clone() + solverPart.CFrame = CFrame.new() + solverPart.BrickColor = BrickColor.new(-1) + + debugPrint("Solving:", bevelKey) + + for x = -1, 1 do + local x0 = (x == 0) + + for y = -1, 1 do + local y0 = (y == 0) + + for z = -1, 1 do + local z0 = (z == 0) + + local isCenter = (x0 and y0 and z0) + local isFace = ((x0 and y0) or (y0 and z0) or (z0 and x0)) + + if not (isCenter or isFace) then + local isCorner = (not x0 and not y0 and not z0) + local depth = isCorner and cornerDepth or edgeDepth + + local offset = Vector3.new(x, y, z) + local cornerPos = (halfSize * offset) + + local plane = negateBase:Clone() + plane.CFrame = CFrame.new(cornerPos, cornerPos + offset) + plane.Size = Vector3.new(planeScale, planeScale, depth) + plane.Parent = part + + table.insert(planes, plane) + end + end + end + end + + local success, union = pcall(function () + return solverPart:SubtractAsync(planes, "Box") + end) + + if success then + union.Name = bevelKey + union.UsePartColor = true + union.Parent = bevelCache + + CollectionService:AddTag(union, "HasBevels") + + if debugBox then + debugBox.Color3 = Color3.new(0, 2, 0) + end + elseif debugBox then + debugBox.Color3 = Color3.new(2, 0, 0) + end + + for _,plane in pairs(planes) do + plane:Destroy() + end + + overload = 0 + else + if debugBox then + debugBox.Color3 = Color3.new(2, 0, 2) + end + + overload = overload + 1 + + if overload % 10 == 0 then + RunService.Heartbeat:Wait() + end + end + + local baseUnion = bevelCache:FindFirstChild(bevelKey) + + if baseUnion then + local archivable = baseUnion.Archivable + baseUnion.Archivable = true + + local union = baseUnion:Clone() + baseUnion.Archivable = archivable + + for _,prop in ipairs(mirrorProps) do + union[prop] = part[prop] + end + + for _,joint in pairs(part:GetJoints()) do + if joint:IsA("JointInstance") or joint:IsA("WeldConstraint") then + if joint.Part0 == part then + joint.Part0 = union + elseif joint.Part1 == part then + joint.Part1 = union + end + end + end + + for _,child in pairs(part:GetChildren()) do + if not child:IsA("TouchTransmitter") and not child:IsA("Texture") then + if child:IsA("BaseScript") then + child.Disabled = true + end + + child.Parent = union + + if child:IsA("BaseScript") then + child.Disabled = false + end + end + end + + if not initializing then + wait() + end + + if CollectionService:HasTag(part, "DoUnlock") then + union.Locked = false + end + + if part.ClassName ~= "Part" then + local holder = Instance.new("Weld") + holder.Part0 = part + holder.Part1 = union + holder.Parent = part + + union.Anchored = false + union.Massless = true + union.Parent = part + + part.Transparency = 1 + CollectionService:AddTag(holder, "GorillaGlue") + else + local parent = part.Parent + part:Destroy() + + union.Parent = parent + end + elseif debugBox then + debugBox.Color3 = Color3.new(2, 0, 0) + end + + if debugBox then + debugBox.Transparency = 0.5 + Debris:AddItem(debugBox, 2) + end +end + +------------------------------------------------------------------------------------------------ + +do + local waitForPlayer = getFlag("BevelsWaitForPlayer") + + if waitForPlayer then + -- Wait for a player to spawn + local playerSpawned = false + + while not playerSpawned do + for _,player in pairs(Players:GetPlayers()) do + if player.Character and player.Character:IsDescendantOf(workspace) then + playerSpawned = true + break + end + end + + workspace.ChildAdded:Wait() + end + end + + warn("Solving bevels...") + + -- Collect all blocks currently in the workspace. + local initialPass = {} + local debugHint + + for _,desc in pairs(workspace:GetDescendants()) do + if canGiveBevels(desc) then + if not desc.Locked then + CollectionService:AddTag(desc, "DoUnlock") + desc.Locked = true + end + + table.insert(initialPass, desc) + end + end + + if waitForPlayer then + -- Sort the blocks by the sum of their distances from players in the game. + local samplePoints = {} + + for _,player in pairs(Players:GetPlayers()) do + local char = player.Character + if char then + local root = char.PrimaryPart + if root then + local rootPos = root.Position + table.insert(samplePoints, rootPos) + end + end + end + + table.sort(initialPass, function (a, b) + local distSumA = 0 + local distSumB = 0 + + local posA = a.Position + local posB = b.Position + + for _,rootPos in pairs(samplePoints) do + local distA = (rootPos - posA).Magnitude + distSumA = distSumA + distA + + local distB = (rootPos - posB).Magnitude + distSumB = distSumB + distB + end + + if distSumA ~= distSumB then + return distSumA < distSumB + end + + if posA.Y ~= posB.Y then + return posA.Y < posB.Y + end + + if posA.X ~= posB.X then + return posA.X < posB.X + end + + if posA.Z ~= posB.Z then + return posA.Z < posB.Z + end + + return 0 + end) + end + + if debugMode then + debugHint = Instance.new("Hint") + debugHint.Text = "Generating Bevels..." + debugHint.Parent = workspace + end + + -- Run through the initial bevel creation phase. + for _,block in ipairs(initialPass) do + createBevels(block, true) + end + + if debugHint then + debugHint:Destroy() + end +end + +-- Listen for new parts being added. +workspace.DescendantAdded:Connect(createBevels) + +-- Allow regeneration to request bevel solving +local bevelSolver = bevelCache:FindFirstChild("RequestSolve") + +if not bevelSolver then + bevelSolver = Instance.new("BindableFunction") + bevelSolver.Name = "RequestSolve" + bevelSolver.Parent = bevelCache + bevelSolver.Archivable = false +end + +function bevelSolver.OnInvoke(inst) + for _,desc in pairs(inst:GetDescendants()) do + if desc:IsA("Part") then + createBevels(desc) + end + end +end + +if RunService:IsStudio() then + local exportBin = Instance.new("Folder") + exportBin.Name = "ExportBin" + exportBin.Parent = ServerStorage + + for _,v in pairs(bevelCache:GetChildren()) do + if v:IsA("TriangleMeshPart") and v.Archivable then + v:Clone().Parent = exportBin + end + end + + wait(.1) + + for _,v in pairs(exportBin:GetChildren()) do + if v:FindFirstChild("LOD") then + v.LOD:Destroy() + end + end +end + +-- Ready! +warn("Bevels ready!") +bevelsReady.Value = true + +------------------------------------------------------------------------------------------------ + + + + + BuildTools + local CollectionService = game:GetService("CollectionService") +local HttpService = game:GetService("HttpService") +local Players = game:GetService("Players") +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local ServerStorage = game:GetService("ServerStorage") + +local loadBuildTools = ServerStorage:FindFirstChild("LoadBuildTools") +if not (loadBuildTools and loadBuildTools.Value) then + return +end + +local looseBranches = ServerStorage:FindFirstChild("LooseBranches") + +if looseBranches and looseBranches:IsA("BoolValue") then + looseBranches = looseBranches.Value +else + looseBranches = false +end + +local toolList = loadBuildTools.Value +if toolList == true then -- If it's a BoolValue, load all of them. + toolList = "GameTool;Clone;Delete" +end + +local DraggerService = Instance.new("Folder") +DraggerService.Name = "DraggerService" +DraggerService.Parent = ReplicatedStorage + +local draggerGateway = Instance.new("RemoteFunction") +draggerGateway.Name = "DraggerGateway" +draggerGateway.Parent = DraggerService + +local submitUpdate = Instance.new("RemoteEvent") +submitUpdate.Name = "SubmitUpdate" +submitUpdate.Parent = DraggerService + +local draggerScript = script:WaitForChild("Dragger") + +local activeKeys = {} +local playerToKey = {} +local partToKey = {} +local debounce = {} + +local SIMULATE_TAG = "SimulateAfterDrag" +local NO_BREAK_TAG = "GorillaGlue" + +local function assertClass(obj, class) + assert(obj) + assert(typeof(obj) == "Instance") + assert(obj:IsA(class)) +end + +local function canGiveKey(player, part) + if part.Locked then + return false + end + local playerHasKey = playerToKey[player] + if playerHasKey then + return false + end + local partHasKey = partToKey[part] + if partHasKey then + return false + end + return true +end + +local function claimAssembly(player, part) + if part:CanSetNetworkOwnership() then + part:SetNetworkOwner(player) + end +end + +local function validJointsOf(part) + return coroutine.wrap(function () + for _,joint in pairs(part:GetJoints()) do + if not CollectionService:HasTag(joint, NO_BREAK_TAG) then + coroutine.yield(joint) + end + end + end) +end + +local function breakJoints(part) + for joint in validJointsOf(part) do + if not CollectionService:HasTag(joint, NO_BREAK_TAG) then + joint:Destroy() + end + end +end + +local function makeJoints(part) + -- Connect this part to a nearby surface + workspace:JoinToOutsiders({part}, "Surface") +end + +local function removePartKey(key) + local data = activeKeys[key] + if data then + local player = data.Player + if player then + playerToKey[player] = nil + end + + local part = data.Part + + if part then + makeJoints(part) + + if CollectionService:HasTag(part, SIMULATE_TAG) then + data.Anchored = false + CollectionService:RemoveTag(part, SIMULATE_TAG) + end + + part.Anchored = data.Anchored + claimAssembly(player, part) + + partToKey[part] = nil + end + + activeKeys[key] = nil + end +end + +local function restoreJointUpstream(part) + local collectedParts = {} + + if part and CollectionService:HasTag(part, SIMULATE_TAG) then + CollectionService:RemoveTag(part, SIMULATE_TAG) + part.Anchored = false + + makeJoints(part) + + for joint in validJointsOf(part) do + local part0 = joint.Part0 + local part1 = joint.Part1 + + if part0 and part ~= part0 then + collectedParts[part0] = true + restoreJointUpstream(part0) + end + + if part1 and part ~= part1 then + collectedParts[part1] = true + restoreJointUpstream(part1) + end + end + end + + return collectedParts +end + +local function collapseJointUpstream(part) + if part and not (part.Locked or CollectionService:HasTag(part, SIMULATE_TAG)) then + CollectionService:AddTag(part, SIMULATE_TAG) + part.Anchored = true + + for joint in validJointsOf(part) do + local part0 = joint.Part0 + local part1 = joint.Part1 + + if part0 and part ~= part0 then + collapseJointUpstream(part0) + end + + if part1 and part ~= part1 then + collapseJointUpstream(part1) + end + end + + breakJoints(part) + end +end + +function draggerGateway.OnServerInvoke(player, request, ...) + if request == "GetKey" then + local part, asClone = ... + assertClass(part, "BasePart") + + if asClone then + local newPart = part:Clone() + newPart.Parent = workspace + + breakJoints(newPart) + newPart.CFrame = CFrame.new(part.Position + Vector3.new(0, part.Size.Y, 0)) + + local copySound = Instance.new("Sound") + copySound.SoundId = "rbxasset://sounds/electronicpingshort.wav" + copySound.PlayOnRemove = true + copySound.Parent = newPart + + wait() + + part = newPart + copySound:Destroy() + end + + if canGiveKey(player, part) then + local key = HttpService:GenerateGUID(false) + claimAssembly(player, part) + + playerToKey[player] = key + partToKey[part] = key + + local collected = restoreJointUpstream(part) + + local anchored = part.Anchored + part.Anchored = true + breakJoints(part) + + for otherPart in pairs(collected) do + if otherPart:IsGrounded() then + collapseJointUpstream(otherPart) + end + end + + activeKeys[key] = + { + Player = player; + Part = part; + Anchored = anchored; + } + + return true, key, part + else + return false + end + elseif request == "ClearKey" then + local key = ... + + if not key then + key = playerToKey[player] + end + + if key then + local data = activeKeys[key] + if data then + local owner = data.Player + if player == owner then + removePartKey(key) + end + end + end + elseif request == "RequestDelete" then + if not debounce[player] then + local part = ... + assertClass(part, "BasePart") + + debounce[player] = true + + if canGiveKey(player, part) then + local e = Instance.new("Explosion") + e.BlastPressure = 0 + e.Position = part.Position + e.Parent = workspace + + local s = Instance.new("Sound") + s.SoundId = "rbxasset://sounds/collide.wav" + s.Volume = 1 + s.PlayOnRemove = true + s.Parent = part + + local connectedParts = restoreJointUpstream(part) + part:Destroy() + + for otherPart in pairs(connectedParts) do + if otherPart:IsGrounded() then + collapseJointUpstream(otherPart) + end + end + end + + wait(.1) + debounce[player] = false + end + end +end + +local function onChildAdded(child) + if child:IsA("Backpack") then + for draggerTool in toolList:gmatch("[^;]+") do + local tool = Instance.new("Tool") + tool.Name = draggerTool + tool.RequiresHandle = false + + local newDragger = draggerScript:Clone() + newDragger.Parent = tool + newDragger.Disabled = false + + tool.Parent = child + end + end +end + +local function onPlayerAdded(player) + for _, v in pairs(player:GetChildren()) do + onChildAdded(v) + end + + player.ChildAdded:Connect(onChildAdded) +end + +local function onPlayerRemoved(player) + local key = playerToKey[player] + if key then + removePartKey(key) + end +end + +local function onSubmitUpdate(player, key, cframe) + local keyData = activeKeys[key] + if keyData then + local owner = keyData.Player + if owner == player then + local part = keyData.Part + if part and part:IsDescendantOf(workspace) then + breakJoints(part) + part.CFrame = cframe + end + end + end +end + +for _, player in pairs(game.Players:GetPlayers()) do + onPlayerAdded(player) +end + +submitUpdate.OnServerEvent:Connect(onSubmitUpdate) +Players.PlayerAdded:Connect(onPlayerAdded) +Players.PlayerRemoving:Connect(onPlayerRemoved) + +-- Garbage Collection + +while wait(5) do + for part, key in pairs(partToKey) do + if not part:IsDescendantOf(workspace) then + removePartKey(key) + end + end +end + + + + Dragger + local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local SoundService = game:GetService("SoundService") +local Dragger = Instance.new("Dragger") + +local tool = script.Parent +local selection = Instance.new("SelectionBox") +selection.Parent = tool +selection.Transparency = 1 + +local icon = Instance.new("StringValue") +icon.Name = "IconOverride" +icon.Parent = tool + +local mode = tool.Name +local draggerService = ReplicatedStorage:WaitForChild("DraggerService") +local gateway = draggerService:WaitForChild("DraggerGateway") +local submitUpdate = draggerService:WaitForChild("SubmitUpdate") + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Connections +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local cons = {} + +local function addConnections(connections) + for event, func in pairs(connections) do + local con = event:Connect(func) + table.insert(cons, con) + end +end + +local function clearCons() + while #cons > 0 do + local connection = table.remove(cons) + connection:Disconnect() + end +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Keys +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local keyLocks = {} + +local function onInputEnded(input) + if keyLocks[input.KeyCode.Name] then + keyLocks[input.KeyCode.Name] = nil + end +end + +local function isKeyDown(key) + if UserInputService:IsKeyDown(key) and not keyLocks[key] then + keyLocks[key] = true + return true + end + return false +end + +UserInputService.InputEnded:Connect(onInputEnded) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Tool Style +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local style = +{ + GameTool = + { + Icon = "rbxassetid://1048129653"; + HoverColor = Color3.fromRGB(25,153,255); + Cursors = + { + Idle = ""; + Hover = "rbxasset://textures/DragCursor.png"; + Grab = "rbxasset://textures/GrabRotateCursor.png"; + }; + }; + Clone = + { + Icon = "rbxasset://textures/Clone.png"; + HoverColor = Color3.fromRGB(25,153,255); + Cursors = + { + Idle = "rbxasset://textures/CloneCursor.png"; + Hover = "rbxassetid://1048136830"; + Grab = "rbxasset://textures/GrabRotateCursor.png"; + } + }; + Delete = + { + Icon = "rbxasset://textures/Hammer.png"; + HoverColor = Color3.new(1,0.5,0); + CanShowWithHover = true; + Cursors = + { + Idle = "rbxasset://textures/HammerCursor.png"; + Hover = "rbxasset://textures/HammerOverCursor.png"; + } + } +} + +local function getIcon(iconType) + return style[mode].Cursors[iconType] +end + +tool.TextureId = style[mode].Icon +selection.Color3 = style[mode].HoverColor + +if style[mode].CanShowWithHover then + selection.Transparency = 0 +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Dragger +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mouse +local currentKey +local down = false +local debounce = false + +local function onIdle() + if not down and mouse then + local mousePart = mouse.Target + + if mousePart and not mousePart.Locked then + selection.Adornee = mousePart + icon.Value = getIcon("Hover") + return + end + + selection.Adornee = nil + icon.Value = getIcon("Idle") + end +end + +local function draggerRotate(axis) + if down then + Dragger:AxisRotate(axis) + end +end + +local function startDraggerAction(mPart) + if mode == "Delete" then + gateway:InvokeServer("RequestDelete",mPart) + return + end + + local pointOnMousePart = mPart.CFrame:ToObjectSpace(mouse.Hit).Position + local canDrag, dragKey, mousePart = gateway:InvokeServer("GetKey", mPart, mode == "Clone") + + if canDrag then + selection.Adornee = mousePart + selection.Transparency = 0 + + down = true + currentKey = dragKey + + icon.Value = getIcon("Grab") + Dragger:MouseDown(mousePart, pointOnMousePart, {mousePart}) + + local lastSubmit = 0 + + while down do + local now = tick() + local joints = {} + + for _,joint in pairs(mousePart:GetJoints()) do + if CollectionService:HasTag(joint, "GorillaGlue") then + joints[joint] = joint.Parent + joint.Parent = nil + end + end + + --local mousePart = selection.Adornee + if down then + Dragger:MouseMove(mouse.UnitRay) + end + + if mousePart and currentKey then + if isKeyDown("R") then + draggerRotate("Z") + elseif isKeyDown("T") then + draggerRotate("X") + end + + if now - lastSubmit > 0.03 then + submitUpdate:FireServer(currentKey, mousePart.CFrame) + lastSubmit = now + end + end + + for joint, parent in pairs(joints) do + joint.Parent = parent + end + + RunService.Heartbeat:Wait() + end + + selection.Transparency = 1 + gateway:InvokeServer("ClearKey", dragKey) + + currentKey = nil + end +end + +local function onButton1Down() + if not debounce then + debounce = true + + local mousePart = selection.Adornee + + if mousePart and not down then + startDraggerAction(mousePart) + end + + debounce = false + end +end + +local function onButton1Up() + if down then + down = false + Dragger:MouseUp() + end +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Tool +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function onEquipped(newMouse) + mouse = newMouse + addConnections + { + [mouse.Button1Down] = onButton1Down; + [mouse.Button1Up] = onButton1Up; + [mouse.Idle] = onIdle; + } +end + +local function onUnequipped() + onButton1Up() + clearCons() + + selection.Adornee = nil + mouse = nil +end + +tool.Equipped:Connect(onEquipped) +tool.Unequipped:Connect(onUnequipped) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + + CaptureTheFlag + local Players = game:GetService("Players") +local CollectionService = game:GetService("CollectionService") +local Teams = game:GetService("Teams") + +local FlagInstance = "FlagInstance" +local FlagStandInstance = "FlagStandInstance" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +-- Flags +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +local function restoreFlag(flag) + local owner = flag:FindFirstChild("FlagStand") + local flagStand = owner and owner.Part0 + + if owner and flagStand then + for _,joint in pairs(flag:GetJoints()) do + if joint.Name == "RightGrip" then + joint:Destroy() + end + end + + if flag.Name == "Handle" then + local tool = flag.Parent + if tool:IsA("Tool") then + flag.Name = tool.Name + tool.Parent = nil + end + end + + flag.CFrame = flagStand.CFrame + flag.Parent = flagStand.Parent + + wait() + + flag.Velocity = Vector3.new() + flag.RotVelocity = Vector3.new() + + owner.Part1 = flag + flag.Anchored = false + end +end + +local function mountFlagAsTool(flag, humanoid) + local owner = flag:FindFirstChild("FlagStand") + local teamColor = flag:FindFirstChild("TeamColor") + + if not (owner and teamColor) or flag.Name == "Handle" then + return + end + + local grip = CFrame.new(0.25, 0, 0) * CFrame.Angles(0, -math.pi / 2, 0) + + local tool = Instance.new("Tool") + tool.Name = flag.Name + tool.Grip = grip + + local deathCon + + local function onDied() + local char = humanoid.Parent + + if char and tool.Parent == char then + humanoid:UnequipTools() + end + + if deathCon then + deathCon:Disconnect() + deathCon = nil + end + end + + local function onUnequipped() + if deathCon then + deathCon:Disconnect() + deathCon = nil + end + + if humanoid then + local rootPart = humanoid.RootPart + + if rootPart then + local cf = rootPart.CFrame * CFrame.new(0, 4, -8) + flag.RotVelocity = Vector3.new(1, 1, 1) + flag.Position = cf.Position + end + end + + if flag.Parent == tool then + flag.Parent = workspace + end + + flag.Name = tool.Name + + spawn(function () + tool:Destroy() + end) + end + + tool.Unequipped:Connect(onUnequipped) + CollectionService:AddTag(tool, "Flag") + + tool.Parent = workspace + owner.Part1 = nil + + flag.Name = "Handle" + flag.Parent = tool + + humanoid:EquipTool(tool) + deathCon = humanoid.Died:Connect(onDied) +end + +local function onFlagAdded(flag) + if not flag:IsA("BasePart") then + return + end + + -- Mount TeamColor + local teamColor = flag:FindFirstChild("TeamColor") + + if not teamColor then + teamColor = Instance.new("BrickColorValue") + teamColor.Value = flag.BrickColor + teamColor.Name = "TeamColor" + teamColor.Parent = flag + end + + -- Mount FlagStand + local flagStand, owner + + for _,part in pairs(flag:GetConnectedParts()) do + if CollectionService:HasTag(part, FlagStandInstance) then + flagStand = part + break + end + end + + if flagStand then + owner = Instance.new("Weld") + owner.C0 = flagStand.CFrame:ToObjectSpace(flag.CFrame) + owner.Name = "FlagStand" + owner.Part0 = flagStand + owner.Parent = flag + + for _,joint in pairs(flag:GetJoints()) do + if joint ~= owner then + joint:Destroy() + end + end + + owner.Part1 = flag + CollectionService:AddTag(owner, "GorillaGlue") + end + + spawn(function () + -- Try to keep the flag from falling out of the world. + local deathPlane = workspace.FallenPartsDestroyHeight + + while flag:IsDescendantOf(workspace) do + if flag.Position.Y < deathPlane + 200 then + local tool = flag.Parent + + if tool:IsA("Tool") then + tool.Parent = workspace + wait() + end + + restoreFlag(flag) + end + + wait() + end + end) + + local function onTouched(hit) + local char = hit.Parent + if char then + local player = Players:GetPlayerFromCharacter(char) + local humanoid = char:FindFirstChildOfClass("Humanoid") + + if player and humanoid then + if player.Neutral then + return + end + + if player.TeamColor == teamColor.Value then + if owner.Part1 ~= flag then + restoreFlag(flag) + end + else + mountFlagAsTool(flag, humanoid) + end + end + end + end + + flag.Touched:Connect(onTouched) +end + +for _,flag in pairs(CollectionService:GetTagged(FlagInstance)) do + onFlagAdded(flag) +end + +local flagAdded = CollectionService:GetInstanceAddedSignal(FlagInstance) +flagAdded:Connect(onFlagAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +-- Flag Stands +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +local function onFlagStandAdded(flagStand) + if not flagStand:IsA("BasePart") then + return + end + + local debounce = false + local teamColor = flagStand:FindFirstChild("TeamColor") + local flagCaptured = flagStand:FindFirstChild("FlagCaptured") + + if not teamColor then + teamColor = Instance.new("BrickColorValue") + teamColor.Value = flagStand.BrickColor + teamColor.Name = "TeamColor" + teamColor.Parent = flagStand + end + + if not flagCaptured then + flagCaptured = Instance.new("BindableEvent") + flagCaptured.Name = "FlagCaptured" + flagCaptured.Parent = flagStand + end + + local function onTouched(hit) + if debounce then + return + end + + local char = hit.Parent + if char then + local player = Players:GetPlayerFromCharacter(char) + if player then + if player.Neutral then + return + end + + if player.TeamColor ~= teamColor.Value then + return + end + + local tool = char:FindFirstChildOfClass("Tool") + local handle = tool and tool:FindFirstChild("Handle") + + if handle and CollectionService:HasTag(handle, FlagInstance) then + debounce = true + print("flag captured!") + + flagCaptured:Fire(player) + restoreFlag(handle) + + tool:Destroy() + + wait(1) + debounce = false + end + end + end + end + + flagStand.Touched:Connect(onTouched) +end + +local function onFlagStandRemoved(flagStand) + local teamColor = flagStand:FindFirstChild("TeamColor") + local flagCaptured = flagStand:FindFirstChild("FlagCaptured") + + if teamColor then + teamColor:Destroy() + end + + if flagCaptured then + flagCaptured:Destroy() + end +end + +for _,flagStand in pairs(CollectionService:GetTagged(FlagStandInstance)) do + onFlagStandAdded(flagStand) +end + +local flagStandAdded = CollectionService:GetInstanceAddedSignal(FlagStandInstance) +flagStandAdded:Connect(onFlagStandAdded) + +local flagStandRemoved = CollectionService:GetInstanceRemovedSignal(FlagStandInstance) +flagStandRemoved:Connect(onFlagStandRemoved) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + + + + + Characters + local CollectionService = game:GetService("CollectionService") +local Players = game:GetService("Players") +local InsertService = game:GetService("InsertService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local ServerStorage = game:GetService("ServerStorage") + +local hats = ServerStorage:WaitForChild("ServerHatCache") +local requestCharacter = ReplicatedStorage:WaitForChild("RequestCharacter") +local assetUtil = require(ReplicatedStorage:WaitForChild("AssetUtil")) +local itemData = ReplicatedStorage:WaitForChild("ItemData") +local hatData = require(itemData:WaitForChild("Hat")) + +local playerDataGet = { Success = false } +pcall(function () + playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) +end) + +if not playerDataGet.Success then + warn("Failed to get PlayerData. Avatars will not be loaded.") +end + +local playerDataStore = playerDataGet.DataStore + +local limbs = {"Head", "Torso", "LeftArm", "RightArm", "LeftLeg", "RightLeg"} + +local function preBufferHat(hatId) + local hat = hats:FindFirstChild(hatId) + + if not hat then + local success, import = assetUtil:SafeCall(InsertService, "LoadAsset", tonumber(hatId)) + + if success then + hat = import:FindFirstChildWhichIsA("Accoutrement") + if hat then + hat.Name = hatId + hat.Parent = hats + end + end + end + + return hat +end + +local function safeDestroy(obj) + spawn(function () + obj:Destroy() + end) +end + +local function onCharacterAdded(char) + local player = Players:GetPlayerFromCharacter(char) + + local bodyColors = script.BodyColors:Clone() + CollectionService:AddTag(bodyColors, "RespectCharacterAsset") + + local graphic = script.ShirtGraphic:Clone() + + local shirt = char:FindFirstChildWhichIsA("Shirt") + if not shirt then + shirt = script.Shirt:Clone() + end + + local pants = char:FindFirstChildWhichIsA("Pants") + if not pants then + pants = script.Pants:Clone() + end + + local faceId = 1104210678 + local tshirtId = 131792587 + + local humanoid = char:WaitForChild("Humanoid") + CollectionService:AddTag(humanoid, "Animator") + + local function onDied() + if char:FindFirstChild("HumanoidRootPart") then + char.HumanoidRootPart:Destroy() + end + + wait(5) + + local player = game.Players:GetPlayerFromCharacter(char) + if player then + player:LoadCharacter() + end + end + + local function onDescendantAdded(desc) + if desc:IsA("CharacterMesh") and not desc.Name:sub(1, 3) == "CL_" then + safeDestroy(desc) + elseif desc:IsA("Accoutrement") then + -- Safe way to deter non-game accessories, since I name them by their AssetId + if not tonumber(desc.Name) then + safeDestroy(desc) + end + elseif desc:IsA("SpecialMesh") and desc.Parent.Name == "Head" then + if desc.Name ~= "HeadMesh" then + wait() + + local override = Instance.new("SpecialMesh") + override.Name = "HeadMesh" + override.Scale = Vector3.new(1.25, 1.25, 1.25) + override.Parent = desc.Parent + + safeDestroy(desc) + end + elseif desc:IsA("BodyColors") and desc ~= bodyColors and not CollectionService:HasTag(bodyColors, "RespectCharacterAsset") then + safeDestroy(desc) + bodyColors.Parent = nil + wait() + bodyColors.Parent = char + end + end + + for _,v in pairs(char:GetDescendants()) do + onDescendantAdded(v) + end + + char.DescendantAdded:Connect(onDescendantAdded) + humanoid.Died:Connect(onDied) + + if player.UserId > 0 and playerDataStore then + local playerData = playerDataStore:GetSaveData(player) + local colorData = playerData:Get("BodyColors") + if colorData then + for _,limb in pairs(limbs) do + local num = colorData[limb] + if num then + bodyColors[limb.."Color"] = BrickColor.new(num) + end + end + end + + local loadout = playerData:Get("Loadout") + if loadout then + local shirtId = loadout.Shirt + if shirtId then + shirt.ShirtTemplate = "rbxassetid://" .. shirtId + end + local pantsId = loadout.Pants + if pantsId then + pants.PantsTemplate = "rbxassetid://" .. pantsId + end + + faceId = loadout.Face or faceId + spawn(function () + local hatId = loadout.Hat or 0 + if hatId > 0 then + local hatSrc = preBufferHat(hatId) + local hat = hatSrc:Clone() + hat.Parent = char + end + end) + end + + tshirtId = playerData:Get("TShirt") or tshirtId + end + + if tshirtId > 0 then + local success,img = assetUtil:RequestImage(tshirtId) + if success and img then + graphic.Graphic = img + graphic.Parent = char + end + end + + bodyColors.Parent = char + shirt.Parent = char + pants.Parent = char + + local head = char:WaitForChild("Head") + local face = head:WaitForChild("face") + face.Texture = "rbxhttp://Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=420&ht=420&aid=" .. faceId +end + +local function onRequestCharacter(player) + if not player.Character then + player:LoadCharacter() + end +end + +local function onPlayerAdded(player) + player.CanLoadCharacterAppearance = false + player.CharacterAdded:connect(onCharacterAdded) + + if player.Character then + onCharacterAdded(player.Character) + end + + if game.JobId == "" then + player:LoadCharacter() + end +end + +for _,v in pairs(Players:GetPlayers()) do + onPlayerAdded(v) +end + +Players.PlayerAdded:connect(onPlayerAdded) +requestCharacter.OnServerEvent:Connect(onRequestCharacter) + + + + + Chat + local Players = game:GetService("Players") +local TextService = game:GetService("TextService") +local Chat = game:GetService("Chat") +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") +local mSafeChatTree = ReplicatedStorage:WaitForChild("SafeChatTree") +local safeChatTree = require(mSafeChatTree) + +local filterCache = {} +local maxChatLength = 128 + +local function onServerEvent(player, message) + assert(typeof(message) == "string", "bad input passed") + assert(#message <= maxChatLength, "Chat message was too long!") + + if message:sub(1,3) == "/sc" then + local tree = safeChatTree + + for t in message:gmatch("%d+") do + local i = tonumber(t) + 1 + tree = tree.Branches[i] + + if not tree then + break + end + end + + message = tree and tree.Label or " " + end + + local asciiMessage = "" + + for p, c in utf8.codes(message) do + if c > 0x1F600 then + asciiMessage = asciiMessage .. "??" + else + asciiMessage = asciiMessage .. utf8.char(c) + end + end + + message = asciiMessage + + local userId = player.UserId + if not filterCache[userId] then + filterCache[userId] = {} + end + + local filterResult = filterCache[userId][message] + + if not filterResult then + filterResult = TextService:FilterStringAsync(message,userId) + filterCache[userId][message] = filterResult + end + + for _,receiver in pairs(Players:GetPlayers()) do + spawn(function () + pcall(function () + local filtered = filterResult:GetChatForUserAsync(receiver.UserId) + chatRemote:FireClient(receiver, player, filtered, filtered ~= message) + end) + end) + end +end + +chatRemote.OnServerEvent:Connect(onServerEvent) + + + + + Cylinders + + + + + CylinderSurface + true + null + false + true + + true + + 100 + 100 + + false + true + 1 + 0 + 50 + true + null + 0 + + 0 + 0 + 0 + + + + Frame + false + + 0.5 + 0.5 + + true + + true + + 0.32549020648002625 + 0.32549020648002625 + 0.32549020648002625 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0 + 20 + 0.699999988079071 + 0 + + 0 + 0 + + true + 1 + + + + + Frame + false + + 0.5 + 0.5 + + true + + true + + 0.32549020648002625 + 0.32549020648002625 + 0.32549020648002625 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.699999988079071 + 0 + 0 + 20 + + 0 + 0 + + true + 1 + + + + + + + Explosions + local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") +local ServerStorage = game:GetService("ServerStorage") + +local FORCE_GRANULARITY = 2 +local allowTeamDamage = false + +local teamDamage = ServerStorage:FindFirstChild("TeamDamage") +if teamDamage then + allowTeamDamage = teamDamage.Value +end + +local function processExplosion(explosion) + local BLAST_RADIUS = explosion.BlastRadius + local BLAST_PRESSURE = explosion.BlastPressure + + if explosion:FindFirstChild("BLAST_PRESSURE") then + BLAST_PRESSURE = explosion.BLAST_PRESSURE.Value + end + + if BLAST_PRESSURE > 0 then + local damagedPlayerSet = {} + local blastCenter = explosion.Position + + local function onExplosionHit(p, dist) + if explosion:FindFirstChild("Owner") then + local player = explosion.Owner.Value + if player then + local char = player.Character + if char and p:IsDescendantOf(char) then + return + end + end + end + + local isInCharacter = false + + if p.Size.Magnitude / 2 < 20 then + --world->ticklePrimitive(p, true); + + local doBreakjoints = true + local hitCharacter = p:FindFirstAncestorWhichIsA("Model") + local hitHumanoid = hitCharacter:FindFirstChild("Humanoid") + + if hitCharacter and hitHumanoid then + -- flag as character + isInCharacter = true + + -- don't breakjoints characters + doBreakjoints = false + + -- work out what damage to do + local hitPlayer = game.Players:GetPlayerFromCharacter(hitCharacter) + local creatorTag = explosion:FindFirstChild("creator") + local myPlayer + + if creatorTag then + myPlayer = creatorTag.Value + end + + if hitPlayer and not damagedPlayerSet[hitPlayer] then + local doDamage = true + + if not allowTeamDamage then + if myPlayer and hitPlayer ~= myPlayer then + if hitPlayer.Team and myPlayer.Team and hitPlayer.Team == myPlayer.Team then + doDamage = false + end + end + end + + if doDamage then + -- flag as damaged + damagedPlayerSet[hitPlayer] = true + + -- assume the torso is a massless frictionless unit ball in a perfect vaccum + dist = math.min(math.max(dist - 0.8, 0), 1) + + -- damage to do + local frac = (dist / BLAST_RADIUS) + + -- do damage. See how much damage to do + if myPlayer == hitPlayer then + hitHumanoid:TakeDamage((BLAST_RADIUS * 20) - (frac * 38)) + hitHumanoid:ChangeState("Ragdoll") + else + hitHumanoid:TakeDamage(100) + end + end + end + end + + -- breakjoints stuff + if doBreakjoints then + if not hitHumanoid and p:CanSetNetworkOwnership() then + p:SetNetworkOwner(nil) + end + + for _,joint in pairs(p:GetJoints()) do + if not CollectionService:HasTag(joint, "GorillaGlue") then + joint:Destroy() + end + end + end + + --Vector3 delta = (p->getCoordinateFrame().translation - position); + local delta = (p.Position - blastCenter) + + --Vector3 normal = + -- (delta == Vector3::zero()) + -- ? Vector3::unitY() + -- : delta.direction(); + local normal = (delta == Vector3.new(0, 0, 0)) + and Vector3.new(0, 1, 0) + or delta.unit + + --float radius = p->getRadius(); + local radius = p.Size.magnitude / 2 + + --float surfaceArea = radius * radius; + local surfaceArea = radius * radius + + --Vector3 impulse = normal * blastPressure * surfaceArea * (1.0f / 4560.0f); // normalizing factor + local impulse = normal * BLAST_PRESSURE * surfaceArea * (1.0 / 4560.0) + + -- How much force to apply (for characters, ramp it down towards the edge) + local frac; + + if isInCharacter then + frac = 1 - math.max(0, math.min(1, (dist - 2) / BLAST_RADIUS)) + else + frac = 1 + end + + --p->getBody()->accumulateLinearImpulse(impulse, p->getCoordinateFrame().translation); + local currentVelocity = p.Velocity + local deltaVelocity = impulse / p:GetMass() -- m * del-v = F * del-t = Impulse + local forceNeeded = workspace.Gravity * p:GetMass() -- F = ma + + local bodyV = Instance.new('BodyVelocity') + bodyV.Velocity = currentVelocity + deltaVelocity + bodyV.MaxForce = Vector3.new(forceNeeded, forceNeeded, forceNeeded) * 10 * frac + bodyV.Parent = p + + Debris:AddItem(bodyV, 0.2 / FORCE_GRANULARITY) + + --p->getBody()->accumulateRotationalImpulse(impulse * 0.5 * radius); // a somewhat arbitrary, but nice torque + local rotImpulse = impulse * 0.5 * radius + local currentRotVelocity = p.RotVelocity + + local momentOfInertia = (2 * p:GetMass() * radius * radius / 5) -- moment of inertia = 2/5*m*r^2 (assuming roughly spherical) + local deltaRotVelocity = rotImpulse / momentOfInertia + local torqueNeeded = 20 * momentOfInertia -- torque = r x F, want about alpha = 20 rad/s^2, alpha * P = torque + + local rot = Instance.new('BodyAngularVelocity') + rot.MaxTorque = Vector3.new(torqueNeeded, torqueNeeded, torqueNeeded) * 10 * frac + rot.AngularVelocity = currentRotVelocity + deltaRotVelocity + rot.Parent = p + + Debris:AddItem(rot, 0.2 / FORCE_GRANULARITY) + end + end + + explosion.Hit:Connect(onExplosionHit) + end +end + +local function onDescendantAdded(desc) + if desc:IsA("Explosion") then + local pressure = desc.BlastPressure + + if pressure > 0 then + local blastPressure = Instance.new("NumberValue") + blastPressure.Name = "BLAST_PRESSURE" + blastPressure.Value = pressure + blastPressure.Parent = desc + + desc.BlastPressure = 0 + end + + processExplosion(desc) + end +end + +workspace.DescendantAdded:Connect(onDescendantAdded) + + + + + ForceFields + local ffAdorns = Instance.new("Folder") +ffAdorns.Name = "_ForceFieldAdorns" +ffAdorns.Parent = workspace + +local hide = false +if game.ServerStorage:FindFirstChild("HideForceFields") then + hide = true +end + +local ignoreNames = +{ + HumanoidRootPart = true; + DebugAdorn = true; + NoForceField = true; +} + +local function onDescendantAdded(desc) + if desc:IsA("ForceField") then + desc.Visible = false + if hide then return end + + local adorns = {} + local char = desc.Parent + + local function registerAdorn(child) + if child:IsA("BasePart") and not ignoreNames[child.Name] then + local adorn = Instance.new("SelectionBox") + adorn.Transparency = 1 + adorn.Adornee = child + adorn.Parent = ffAdorns + table.insert(adorns,adorn) + end + end + + for _,part in pairs(char:GetDescendants()) do + registerAdorn(part) + end + + local regSignal = char.DescendantAdded:Connect(registerAdorn) + + + while desc:IsDescendantOf(workspace) do + desc.AncestryChanged:Wait() + end + + for _,adorn in pairs(adorns) do + adorn:Destroy() + end + + adorns = nil + regSignal:Disconnect() + + end +end + +for _,v in pairs(workspace:GetDescendants()) do + onDescendantAdded(v) +end + +workspace.DescendantAdded:Connect(onDescendantAdded) + + + + + HatGranter + local ReplicatedStorage = game:GetService("ReplicatedStorage") +local itemData = ReplicatedStorage:WaitForChild("ItemData") +local hatData = require(itemData:WaitForChild("Hat")) + +local ServerStorage = game:GetService("ServerStorage") +local grantHatToUser = ServerStorage:WaitForChild("GrantHatToUser") + +local authTable = +{ + ["1073469644"] = { ["96"] = true }; + + ["1081616136"] = { ["97"] = true, + ["98"] = true }; + + ["2421080323"] = { ["100"] = true }; + + ["2471146032"] = { ["101"] = true, + ["102"] = true }; +} + +local playerDataGet = { Success = false } + +pcall(function () + playerDataGet = require(ServerStorage:WaitForChild("PlayerDataStore")) +end) + +if not playerDataGet.Success then + warn("Failed to load PlayerData. HatGranter will not work.") +end + +local playerData = playerDataGet.DataStore + +local function onGrantHat(player,hatId) + local userId = player.UserId + + if userId > 0 then + local auth = authTable[tostring(game.PlaceId)] + + if auth then + local canGiveHat = auth[tostring(hatId)] + + if canGiveHat and playerData then + local hatInfo = hatData[hatId] + local hatAsset = hatInfo.AssetId + + local myData = playerData:GetSaveData(player) + local items = myData:Get("Items") + local loadout = myData:Get("Loadout") + + local id = tostring(hatAsset) + + if not items.Hat[id] then + items.Hat[id] = true + myData:Set("Items", items) + end + + loadout.Hat = hatAsset + myData:Set("Loadout", loadout) + end + end + end +end + +grantHatToUser.Event:Connect(onGrantHat) + + + + + Heads + local function processObject(obj) + if obj:IsA("SpecialMesh") and obj.MeshType == Enum.MeshType.Head then + local head = obj.Parent + + local col = math.min(head.Size.X,head.Size.Z) + local thickness = head.Size.Y/col + + if math.abs(thickness-1) <= 0.01 then + local face = head:FindFirstChild("face") + if face and face.Texture:lower() == "rbxasset://textures/face.png" then + face.Texture = "rbxassetid://1104210678" + end + obj.Name = "MeshHead" + obj.MeshId = "rbxassetid://1104623876" + obj.Scale = obj.Scale * head.Size.Y + for _,surface in pairs(Enum.NormalId:GetEnumItems()) do + head[surface.Name .. "Surface"] = 0 + end + end + end +end + +for _,desc in pairs(workspace:GetDescendants()) do + processObject(desc) +end + +workspace.DescendantAdded:Connect(processObject) + + + + + InputGateway + local self = script.Parent +local remote = self:WaitForChild("Gateway") + +local tool = self.Parent +tool.ManualActivationOnly = true + +local keyEvent = Instance.new("BindableEvent") +keyEvent.Name = "KeyEvent" +keyEvent.Parent = tool + +local function onGatewayReceive(sendingPlayer, request, ...) + local char = tool.Parent + + if char and char:IsA("Model") then + local humanoid = char:FindFirstChild("Humanoid") + + if humanoid then + local player = game.Players:GetPlayerFromCharacter(char) + assert(sendingPlayer == player) + + if request == "SetActive" then + local down, target = ... + assert(typeof(target) == "CFrame","Expected CFrame") + + humanoid.TargetPoint = target.p + + if humanoid.Health > 0 and tool:IsDescendantOf(char) then + if down then + tool:Activate() + else + tool:Deactivate() + end + end + elseif request == "SetTarget" then + local target = ... + assert(typeof(target) == "CFrame","Expected CFrame") + humanoid.TargetPoint = target.p + elseif request == "KeyEvent" then + local key, down = ... + assert(typeof(key) == "string","bad key cast") + assert(typeof(down) == "boolean","bad down state cast") + keyEvent:Fire(key, down) + end + end + end +end + +remote.OnServerEvent:Connect(onGatewayReceive) + + + + + Leaderboard + 0) then CTF_mode = true end + +for _,v in pairs(game.Players:GetPlayers()) do + onPlayerEntered(v) +end + +game.Players.ChildAdded:connect(onPlayerEntered) + + +]]> + + + + + LoadTools + local ServerStorage = game:GetService("ServerStorage") +local StarterPack = game:GetService("StarterPack") +local Players = game:GetService("Players") + +local standardTools = ServerStorage:WaitForChild("StandardTools") +local loadTools = ServerStorage:FindFirstChild("LoadTools") + +if loadTools then + for toolName in loadTools.Value:gmatch("[^;]+") do + local tool = standardTools:WaitForChild(toolName) + tool:Clone().Parent = StarterPack + + for _,v in pairs(Players:GetPlayers()) do + if v:FindFirstChild("Backpack") and not v:FindFirstChild(tool.Name) then + tool:Clone().Parent = v.Backpack + end + end + end +end + + + + + Part + + + + + + Regeneration + local CollectionService = game:GetService("CollectionService") +local ServerStorage = game:GetService("ServerStorage") + +local regen = ServerStorage:FindFirstChild("Regeneration") + +if regen then + local REGEN_TIME = 800 + local REGEN_DELAY = 4 + + if regen:FindFirstChild("RegenTime") then + REGEN_TIME = regen.RegenTime.Value + end + + if regen:FindFirstChild("RegenDelay") then + REGEN_DELAY = regen.RegenDelay.Value + end + + local ready = Instance.new("BoolValue") + ready.Name = "Ready" + ready.Parent = regen + + local bevelCache = ServerStorage:WaitForChild("BevelCache") + local bevelsReady = bevelCache:WaitForChild("BevelsReady") + + local function isLodPart(part) + return part and CollectionService:HasTag(part, "PartLOD") + end + + local function setupModelRegen(model, title) + local title = title or model.Name + + local parent = model.Parent + local backup = model:Clone() + + local message, text + + if typeof(title) == "string" then + message = Instance.new("Message") + text = "Regenerating " .. title .. "..." + end + + spawn(function () + while not bevelsReady.Value do + bevelsReady.Changed:Wait() + end + + local requestSolve = bevelCache:FindFirstChild("RequestSolve") + if requestSolve then + requestSolve:Invoke(backup) + end + + while wait(REGEN_TIME * (1 - (math.random() * .8))) do + local cooldown = 0 + + if message then + message.Text = text + message.Parent = workspace + end + + model:Destroy() + wait(REGEN_DELAY) + + model = backup:Clone() + model.Parent = parent + + for _,inst in pairs(model:GetDescendants()) do + if inst:IsA("BasePart") then + workspace:JoinToOutsiders({inst}, Enum.JointCreationMode.All) + end + end + + for _,joint in pairs(model:GetDescendants()) do + if joint:IsA("JointInstance") and joint.Name:sub(-12) == "Strong Joint" then + if isLodPart(joint.Part0) or isLodPart(joint.Part1) then + joint:Destroy() + end + end + end + + if message then + message.Parent = nil + end + end + end) + end + + for _,v in pairs(regen:GetChildren()) do + if v:IsA("ObjectValue") then + if v.Name == "" then + setupModelRegen(v.Value, true) + else + setupModelRegen(v.Value, v.Name) + end + end + end + + ready.Value = true +end + + + + + SessionTracker + local MessagingService = game:GetService("MessagingService") +local Players = game:GetService("Players") + +local jobId = game.JobId +local placeId = game.PlaceId + +if jobId == "" then + return +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local closed = false + +local function publishUpdate() + local playerCount = #Players:GetPlayers() + + local serverInfo = + { + JobId = jobId; + PlaceId = placeId; + Players = playerCount; + } + + if closed then + serverInfo.Closed = true; + end + + pcall(function () + MessagingService:PublishAsync("ServerData", serverInfo) + end) +end + +local function onGameClosing() + closed = true + publishUpdate() +end + +game:BindToClose(onGameClosing) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +while #Players:GetPlayers() < 1 do + wait(1) +end + +while not closed do + publishUpdate() + wait(5) +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + Time + + + + + + + StarterCharacterScripts + + + + Animate + local Players = game:GetService("Players") + +local character = script.Parent +local player = Players:GetPlayerFromCharacter(character) + +local climbing = Instance.new("BoolValue") +climbing.Name = "Climbing" +climbing.Parent = character + +local setValue = Instance.new("RemoteEvent") +setValue.Name = "SetValue" +setValue.Parent = climbing + +local function onSetValue(requester, value) + if requester ~= player then + return + end + + if typeof(value) ~= "boolean" then + return + end + + climbing.Value = value +end + +setValue.OnServerEvent:Connect(onSetValue) + + + + + Bounciness + local Debris = game:GetService("Debris") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local head = char:WaitForChild("Head") + +local function onStateChanged(old,new) + if new.Name == "Landed" then + local velocity = humanoid.Torso.Velocity + local power = (-velocity.Y * workspace.Gravity) / 2 + + local force = Instance.new("BodyForce") + force.Name = "Bounce" + force.Force = Vector3.new(0,power,0) + force.Parent = head + + Debris:AddItem(force, 1/30) + end +end + +humanoid.StateChanged:connect(onStateChanged) + + + + + DropHats + local Players = game:GetService("Players") + +local char = script.Parent +local torso = char:WaitForChild("HumanoidRootPart") + +local humanoid = char:WaitForChild("Humanoid") +local hatPickup = script:WaitForChild("HatPickup") + +local dropHat = Instance.new("RemoteEvent") +dropHat.Name = "DropHat" +dropHat.Parent = script + +local function onDropHat(player) + local myPlayer = Players:GetPlayerFromCharacter(char) + assert(player == myPlayer, "Cannot drop hats unless it is your character.") + + local dropPos = torso.CFrame * CFrame.new(0, 5.4, -8) + + for _,hat in pairs(humanoid:GetAccessories()) do + local handle = hat:FindFirstChild("Handle") + + if handle then + local newHandle = handle:Clone() + + for _,joint in pairs(newHandle:GetJoints()) do + joint:Destroy() + end + + newHandle.CFrame = dropPos + newHandle.Anchored = true + newHandle.CanCollide = false + newHandle.Parent = workspace + + handle:Destroy() + hat.Parent = newHandle + + wait(.1) + + newHandle.Anchored = false + newHandle.CanCollide = true + newHandle:SetNetworkOwner(nil) + + local pickup = hatPickup:Clone() + pickup.Parent = newHandle + pickup.Disabled = false + end + end +end + +dropHat.OnServerEvent:Connect(onDropHat) + + + + HatPickup + + + + + + LocalDropHat + local UserInputService = game:GetService("UserInputService") + +local server = script.Parent +local dropHat = server:WaitForChild("DropHat") + +local function onInputBegan(input, gameProcessed) + if not gameProcessed then + local keyCode = input.KeyCode.Name + if keyCode == "Equals" or keyCode == "DPadDown" then + dropHat:FireServer() + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + + + + + + EdgeWalking + local RunService = game:GetService("RunService") + +local char = script.Parent +local rootPart = char:WaitForChild("HumanoidRootPart") + +local platform = Instance.new("Part") +platform.Name = "NoForceField" +platform.TopSurface = 0 +platform.BottomSurface = 0 +platform.BrickColor = BrickColor.new("Bright orange") +platform.Size = Vector3.new(5, 1, 2) +platform.Anchored = true +platform.Transparency = 1 + +local down = Vector3.new(0, -100, 0) +local platformOffset = Vector3.new(0, -.5, 0) + +while wait() do + local start = rootPart.CFrame + local startPos = start.p + local startRay = Ray.new(startPos, start.lookVector * 5) + + local hit, pos, norm = workspace:FindPartOnRay(startRay, char) + local floorCheckRay + + local pass = false + + if hit and hit.CanCollide and hit:IsGrounded() then + if hit:IsA("UnionOperation") or (not hit:IsA("Part") or hit.Shape.Name == "Block") then + local floorCheckRay = Ray.new(pos - (norm / 5), down) + local floor, floorPos = workspace:FindPartOnRayWithIgnoreList(floorCheckRay, {char, hit}) + + if floor and floor.CanCollide and startPos.Y - 2 > floorPos.Y then + floorPos = floorPos + platformOffset + platform.Parent = char + platform.CFrame = CFrame.new(Vector3.new(pos.X + norm.X, floorPos.Y, pos.Z + norm.Z),floorPos) + pass = true + end + end + end + + if not pass then + platform.Parent = nil + end +end + + + + + FloorDrag + local RunService = game:GetService("RunService") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local rootPart = char:WaitForChild("HumanoidRootPart") +local climbForce = rootPart:WaitForChild("ClimbForce") +local rayDown = Vector3.new(0, -5000, 0) + +local function moveTowards(value, goal, rate) + if value < goal then + return math.min(goal, value + rate) + elseif value > goal then + return math.max(goal, value - rate) + else + return goal + end +end + +local lastFloorLevel = 0 + +local function getFloorLevel() + local origin = rootPart.Position + local ray = Ray.new(origin, rayDown) + local hit, pos = workspace:FindPartOnRay(ray, char) + return pos.Y, math.clamp(math.abs(pos.Y - origin.Y), -1, 1) +end + +local lastLevel = getFloorLevel() +local updateCon + +local function update() + if humanoid.Health == 0 then + updateCon:Disconnect() + return + end + + local level, dist = getFloorLevel() + + if humanoid.SeatPart then + humanoid.HipHeight = 0 + lastLevel = level + return + end + + local yVel = rootPart.Velocity.Y + + if math.abs(yVel) > 8 then + local goal = math.sign(yVel) + humanoid.HipHeight = moveTowards(humanoid.HipHeight, goal, 0.1) + elseif lastLevel ~= level then + humanoid.HipHeight = math.sign(lastLevel - level) * math.clamp(dist - 3, 0, 1) + lastLevel = level + else + humanoid.HipHeight = humanoid.HipHeight * 0.925 + end +end + +updateCon = RunService.RenderStepped:Connect(update) + + + + + GoofyBalance + local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") + +local function onStateChanged(old,new) + if new == Enum.HumanoidStateType.RunningNoPhysics then + humanoid:ChangeState(Enum.HumanoidStateType.Running) + elseif new == Enum.HumanoidStateType.FallingDown then + humanoid:ChangeState("Ragdoll") + + while wait(0.5) do + if humanoid.RootPart then + local velocity = humanoid.RootPart.Velocity + + if velocity.Magnitude < 0.1 then + wait(2) + humanoid:ChangeState("GettingUp") + break + end + else + break + end + end + end +end + +humanoid.StateChanged:Connect(onStateChanged) + + + + + GoofyMotion + local RunService = game:GetService("RunService") +local GameSettings = UserSettings():GetService("UserGameSettings") + +local char = script.Parent +local humanoid = char:WaitForChild("Humanoid") +local climbing = char:WaitForChild("Climbing") +local rootPart = humanoid.RootPart + +local c = workspace.CurrentCamera +local blankV3 = Vector3.new() +local xz = Vector3.new(1,0,1) +local bg = rootPart:FindFirstChild("FirstPersonGyro") + +local runState = Enum.HumanoidStateType.Running + +if not bg then + bg = Instance.new("BodyGyro") + bg.Name = "FirstPersonGyro" + bg.MaxTorque = Vector3.new(0,10e6,0) + bg.D = 100 +end + +local function toRotation(dir) + return CFrame.new(blankV3,dir) +end + +local velocityThreshold = 200 +spawn(function () + local threshold = char:WaitForChild("VelocityThreshold",5) + if threshold then + velocityThreshold = threshold.Value + end +end) + +local function update() + local rotationType = GameSettings.RotationType + local seatPart = humanoid.SeatPart + + if rotationType.Name == "CameraRelative" and not seatPart then + local dir = c.CFrame.lookVector * xz + bg.CFrame = toRotation(dir) + bg.Parent = rootPart + humanoid.AutoRotate = false + else + local state = humanoid:GetState() + local isRunning = (state == runState) + local isClimbing = climbing.Value + humanoid.AutoRotate = (isRunning or isClimbing) + bg.Parent = nil + end + + if rootPart.Velocity.Magnitude > velocityThreshold and not seatPart then + humanoid:ChangeState("FallingDown") + end +end + +humanoid.AutoRotate = false +humanoid:SetStateEnabled("Climbing",false) +RunService.RenderStepped:connect(update) +c.FieldOfView = 65 + + + + + InputGateway + local ServerStorage = game:GetService("ServerStorage") +local inputGateway = ServerStorage:WaitForChild("InputGateway") +local char = script.Parent + +local function onChildAdded(child) + if child:IsA("Tool") and not child:FindFirstChild("InputGateway") then + wait(.1) + local gateway = inputGateway:Clone() + gateway.Parent = child + end +end + +local tool = char:FindFirstChildWhichIsA("Tool") +if tool then + onChildAdded(tool) +end + +char.ChildAdded:Connect(onChildAdded) + + + + + JumpLimiter + + + + + + RetroClimbing + -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Setup +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local char = script.Parent + +local humanoid = char:WaitForChild("Humanoid") +humanoid:SetStateEnabled("Climbing", false) + +local rootPart = humanoid.RootPart +local bv = rootPart:FindFirstChild("ClimbForce") + +if not bv then + bv = Instance.new("BodyVelocity") + bv.Name = "ClimbForce" + bv.Parent = humanoid.RootPart +end + +bv.MaxForce = Vector3.new() + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Climbing State +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local climbing = char:WaitForChild("Climbing") +local setValue = climbing:WaitForChild("SetValue") + +local function onClimbing(value) + setValue:FireServer(value) +end + +climbing.Changed:Connect(onClimbing) + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Debug Visuals +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local Debris = game:GetService("Debris") +local isDevTest = false + +local DEBUG_COLOR_RED = Color3.new(1, 0, 0) +local DEBUG_COLOR_YLW = Color3.new(1, 1, 0) +local DEBUG_COLOR_GRN = Color3.new(0, 1, 0) + +local debugBox = Instance.new("BoxHandleAdornment") +debugBox.Adornee = workspace.Terrain +debugBox.Color3 = DEBUG_COLOR_RED +debugBox.Visible = false +debugBox.Parent = script + +local debugCylinder = Instance.new("CylinderHandleAdornment") +debugCylinder.Color = BrickColor.new("Bright violet") +debugCylinder.Adornee = workspace.Terrain +debugCylinder.Height = 0.2 +debugCylinder.Radius = 1.0 +debugCylinder.Visible = false +debugCylinder.Parent = script + +local debugSBox = Instance.new("SelectionBox") +debugSBox.Color3 = DEBUG_COLOR_RED +debugSBox.Parent = script + +local function drawRayIfDebugging(rayStart, look, length, color) + if isDevTest then + local line = Instance.new("LineHandleAdornment") + line.CFrame = CFrame.new(rayStart, rayStart + (look.Unit * length)) + line.Adornee = workspace.Terrain + line.Length = length + line.Color3 = color + line.Thickness = 4 + line.Parent = script + + local cone = Instance.new("ConeHandleAdornment") + cone.CFrame = CFrame.new(rayStart + (look.Unit * (length - 0.32)), rayStart + (look.Unit * length)) + cone.Adornee = workspace.Terrain + cone.Color3 = color + cone.Radius = 1 / 10 + cone.Height = 1 / 3 + cone.Parent = script + + Debris:AddItem(line, .5) + Debris:AddItem(cone, .5) + end +end + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Main Climbing Logic +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local searchDepth = 0.7 +local maxClimbDist = 2.45 +local sampleSpacing = 1 / 7 +local lowLadderSearch = 2.7 +local stepForwardFrames = 0 +local ladderSearchDist = 2.0 + +local running = Enum.HumanoidStateType.Running +local freefall = Enum.HumanoidStateType.Freefall + +local function findPartInLadderZone() + debug.profilebegin("FastClimbCheck") + -- + + local cf = rootPart.CFrame + + local top = -humanoid.HipHeight + local bottom = -lowLadderSearch + top + local radius = 0.5 * ladderSearchDist + + local center = cf.Position + (cf.LookVector * ladderSearchDist * 0.5) + local min = Vector3.new(-radius, bottom, -radius) + local max = Vector3.new(radius, top, radius) + + local extents = Region3.new(center + min, center + max) + local parts = workspace:FindPartsInRegion3(extents, char) + + if isDevTest then + if #parts > 0 then + debugBox.Visible = false + debugSBox.Visible = true + debugSBox.Adornee = parts[1] + else + debugBox.Visible = true + debugSBox.Visible = false + + debugBox.Size = extents.Size + debugBox.CFrame = extents.CFrame + + debugCylinder.Visible = false + end + end + + -- + debug.profileend() + return #parts > 0 +end + +local function findLadder() + if not findPartInLadderZone() then + return false + end + + debug.profilebegin("ExpensiveClimbCheck") + + local torsoCoord = rootPart.CFrame + local torsoLook = torsoCoord.LookVector + + local firstSpace = 0 + local firstStep = 0 + + local lookForSpace = true + local lookForStep = false + + local debugColor = DEBUG_COLOR_YLW + local topRay = math.floor(lowLadderSearch / sampleSpacing) + + for i = 1, topRay do + local distFromBottom = i * sampleSpacing + local originOnTorso = Vector3.new(0, -lowLadderSearch + distFromBottom, 0) + + local casterOrigin = torsoCoord.Position + originOnTorso + local casterDirection = torsoLook * ladderSearchDist + + local ray = Ray.new(casterOrigin, casterDirection) + local hitPrim, hitLoc = workspace:FindPartOnRay(ray, char) + + -- make trusses climbable. + if hitPrim and hitPrim:IsA("TrussPart") then + return true + end + + local mag = (hitLoc - casterOrigin).Magnitude + + if mag < searchDepth then + if lookForSpace then + debugColor = DEBUG_COLOR_GRN + firstSpace = distFromBottom + + lookForSpace = false + lookForStep = true + end + elseif lookForStep then + firstStep = distFromBottom - firstSpace + debugColor = DEBUG_COLOR_RED + lookForStep = false + end + + drawRayIfDebugging(casterOrigin, casterDirection, mag, debugColor) + end + + local found = (firstSpace < maxClimbDist and firstStep > 0 and firstStep < maxClimbDist) + debugCylinder.Visible = isDevTest and found + + if debugCylinder.Visible then + local y = Vector3.FromAxis('Y') + local pos = torsoCoord.Position + Vector3.new(0, 5, 0) + debugCylinder.CFrame = CFrame.new(pos, pos + y) + end + + debug.profileend() + return found +end + +while wait() do + local canClimb = false + + local state = humanoid:GetState() + local speed = humanoid.WalkSpeed + + if state == freefall or state == running then + canClimb = findLadder() + end + + if canClimb then + local climbSpeed = speed * 0.7 + bv.Velocity = Vector3.new(0, climbSpeed, 0) + bv.MaxForce = Vector3.new(climbSpeed * 100, 10e6, climbSpeed * 100) + else + if climbing.Value then + stepForwardFrames = 2 + end + + bv.MaxForce = Vector3.new() + end + + if stepForwardFrames > 0 then + local cf = rootPart.CFrame + humanoid:Move(cf.LookVector) + stepForwardFrames = stepForwardFrames - 1 + end + + climbing.Value = canClimb +end + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + Sound + 0.1) +end + +-- connect up + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.GettingUp:connect(function(state) onState(state, sGettingUp) end) +Humanoid.FreeFalling:connect(function(state) + --if not Climbing.Value then + onState(state, sFreeFalling) + --end +end) + +Humanoid.FallingDown:connect(function(state) onState(state, sFallingDown) end) +]]> + + + + + TeamColors + local CollectionService = game:GetService("CollectionService") +local Players = game:GetService("Players") + +local char = script.Parent +local player = Players:GetPlayerFromCharacter(char) +local teamListener = player:GetPropertyChangedSignal("TeamColor") +local bodyColors = char:WaitForChild("BodyColors") + +local teamColors = Instance.new("BodyColors") +teamColors.Name = "TeamColors" +teamColors.HeadColor = BrickColor.new("Bright yellow") +teamColors.LeftArmColor = BrickColor.Black() +teamColors.LeftLegColor = BrickColor.Black() +teamColors.RightArmColor = BrickColor.Black() +teamColors.RightLegColor = BrickColor.Black() + +CollectionService:AddTag(teamColors, "RespectCharacterAsset") + +local function onTeamChanged() + local team = player.Team + if team then + teamColors.TorsoColor = player.TeamColor + bodyColors.Parent = nil + + if not CollectionService:HasTag(team, "NoAutoColor") then + teamColors.Parent = char + end + else + teamColors.Parent = nil + bodyColors.Parent = char + end +end + +onTeamChanged() +teamListener:Connect(onTeamChanged) + + + + + ToolSoundGlitch + -- This replicates an old sound bug that used to occur with tools back then. + +local CollectionService = game:GetService("CollectionService") +local Debris = game:GetService("Debris") + +local char = script.Parent +local torso = char:WaitForChild("Torso") +local marked = {} + +local function processHandle(handle) + for _,child in pairs(handle:GetChildren()) do + if child:IsA("Sound") then + if not marked[child.SoundId] then + marked[child.SoundId] = true + else + local replica = child:Clone() + replica.Name = "ToolSoundGlitch" + replica.MaxDistance = 0 + replica.Parent = torso + + CollectionService:AddTag(replica, "ToolSoundGlitch") + replica:Play() + + replica.Ended:connect(function () + Debris:AddItem(replica, 1) + end) + end + end + end +end + +local function onChild(child) + if child:IsA("Tool") then + local handle = child:FindFirstChild("Handle") + + if handle then + processHandle(handle) + end + end +end + +char.ChildAdded:connect(onChild) +char.ChildRemoved:connect(onChild) + + + + + + StarterGui + + + + UI + + + + Backpack + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- @CloneTrooper1019, 2015 +-- Backpack +-- Simulates the 2008 backpack from scratch. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Setup + +local ui = script.Parent +local rootFrame = ui:WaitForChild("RootFrame") + +local self = rootFrame:WaitForChild("Backpack") +local slotTemp = script:WaitForChild("SlotTemp") + +local backdrop = self:WaitForChild("Backdrop") +local slotsBin = self:WaitForChild("Slots") + +local player = game.Players.LocalPlayer +local UserInputService = game:GetService("UserInputService") + +local toolIndex = 0 + +local tools = {} +local slots = {} +local tokens = +{ + One = 1; + Two = 2; + Three = 3; + Four = 4; + Five = 5; + Six = 6; + Seven = 7; + Eight = 8; + Nine = 9; + Zero = 10; -- shhh not a hack +} + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Key Hookup + +local eNumPress = Instance.new("BindableEvent") +local numPress = eNumPress.Event + +-- Hack to work around the inputs being overridden while the Plane tool is active. +local function allowGameProcessedBypassHack() + local lastInputType = UserInputService:GetLastInputType() + if lastInputType.Name == "Gamepad1" then + local char = player.Character + if char then + local tool = char:FindFirstChildWhichIsA("Tool") + if tool and not tool.Enabled then + return true + end + end + end + return false +end + +local function onInputBegan(input,gameProcessed) + if not gameProcessed or allowGameProcessedBypassHack() then + local name = input.UserInputType.Name + local keyCode = input.KeyCode.Name + if name == "Keyboard" then + local toIndex = tokens[keyCode] + if toIndex then + eNumPress:Fire(toIndex) + end + elseif name == "Gamepad1" then + if keyCode == "ButtonL1" or keyCode == "ButtonR1" then + local nextIndex = toolIndex + if keyCode == "ButtonL1" then + nextIndex = nextIndex - 1 + elseif keyCode == "ButtonR1" then + nextIndex = nextIndex + 1 + end + print(nextIndex,#tools) + if nextIndex > 0 and nextIndex <= #tools then + eNumPress:Fire(nextIndex) + else + eNumPress:Fire(toolIndex) + end + end + end + end +end + +UserInputService.InputBegan:connect(onInputBegan) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function resortSlots() + for index,tool in ipairs(tools) do + local slot = slots[tool] + slot.Index.Text = index + slot.LayoutOrder = index + slot.Visible = true + end + backdrop.Size = UDim2.new(#tools,0,1,0) +end + +local function createSlot(tool) + if not slots[tool] then + local index = #tools+1 + tools[index] = tool + + local slot = slotTemp:clone() + slot.Name = tool.Name + slot.Parent = slotsBin + + local textHover = slot:WaitForChild("TextHover") + local selectionOutline = slot:WaitForChild("SelectionOutline") + local toolIcon = slot:WaitForChild("ToolIcon") + local indexLbl = slot:WaitForChild("Index") + local toolName = slot:WaitForChild("ToolName") + + local isHovering = false + local isDown = false + + local backpack = player:WaitForChild("Backpack") + local char = player.Character or player.CharacterAdded:Wait() + + local humanoid = char:WaitForChild("Humanoid") + local conReg = {} + + local function killTool() + local currentIndex = tonumber(indexLbl.Text) + table.remove(tools, currentIndex) + + for _,con in pairs(conReg) do + con:disconnect() + end + + slots[tool] = nil + slot:Destroy() + + resortSlots() + end + + local function checkParent() + if tool.Parent == char then + selectionOutline.Visible = true + elseif tool.Parent == backpack then + selectionOutline.Visible = false + else + killTool() + end + end + + local function toggleTool() + if tool.Parent == char then + humanoid:UnequipTools() + else + toolIndex = tonumber(indexLbl.Text) + humanoid:EquipTool(tool) + end + end + + local function renderUpdate() + if tool.TextureId ~= "" then + toolName.Visible = false + toolIcon.Visible = true + toolIcon.Image = tool.TextureId + else + toolIcon.Visible = false + toolName.Visible = true + toolName.Text = tool.Name + end + if tool.TextureId ~= "" then + textHover.Visible = false + if isHovering then + toolIcon.BackgroundTransparency = 0 + if isDown then + toolIcon.BackgroundColor3 = Color3.new(0,0,1) + else + toolIcon.BackgroundColor3 = Color3.new(1,1,0) + end + else + toolIcon.BackgroundTransparency = 1 + end + else + textHover.Visible = true + if isHovering then + textHover.BackgroundTransparency = 0 + if isDown then + textHover.BackgroundColor3 = Color3.new(1,1,0) + else + textHover.BackgroundColor3 = Color3.new(0.706,0.706,0.706) + end + else + textHover.BackgroundTransparency = 1 + end + end + end + + local function onInputBegan(input) + if input.UserInputType.Name == "MouseButton1" then + isDown = true + elseif input.UserInputType.Name == "MouseMovement" or input.UserInputType.Name == "Touch" then + isHovering = true + end + renderUpdate() + end + + local function onInputEnded(input) + if input.UserInputType.Name == "MouseButton1" then + isDown = false + if isHovering then + toggleTool() + end + elseif input.UserInputType.Name == "MouseMovement" then + isHovering = false + elseif input.UserInputType.Name == "Touch" then + isHovering = false + if humanoid.MoveDirection == Vector3.new() then + toggleTool() + end + end + + renderUpdate() + end + + local function onNumDown(num) + local currentIndex = tonumber(indexLbl.Text) + + if num == currentIndex then + toggleTool() + end + end + + local function onToolChanged(property) + if property == "TextureId" or property == "Name" then + renderUpdate() + elseif property == "Parent" then + checkParent() + end + end + + local eventMounts = + { + [numPress] = onNumDown; + [tool.Changed] = onToolChanged; + [slot.InputBegan] = onInputBegan; + [slot.InputEnded] = onInputEnded; + [humanoid.Died] = killTool; + } + + renderUpdate() + checkParent() + + for event, func in pairs(eventMounts) do + local connection = event:Connect(func) + table.insert(conReg, connection) + end + + slots[tool] = slot + resortSlots() + end +end + +local currentChar + +local function onCharacterAdded(char) + if currentChar ~= char then + currentChar = char + + for _,v in pairs(slots) do + v:Destroy() + end + + slots = {} + tools = {} + + local function onChildAdded(child) + if child:IsA("Tool") then + createSlot(child) + end + end + + local backpack = player:WaitForChild("Backpack") + + for _,v in pairs(backpack:GetChildren()) do + onChildAdded(v) + end + + for _,v in pairs(char:GetChildren()) do + onChildAdded(v) + end + + char.ChildAdded:connect(onChildAdded) + backpack.ChildAdded:connect(onChildAdded) + end +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:connect(onCharacterAdded) + +game.StarterGui.ResetPlayerGuiOnSpawn = false + + + + SlotTemp + true + + 0 + 0 + + true + + false + true + + 0.7058823704719543 + 0.7058823704719543 + 0.7058823704719543 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 3 + 0 + 1 + false + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + false + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + false + 2 + 1 + false + 1 + + + + Index + true + + 0 + 1 + + true + + true + + 0.6666666865348816 + 0.6666666865348816 + 0.6666666865348816 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + null + null + null + null + + 0.029999999329447746 + 2 + 0.9700000286102295 + -2 + + null + 0 + false + null + + 0.20000000298023224 + 0 + 0.20000000298023224 + 0 + + 2 + + 1 + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.800000011920929 + 0 + 0 + true + 2 + 1 + true + 3 + + + + UITextSizeConstraint + true + + 20 + 1 + + + + + + + SelectionOutline + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + -1 + 0 + -1 + + null + 0 + false + null + + 1 + 2 + 1 + 2 + + 0 + 0 + + false + 1 + + + + Outline + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0.9700000286102295 + 0 + + null + 0 + false + null + + 1 + 0 + 0.029999999329447746 + 0 + + 0 + 0 + + true + 3 + + + + + Outline + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.9700000286102295 + 0 + 0 + 0 + + null + 0 + false + null + + 0.029999999329447746 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + + + + + Outline + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.029999999329447746 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + + + + + Outline + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.029999999329447746 + 0 + + 0 + 0 + + true + 3 + + + + + + TextHover + false + + 0 + 0 + + true + + true + + 0.7058823704719543 + 0.7058823704719543 + 0.7058823704719543 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + false + 3 + + + + + ToolIcon + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 0.15000000596046448 + 0 + 0.15000000596046448 + 0 + + null + 0 + 0 + false + null + + 0.699999988079071 + 0 + 0.699999988079071 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 4 + + + + + ToolName + true + + 0 + 0.5 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + null + null + null + null + + 0.10000000149011612 + 0 + 0.4749999940395355 + 0 + + null + 0 + false + null + + 2 + 0 + 0.17000000178813934 + 0 + + 0 + + Tool + + 1 + 1 + 1 + + true + 100 + + 0.498039186000824 + 0.498039186000824 + 0.498039186000824 + + 0.5 + 0.20000000298023224 + 0 + true + 0 + 1 + true + 4 + + + + + + + Chat + -------------------------------------------------------------------------------------------- +-- Constants +-------------------------------------------------------------------------------------------- + +local Debris = game:GetService("Debris") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local RunService = game:GetService("RunService") +local TextService = game:GetService("TextService") +local UserInputService = game:GetService("UserInputService") + +local LinkedList = require(script:WaitForChild("LinkedList")) + +local ui = script.Parent +local rootFrame = ui:WaitForChild("RootFrame") + +local chat = rootFrame:WaitForChild("Chat") +local chatBar = chat:WaitForChild("ChatBar") +local chatOutput = chat:WaitForChild("ChatOutput") +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") + +local focusBackdrop = chatBar:WaitForChild("FocusBackdrop") +local mainBackdrop = chat:WaitForChild("MainBackdrop") +local messageTemplate = script:WaitForChild("MessageTemplate") + +local hasCoreGateway, coreGateway = pcall(function () + local getCoreGateway = script:WaitForChild("GetCoreGateway") + return require(getCoreGateway) +end) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Colors +-------------------------------------------------------------------------------------------------------------------------------------- + +local PLAYER_COLORS = +{ + [0] = Color3.fromRGB(173, 35, 35); -- red + [1] = Color3.fromRGB( 42, 75, 215); -- blue + [2] = Color3.fromRGB( 29, 105, 20); -- green + [3] = Color3.fromRGB(129, 38, 192); -- purple + [4] = Color3.fromRGB(255, 146, 51); -- orange + [5] = Color3.fromRGB(255, 238, 51); -- yellow + [6] = Color3.fromRGB(255, 205, 243); -- pink + [7] = Color3.fromRGB(233, 222, 187); -- tan +} + +local function computePlayerColor(player) + if player.Team then + return player.TeamColor.Color + else + local pName = player.Name + local length = #pName + + local oddShift = (1 - (length % 2)) + local value = 0 + + for i = 1,length do + local char = pName:sub(i, i):byte() + local rev = (length - i) + oddShift + + if (rev % 4) >= 2 then + value = value - char + else + value = value + char + end + end + + return PLAYER_COLORS[value % 8] + end +end + +-------------------------------------------------------------------------------------------- +-- Chat Input +-------------------------------------------------------------------------------------------- + +local function beginChatting() + focusBackdrop.Visible = true + + if not chatBar:IsFocused() then + chatBar.TextTransparency = 1 + chatBar:CaptureFocus() + wait() + chatBar.Text = "" + chatBar.TextTransparency = 0 + end +end + +local function onInputBegan(input, processed) + if not processed and input.UserInputType == Enum.UserInputType.Keyboard then + if input.KeyCode == Enum.KeyCode.Slash then + beginChatting() + end + end +end + +local function onChatFocusLost(enterPressed) + local msg = chatBar.Text + + if enterPressed and #msg > 0 then + if #msg > 128 then + msg = msg:sub(1, 125) .. "..." + end + + chatRemote:FireServer(msg) + + if hasCoreGateway then + coreGateway.ChatWindow.MessagePosted:Fire(msg) + end + end + + chatBar.Text = "" + focusBackdrop.Visible = false +end + +UserInputService.InputBegan:Connect(onInputBegan) + +chatBar.Focused:Connect(beginChatting) +chatBar.FocusLost:Connect(onChatFocusLost) + +-------------------------------------------------------------------------------------------- +-- Chat Output +-------------------------------------------------------------------------------------------- + +local messageId = 0 +local blank_v2 = Vector2.new() +local chatQueue = LinkedList.new() + +local function computeTextBounds(label) + local bounds = TextService:GetTextSize(label.Text, label.TextSize, label.Font, blank_v2) + return UDim2.new(0, bounds.X, 0, bounds.Y) +end + +local function getMessageId() + messageId = messageId + 1 + return messageId +end + +local function onReceiveChat(player, message, wasFiltered) + -- Process the message + if message:sub(1, 1) == "%" then + message = "(TEAM) " .. message:sub(2) + end + + if wasFiltered then + message = message:gsub("#[# ]+#", "[ Content Deleted ]") + end + + -- Create the message + local msg = messageTemplate:Clone() + + local playerLbl = msg:WaitForChild("PlayerName") + playerLbl.TextColor3 = computePlayerColor(player) + playerLbl.TextStrokeColor3 = playerLbl.TextColor3 + playerLbl.Text = player.Name .. "; " + playerLbl.Size = computeTextBounds(playerLbl) + + local msgLbl = msg:WaitForChild("Message") + msgLbl.Text = message + msgLbl.Size = computeTextBounds(msgLbl) + + local width = playerLbl.AbsoluteSize.X + msgLbl.AbsoluteSize.X + + msg.Size = msg.Size + UDim2.new(0, width, 0, 0) + msg.LayoutOrder = getMessageId() + + msg.Name = "Message" .. msg.LayoutOrder + msg.Parent = chatOutput + + if chatQueue.size == 6 then + local front = chatQueue.front + front.data:Destroy() + + chatQueue:Remove(front.id) + end + + chatQueue:Add(msg) + Debris:AddItem(msg, 60) +end + +chatRemote.OnClientEvent:Connect(onReceiveChat) + +-------------------------------------------------------------------------------------------- + + + + GetCoreGateway + local ChatConnections = {} + +local function AddObjects(bindableClass,targetName,...) + local target = ChatConnections[targetName] + if not target then + target = {} + ChatConnections[targetName] = target + end + local names = {...} + for _,name in pairs(names) do + local signal = Instance.new(bindableClass) + signal.Name = targetName .. "_" .. name + signal.Parent = script + target[name] = signal + end +end + +AddObjects("BindableEvent","ChatWindow", + --------------------------- + -- Fired from the CoreGui + --------------------------- + "ToggleVisibility", -- Fired when the CoreGui chat button is pressed. + "SetVisible", -- Fired when the CoreGui wants to directly change the visiblity state of the chat window. + "FocusChatBar", -- Fired when the CoreGui wants to capture the Chatbar's Focus. + "TopbarEnabledChanged", -- Fired when the visibility of the Topbar is changed. + "SpecialKeyPressed", -- Fired when the reserved ChatHotkey is pressed. + "CoreGuiEnabled", -- Fired when a user changes the SetCoreGuiEnabled state of the Chat Gui. + + --------------------------- + -- Fired to the CoreGui + --------------------------- + "ChatBarFocusChanged", + -- ^ Fire this with 'true' when you want to assure the CoreGui that the ChatBar is being focused on. + + "VisibilityStateChanged", + -- ^ Fire this with 'true' when the user shows or hides the chat. + + "MessagesChanged", + -- ^ Fire this with a number to change the number of messages that have been recorded by the chat window. + -- If the CoreGui thinks the chat window isn't visible, it will display the recorded difference between + -- the number of messages that was displayed when it was visible, and the number you supply. + + "MessagePosted" + -- ^ Fire this to make the player directly chat under ROBLOX's C++ API. + -- This will fire the LocalPlayer's Chatted event. + -- Please only fire this on the player's behalf. If you attempt to spoof a player's chat + -- to get them in trouble, you could face serious moderation action. +) + +AddObjects("BindableFunction","ChatWindow", + "IsFocused" -- This will be invoked by the CoreGui when it wants to check if the chat window is active. +) + +-- The following events are fired if the user calls StarterGui:SetCore(string name, Variant data) +-- Note that you can only hook onto these ones specifically. +AddObjects("BindableEvent","SetCore", + "ChatMakeSystemMessage", + "ChatWindowPosition", + "ChatWindowSize", + "ChatBarDisabled" +) + +-- The following functions are invoked if the user calls StarterGui:GetCore(string name) +-- Note that you can only hook onto these ones specifically. +AddObjects("BindableFunction","GetCore", + "ChatWindowPosition", -- Should return a UDim2 representing the position of the chat window. + "ChatWindowSize", -- Should return a UDim2 representing the size of the chat window. + "ChatBarDisabled" -- Should return true if the chat bar is currently disabled. +) + +-- Connect ChatConnections to the CoreGui. +local StarterGui = game:GetService("StarterGui") +local GuiService = game:GetService("GuiService") + +if not GuiService:IsTenFootInterface() then + local tries = 0 + local maxAttempts = 30 + + while (tries < maxAttempts) do + local success,result = pcall(function () + StarterGui:SetCore("CoreGuiChatConnections", ChatConnections) + end) + if success then + break + else + tries = tries + 1 + if tries == maxAttempts then + error("Error calling SetCore CoreGuiChatConnections: " .. result) + else + wait() + end + end + end +end + +return ChatConnections + + + + + LinkedList + local LinkedList = {} +LinkedList.__index = LinkedList + +function LinkedList:Add(data) + local node = {} + node.data = data + node.id = tostring(node):sub(8) + + local back = self.back + if back then + back.next = node + node.prev = back + end + + if not self.front then + self.front = node + end + + self.back = node + self.size = self.size + 1 + + self.nodes[node.id] = node + self.lookup[data] = node + + return node.id +end + +function LinkedList:Get(id) + local node = self.nodes[id] + if node then + return node.data + end +end + +function LinkedList:Remove(id) + local node = self.nodes[id] + + if node then + if node.prev then + node.prev.next = node.next + end + + if node.next then + node.next.prev = node.prev + end + + if node == self.front then + self.front = node.next + end + + if node == self.back then + self.back = node.prev + end + + if node.data then + node.data = nil + end + + self.size = self.size - 1 + end +end + +function LinkedList:GetEnumerator() + return coroutine.wrap(function () + local node = self.front + while node ~= nil do + coroutine.yield(node.id, node.data) + node = node.next + end + end) +end + +function LinkedList.new() + local list = + { + nodes = {}; + lookup = {}; + size = 0; + } + + return setmetatable(list, LinkedList) +end + +return LinkedList + + + + + MessageTemplate + false + + 0 + 0 + + true + + true + + 0.6000000238418579 + 0.6000000238418579 + 0.6000000238418579 + + 0.6000000238418579 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 0 + 16 + + 0 + 0 + + true + 1 + + + + Message + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 1 + 1 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + + + + 1 + 1 + 1 + + false + 16 + + 1 + 1 + 1 + + 0.8999999761581421 + 0 + 0 + false + 0 + 1 + true + 1 + + + + + PlayerName + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + + + + 0 + 0 + 0 + + false + 16 + + 0 + 0 + 0 + + 0.8999999761581421 + 0 + 0 + false + 0 + 1 + true + 1 + + + + + AutoLayout + true + + 0 + 1 + + 0 + 0 + + 2 + + 1 + + + + + + + Health + local StarterGui = game:GetService("StarterGui") +StarterGui:SetCoreGuiEnabled("All",false) + +local health = script.Parent +local redBar = health:WaitForChild("RedBar") +local greenBar = redBar:WaitForChild("GreenBar") + +local player = game.Players.LocalPlayer +local c = workspace.CurrentCamera + +if c.ViewportSize.Y < 600 then + local scale = Instance.new("UIScale") + scale.Scale = 0.6 + scale.Parent = health +end + +local function onCharacterAdded(char) + local humanoid = char:WaitForChild("Humanoid") + + local function updateHealth(health) + greenBar.Size = UDim2.new(1, 0, health / humanoid.MaxHealth, 0) + end + + updateHealth(humanoid.MaxHealth) + humanoid.HealthChanged:Connect(updateHealth) +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:Connect(onCharacterAdded) + + + + + Messages + local Players = game:GetService("Players") +local RunService = game:GetService("RunService") + +local gui = script.Parent +local player = Players.LocalPlayer + +local hintBin = Instance.new("Folder") +local msgNameFmt = "MsgLbl_%s [%s]" + +local function addMessage(sourceMsg,msgType) + local isInPlayer = (sourceMsg.Parent == player) + local msgType = sourceMsg.ClassName + + if msgType == "Message" and isInPlayer then + msgType = "Player" + end + + local msgTemp = script:WaitForChild(msgType) + + local msg = msgTemp:Clone() + msg.Name = msgNameFmt:format(msgType, sourceMsg:GetFullName()) + + local textUpdater = sourceMsg:GetPropertyChangedSignal("Text") + local isUpdating = false + + local function updateText() + if not isUpdating then + isUpdating = true + + msg.Text = sourceMsg.Text + sourceMsg.Text = "" + + if msgType ~= "Hint" then + msg.Visible = (#msg.Text > 0) + end + + isUpdating = false + end + end + + local function onAncestryChanged() + local desiredAncestor + + if msgType == "Hint" then + desiredAncestor = hintBin + elseif isInPlayer then + desiredAncestor = player + else + desiredAncestor = workspace + end + + if not sourceMsg:IsDescendantOf(desiredAncestor) then + msg:Destroy() + end + end + + --[[ + I have to parent the Hint somewhere where it won't render since it + draws even if the Hint has no text. The server will remove the object + by it's reference address even if I change the parent, so this isn't a + problem online. But I can't rely on this in a non-network scenario so + regular Hints will still be visible offline if they're in the Workspace :( + --]] + + if msgType == "Hint" then + wait() + sourceMsg.Parent = hintBin + end + + updateText() + textUpdater:Connect(updateText) + sourceMsg.AncestryChanged:Connect(onAncestryChanged) + + msg.Parent = gui +end + +local function registerMessage(obj) + if obj:IsA("Message") then + addMessage(obj) + end +end + +for _,v in pairs(workspace:GetDescendants()) do + registerMessage(v) +end + +for _,v in pairs(player:GetChildren()) do + registerMessage(v) +end + +player.ChildAdded:Connect(registerMessage) +workspace.DescendantAdded:Connect(registerMessage) + + + + Hint + false + + 0 + 1 + + true + + true + + 0 + 0 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 0 + 20 + + 0 + + + + 0.8823530077934265 + 0.8823530077934265 + 0.8823530077934265 + + false + 16 + + 0.7843137979507446 + 0.7843137979507446 + 0.7843137979507446 + + 0.8999999761581421 + 0 + 0 + false + 2 + 2 + true + 1 + + + + + Message + false + + 0 + 0 + + true + + true + + 0.498039186000824 + 0.498039186000824 + 0.498039186000824 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0 + -36 + + null + 0 + false + null + + 1 + 0 + 1 + 36 + + 0 + + + + 1 + 1 + 1 + + false + 18 + + 0 + 0 + 0 + + 0.10000000149011612 + 0.10000000149011612 + 0 + true + 2 + 1 + false + 1 + + + + + Player + false + + 0 + 0 + + true + + true + + 0.5882353186607361 + 0.5882353186607361 + 0.5882353186607361 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 32 + 0 + 5 + + null + 0 + false + null + + 0.25 + 0 + 0.25 + 0 + + 0 + + Test + + 1 + 1 + 1 + + false + 18 + + 0 + 0 + 0 + + 0.10000000149011612 + 0.10000000149011612 + 0 + true + 2 + 1 + true + 10 + + + + + + PlayerList + local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local Teams = game:GetService("Teams") + +spawn(function () + local StarterGui = game:GetService("StarterGui") + StarterGui:SetCoreGuiEnabled("PlayerList", false) + + local player = Players.LocalPlayer + + local playerGui = player:WaitForChild("PlayerGui") + playerGui:SetTopbarTransparency(1) +end) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Setup +-------------------------------------------------------------------------------------------------------------------------------------- + +local playerStates = {} +local teamGroups = {} + +local statLookup = {} +local statNames = {} + +local inTeamMode = false + +local basePlayerLbl = script:WaitForChild("BasePlayerLbl") +local baseGroup = script:WaitForChild("BaseGroup") +local baseStat = script:WaitForChild("BaseStat") + +local playerList = script.Parent +local backdrop = playerList:WaitForChild("Backdrop") +local container = playerList:WaitForChild("Container") + +local coreGroup = baseGroup:Clone() +coreGroup.Name = "Default" +coreGroup.Parent = container + +local coreFooter = coreGroup.Footer +local coreHeader = coreGroup.Header + +local eUpdateStatLayout = Instance.new("BindableEvent") +local updateStatLayout = eUpdateStatLayout.Event + +local eUpdateTeamTotal = Instance.new("BindableEvent") +local updateTeamTotal = eUpdateTeamTotal.Event + +local ePlayerTeamChanged = Instance.new("BindableEvent") +local playerTeamChanged = ePlayerTeamChanged.Event + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Colors +-------------------------------------------------------------------------------------------------------------------------------------- + +local PLAYER_COLORS = +{ + [0] = Color3.fromRGB(173, 35, 35); -- red + [1] = Color3.fromRGB( 42, 75, 215); -- blue + [2] = Color3.fromRGB( 29, 105, 20); -- green + [3] = Color3.fromRGB(129, 38, 192); -- purple + [4] = Color3.fromRGB(255, 146, 51); -- orange + [5] = Color3.fromRGB(255, 238, 51); -- yellow + [6] = Color3.fromRGB(255, 205, 243); -- pink + [7] = Color3.fromRGB(233, 222, 187); -- tan +} + +local function computePlayerColor(player) + local pName = player.Name + local length = #pName + local oddShift = (1 - (length % 2)) + local value = 0 + + for i = 1,length do + local char = pName:sub(i,i):byte() + local rev = (length - i) + oddShift + if (rev % 4) >= 2 then + value = value - char + else + value = value + char + end + end + + return PLAYER_COLORS[value % 8] +end + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Backdrop Handler +-------------------------------------------------------------------------------------------------------------------------------------- + +local isTeamMode = false +local hasStats = false + +local size1x1 = Vector2.new(1,1) +local rawGroups = {} + +local function onContainerChildAdded(child) + if child:IsA("Frame") then + local listLayout = child:WaitForChild("ListLayout",2) + if listLayout then + rawGroups[child] = listLayout + end + end +end + +local function onContainerChildRemoved(child) + if rawGroups[child] then + rawGroups[child] = nil + end +end + +local function sortGroups(a,b) + if a == coreGroup then + return true + elseif b == coreGroup then + return false + else + local orderA,orderB = a.LayoutOrder,b.LayoutOrder + if orderA == orderB then + return a.Name < b.Name + else + return orderA < orderB + end + end +end + +local function updateBackdrop() + local groups = {} + local at = 1 + + for group in pairs(rawGroups) do + if group.Visible then + groups[at] = group + at = at + 1 + end + end + + local height = 0 + table.sort(groups,sortGroups) + + for i = 1,#groups do + local group = groups[i] + local layout = rawGroups[group] + group.Position = UDim2.new(0,0,0,height) + height = height + layout.AbsoluteContentSize.Y + end + + if #statNames > 0 and not hasStats then + hasStats = true + container.AnchorPoint = Vector2.new(1,0) + for _,group in pairs(groups) do + group.Header.TeamUnderline.Size = UDim2.new(2,-4,0,1) + end + eUpdateStatLayout:Fire() + elseif #statNames == 0 and hasStats then + hasStats = false + container.AnchorPoint = Vector2.new(0,0) + for _,group in pairs(groups) do + group.Header.TeamUnderline.Size = UDim2.new(1,-4,0,1) + end + eUpdateStatLayout:Fire() + end + + if isTeamMode then + height = height + coreHeader.AbsoluteSize.Y + end + + local width = container.AbsoluteSize.X * (container.AnchorPoint.X+1) + backdrop.Size = UDim2.new(0,width,0,height) +end + +for _,child in pairs(container:GetChildren()) do + onContainerChildAdded(child) +end + +container.ChildAdded:Connect(onContainerChildAdded) +container.ChildRemoved:Connect(onContainerChildRemoved) +RunService.Heartbeat:Connect(updateBackdrop) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Header Size Stuff +-------------------------------------------------------------------------------------------------------------------------------------- + +local function switchHeaderMode(isTeamMode) + if isTeamMode then + coreHeader.Size = UDim2.new(1,0,1/3,0) + coreHeader.Stats.Size = UDim2.new(0.75,0,1,0) + coreHeader.Title.Size = UDim2.new(1,0,1,0) + else + coreHeader.Size = UDim2.new(1,0,0.4,0) + coreHeader.Stats.Size = UDim2.new(0.75,0,0.85,0) + coreHeader.Title.Size = UDim2.new(1,0,0.85,0) + end +end + +switchHeaderMode(false) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Stats +-------------------------------------------------------------------------------------------------------------------------------------- + +local function incrementStat(statName) + if not statLookup[statName] then + statLookup[statName] = 1 + table.insert(statNames,statName) + else + statLookup[statName] = statLookup[statName] + 1 + end + eUpdateStatLayout:Fire() +end + +local function decrementStat(statName) + if statLookup[statName] then + statLookup[statName] = statLookup[statName] - 1 + + if statLookup[statName] == 0 then + statLookup[statName] = nil + for i,name in ipairs(statNames) do + if name == statName then + table.remove(statNames,i) + break + end + end + end + + eUpdateStatLayout:Fire() + end +end + +local function getPlayerStateFromStat(stat) + local leaderstats = stat.Parent + if leaderstats then + local player = leaderstats.Parent + if player then + return playerStates[player] + end + end +end + +local function refreshTeamStats() + for _,team in pairs(Teams:GetTeams()) do + eUpdateTeamTotal:Fire(team) + end +end + +local function onStatRemoved(stat,statName) + if stat.ClassName == "IntValue" then + local statName = statName or stat.Name + local playerState = getPlayerStateFromStat(stat) + if playerState and playerState.Stats[statName] then + playerState.Stats[statName]:Destroy() + playerState.Stats[statName] = nil + end + decrementStat(statName) + refreshTeamStats() + end +end + +local function onStatAdded(stat) + if stat.ClassName == "IntValue" then + local statName = stat.Name + local playerState = getPlayerStateFromStat(stat) + if playerState then + local changeSignal + + if not playerState.Stats[statName] then + local statLbl = baseStat:Clone() + statLbl.Name = statName + + local function updateStat() + statLbl.Text = stat.Value + if isTeamMode then + local team = playerState.Player.Team + if team then + eUpdateTeamTotal:Fire(team) + end + end + end + + updateStat() + changeSignal = stat.Changed:Connect(updateStat) + + statLbl.Parent = playerState.Label.Stats + playerState.Stats[statName] = statLbl + end + + local nameSignal do + local function onNameChanged() + if changeSignal then + changeSignal:Disconnect() + changeSignal = nil + end + nameSignal:Disconnect() + nameSignal = nil + + -- Rebuild the stat + onStatRemoved(stat,statName) + onStatAdded(stat) + end + + nameSignal = stat:GetPropertyChangedSignal("Name"):Connect(onNameChanged) + end + end + + incrementStat(statName) + refreshTeamStats() + end +end + +local function onPlayerChildAdded(leaderstats) + if leaderstats.Name == "leaderstats" then + local player = leaderstats.Parent + local playerState = playerStates[player] + if playerState and not playerState.leaderstats then + playerState.leaderstats = leaderstats + for _,stat in pairs(leaderstats:GetChildren()) do + onStatAdded(stat) + end + leaderstats.ChildAdded:Connect(onStatAdded) + leaderstats.ChildRemoved:Connect(onStatRemoved) + end + end +end + +local function onPlayerChildRemoved(child) + if child.Name == "leaderstats" then + for _,stat in pairs(child:GetChildren()) do + onStatRemoved(stat) + end + for player,playerState in pairs(playerStates) do + if playerState.leaderstats == child then + playerState.leaderstats = nil + break + end + end + end +end + +local function updateStatLbl(statLbl,index) + statLbl.Size = UDim2.new(1/#statNames,0,1,0) + statLbl.Position = UDim2.new((index-1)/#statNames) +end + +local function onUpdateStatLayout() + local statBin = coreHeader.Stats + + for _,statLbl in pairs(statBin:GetChildren()) do + if statLbl:IsA("TextLabel") and not statLookup[statLbl.Name] then + statLbl:Destroy() + end + end + + for i,statName in pairs(statNames) do + local statLbl = statBin:FindFirstChild(statName) + if not statLbl then + statLbl = baseStat:Clone() + statLbl.Name = statName + statLbl.Text = statName + statLbl.Parent = statBin + end + updateStatLbl(statLbl,i) + end + + for player,playerState in pairs(playerStates) do + for statName,statLbl in pairs(playerState.Stats) do + if not statLookup[statName] then + statLbl:Destroy() + playerState.Stats[statName] = nil + end + end + + for i,statName in pairs(statNames) do + local statLbl = playerState.Stats[statName] + if statLbl then + if player.Team then + statLbl.TextColor = player.Team.TeamColor + else + statLbl.TextColor3 = Color3.new(1,1,1) + end + updateStatLbl(statLbl,i) + end + end + end + + isTeamMode = (#Teams:GetTeams() > 0) + + if isTeamMode then + coreHeader.Visible = hasStats + coreHeader.Title.Text = "Team" + else + coreHeader.Visible = true + if hasStats then + coreHeader.Title.Text = "Players" + else + coreHeader.Title.Text = "Player List" + end + end + + switchHeaderMode(isTeamMode) +end + +updateStatLayout:Connect(onUpdateStatLayout) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player States +-------------------------------------------------------------------------------------------------------------------------------------- + +local function onPlayerAdded(player) + local playerState = {} + local name = player.Name + + local lbl = basePlayerLbl:Clone() + lbl.Name = name + lbl.PlayerName.Text = name + lbl.PlayerName.TextColor3 = computePlayerColor(player) + lbl.Parent = coreGroup + + playerState.Player = player + playerState.Label = lbl + playerState.Stats = {} + playerStates[player] = playerState + + for _,child in pairs(player:GetChildren()) do + onPlayerChildAdded(child) + end + + player.ChildAdded:Connect(onPlayerChildAdded) + player.ChildRemoved:Connect(onPlayerChildRemoved) + + player.Changed:Connect(function (property) + if property == "Team" then + ePlayerTeamChanged:Fire(player) + end + end) + + ePlayerTeamChanged:Fire(player) +end + +local function onPlayerRemoved(player) + local state = playerStates[player] + playerStates[player] = nil + + if state and state.Label then + state.Label:Destroy() + end +end + +for _,player in pairs(Players:GetPlayers()) do + onPlayerAdded(player) +end + +Players.PlayerAdded:Connect(onPlayerAdded) +Players.PlayerRemoving:Connect(onPlayerRemoved) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Teams +-------------------------------------------------------------------------------------------------------------------------------------- + +local function neutralizePlayer(player) + local playerState = playerStates[player] + if playerState then + local playerLbl = playerState.Label + playerLbl.PlayerName.Text = player.Name + playerLbl.PlayerName.TextColor3 = computePlayerColor(player) + playerLbl.PlayerName.Position = UDim2.new(0,0,0,0) + for stat,statLbl in pairs(playerState.Stats) do + statLbl.TextColor3 = Color3.new(1,1,1) + end + playerLbl.Visible = (not isTeamMode) + playerLbl.Parent = coreGroup + end +end + +local function onPlayerAddedToTeam(player) + local team = player.Team + local group = teamGroups[team] + if group then + local playerState = playerStates[player] + if playerState then + local playerLbl = playerState.Label + playerLbl.PlayerName.TextColor = team.TeamColor + playerLbl.PlayerName.Position = UDim2.new(0,4,0,0) + for stat,statLbl in pairs(playerState.Stats) do + statLbl.TextColor = team.TeamColor + end + playerLbl.Parent = group + playerLbl.Visible = true + eUpdateStatLayout:Fire() + refreshTeamStats() + end + end +end + +local function onPlayerRemovedFromTeam(player) + if not player.Team then + neutralizePlayer(player) + refreshTeamStats() + end +end + +local function onUpdateTeamTotal(team) + local teamGroup = teamGroups[team] + if teamGroup then + local teamStats = teamGroup.Header.Stats + local totals = {} + + for i,statName in ipairs(statNames) do + local total = totals[i] + if not total then + total = { Name = statName, Value = 0 } + totals[i] = total + end + for _,player in pairs(team:GetPlayers()) do + local playerState = playerStates[player] + if playerState then + local leaderstats = playerState.leaderstats + if leaderstats then + local stat = leaderstats:FindFirstChild(statName) + if stat then + total.Value = total.Value + stat.Value + end + end + end + end + end + + local numStats = #statNames + + for i,statRecord in ipairs(totals) do + local statName = statRecord.Name + local statLbl = teamStats:FindFirstChild(statName) + if not statLbl then + statLbl = baseStat:Clone() + statLbl.Name = statName + statLbl.TextColor = team.TeamColor + statLbl.TextStrokeTransparency = 0.5 + statLbl.Parent = teamStats + end + statLbl.Text = statRecord.Value + updateStatLbl(statLbl,i) + end + + for _,statLbl in pairs(teamStats:GetChildren()) do + if not statLookup[statLbl.Name] then + statLbl:Destroy() + end + end + end +end + +local function onTeamAdded(team) + if team.ClassName == "Team" then + local teamGroup = baseGroup:Clone() + teamGroup.Name = team.Name + teamGroup.Footer.Visible = true + + local teamHeader = teamGroup.Header + + local teamUnderline = teamHeader.TeamUnderline + teamUnderline.Visible = true + teamUnderline.BackgroundColor = team.TeamColor + + if hasStats then + teamUnderline.Size = teamUnderline.Size + UDim2.new(1,0,0,0) + end + + local teamTitle = teamHeader.Title + teamTitle.Text = team.Name + teamTitle.TextColor = team.TeamColor + teamTitle.TextStrokeTransparency = 0.5 + + teamGroup.Parent = container + teamGroups[team] = teamGroup + + for _,player in pairs(team:GetPlayers()) do + onPlayerAddedToTeam(player) + end + + eUpdateTeamTotal:Fire(team) + eUpdateStatLayout:Fire() + end + if #Teams:GetTeams() > 0 and not isTeamMode then + isTeamMode = true + for _,player in pairs(Players:GetPlayers()) do + if not player.Team then + neutralizePlayer(player) + end + end + end +end + +local function onTeamRemoved(team) + if teamGroups[team] then + for _,player in pairs(Players:GetPlayers()) do + if player.TeamColor == team.TeamColor then + neutralizePlayer(player) + end + end + teamGroups[team]:Destroy() + teamGroups[team] = nil + eUpdateStatLayout:Fire() + end + if #Teams:GetTeams() == 0 then + isTeamMode = false + for _,player in pairs(Players:GetPlayers()) do + neutralizePlayer(player) + end + end +end + +local function onPlayerTeamChange(player) + local team = player.Team + if team then + onPlayerAddedToTeam(player) + else + onPlayerRemovedFromTeam(player) + end +end + +for _,team in pairs(Teams:GetTeams()) do + onTeamAdded(team) +end + +for _,player in pairs(Players:GetPlayers()) do + onPlayerTeamChange(player) +end + +Teams.ChildAdded:Connect(onTeamAdded) +Teams.ChildRemoved:Connect(onTeamRemoved) +updateTeamTotal:Connect(onUpdateTeamTotal) +playerTeamChanged:Connect(onPlayerTeamChange) + +-------------------------------------------------------------------------------------------------------------------------------------- + + + + BaseGroup + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + -9999 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + Footer + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 999999999 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.16500000655651093 + 0 + + 0 + 0 + + false + 1 + + + + + Header + false + + 0 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + -9999999 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.3330000042915344 + 0 + + 0 + 0 + + true + 1 + + + + Title + false + + 1 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + Player List + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + + + + + Stats + false + + 0 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.75 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + + TeamUnderline + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + -1 + 2 + 0.875 + 0 + + null + 0 + false + null + + 1 + -4 + 0 + 1 + + 0 + 0 + + false + 2 + + + + + + ListLayout + true + + 1 + 1 + + 0 + 0 + + 2 + + 1 + + + + + + BasePlayerLbl + false + + 0 + 0 + + true + + true + + 0 + 1 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.33329999446868896 + 0 + + 0 + 0 + + true + 1 + + + + PlayerName + false + + 1 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + OnlyTwentyCharacters + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + + + + + Stats + false + + 0 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.75 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + + + BaseStat + false + + 0 + 0 + + true + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + 0 + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + + + + + + RootFrame + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + ChatPadding + + + 0 + 20 + + + 0 + 0 + + + 0 + 0 + + + 0 + 0 + + + + + + + ClassicMouse + false + + 0.5 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + + rbxassetid://334630296 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + 0 + false + null + + 0 + 80 + 0 + 80 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 10 + + + + + SafeChat + true + + 0 + 1 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + rbxassetid://991182833 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + null + null + null + null + + 0 + 22 + 0.75 + 0 + + + + + + null + 0 + 0 + true + false + null + + 0 + 32 + 0 + 30 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + GamepadHint + false + + 0.5 + 0.75 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + + rbxasset://textures/ui/Settings/Help/XButtonDark@2x.png + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 1 + 5 + 0 + 0 + + null + 0 + 0 + false + null + + 0.75 + 0 + 0.75 + 0 + + 2 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 1 + + + + + + ZoomControls + false + + 1 + 1 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 1 + 0 + 1 + 0 + + null + 0 + false + null + + 0 + 70 + 0 + 70 + + 0 + 0 + + true + 1 + + + + RotateUp + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + rbxassetid://598662248 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + null + null + null + null + + 0 + 0 + 0 + 0 + + + + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + RotateDown + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + rbxassetid://598662248 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + null + null + null + null + + 0 + 0 + 0 + 35 + + + + + + null + -180 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + ZoomIn + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + rbxassetid://598663795 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + null + null + null + null + + 0 + 35 + 0 + 0 + + + + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + Lock + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 35 + 0 + 35 + + 0 + 0 + + false + 3 + + + + + + ZoomOut + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + + + + + + rbxassetid://598665130 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + null + null + null + null + + 0 + 35 + 0 + 35 + + + + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + FirstPersonIndicator + false + + 1 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + + rbxassetid://598702035 + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + null + null + null + null + + 1 + 0 + 0 + -97 + + null + 0 + 0 + false + null + + 0 + 168 + 0 + 42 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 2 + + + + + + Health + false + + 1 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 1 + -31 + 0.5 + 0 + + null + 0 + false + null + + 0 + 66 + 0 + 137 + + 0 + 0 + + true + 1 + + + + RedBar + false + + 0.5 + 0 + + + true + + 1 + 0 + 0 + + 0 + + 1 + 0 + 0 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 12 + 0 + 112 + + 0 + 0 + + true + 2 + + + + GreenBar + false + + 0.5 + 1 + + + true + + 0.5058823823928833 + 0.7725490927696228 + 0.08627451211214066 + + 0 + + 0.5058823823928833 + 0.7725490927696228 + 0.08627451211214066 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + + + + + + HealthLbl + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0 + 0 + 1 + -24 + + null + 0 + false + null + + 1 + 0 + 0 + 24 + + 0 + + Health + + 0 + 0 + 1 + + true + 18 + + 0 + 0 + 1 + + 0.8999999761581421 + 0 + 0 + true + 2 + 1 + true + 2 + + + + + + Chat + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + ChatBar + true + + 1 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.16862750053405762 + 0.16862750053405762 + 0.16862750053405762 + + 0 + 0 + true + false + false + 4 + 0 + 1 + false + null + null + null + null + + 1 + 1 + 0.7843137979507446 + + To chat click here or press the "/" key + + 1 + 0 + 1 + 0 + + null + 0 + true + null + true + + 1 + -3 + 0 + 15 + + 0 + + + + 0 + 0 + 0 + + true + false + 15 + + 0 + 0 + 0 + + 1 + 0 + 0 + false + 0 + 1 + true + 3 + + + + FocusBackdrop + false + + 1 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 1 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 3 + 1 + 0 + + 0 + 0 + + false + 2 + + + + + + MainBackdrop + false + + 0 + 0 + + + true + + 0.250980406999588 + 0.250980406999588 + 0.250980406999588 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 0 + 20 + + 0 + 0 + + true + 1 + + + + + ChatOutput + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + true + false + 0 + null + null + null + null + + 0 + 23 + 0 + 29 + + null + 0 + false + null + + 1 + 0 + 0 + 96 + + 0 + 0 + + true + 1 + + + + Stream + + 1 + 1 + + 0 + 0 + + 2 + + 2 + + + + + + + Backpack + true + + 0 + 1 + + + true + + 0.498039186000824 + 0.498039186000824 + 0.498039186000824 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 2 + 0 + + true + 1 + + + + UIScale + + 0.13300000131130219 + + + + + + Backdrop + false + + 0 + 0 + + + true + + 0.7058823704719543 + 0.7058823704719543 + 0.7058823704719543 + + 0.5 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + 0 + + true + 2 + + + + + Slots + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + UIListLayout + + 0 + 1 + + 0 + 0 + + 2 + + 1 + + + + + + + PlayerList + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + -36 + + null + 0 + false + null + + 1 + 0 + 1 + 36 + + 0 + 0 + + true + 1 + + + + Backdrop + false + + 1 + 0 + + + true + + 0.6000000238418579 + 0.6000000238418579 + 0.6000000238418579 + + 0.4000000059604645 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 1 + -10 + 0 + 10 + + null + 0 + false + null + + 0 + 10 + 0 + 10 + + 0 + 0 + + true + 1 + + + + + Container + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 1 + -10 + 0 + 10 + + null + 0 + false + null + + 0.16500000655651093 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + AspectRatio + 3 + 0 + + 0 + + + + + + + + + SafeChat + local UserInputService = game:GetService("UserInputService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local GuiService = game:GetService("GuiService") + +local c = workspace.CurrentCamera +local resUpdate = c:GetPropertyChangedSignal("ViewportSize") +local safeChat = script.Parent +local click = script:WaitForChild("Click") + +local IMG_CHAT = "rbxassetid://991182833" +local IMG_CHAT_DN = "rbxassetid://991182832" +local IMG_CHAT_OVR = "rbxassetid://991182834" + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Fetch Tree Data + +local mSafeChatTree = ReplicatedStorage:WaitForChild("SafeChatTree") +local safeChatTree = require(mSafeChatTree) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Button Positioning + +local IS_PHONE = c.ViewportSize.Y < 600 + +local function onResolutionUpdate() + local viewPort = c.ViewportSize + local chatX = math.min(25,viewPort.Y/40) + local chatY = (viewPort.X/viewPort.Y) * (viewPort.Y * 0.225) + safeChat.Position = UDim2.new(0,chatX,1,-chatY) +end + +onResolutionUpdate() +resUpdate:Connect(onResolutionUpdate) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Safe Chat Tree + +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") +local tempBranch = script:WaitForChild("TempBranch") +local tempButton = script:WaitForChild("TempButton") +local isActivated = false +local rootTree + +local function recursivelyDeactivateTree(obj) + if obj:IsA("Frame") then + obj.Visible = false + elseif obj:IsA("TextButton") then + obj.BackgroundColor3 = Color3.new(1,1,1) + end + for _,v in pairs(obj:GetChildren()) do + recursivelyDeactivateTree(v) + end +end + +local function deactivateRootTree() + isActivated = false + safeChat.Image = IMG_CHAT + recursivelyDeactivateTree(rootTree) + + if GuiService.SelectedObject then + GuiService.SelectedObject = nil + GuiService:RemoveSelectionGroup("SafechatNav") + end +end + +local function activateRootTree() + isActivated = true + rootTree.Visible = true + safeChat.Image = IMG_CHAT_DN + + if UserInputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then + GuiService:AddSelectionParent("SafechatNav",safeChat) + GuiService.SelectedObject = safeChat + end +end + +local function assembleTree(tree) + local treeFrame = tempBranch:Clone() + treeFrame.Name = "Branches" + + local currentBranch + + for i,branch in ipairs(tree.Branches) do + local label = branch.Label + local branches = branch.Branches + local button = tempButton:Clone() + button.Name = label + button.Text = label + button.LayoutOrder = i + local branchFrame = assembleTree(branch) + branchFrame.Parent = button + button.Parent = treeFrame + + local function onEnter() + if currentBranch then + recursivelyDeactivateTree(currentBranch) + end + currentBranch = button + button.BackgroundColor3 = Color3.new(0.7,0.7,0.7) + branchFrame.Visible = true + end + + local function onActivate() + local submit = true + if UserInputService.TouchEnabled then + if not branchFrame.Visible and #branchFrame:GetChildren() > 1 then + branchFrame.Visible = true + submit = false + end + end + if submit then + deactivateRootTree() + chatRemote:FireServer(label) + click:Play() + end + end + + button.MouseEnter:Connect(onEnter) + button.SelectionGained:Connect(onEnter) + button.MouseButton1Down:Connect(onActivate) + end + + return treeFrame +end + +rootTree = assembleTree(safeChatTree) +rootTree.Parent = safeChat + +if IS_PHONE then + local uiScale = Instance.new("UIScale") + uiScale.Parent = rootTree + uiScale.Scale = 0.7 +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Button State + +local isActivated = false +local isHovering = false + +do + local function onMouseEnter() + if not isActivated then + safeChat.Image = IMG_CHAT_OVR + end + isHovering = true + end + + local function onMouseLeave() + if not isActivated then + safeChat.Image = IMG_CHAT + end + isHovering = false + end + + local function onMouseDown() + safeChat.Image = IMG_CHAT_DN + end + + local function onMouseUp() + if isHovering then + activateRootTree() + end + end + + local function onInputBegan(input,gameProcessed) + if input.UserInputType == Enum.UserInputType.MouseButton1 and not gameProcessed and isActivated then + deactivateRootTree() + end + end + + safeChat.MouseEnter:Connect(onMouseEnter) + safeChat.MouseLeave:Connect(onMouseLeave) + safeChat.MouseButton1Down:Connect(onMouseDown) + safeChat.MouseButton1Up:Connect(onMouseUp) + + UserInputService.InputBegan:Connect(onInputBegan) +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Gamepad Stuff +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local gamepadHint = safeChat:WaitForChild("GamepadHint") + +if GuiService:IsTenFootInterface() then + gamepadHint.Visible = true +else + local function onLastInputTypeChanged(inputType) + gamepadHint.Visible = (inputType.Name == "Gamepad1") + end + + onLastInputTypeChanged(UserInputService:GetLastInputType()) + UserInputService.LastInputTypeChanged:Connect(onLastInputTypeChanged) +end + + +local function onInputBegan(input) + if input.KeyCode == Enum.KeyCode.ButtonX then + activateRootTree() + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + + + + Click + true + + 10 + false + 10000 + false + 1 + false + 0 + null + + rbxasset://sounds/switch.mp3 + + + 0 + 0.5 + 10 + + + + + NullSelectionImageObject + false + + 0 + 0 + + true + + true + + 1 + 1 + 1 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 0 + 0 + + 0 + 0 + + true + 1 + + + + + TempBranch + false + + 0 + 0.5 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 0 + null + null + null + null + + 1 + 5 + 0.5 + 0 + + null + 0 + false + null + + 0 + 140 + 0 + 24 + + 0 + 0 + + false + 2 + + + + UIListLayout + true + + 1 + 1 + + 0 + 5 + + 2 + + 0 + + + + + + TempButton + true + + 0 + 0 + + true + + false + true + + 1 + 1 + 1 + + 0 + + 0.24705879390239716 + 0.24705879390239716 + 0.24705879390239716 + + 0 + 1 + false + false + 9 + 0 + 1 + false + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + true + false + null + + 0 + 140 + 0 + 24 + + 0 + 0 + + ROOT + + 0 + 0 + 0 + + false + 12 + + 0 + 0 + 0 + + 0.949999988079071 + 0.25 + 0 + false + 2 + 1 + true + 2 + + + + + + + + StarterPlayerScripts + + + + Animator + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Services +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local CollectionService = game:GetService("CollectionService") +local RunService = game:GetService("RunService") + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Animator Data +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local Animators = {} + +local function createAnimator(humanoid) + local Figure = humanoid.Parent + local Torso = Figure:WaitForChild("Torso") + local Climbing = Figure:WaitForChild("Climbing") + + local animator = {} + animator.Joints = {} + + do + local joints = + { + RightShoulder = Torso:WaitForChild("Right Shoulder", 5); + LeftShoulder = Torso:WaitForChild("Left Shoulder", 5); + RightHip = Torso:WaitForChild("Right Hip", 5); + LeftHip = Torso:WaitForChild("Left Hip", 5); + } + + if not (joints.RightShoulder and joints.LeftShoulder) then + return + end + + if not (joints.RightHip and joints.LeftHip) then + return + end + + for name, joint in pairs(joints) do + local object = + { + JointObject = joint; + MaxVelocity = joint.MaxVelocity; + DesiredAngle = joint.DesiredAngle; + CurrentAngle = joint.CurrentAngle; + } + + animator.Joints[name] = object + end + end + + local joints = animator.Joints + + local pi = math.pi + local sin = math.sin + + local pose = "Standing" + local toolAnim = "None" + local toolAnimTime = 0 + + local RightShoulder = joints.RightShoulder + local LeftShoulder = joints.LeftShoulder + + local RightHip = joints.RightHip + local LeftHip = joints.LeftHip + + function animator:SetMaxVelocities(value) + RightShoulder.MaxVelocity = value + LeftShoulder.MaxVelocity = value + + RightHip.MaxVelocity = value + LeftHip.MaxVelocity = value + end + + function animator:Update() + local now = tick() + + if Climbing.Value then + pose = "Climbing" + else + local stateType = humanoid:GetState() + pose = stateType.Name + + if pose == "Running" then + local speed = humanoid.WalkSpeed + local movement = (Torso.Velocity * Vector3.new(1, 0, 1)).Magnitude + + if (speed * movement) < 1 then + pose = "Standing" + end + end + end + + if pose == "Jumping" then + self:SetMaxVelocities(.5) + + RightShoulder.DesiredAngle = 1 + LeftShoulder.DesiredAngle = -1 + + RightHip.DesiredAngle = 0 + LeftHip.DesiredAngle = 0 + elseif pose == "Freefall" then + self:SetMaxVelocities(.5) + + RightShoulder.DesiredAngle = pi + LeftShoulder.DesiredAngle = -pi + + RightHip.DesiredAngle = 0 + LeftHip.DesiredAngle = 0 + elseif pose == "Seated" then + self:SetMaxVelocities(.15) + + RightShoulder.DesiredAngle = pi / 2 + LeftShoulder.DesiredAngle = -pi / 2 + + RightHip.DesiredAngle = pi / 2 + LeftHip.DesiredAngle = -pi / 2 + else + local climbFudge = 0 + local amplitude = .1 + local frequency = 1 + + if pose == "Running" then + self:SetMaxVelocities(0.15) + amplitude = 1 + frequency = 9 + elseif pose == "Climbing" then + self:SetMaxVelocities(0.5) + climbFudge = pi + + amplitude = 1 + frequency = 9 + end + + local desiredAngle = amplitude * sin(now * frequency) + + RightShoulder.DesiredAngle = desiredAngle + climbFudge + LeftShoulder.DesiredAngle = desiredAngle - climbFudge + + RightHip.DesiredAngle = -desiredAngle + LeftHip.DesiredAngle = -desiredAngle + + local tool = Figure:FindFirstChildWhichIsA("Tool") + + if tool and tool.RequiresHandle and not CollectionService:HasTag(tool, "Flag") then + local animString = tool:FindFirstChild("toolanim") + + if animString and animString:IsA("StringValue") then + -- apply tool animation + toolAnim = animString.Value + toolAnimTime = now + .3 + + -- delete event sender + animString:Destroy() + end + + if now > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + if toolAnim == "None" then + RightShoulder.DesiredAngle = pi / 2 + elseif toolAnim == "Slash" then + RightShoulder.MaxVelocity = 0.5 + RightShoulder.DesiredAngle = 0 + elseif toolAnim == "Lunge" then + self:SetMaxVelocities(0.5) + + RightShoulder.DesiredAngle = pi / 2 + RightHip.DesiredAngle = pi / 2 + + LeftShoulder.DesiredAngle = 1 + LeftHip.DesiredAngle = 1 + end + else + toolAnim = "None" + toolAnimTime = 0 + end + end + end + + return animator +end + +local function onAnimatorAdded(humanoid) + if humanoid:IsA("Humanoid") then + local animator = createAnimator(humanoid) + Animators[humanoid] = animator + end +end + +local function onAnimatorRemoved(humanoid) + if Animators[humanoid] then + Animators[humanoid] = nil + end +end + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Collection Handler +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local animTag = "Animator" + +local animAdded = CollectionService:GetInstanceAddedSignal(animTag) +local animRemoved = CollectionService:GetInstanceRemovedSignal(animTag) + +for _,humanoid in pairs(CollectionService:GetTagged(animTag)) do + spawn(function () + onAnimatorAdded(humanoid) + end) +end + +animAdded:Connect(onAnimatorAdded) +animRemoved:Connect(onAnimatorRemoved) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Motor Angle Updater +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local desiredFPS = 1 / 30 -- The framerate that would be expected given the MaxVelocity in use. +local lastUpdate = tick() + +local function updateAnimations(deltaTime) + local velocityAdjust = (1 / desiredFPS) * deltaTime + + for humanoid, animator in pairs(Animators) do + -- Update the motor states + animator:Update() + + -- Step the motor angles + for name, jointData in pairs(animator.Joints) do + local joint = jointData.JointObject + local maxVelocity = jointData.MaxVelocity + + local desiredAngle = jointData.DesiredAngle + local currentAngle = jointData.CurrentAngle + + -- Adjust the MaxVelocity based on the current framerate + maxVelocity = math.abs(maxVelocity * velocityAdjust) + + -- Update the CurrentAngle + local delta = (desiredAngle - currentAngle) + + if math.abs(delta) < maxVelocity then + currentAngle = desiredAngle + elseif delta > 0 then + currentAngle = currentAngle + maxVelocity + else + currentAngle = currentAngle - maxVelocity + end + + -- Apply the motor transform + joint.Transform = CFrame.Angles(0, 0, currentAngle) + jointData.CurrentAngle = currentAngle + end + end +end + +RunService:BindToRenderStep("UpdateAnimations", 301, updateAnimations) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + Camera + + + + Main + local Players = game:GetService("Players") +local UserInputService = game:GetService("UserInputService") +local StarterGui = game:GetService("StarterGui") +local GuiService = game:GetService("GuiService") +local ContextActionService = game:GetService("ContextActionService") +local TeleportService = game:GetService("TeleportService") +local Debris = game:GetService("Debris") + +local LocalPlayer = Players.LocalPlayer +local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") +local GameSettings = UserSettings():GetService("UserGameSettings") + +local math_abs = math.abs +local math_asin = math.asin +local math_atan2 = math.atan2 +local math_floor = math.floor +local math_min = math.min +local math_max = math.max +local math_pi = math.pi +local math_rad = math.rad +local Vector2_new = Vector2.new +local Vector3_new = Vector3.new +local CFrame_Angles = CFrame.Angles +local CFrame_new = CFrame.new + +local MIN_Y = math_rad(-80) +local MAX_Y = math_rad(80) + +local ZERO_VECTOR2 = Vector2_new() +local ZERO_VECTOR3 = Vector3_new() +local UP_VECTOR = Vector3_new(0, 1, 0) +local XZ_VECTOR = Vector3_new(1, 0, 1) + +local TOUCH_SENSITIVTY = Vector2_new(math_pi*2.25, math_pi*2) +local MOUSE_SENSITIVITY = Vector2_new(math_pi*4, math_pi*1.9) + +local THUMBSTICK_DEADZONE = 0.2 +local DEADZONE = 0.1 +local ZOOM_FACTOR = 0.25 + +local humanoid + +local function findPlayerHumanoid(player) + local character = player and player.Character + if character then + if not (humanoid and humanoid.Parent == character) then + humanoid = character:FindFirstChildOfClass("Humanoid") + end + end + return humanoid +end + +local function clamp(low, high, num) + return (num > high and high or num < low and low or num) +end + +local function findAngleBetweenXZVectors(vec2, vec1) + return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z) +end + +local function IsFinite(num) + return num == num and num ~= 1/0 and num ~= -1/0 +end + +local function SCurveTranform(t) + t = clamp(-1,1,t) + if t >= 0 then + return (.35*t) / (.35 - t + 1) + end + return -((.8*-t) / (.8 + t + 1)) +end + +local function toSCurveSpace(t) + return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE +end + +local function fromSCurveSpace(t) + return t/2 + 0.5 +end + +local function gamepadLinearToCurve(thumbstickPosition) + local function onAxis(axisValue) + local sign = 1 + if axisValue < 0 then + sign = -1 + end + local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math_abs(axisValue)))) + point = point * sign + return clamp(-1, 1, point) + end + return Vector2_new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y)) +end + +-- Reset the camera look vector when the camera is enabled for the first time +local SetCameraOnSpawn = true +local this = {} + +local isFirstPerson = false +local isRightMouseDown = false +local isMiddleMouseDown = false + +this.Enabled = false +this.RotateInput = ZERO_VECTOR2 +this.DefaultZoom = 10 +this.activeGamepad = nil +this.PartSubjectHack = nil + +function this:GetHumanoid() + local player = Players.LocalPlayer + return findPlayerHumanoid(player) +end + +function this:GetHumanoidRootPart() + local humanoid = this:GetHumanoid() + return humanoid and humanoid.Torso +end + +function this:GetSubjectPosition() + local camera = workspace.CurrentCamera + local result = camera.Focus.p + + local cameraSubject = camera and camera.CameraSubject + if cameraSubject then + if cameraSubject:IsA("Humanoid") then + local char = cameraSubject.Parent + if char then + local head = char:FindFirstChild("Head") + if head and head:IsA("BasePart") then + result = head.Position + end + end + if this.PartSubjectHack then + this:ZoomCamera(this.PartSubjectHack) + this.PartSubjectHack = nil + this:UpdateMouseBehavior() + end + elseif cameraSubject:IsA("BasePart") then + result = cameraSubject.Position + if not this.PartSubjectHack then + this.PartSubjectHack = this:GetCameraZoom() + this:ZoomCamera(10) + this:UpdateMouseBehavior() + end + end + end + + return result +end + +function this:GetCameraLook() + return workspace.CurrentCamera and workspace.CurrentCamera.CFrame.lookVector or Vector3.new(0,0,1) +end + +function this:GetCameraZoom() + if this.currentZoom == nil then + local player = Players.LocalPlayer + this.currentZoom = player and clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, this.DefaultZoom) or this.DefaultZoom + end + return this.currentZoom +end + +function this:GetCameraActualZoom() + local camera = workspace.CurrentCamera + if camera then + return (camera.CFrame.p - camera.Focus.p).Magnitude + end +end + +function this:ViewSizeX() + local result = 1024 + local camera = workspace.CurrentCamera + if camera then + result = camera.ViewportSize.X + end + return result +end + +function this:ViewSizeY() + local result = 768 + local camera = workspace.CurrentCamera + if camera then + result = camera.ViewportSize.Y + end + return result +end + +function this:ScreenTranslationToAngle(translationVector) + local screenX = this:ViewSizeX() + local screenY = this:ViewSizeY() + local xTheta = (translationVector.x / screenX) + local yTheta = (translationVector.y / screenY) + return Vector2_new(xTheta, yTheta) +end + +function this:MouseTranslationToAngle(translationVector) + local xTheta = (translationVector.x / 1920) + local yTheta = (translationVector.y / 1200) + return Vector2_new(xTheta, yTheta) +end + +function this:RotateVector(startVector, xyRotateVector) + local startCFrame = CFrame_new(ZERO_VECTOR3, startVector) + local resultLookVector = (CFrame_Angles(0, -xyRotateVector.x, 0) * startCFrame * CFrame_Angles(-xyRotateVector.y,0,0)).lookVector + return resultLookVector, Vector2_new(xyRotateVector.x, xyRotateVector.y) +end + +function this:RotateCamera(startLook, xyRotateVector) + local startVertical = math_asin(startLook.y) + local yTheta = clamp(-MAX_Y + startVertical, -MIN_Y + startVertical, xyRotateVector.y) + return self:RotateVector(startLook, Vector2_new(xyRotateVector.x, yTheta)) +end + +function this:IsInFirstPerson() + return isFirstPerson +end + +function this:UpdateMouseBehavior() + if isFirstPerson or this.PartSubjectHack then + GameSettings.RotationType = Enum.RotationType.CameraRelative + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + else + GameSettings.RotationType = Enum.RotationType.MovementRelative + if isRightMouseDown or isMiddleMouseDown then + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition + else + UserInputService.MouseBehavior = Enum.MouseBehavior.Default + end + end +end + +function this:PlayTick() + local now = tick() + local lastTickSound = this.LastTickSound + if not lastTickSound then + lastTickSound = 0 + end + + if (now - lastTickSound) > .03 then + local s = Instance.new("Sound") + s.SoundId = "rbxasset://sounds/switch3.wav" + s.Parent = script + s:Play() + Debris:AddItem(s,1) + this.LastTickSound = now + end +end + +function this:ZoomCamera(desiredZoom) + this.currentZoom = clamp(0.25, 400, desiredZoom) + isFirstPerson = self:GetCameraZoom() < 1.5 + + -- set mouse behavior + self:UpdateMouseBehavior() + return self:GetCameraZoom() +end + +function this:ZoomCameraBy(input) + if TeleportService:GetTeleportSetting("FPSCapTo30") then + input = input * 1.5 + end + + local zoom = this:GetCameraActualZoom() + if zoom then + if input > 0 then + zoom = math.max( 1, zoom / (1 + ZOOM_FACTOR*input)) + elseif input < 0 then + zoom = math.min(5000, zoom * (1 - ZOOM_FACTOR*input)) + end + self:ZoomCamera(zoom) + end + + self:PlayTick() + return self:GetCameraZoom() +end + +function this:ZoomCameraFixedBy(zoomIncrement) + return self:ZoomCamera(self:GetCameraZoom() + zoomIncrement) +end + +------------------------ +---- Input Events ---- +------------------------ + +do + local startPos = nil + local lastPos = nil + local panBeginLook = nil + local lastTapTime = nil + + local fingerTouches = {} + local NumUnsunkTouches = 0 + + local inputStartPositions = {} + local inputStartTimes = {} + + local StartingDiff = nil + local pinchBeginZoom = nil + + local dynamicThumbstickFrame = nil + local flaggedDynamic = {} + + local function getDynamicThumbstickFrame() + if dynamicThumbstickFrame and dynamicThumbstickFrame:IsDescendantOf(game) then + return dynamicThumbstickFrame + else + local touchGui = PlayerGui:FindFirstChild("TouchGui") + if not touchGui then return nil end + + local touchControlFrame = touchGui:FindFirstChild("TouchControlFrame") + if not touchControlFrame then return nil end + + dynamicThumbstickFrame = touchControlFrame:FindFirstChild("DynamicThumbstickFrame") + return dynamicThumbstickFrame + end + end + + this.ZoomEnabled = true + this.PanEnabled = true + this.KeyPanEnabled = true + + local function inputIsDynamic(input) + if flaggedDynamic[input] ~= nil then + return flaggedDynamic[input] + end + + if GameSettings.TouchMovementMode ~= Enum.TouchMovementMode.DynamicThumbstick then + return false + end + + local df = getDynamicThumbstickFrame() + if not df then return end + + local pos = input.Position + local p0 = df.AbsolutePosition + local p1 = p0 + df.AbsoluteSize + + if p0.X <= pos.X and p0.Y <= pos.Y then + if pos.X <= p1.X and pos.Y <= p1.Y then + flaggedDynamic[input] = true + return true + end + end + + flaggedDynamic[input] = false + return false + end + + local function OnTouchBegan(input, processed) + if not inputIsDynamic(input) then + fingerTouches[input] = processed + if not processed then + + inputStartPositions[input] = input.Position + inputStartTimes[input] = tick() + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + end + + local function OnTouchChanged(input, processed) + if inputIsDynamic(input) then + return + end + + if fingerTouches[input] == nil then + fingerTouches[input] = processed + if not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + + if NumUnsunkTouches == 1 then + if fingerTouches[input] == false then + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + + local delta = input.Position - lastPos + + delta = Vector2.new(delta.X, delta.Y * GameSettings:GetCameraYInvertValue()) + + if this.PanEnabled then + local desiredXYVector = this:ScreenTranslationToAngle(delta) * TOUCH_SENSITIVTY + this.RotateInput = this.RotateInput + desiredXYVector + end + + lastPos = input.Position + end + else + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + + if NumUnsunkTouches == 2 then + local unsunkTouches = {} + for touch, wasSunk in pairs(fingerTouches) do + if not wasSunk then + table.insert(unsunkTouches, touch) + end + end + if #unsunkTouches == 2 then + local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude + if StartingDiff and pinchBeginZoom then + local scale = difference / math_max(0.01, StartingDiff) + local clampedScale = clamp(0.1, 10, scale) + if this.ZoomEnabled then + this:ZoomCamera(pinchBeginZoom / clampedScale) + this:PlayTick() + end + else + StartingDiff = difference + pinchBeginZoom = this:GetCameraActualZoom() + end + end + else + StartingDiff = nil + pinchBeginZoom = nil + end + end + + local function calcLookBehindRotateInput(torso) + if torso then + local newDesiredLook = (torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit + local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook()) + local vertShift = math_asin(this:GetCameraLook().y) - math_asin(newDesiredLook.y) + if not IsFinite(horizontalShift) then + horizontalShift = 0 + end + if not IsFinite(vertShift) then + vertShift = 0 + end + + return Vector2.new(horizontalShift, vertShift) + end + return nil + end + + local function OnTouchEnded(input, processed) + if fingerTouches[input] == false then + if NumUnsunkTouches == 1 then + panBeginLook = nil + startPos = nil + lastPos = nil + elseif NumUnsunkTouches == 2 then + StartingDiff = nil + pinchBeginZoom = nil + end + end + + if fingerTouches[input] ~= nil and fingerTouches[input] == false then + NumUnsunkTouches = NumUnsunkTouches - 1 + end + fingerTouches[input] = nil + inputStartPositions[input] = nil + inputStartTimes[input] = nil + flaggedDynamic[input] = nil + end + + local function OnMousePanButtonPressed(input, processed) + if processed then return end + this:UpdateMouseBehavior() + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + end + + local function OnMousePanButtonReleased(input, processed) + this:UpdateMouseBehavior() + if not (isRightMouseDown or isMiddleMouseDown) then + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + end + + local function OnMouse2Down(input, processed) + if processed then return end + + isRightMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse2Up(input, processed) + isRightMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouse3Down(input, processed) + if processed then return end + + isMiddleMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse3Up(input, processed) + isMiddleMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouseMoved(input, processed) + + local inputDelta = input.Delta + inputDelta = Vector2.new(inputDelta.X, inputDelta.Y * GameSettings:GetCameraYInvertValue()) + + if startPos and lastPos and panBeginLook then + local currPos = lastPos + input.Delta + local totalTrans = currPos - startPos + if this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + lastPos = currPos + elseif (this:IsInFirstPerson() or this.PartSubjectHack) and this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + end + + local function OnMouseWheel(input, processed) + if not processed then + if this.ZoomEnabled then + this:ZoomCameraBy(clamp(-1, 1, input.Position.Z)) + end + end + end + + local function round(num) + return math_floor(num + 0.5) + end + + local eight2Pi = math_pi / 4 + + local function rotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount) + if camLook ~= ZERO_VECTOR3 then + camLook = camLook.unit + local currAngle = math_atan2(camLook.z, camLook.x) + local newAngle = round((math_atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount + return newAngle - currAngle + end + return 0 + end + + local function OnKeyDown(input, processed) + if processed then return end + if this.ZoomEnabled then + if input.KeyCode == Enum.KeyCode.I then + this:ZoomCameraBy(1) + elseif input.KeyCode == Enum.KeyCode.O then + this:ZoomCameraBy(-1) + end + end + if panBeginLook == nil and this.KeyPanEnabled then + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = true + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = true + elseif input.KeyCode == Enum.KeyCode.Comma then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), -eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.Period then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.PageUp then + this.RotateInput = this.RotateInput + Vector2.new(0,math_pi/12) + this.LastCameraTransform = nil + this:PlayTick() + elseif input.KeyCode == Enum.KeyCode.PageDown then + this.RotateInput = this.RotateInput + Vector2.new(0,-math_pi/12) + this.LastCameraTransform = nil + this:PlayTick() + end + end + end + + local function OnKeyUp(input, processed) + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = false + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = false + end + end + + local lastThumbstickRotate = nil + local numOfSeconds = 0.7 + local currentSpeed = 0 + local maxSpeed = 6 + local lastThumbstickPos = Vector2.new(0,0) + local ySensitivity = 0.65 + local lastVelocity = nil + + function this:UpdateGamepad() + local gamepadPan = this.GamepadPanningCamera + if gamepadPan then + gamepadPan = gamepadLinearToCurve(gamepadPan) + local currentTime = tick() + if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then + this.userPanningTheCamera = true + elseif gamepadPan == ZERO_VECTOR2 then + lastThumbstickRotate = nil + if lastThumbstickPos == ZERO_VECTOR2 then + currentSpeed = 0 + end + end + + local finalConstant = 0 + + if lastThumbstickRotate then + local elapsed = (currentTime - lastThumbstickRotate) * 10 + currentSpeed = currentSpeed + (maxSpeed * ((elapsed*elapsed)/numOfSeconds)) + + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + + if lastVelocity then + local velocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + local velocityDeltaMag = (velocity - lastVelocity).magnitude + + if velocityDeltaMag > 12 then + currentSpeed = currentSpeed * (20/velocityDeltaMag) + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + end + end + + local gamepadCameraSensitivity = GameSettings.GamepadCameraSensitivity + finalConstant = (gamepadCameraSensitivity * currentSpeed) + lastVelocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + end + + lastThumbstickPos = gamepadPan + lastThumbstickRotate = currentTime + + return Vector2_new( gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * ySensitivity * GameSettings:GetCameraYInvertValue()) + end + + return ZERO_VECTOR2 + end + + local InputEvents = {} + + function this:DisconnectInputEvents() + -- Disconnect all input events. + while true do + local signalName = next(InputEvents) + if signalName then + InputEvents[signalName]:Disconnect() + InputEvents[signalName] = nil + else + break + end + end + + this.TurningLeft = false + this.TurningRight = false + this.LastCameraTransform = nil + this.UserPanningTheCamera = false + this.RotateInput = ZERO_VECTOR2 + this.GamepadPanningCamera = ZERO_VECTOR2 + + -- Reset input states + startPos = nil + lastPos = nil + panBeginLook = nil + isRightMouseDown = false + isMiddleMouseDown = false + + fingerTouches = {} + NumUnsunkTouches = 0 + + StartingDiff = nil + pinchBeginZoom = nil + + -- Unlock mouse for example if right mouse button was being held down + if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then + UserInputService.MouseBehavior = Enum.MouseBehavior.Default + end + end + + local function resetInputStates() + isRightMouseDown = false + isMiddleMouseDown = false + OnMousePanButtonReleased() -- this function doesn't seem to actually need parameters + + if UserInputService.TouchEnabled then + --[[menu opening was causing serious touch issues + this should disable all active touch events if + they're active when menu opens.]] + for inputObject, value in pairs(fingerTouches) do + fingerTouches[inputObject] = nil + end + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + StartingDiff = nil + pinchBeginZoom = nil + NumUnsunkTouches = 0 + end + end + + local function getGamepadPan(name, state, input) + if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then + + if state == Enum.UserInputState.Cancel then + this.GamepadPanningCamera = ZERO_VECTOR2 + return + end + + local inputVector = Vector2.new(input.Position.X, -input.Position.Y) + if inputVector.magnitude > THUMBSTICK_DEADZONE then + this.GamepadPanningCamera = Vector2_new(input.Position.X, -input.Position.Y) + else + this.GamepadPanningCamera = ZERO_VECTOR2 + end + end + end + + local function doGamepadZoom(name, state, input) + if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.ButtonR3 and state == Enum.UserInputState.Begin then + if this.ZoomEnabled then + if this:GetCameraZoom() > 0.5 then + this:ZoomCamera(0) + else + this:ZoomCamera(10) + end + end + end + end + + local function assignActivateGamepad() + local connectedGamepads = UserInputService:GetConnectedGamepads() + if #connectedGamepads > 0 then + for i = 1, #connectedGamepads do + if this.activeGamepad == nil then + this.activeGamepad = connectedGamepads[i] + elseif connectedGamepads[i].Value < this.activeGamepad.Value then + this.activeGamepad = connectedGamepads[i] + end + end + end + + if this.activeGamepad == nil then -- nothing is connected, at least set up for gamepad1 + this.activeGamepad = Enum.UserInputType.Gamepad1 + end + end + + local function onInputBegan(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchBegan(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Down(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Down(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyDown(input, processed) + end + end + + local function onInputChanged(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchChanged(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseMovement then + OnMouseMoved(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseWheel then + OnMouseWheel(input, processed) + end + end + + local function onInputEnded(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchEnded(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Up(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Up(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyUp(input, processed) + end + end + + local inputPassCmds = + { + ZoomIn = Enum.KeyCode.I; + ZoomOut = Enum.KeyCode.O; + RotateUp = Enum.KeyCode.PageUp; + RotateDown = Enum.KeyCode.PageDown; + } + + local function onInputPassed(command) + local passKey = inputPassCmds[command] + if passKey then + OnKeyDown({KeyCode = passKey}, false) + end + end + + local function onGamepadConnected(gamepadEnum) + if this.activeGamepad == nil then + assignActivateGamepad() + end + end + + local function onGamepadDisconnected(gamepadEnum) + if this.activeGamepad ~= gamepadEnum then return end + this.activeGamepad = nil + assignActivateGamepad() + end + + function this:ConnectInputEvents() + local player = Players.LocalPlayer + local playerScripts = player:WaitForChild("PlayerScripts") + local passCameraEvent = playerScripts:WaitForChild("PassCameraEvent") + + this.RotateInput = ZERO_VECTOR2 + this.activeGamepad = nil + + InputEvents = + { + InputBegan = UserInputService.InputBegan:Connect(onInputBegan); + InputChanged = UserInputService.InputChanged:Connect(onInputChanged); + InputEnded = UserInputService.InputEnded:Connect(onInputEnded); + MenuOpened = GuiService.MenuOpened:Connect(resetInputStates); + MenuOpenedConn = GuiService.MenuOpened:Connect(resetInputStates); + GamepadConnected = UserInputService.GamepadConnected:Connect(onGamepadConnected); + GamepadDisconnected = UserInputService.GamepadDisconnected:Connect(onGamepadDisconnected); + InputPassed = passCameraEvent.Event:Connect(onInputPassed); + } + + ContextActionService:BindAction("RootCamGamepadPan", getGamepadPan, false, Enum.KeyCode.Thumbstick2) + ContextActionService:BindAction("RootCamGamepadZoom", doGamepadZoom, false, Enum.KeyCode.ButtonR3) + + assignActivateGamepad() + + -- set mouse behavior + self:UpdateMouseBehavior() + end + + function this:SetEnabled(newState) + if newState ~= self.Enabled then + self.Enabled = newState + if self.Enabled then + self:ConnectInputEvents() + else + self:DisconnectInputEvents() + end + end + end + + local function OnPlayerAdded(player) + player.Changed:Connect(function (prop) + if this.Enabled then + if prop == "CameraMode" or prop == "CameraMaxZoomDistance" or prop == "CameraMinZoomDistance" then + this:ZoomCameraFixedBy(0) + end + end + end) + + local function OnCharacterAdded(newCharacter) + local humanoid = findPlayerHumanoid(player) + local start = tick() + while tick() - start < 0.3 and (humanoid == nil or humanoid.Torso == nil) do + wait() + humanoid = findPlayerHumanoid(player) + end + + if humanoid and humanoid.Torso and player.Character == newCharacter then + local newDesiredLook = (humanoid.Torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit + local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook()) + local vertShift = math_asin(this:GetCameraLook().y) - math_asin(newDesiredLook.y) + if not IsFinite(horizontalShift) then + horizontalShift = 0 + end + if not IsFinite(vertShift) then + vertShift = 0 + end + this.RotateInput = Vector2.new(horizontalShift, vertShift) + + -- reset old camera info so follow cam doesn't rotate us + this.LastCameraTransform = nil + end + + -- Need to wait for camera cframe to update before we zoom in + -- Not waiting will force camera to original cframe + wait() + this:ZoomCamera(this.DefaultZoom) + end + + player.CharacterAdded:Connect(function (character) + if this.Enabled or SetCameraOnSpawn then + OnCharacterAdded(character) + SetCameraOnSpawn = false + end + end) + + if player.Character then + spawn(function () OnCharacterAdded(player.Character) end) + end + end + + if Players.LocalPlayer then + OnPlayerAdded(Players.LocalPlayer) + end + + Players.ChildAdded:Connect(function (child) + if child and Players.LocalPlayer == child then + OnPlayerAdded(Players.LocalPlayer) + end + end) + +end + +------------------------ +---- Main Updater ---- +------------------------ + +do + local tweenAcceleration = math_rad(220) + local tweenSpeed = math_rad(0) + local tweenMaxSpeed = math_rad(250) + local timeBeforeAutoRotate = 2 + + local lastUpdate = tick() + this.LastUserPanCamera = lastUpdate + + + function this:Update() + local now = tick() + local timeDelta = (now - lastUpdate) + + local userPanningTheCamera = (self.UserPanningTheCamera == true) + local camera = workspace.CurrentCamera + local humanoid = self:GetHumanoid() + local cameraSubject = camera and camera.CameraSubject + local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat') + local isOnASkateboard = cameraSubject and cameraSubject:IsA('SkateboardPlatform') + + if isInVehicle and cameraSubject.Occupant == humanoid then + cameraSubject = humanoid + camera.CameraSubject = humanoid + isInVehicle = false + end + + if lastUpdate == nil or (now - lastUpdate) > 1 then + self.LastCameraTransform = nil + end + + if lastUpdate then + local gamepadRotation = self:UpdateGamepad() + + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math_min(0.1, now - lastUpdate) + + if gamepadRotation ~= ZERO_VECTOR2 then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + + local angle = 0 + if not (isInVehicle or isOnASkateboard) then + angle = angle + (self.TurningLeft and -120 or 0) + angle = angle + (self.TurningRight and 120 or 0) + end + + if angle ~= 0 then + self.RotateInput = self.RotateInput + Vector2.new(math_rad(angle * delta), 0) + userPanningTheCamera = true + end + end + + -- Reset tween speed if user is panning + if userPanningTheCamera then + tweenSpeed = 0 + self.LastUserPanCamera = now + end + + local userRecentlyPannedCamera = now - self.LastUserPanCamera < timeBeforeAutoRotate + local subjectPosition = self:GetSubjectPosition() + + if subjectPosition and camera then + local zoom = self:GetCameraZoom() + if zoom < 0.25 then + zoom = 0.25 + end + + if TeleportService:GetTeleportSetting("FollowCamera") then + if self.LastCameraTransform and not self:IsInFirstPerson() then + local lastVec = -(self.LastCameraTransform.p - subjectPosition) + local y = findAngleBetweenXZVectors(lastVec, self:GetCameraLook()) + -- Check for NaNs + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + end + end + + camera.Focus = CFrame_new(subjectPosition) + + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = ZERO_VECTOR2 + + if self.LastZoom ~= zoom then + self.LastZoom = zoom + + if camera.CameraSubject and camera.CameraSubject:IsA("Humanoid") then + -- Flatten the lookVector + newLookVector = (newLookVector * XZ_VECTOR).Unit + + -- Apply upwards tilt + local upY = -math_min(6, zoom/40) + newLookVector = (newLookVector + (UP_VECTOR * upY)).Unit + end + end + + local newCF = CFrame_new(subjectPosition - (zoom * newLookVector), subjectPosition) + camera.CFrame = camera.CFrame:Lerp(newCF,.8) + self.LastCameraTransform = camera.CFrame + end + + lastUpdate = now + end + + GameSettings:SetCameraYInvertVisible() + GameSettings:SetGamepadCameraSensitivityVisible() +end + +return this + + + + + Opacity + -- SolarCrane + +local module = {} + +local LastUpdate = tick() +local TransparencyDirty = false +local Enabled = false +local LastTransparency = nil + +local DescendantAddedConn, DescendantRemovingConn = nil, nil +local ToolDescendantAddedConns = {} +local ToolDescendantRemovingConns = {} +local CachedParts = {} + +local function HasToolAncestor(object) + return (object:FindFirstAncestorWhichIsA("Tool")) ~= nil +end + +local function IsValidPartToModify(part) + if part:IsA('BasePart') or part:IsA('Decal') then + return not HasToolAncestor(part) + end + return false +end + +local function TeardownTransparency() + for child, _ in pairs(CachedParts) do + child.LocalTransparencyModifier = 0 + end + + CachedParts = {} + TransparencyDirty = true + LastTransparency = nil + + if DescendantAddedConn then + DescendantAddedConn:disconnect() + DescendantAddedConn = nil + end + + if DescendantRemovingConn then + DescendantRemovingConn:disconnect() + DescendantRemovingConn = nil + end + + for object, conn in pairs(ToolDescendantAddedConns) do + conn:disconnect() + ToolDescendantAddedConns[object] = nil + end + + for object, conn in pairs(ToolDescendantRemovingConns) do + conn:disconnect() + ToolDescendantRemovingConns[object] = nil + end +end + +local function SetupTransparency(character) + TeardownTransparency() + + if DescendantAddedConn then + DescendantAddedConn:Disconnect() + end + + DescendantAddedConn = character.DescendantAdded:connect(function (object) + -- This is a part we want to invisify + if IsValidPartToModify(object) then + CachedParts[object] = true + TransparencyDirty = true + -- There is now a tool under the character + elseif object:IsA('Tool') then + if ToolDescendantAddedConns[object] then + ToolDescendantAddedConns[object]:Disconnect() + end + + ToolDescendantAddedConns[object] = object.DescendantAdded:connect(function (toolChild) + CachedParts[toolChild] = nil + if toolChild:IsA('BasePart') or toolChild:IsA('Decal') then + -- Reset the transparency + toolChild.LocalTransparencyModifier = 0 + end + end) + + if ToolDescendantRemovingConns[object] then + ToolDescendantRemovingConns[object]:Disconnect() + end + + ToolDescendantRemovingConns[object] = object.DescendantRemoving:connect(function (formerToolChild) + wait() -- wait for new parent + if character and formerToolChild and formerToolChild:IsDescendantOf(character) then + if IsValidPartToModify(formerToolChild) then + CachedParts[formerToolChild] = true + TransparencyDirty = true + end + end + end) + end + end) + + if DescendantRemovingConn then + DescendantRemovingConn:Disconnect() + end + + DescendantRemovingConn = character.DescendantRemoving:connect(function (object) + if CachedParts[object] then + CachedParts[object] = nil + -- Reset the transparency + object.LocalTransparencyModifier = 0 + end + end) + + for _,desc in pairs(character:GetDescendants()) do + if IsValidPartToModify(desc) then + CachedParts[desc] = true + TransparencyDirty = true + end + end +end + + +function module:SetEnabled(newState) + if Enabled ~= newState then + Enabled = newState + self:Update() + end +end + +function module:SetSubject(subject) + local character = nil + if subject and subject:IsA("Humanoid") then + character = subject.Parent + end + if subject and subject:IsA("VehicleSeat") and subject.Occupant then + character = subject.Occupant.Parent + end + if character then + SetupTransparency(character) + else + TeardownTransparency() + end +end + +function module:Update() + local instant = false + local now = tick() + local currentCamera = workspace.CurrentCamera + + if currentCamera then + local transparency = 0 + if not Enabled then + instant = true + else + local distance = (currentCamera.Focus.p - currentCamera.CFrame.p).magnitude + if distance < 2 then + transparency = 1 + elseif distance < 6 then + transparency = 0.5 + else + transparency = 0 + end + end + + if TransparencyDirty or LastTransparency ~= transparency then + for child in pairs(CachedParts) do + if child.ClassName == "Decal" then + child.LocalTransparencyModifier = math.floor(transparency) + else + child.LocalTransparencyModifier = transparency + end + end + TransparencyDirty = false + LastTransparency = transparency + end + end + LastUpdate = now +end + +return module + + + + + Popper + -- PopperCam Version 16 +-- OnlyTwentyCharacters + +local PopperCam = {} -- Guarantees your players won't see outside the bounds of your map! + +----------------- +--| Constants |-- +----------------- + +local POP_RESTORE_RATE = 0.3 +local MIN_CAMERA_ZOOM = 0.5 + +local VALID_SUBJECTS = { + 'Humanoid', + 'VehicleSeat', + 'SkateboardPlatform', +} + +----------------- +--| Variables |-- +----------------- + +local Players = game:GetService('Players') + +local Camera = nil +local CameraSubjectChangeConn = nil + +local SubjectPart = nil + +local PlayerCharacters = {} -- For ignoring in raycasts +local VehicleParts = {} -- Also just for ignoring + +local LastPopAmount = 0 +local LastZoomLevel = 0 +local PopperEnabled = true + +local CFrame_new = CFrame.new + +----------------------- +--| Local Functions |-- +----------------------- + +local math_abs = math.abs + +local function OnCharacterAdded(player, character) + PlayerCharacters[player] = character +end + +local function OnPlayersChildAdded(child) + if child:IsA('Player') then + child.CharacterAdded:connect(function(character) + OnCharacterAdded(child, character) + end) + if child.Character then + OnCharacterAdded(child, child.Character) + end + end +end + +local function OnPlayersChildRemoved(child) + if child:IsA('Player') then + PlayerCharacters[child] = nil + end +end + +------------------------- +--| Exposed Functions |-- +------------------------- + +function PopperCam:Update() + if PopperEnabled then + -- First, prep some intermediate vars + local Camera = workspace.CurrentCamera + local cameraCFrame = Camera.CFrame + local focusPoint = Camera.Focus.p + + if SubjectPart then + focusPoint = SubjectPart.CFrame.p + end + + local ignoreList = {} + for _, character in pairs(PlayerCharacters) do + ignoreList[#ignoreList + 1] = character + end + for i = 1, #VehicleParts do + ignoreList[#ignoreList + 1] = VehicleParts[i] + end + + -- Get largest cutoff distance + local largest = Camera:GetLargestCutoffDistance(ignoreList) + + -- Then check if the player zoomed since the last frame, + -- and if so, reset our pop history so we stop tweening + local zoomLevel = (cameraCFrame.p - focusPoint).Magnitude + if math_abs(zoomLevel - LastZoomLevel) > 0.001 then + LastPopAmount = 0 + end + + -- Finally, zoom the camera in (pop) by that most-cut-off amount, or the last pop amount if that's more + local popAmount = largest + if LastPopAmount > popAmount then + popAmount = LastPopAmount + end + + if popAmount > 0 then + Camera.CFrame = cameraCFrame + (cameraCFrame.lookVector * popAmount) + LastPopAmount = popAmount - POP_RESTORE_RATE -- Shrink it for the next frame + if LastPopAmount < 0 then + LastPopAmount = 0 + end + end + + LastZoomLevel = zoomLevel + end +end + +-------------------- +--| Script Logic |-- +-------------------- + + +-- Connect to all Players so we can ignore their Characters +Players.ChildRemoved:connect(OnPlayersChildRemoved) +Players.ChildAdded:connect(OnPlayersChildAdded) +for _, player in pairs(Players:GetPlayers()) do + OnPlayersChildAdded(player) +end + +return PopperCam + + + + + + Camera + local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") +local Players = game:GetService("Players") + +local playerScripts = script.Parent +local playerModule = require(playerScripts:WaitForChild("PlayerModule")) + +local cameraSystem = playerModule:GetCameras() + +local main = require(script:WaitForChild("Main")) +local popper = require(script:WaitForChild("Popper")) +local opacity = require(script:WaitForChild("Opacity")) + +local cameraSubjectChangedConn = nil +local renderSteppedConn = nil + +local function onCameraSubjectChanged() + local currentCamera = workspace.CurrentCamera + if currentCamera then + local newSubject = currentCamera.CameraSubject + opacity:SetSubject(newSubject) + end +end + +local function onNewCamera() + local currentCamera = workspace.CurrentCamera + if currentCamera then + if cameraSubjectChangedConn then + cameraSubjectChangedConn:Disconnect() + end + + local cameraSubjectChanged = currentCamera:GetPropertyChangedSignal("CameraSubject") + cameraSubjectChangedConn = cameraSubjectChanged:Connect(onCameraSubjectChanged) + + onCameraSubjectChanged() + end +end + +-- Initialize cameras. +local cameraUpdated = workspace:GetPropertyChangedSignal("CurrentCamera") +cameraUpdated:Connect(onNewCamera) + +onNewCamera() +main:SetEnabled(true) +opacity:SetEnabled(true) + +-- Overload the camera update function. +function cameraSystem:Update() + if cameraSystem.activeCameraController then + cameraSystem.activeCameraController:Enable(false) + cameraSystem.activeCameraController = nil + end + + main:Update() + popper:Update() + opacity:Update() +end + +playerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Default) +playerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Default) + + + + + CharacterBevels + + + + + + ClickToMove + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- @CloneTrooper1019, 2018 +-- ClickToMove +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constants +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local ContextActionService = game:GetService("ContextActionService") +local GuiService = game:GetService("GuiService") +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local TeleportService = game:GetService("TeleportService") +local UserInputService = game:GetService("UserInputService") + +local IS_TOUCH = UserInputService.TouchEnabled + +local ICON_IDLE = "rbxassetid://334630296" +local ICON_HOVER = "rbxassetid://1000000" +local ICON_CLICK = "rbxasset://textures/DragCursor.png" + +local DISK_OFFSET = CFrame.Angles(math.pi / 2,0,0) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Character Listener +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local player = game.Players.LocalPlayer +local character,humanoid + +local function onCharacterAdded(char) + humanoid = char:WaitForChild("Humanoid") + character = char +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:Connect(onCharacterAdded) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Gui Focus +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local isMouseHoveringUi = false + +local function onInputChanged(input, gameProcessed) + local inputType = input.UserInputType.Name + + if inputType == "MouseMovement" then + isMouseHoveringUi = gameProcessed + end +end + +local function isGuiFocused() + return isMouseHoveringUi or GuiService.SelectedObject ~= nil +end + +UserInputService.InputChanged:Connect(onInputChanged) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Movement Goal +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local currentGoal, moveSignal + +local function findAngleBetweenXZVectors(vec2, vec1) + return math.atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z) +end + +local function isFinite(num) + return num == num and num ~= 1/0 and num ~= -1/0 +end + +local function rotateCameraTowardsGoal() + local c = workspace.CurrentCamera + if c then + local cf = c.CFrame + local focus = c.Focus + + local desiredAngle = CFrame.new(cf.p,currentGoal).lookVector + local currentAngle = cf.lookVector + + local angleBetween = findAngleBetweenXZVectors(desiredAngle,currentAngle) + + if isFinite(angleBetween) then + local abs = math.abs(angleBetween) + local sign = math.sign(angleBetween) + local rotation = math.min(0.01,abs) + + local cfLocal = focus:toObjectSpace(cf) + c.CFrame = focus * CFrame.Angles(0,-rotation*sign,0) * cfLocal + end + end +end + +local function finishGoal() + if currentGoal then + currentGoal = nil + end + if moveSignal then + moveSignal:Disconnect() + moveSignal = nil + end +end + +local function clickToMove(goal) + finishGoal() + currentGoal = goal + + moveSignal = humanoid.MoveToFinished:Connect(finishGoal) + + humanoid:Move(Vector3.new(1,1,1)) + humanoid:MoveTo(currentGoal) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Green Disk +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mouse = player:GetMouse() +local mouseIcon = script.Parent +mouse.TargetFilter = workspace.CurrentCamera + +local lastTarget +local lastTargetCanClick = false + +local disk = Instance.new("CylinderHandleAdornment") +disk.Name = "Disk" +disk.Color3 = Color3.new(0,1,0) +disk.Radius = 1 +disk.Height = 0.2 +disk.Visible = false +disk.Adornee = workspace.Terrain +disk.Parent = script + +local goalDisk = disk:Clone() +goalDisk.Name = "Goal" +goalDisk.Parent = script + +local function hasTool() + if character then + return character:FindFirstChildOfClass("Tool") ~= nil + end + + return false +end + +local function isFirstPerson() + if character then + local head = character:FindFirstChild("Head") + if head then + return head.LocalTransparencyModifier == 1 + end + end + return false +end + +local function canClickTarget() + local target = mouse.Target + if target then + if target ~= lastTarget then + local canClick = false + local clickDetector = target:FindFirstChildOfClass("ClickDetector") + + if clickDetector then + local dist = player:DistanceFromCharacter(target.Position) + if dist <= clickDetector.MaxActivationDistance then + canClick = true + end + end + + lastTarget = target + lastTargetCanClick = canClick + end + + return lastTargetCanClick + end +end + +local function canRenderDisk(rendering) + if not TeleportService:GetTeleportSetting("ClickToMove") then + return false + end + + if rendering and IS_TOUCH then + return false + end + + if humanoid then + local movement = humanoid.MoveDirection + if movement.Magnitude == 0 then + local pos = mouse.Hit.p + local dist = player:DistanceFromCharacter(pos) + + if dist < 32 then + local blockers = {hasTool, isFirstPerson, canClickTarget, isGuiFocused} + + for _,blocker in pairs(blockers) do + if blocker() then + return false + end + end + + return true + end + else + finishGoal() + end + end + + return false +end + +local function render3dAdorn() + disk.Visible = canRenderDisk(true) + + if disk.Visible then + disk.CFrame = CFrame.new(mouse.Hit.p) * DISK_OFFSET + mouseIcon.Image = ICON_HOVER + elseif canClickTarget() then + mouseIcon.Image = ICON_CLICK + elseif not hasTool() then + mouseIcon.Image = ICON_IDLE + end + + if currentGoal then + goalDisk.Visible = true + goalDisk.CFrame = CFrame.new(currentGoal) * DISK_OFFSET + rotateCameraTowardsGoal() + else + goalDisk.Visible = false + end +end + +RunService.Heartbeat:Connect(render3dAdorn) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Click Action +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function onInputBegan(input,gameProcessed) + local goal = mouse.Hit.p + if not gameProcessed and canRenderDisk() and humanoid then + local name = input.UserInputType.Name + + if name == "MouseButton1" then + clickToMove(goal) + elseif name == "Touch" then + wait(.1) + if input.UserInputState == Enum.UserInputState.End then + clickToMove(goal) + end + elseif name == "Gamepad1" then + if input.KeyCode == Enum.KeyCode.ButtonR2 then + clickToMove(goal) + end + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- OBLITERATE the invasive click to move mode that Roblox provides +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +pcall(function () + if IS_TOUCH then + local playerScripts = player:WaitForChild("PlayerScripts") + local no = function () end + + spawn(function () + local controlScript = playerScripts:WaitForChild("ControlScript", 86400) + if controlScript then + local masterControl = controlScript:WaitForChild("MasterControl") + + local clickToMove = masterControl:WaitForChild("ClickToMoveController") + clickToMove = require(clickToMove) + + clickToMove:Disable() + clickToMove.Enable = no + end + end) + + spawn(function () + local playerModule = playerScripts:WaitForChild("PlayerModule", 86400) + if playerModule then + local controlModule = playerModule:WaitForChild("ControlModule") + + local clickToMove = controlModule:WaitForChild("ClickToMoveController") + clickToMove = require(clickToMove) + + clickToMove:Stop() + clickToMove.Enable = no + end + end) + end +end) + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + ConsoleTweaks + local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +local function addUIScale(obj,scale) + local uiScale = Instance.new("UIScale") + uiScale.Scale = scale + uiScale.Parent = obj +end + +if GuiService:IsTenFootInterface() then + local gui = script.Parent + local zoomControls = gui:WaitForChild("ZoomControls") + zoomControls.Visible = false + + local backpack = gui:WaitForChild("Backpack") + backpack.Position = UDim2.new(0, 0, 1, 0) + + local chat = gui:WaitForChild("Chat") + addUIScale(chat, 1.5) + + local chatPadding = gui:WaitForChild("ChatPadding", 1) + if chatPadding then + chatPadding:Destroy() + end + + local safeChat = gui:WaitForChild("SafeChat") + addUIScale(safeChat, 1.5) + + local health = gui:WaitForChild("Health") + addUIScale(health, 1.5) +end + +wait() +script:Destroy() + + + + + Explosions + local TeleportService = game:GetService("TeleportService") + +local classicExp = script:WaitForChild("ClassicExp") +local c = workspace.CurrentCamera + +local baseExpAdorn = Instance.new("UnionOperation") +baseExpAdorn.Name = "ExplosionAdorn" +baseExpAdorn.Anchored = true +baseExpAdorn.CanCollide = false +baseExpAdorn.Locked = true +baseExpAdorn.Transparency = 1 +baseExpAdorn.Size = Vector3.new() + +local function onDescendantAdded(exp) + if exp:IsA("Explosion") then + local cf = CFrame.new(exp.Position) + local expAdorn = baseExpAdorn:Clone() + local lifeTime = 1.5 + exp.Visible = false + if TeleportService:GetTeleportSetting("RetroExplosions") then + local expObj = Instance.new("SphereHandleAdornment") + expObj.Adornee = expAdorn + expObj.Radius = exp.BlastRadius + expObj.Color3 = Color3.new(1,0,0) + expObj.CFrame = cf + expObj.Parent = expAdorn + lifeTime = 1 + if exp.BlastRadius > 1 then + lifeTime = lifeTime - (1/exp.BlastRadius) + end + else + spawn(function () + local e = classicExp:Clone() + e.Parent = expAdorn + expAdorn.CFrame = cf + local lessParticles = TeleportService:GetTeleportSetting("ReducedParticles") + local count = lessParticles and 25 or 100 + for i = 1,8 do + e:Emit(count) + wait(0.125) + end + end) + end + expAdorn.Parent = c + wait(lifeTime) + expAdorn:Destroy() + end +end + +workspace.DescendantAdded:Connect(onDescendantAdded) + + + + + ForceFields + local RunService = game:GetService("RunService") + +local ffAdorns = workspace:WaitForChild("_ForceFieldAdorns") +local registry = {} +local cycleStates = {} +local cycles = 60 + +local function onChildAdded(child) + if child:IsA("SelectionBox") then + spawn(function () + while not child.Adornee do + child.Changed:Wait() + end + registry[child] = child.Adornee + end) + end +end + +local function onChildRemoved(child) + if registry[child] then + registry[child] = nil + end +end + +local function update() + local now = tick() + for adorn,adornee in pairs(registry) do + local model = adornee:FindFirstAncestorWhichIsA("Model") + local key + if model then + local key = model:GetFullName() + local startTime = cycleStates[key] + if not startTime then + startTime = tick() + cycleStates[key] = startTime + end + local cycle = math.floor(((now-startTime)*2) * cycles) % (cycles*2) + if cycle > cycles then + cycle = cycles - (cycle - cycles) + end + local invertCycle = cycles - cycle + adorn.Color3 = Color3.new(cycle/cycles, 0, invertCycle/cycles) + adorn.Transparency = 0 + end + adorn.Visible = adornee:IsDescendantOf(workspace) and adornee.LocalTransparencyModifier < 1 + end +end + +for _,v in pairs(ffAdorns:GetChildren()) do + onChildAdded(v) +end + +RunService.Heartbeat:Connect(update) +ffAdorns.ChildAdded:Connect(onChildAdded) +ffAdorns.ChildRemoved:Connect(onChildRemoved) + + + + + GamepadPatch + -- Seriously Roblox? + +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") + +local player = Players.LocalPlayer +local playerScripts = player:WaitForChild("PlayerScripts") + +local playerModule = playerScripts:WaitForChild("PlayerModule") +local controlModule = playerModule:WaitForChild("ControlModule") +local gamepad = require(controlModule:WaitForChild("Gamepad")) + +playerModule = require(playerModule) +controlModule = playerModule:GetControls() + +local function fixGamepad() + local lastInputType = UserInputService:GetLastInputType() + + if lastInputType.Name == "Gamepad1" then + local controllers = controlModule.controllers + + if controlModule.activeController ~= controllers[gamepad] then + controlModule:SwitchToController(gamepad) + end + end +end + +RunService:BindToRenderStep("GamepadPatch", 0, fixGamepad) + + + + + HumanoidLabels + local humanoids = {} +local player = game.Players.LocalPlayer +local pgui = player:WaitForChild("PlayerGui") +local healthBase = script:WaitForChild("Health") +local rs = game:GetService("RunService") + +local farStudsOffset = Vector3.new(0,2,0) +local closeStudsOffset = Vector3.new(0,1,0) + +local farSize = UDim2.new(0,50,0,20) +local closeSize = UDim2.new(0,100,0,30) + +local function isFinite(num) + return num == num and num ~= -1/0 and num ~= 1/0 +end + +local function setupHumanoid(h) + local updateCon = nil + local currentHealth = nil + + local function onAncestryChanged() + if updateCon then + updateCon:disconnect() + updateCon = nil + end + + if currentHealth then + currentHealth:Destroy() + currentHealth = nil + end + + local char = h.Parent + + if char then + while not char:FindFirstChild("Head") do + if h.Parent ~= char then break end + char.ChildAdded:wait() + end + + local head = char:FindFirstChild("Head") + + if head then + local health = healthBase:Clone() + local playerName = health:WaitForChild("PlayerName") + local redBar = health:WaitForChild("RedBar") + local greenBar = redBar:WaitForChild("GreenBar") + local inOverWrite = false + local overWriter = nil + + local hPlayer = game.Players:GetPlayerFromCharacter(char) + playerName.Text = char.Name + health.Adornee = head + health.PlayerToHideFrom = hPlayer + health.Parent = head + + local c = workspace.CurrentCamera + + local function update() + local dist = (c.CFrame.p - head.Position).magnitude + local fontSize = 12 + + if dist < 20 then + fontSize = 24 + elseif dist < 50 then + fontSize = 18 + end + + local ratio = h.Health / h.MaxHealth + redBar.Visible = isFinite(ratio) + redBar.BackgroundTransparency = math.floor(ratio) + redBar.Size = UDim2.new(0, fontSize * 4, 0, fontSize / 2) + greenBar.Size = UDim2.new(ratio, 0, 1, 0) + + local width = fontSize * 4 + health.Size = UDim2.new(0, width, 0, fontSize) + health.Enabled = (dist <= 100 and head.Transparency < 1) + health.StudsOffsetWorldSpace = Vector3.new(0, 1.5, 0) + + if hPlayer and game:FindService("Teams") then + playerName.TextColor = hPlayer.TeamColor + else + playerName.TextColor3 = Color3.new(1, 1, 1) + end + + local overWriter = char:FindFirstChild("NameOverwrite") + if overWriter and overWriter:IsA("StringValue") then + playerName.Text = overWriter.Value + else + playerName.Text = char.Name + end + end + + updateCon = rs.RenderStepped:Connect(update) + currentHealth = health + h.DisplayDistanceType = "None" + end + end + end + onAncestryChanged() + h.AncestryChanged:Connect(onAncestryChanged) +end + +local function recurse(obj) + for _,v in pairs(obj:GetChildren()) do + if v:IsA("Humanoid") then + humanoids[v] = true + else + recurse(v) + end + end +end + +recurse(workspace) + +for h in pairs(humanoids) do + humanoids[h] = true + + spawn(function () + setupHumanoid(h) + end) +end + +local function onDescendantAdded(child) + if child:IsA("Humanoid") then + humanoids[child] = true + setupHumanoid(child) + end +end + +local function onDescendantRemoved(child) + if humanoids[child] then + humanoids[child] = nil + end +end + +recurse(workspace) + +workspace.DescendantAdded:connect(onDescendantAdded) +workspace.DescendantRemoving:connect(onDescendantRemoved) + + + + Health + false + null + true + true + + true + false + 0 + 0 + -1 + true + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 0 + INF + null + true + null + + 0 + 96 + 0 + 24 + + + 0 + 0 + + + 0 + 0 + 0 + + + 0 + 1.5 + 0 + + + 0 + + + + PlayerName + false + + 0.5 + 0.75 + + true + + true + + 1 + 1 + 1 + + 1 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 1 + false + false + 9 + 0 + 1 + null + null + null + null + + 0.5 + 0 + 0 + 0 + + null + 0 + false + null + + 10 + 0 + 1 + 0 + + 0 + + CloneTrooper1019 + + 1 + 1 + 1 + + true + 24 + + 0 + 0 + 0 + + 0 + 0 + 0 + true + 2 + 1 + true + 1 + + + + + RedBar + false + + 0.5 + 0.5 + + true + + true + + 1 + 0 + 0 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + false + null + + 0.6000000238418579 + 0 + 0.30000001192092896 + 0 + + 0 + 0 + + true + 1 + + + + GreenBar + false + + 0 + 0 + + true + + true + + 0.5058823823928833 + 0.7725490927696228 + 0.08627451211214066 + + 0 + + 0.10588239878416061 + 0.16470590233802795 + 0.20784319937229156 + + 0 + 0 + false + false + 0 + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + + + + + InputGateway + local UserInputService = game:GetService("UserInputService") +local ContextActionService = game:GetService("ContextActionService") +local Debris = game:GetService("Debris") + +local gateway = script.Parent +local tool = gateway.Parent +local remote = gateway:WaitForChild("Gateway") +local player = game.Players.LocalPlayer +local mouse = player:GetMouse() +local isActive = false + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Standard Input +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function activate(active,cf) + isActive = active + remote:FireServer("SetActive",active,cf) + while isActive do + wait(.1) + remote:FireServer("SetTarget",mouse.Hit) + end +end + +local function onKey(input) + local keyCode = input.KeyCode.Name + local down = (input.UserInputState.Name == "Begin") + remote:FireServer("KeyEvent",keyCode,down) +end + +local function onInputBegan(input,gameProcessed) + if not gameProcessed then + local name = input.UserInputType.Name + if name == "MouseButton1" then + activate(true,mouse.Hit) + elseif name == "Touch" then + wait(.1) + local state = input.UserInputState.Name + if state == "End" or state == "Cancel" then + activate(true,mouse.Hit) + end + elseif name == "Gamepad1" then + local keyCode = input.KeyCode.Name + if keyCode == "ButtonR2" then + activate(true,mouse.Hit) + end + elseif name == "Keyboard" then + onKey(input) + end + end +end + +local function onInputEnded(input,gameProcessed) + if not gameProcessed and isActive then + local name = input.UserInputType.Name + if name == "MouseButton1" or name == "Touch" or name == "Gamepad1" then + activate(false,mouse.Hit) + elseif name == "Keyboard" then + onKey(input) + end + end +end + +UserInputService.InputBegan:Connect(onInputBegan) +UserInputService.InputEnded:Connect(onInputEnded) + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Special case Input +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local mControlScheme = tool:WaitForChild("ControlScheme",5) + +if mControlScheme then + local controlSchemeData = require(mControlScheme) + local controlScheme = controlSchemeData.Buttons + local activateContext = controlSchemeData.ActivateContext + local keyEvent = tool:WaitForChild("KeyEvent") + local callbacks = {} + + local hands = { L = "Left", R = "Right" } + local handTypes = {"Bumper","Trigger","Joystick (Press)"} + + local schemeDocs = + { + Keyboard = {"Hold Left Mouse Button - " .. activateContext}; + Gamepad = {"Hold Right Trigger - " .. activateContext}; + } + + for key,data in pairs(controlScheme) do + local down = false + callbacks[key] = function (actionName,inputState,inputObject) + if (inputState.Name == "Begin") and not down then + down = true + if data.Client then + keyEvent:Fire(key,true) + else + remote:FireServer("KeyEvent",key,true) + end + elseif (inputState.Name == "End") and down then + down = false + if data.Client then + keyEvent:Fire(key,false) + else + remote:FireServer("KeyEvent",key,false) + end + end + end + + local xBtn = data.XboxButton:gsub("Button","") + if #xBtn == 2 then + local handId,hTypeId = xBtn:match("(%u)(%d)") + local hand = hands[handId] + local hType = handTypes[tonumber(hTypeId)] + xBtn = hand .. " " .. hType + else + xBtn = "(" .. xBtn .. ")" + end + table.insert(schemeDocs.Keyboard,key .. " - " .. data.Label) + table.insert(schemeDocs.Gamepad,xBtn .. " - " .. data.Label) + end + + local currentSchemeDocMsg + + local function onLastInputTypeChanged(inputType) + if currentSchemeDocMsg and not UserInputService.TouchEnabled and not controlSchemeData.HideControls then + local schemeDoc + if inputType.Name:find("Gamepad") then + schemeDoc = "Gamepad" + else + schemeDoc = "Keyboard" + end + currentSchemeDocMsg.Text = schemeDoc .. " Controls:\n\n" .. table.concat(schemeDocs[schemeDoc],"\n") + end + end + + local diedCon + local equipped = false + + local function onUnequipped() + if equipped then + equipped = false + for key,data in pairs(controlScheme) do + ContextActionService:UnbindAction(data.Label) + end + currentSchemeDocMsg:Destroy() + currentSchemeDocMsg = nil + end + end + + local function onEquipped() + if not equipped then + equipped = true + for key,data in pairs(controlScheme) do + ContextActionService:BindAction(data.Label,callbacks[key],true,Enum.KeyCode[data.XboxButton]) + ContextActionService:SetTitle(data.Label,data.Label) + end + if UserInputService.TouchEnabled then + spawn(function () + local playerGui = player:WaitForChild("PlayerGui") + local contextActionGui = playerGui:WaitForChild("ContextActionGui") + local contextButtonFrame = contextActionGui:WaitForChild("ContextButtonFrame") + contextButtonFrame.Size = UDim2.new(3/8,0,3/8,0) + contextButtonFrame.AnchorPoint = Vector2.new(1,1) + contextButtonFrame.Position = UDim2.new(1,0,1,0) + end) + end + currentSchemeDocMsg = Instance.new("Message") + currentSchemeDocMsg.Parent = player + onLastInputTypeChanged(UserInputService:GetLastInputType()) + if not diedCon then + local char = tool.Parent + if char then + local humanoid = char:FindFirstChildWhichIsA("Humanoid") + if humanoid then + diedCon = humanoid.Died:Connect(onUnequipped) + end + end + end + end + end + + tool.Equipped:Connect(onEquipped) + tool.Unequipped:Connect(onUnequipped) + UserInputService.LastInputTypeChanged:Connect(onLastInputTypeChanged) +end + + + + + Music + local TeleportService = game:GetService("TeleportService") +local gameMusic = workspace:WaitForChild("GameMusic",10) +if gameMusic and TeleportService:GetTeleportSetting("AllowMusic") then + gameMusic:Play() +end + + + + + Shared + local TARGET = script.Name + +do + local ReplicatedStorage = game:GetService("ReplicatedStorage") + local client = ReplicatedStorage:WaitForChild("Client") + local targetScript = client:WaitForChild(TARGET) + local activation = require(targetScript) + activation(script) +end + + + + + ToolSoundGlitch + local CollectionService = game:GetService("CollectionService") +local TeleportService = game:GetService("TeleportService") + +local function onGlitchSoundAdded(glitchSound) + if TeleportService:GetTeleportSetting("SoundEquipBug") then + glitchSound.MaxDistance = 10000 + glitchSound:Play() + end +end + +local addSignal = CollectionService:GetInstanceAddedSignal("ToolSoundGlitch") +addSignal:Connect(onGlitchSoundAdded) + + + + + ZoomControls + local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +if GuiService:IsTenFootInterface() then + return +end + +local IS_TOUCH = UserInputService.TouchEnabled + +local player = game.Players.LocalPlayer +local playerScripts = player:WaitForChild("PlayerScripts") +local passCameraEvent = playerScripts:WaitForChild("PassCameraEvent") + +local self = script.Parent +local zoomIn = self:WaitForChild("ZoomIn") +local zoomLock = zoomIn:WaitForChild("Lock") +local firstPersonIndicator = self:WaitForChild("FirstPersonIndicator") + +local yellow = Color3.new(1,1,0) +local cyan = Color3.new(0,1,1) +local white = Color3.new(1,1,1) + +local c = workspace.CurrentCamera +local currentlyDown + +local function updateCameraStatus() + local dist = (c.Focus.p - c.CFrame.p).magnitude + firstPersonIndicator.Visible = (dist <= 1.5) + zoomLock.Visible = (dist <= 1) +end + +local function setupButton(btn) + local isDown = false + local inBounds = false + local lock = btn:FindFirstChild("Lock") + local mouse = player:GetMouse() + btn.MouseEnter:connect(function () + if (lock == nil or not lock.Visible) then + if (currentlyDown == nil or currentlyDown == btn) then + inBounds = true + if isDown then + btn.ImageColor3 = yellow + else + btn.ImageColor3 = cyan + end + end + end + end) + btn.MouseLeave:connect(function () + if (lock == nil or not lock.Visible) then + inBounds = false + if isDown then + btn.ImageColor3 = cyan + else + btn.ImageColor3 = white + end + end + end) + btn.MouseButton1Down:connect(function () + if (lock == nil or not lock.Visible) then + isDown = true + currentlyDown = btn + btn.ImageColor3 = yellow + end + end) + btn.MouseButton1Click:connect(function () + if (lock == nil or not lock.Visible) then + isDown = false + currentlyDown = nil + inBounds = false + passCameraEvent:Fire(btn.Name) + if IS_TOUCH then + btn.ImageColor3 = white + end + end + end) + mouse.Button1Up:connect(function () + if (lock == nil or not lock.Visible) then + if isDown then + isDown = false + currentlyDown = nil + if inBounds then + inBounds = false + passCameraEvent:Fire(btn.Name) + end + end + end + btn.ImageColor3 = white + end) + if lock then + lock.Changed:connect(function () + if lock.Visible then + btn.ImageColor3 = white + isDown = false + if currentlyDown == btn then + currentlyDown = nil + end + end + end) + end + if IS_TOUCH then + btn.Modal = true + end +end + +for _,v in pairs(script.Parent:GetChildren()) do + if v:IsA("ImageButton") then + setupButton(v) + end +end + +c.Changed:connect(updateCameraStatus) + + + + + \ No newline at end of file diff --git a/Tools/Models/JetBoots.rbxmx b/Tools/Models/JetBoots.rbxmx new file mode 100644 index 0000000..1596d01 --- /dev/null +++ b/Tools/Models/JetBoots.rbxmx @@ -0,0 +1,32 @@ + + + + + true + true + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + JetBoots + false + + + rbxasset://Textures/Rocketboots.png + + + true + + + \ No newline at end of file diff --git a/Tools/Models/Multirocket.rbxmx b/Tools/Models/Multirocket.rbxmx new file mode 100644 index 0000000..51a4867 --- /dev/null +++ b/Tools/Models/Multirocket.rbxmx @@ -0,0 +1,76 @@ + + + + + true + true + + 0.7 + 0 + -0.5 + 0 + 0 + -1 + -1 + 0 + 0 + 0 + 1 + 0 + + false + Multirocket + false + + + rbxasset://Textures/Multirocket.png + + + true + + + + + 10 + true + Swoosh + false + 1 + false + 0 + null + + rbxasset://sounds/Rocket whoosh 01.wav + + + 0 + 0.7 + 10000 + 10 + true + + + + + + 10 + false + Explosion + false + 1 + false + 0 + null + + rbxasset://sounds/collide.wav + + + 0 + 1 + 10000 + 10 + true + + + + \ No newline at end of file diff --git a/Tools/Models/PaintballGun.rbxmx b/Tools/Models/PaintballGun.rbxmx new file mode 100644 index 0000000..3bf9e28 --- /dev/null +++ b/Tools/Models/PaintballGun.rbxmx @@ -0,0 +1,163 @@ + + + + + true + true + + -0.4 + -0.5 + -0.07 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + false + PaintballGun + true + + + rbxasset://Textures/PaintballIcon.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 488.7946 + 3.313973 + 438.8193 + -0.3090168 + 0.9510567 + 0 + 0 + 0 + -1 + -0.9510566 + -0.3090168 + 0 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 3 + 2 + 1 + + true + + + + + 10 + false + Fire + false + 1 + false + 0 + null + + rbxasset://sounds//paintball.wav + + + 0 + 1 + 10000 + 10 + true + + + + + + 2 + 2 + + rbxassetid://998137795 + + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + rbxasset://textures/PaintballGunTex128.png + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Plane.rbxmx b/Tools/Models/Plane.rbxmx new file mode 100644 index 0000000..4d9dbad --- /dev/null +++ b/Tools/Models/Plane.rbxmx @@ -0,0 +1,171 @@ + + + + + true + false + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + Plane + false + + + + + + true + + + + + IconOverride + + rbxassetid://1067894989 + true + + + + + true + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + -561.6701 + 6.200422 + -528.76 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + -1 + + true + true + 0 + 4279970357 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + false + 256 + Rocket + 0.2 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 1 + 2 + + true + + + + + Owner + + null + true + + + + + + 10 + false + Explosion + true + 1 + false + 0 + null + + rbxasset://sounds/collide.wav + + + 0 + 1 + 10000 + 10 + true + + + + + + 10 + true + Swoosh + false + 1 + false + 0 + null + + rbxasset://sounds/Rocket whoosh 01.wav + + + 0 + 0.7 + 10000 + 10 + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Reset.rbxmx b/Tools/Models/Reset.rbxmx new file mode 100644 index 0000000..17c6083 --- /dev/null +++ b/Tools/Models/Reset.rbxmx @@ -0,0 +1,41 @@ + + + + + true + true + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + Reset + false + + + + + + true + + + + + IconOverride + + rbxassetid://1000000 + true + + + + \ No newline at end of file diff --git a/Tools/Models/RocketLauncher.rbxmx b/Tools/Models/RocketLauncher.rbxmx new file mode 100644 index 0000000..97dacf4 --- /dev/null +++ b/Tools/Models/RocketLauncher.rbxmx @@ -0,0 +1,185 @@ + + + + + true + true + + 0.7 + 0 + -0.5 + 0 + 0 + -1 + -1 + 0 + 0 + 0 + 1 + 0 + + false + RocketLauncher + true + + + rbxasset://Textures/Rocket.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 416.4301 + 1.621786 + 446.26 + 1 + 0 + 0 + 0 + 6.301701E-05 + 1 + 0 + -1 + 6.301701E-05 + + false + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 4.920006 + 0.7400005 + 0.8399998 + + true + + + + + 2 + 2 + + rbxasset://fonts/rocketlauncher.mesh + + 5 + Mesh + + 0 + 0 + 0 + + + 0.75 + 0.75 + 0.75 + + + + rbxasset://textures/rocketlaunchertex.png + + + 1 + 1 + 1 + + true + + + + + + + 10 + false + Explosion + false + 1 + false + 0 + null + + rbxasset://sounds/collide.wav + + + 0 + 1 + 10000 + 10 + true + + + + + + 10 + true + Swoosh + false + 1 + false + 0 + null + + rbxasset://sounds/Rocket whoosh 01.wav + + + 0 + 0.7 + 10000 + 10 + true + + + + \ No newline at end of file diff --git a/Tools/Models/Slingshot.rbxmx b/Tools/Models/Slingshot.rbxmx new file mode 100644 index 0000000..c9528ce --- /dev/null +++ b/Tools/Models/Slingshot.rbxmx @@ -0,0 +1,163 @@ + + + + + true + true + + 0 + -0.7 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + Slingshot + true + + + rbxasset://Textures/Slingshot.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 421.4299 + 3.221793 + 416.7602 + 1 + 0 + -5.545024E-06 + 0 + 1 + 0 + 5.545024E-06 + 0 + 1 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 1 + 1 + + 2 + 2.4 + 1 + + true + + + + + 10 + false + SlingshotSound + false + 1 + false + 0 + null + + rbxasset://sounds//Rubber band sling shot.mp3 + + + 0 + 1 + 10000 + 10 + true + + + + + + 2 + 2 + + rbxasset://fonts/slingshot.mesh + + 5 + Mesh + + 0 + 0 + 0 + + + 0.5 + 0.5 + 0.5 + + + + rbxasset://textures/SlingshotTexture.png + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Superball.rbxmx b/Tools/Models/Superball.rbxmx new file mode 100644 index 0000000..f4cca0f --- /dev/null +++ b/Tools/Models/Superball.rbxmx @@ -0,0 +1,136 @@ + + + + + true + true + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + Superball + true + + + rbxasset://Textures/Superball.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 393.3251 + 6.242048 + 433.0556 + -0.3313951 + 0.000743661 + -0.9434918 + -1.846121E-06 + 0.9999996 + 0.000788849 + 0.943492 + 0.0002631625 + -0.331395 + + true + true + 0 + 4291045404 + + true + 0.7 + 0 + 1 + 1 + 1 + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0.2 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 0 + + 2 + 2 + 2 + + true + + + + + 10 + false + Boing + false + 1 + false + 0 + null + + rbxasset://sounds//short spring sound.wav + + + 0 + 1 + 10000 + 10 + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Sword.rbxmx b/Tools/Models/Sword.rbxmx new file mode 100644 index 0000000..f4181f0 --- /dev/null +++ b/Tools/Models/Sword.rbxmx @@ -0,0 +1,207 @@ + + + + + true + true + + 0 + 0 + -1.5 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + 0 + + false + Sword + true + + + rbxasset://Textures/Sword128.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 355.9418 + 59.54162 + 392.76 + 5.960464E-08 + -8.921718E-19 + -0.9999999 + -5.904603E-18 + 1 + -8.921718E-19 + 0.9999999 + 5.904603E-18 + 5.960464E-08 + + true + true + 0 + 4284702562 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0.4 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 2 + 1 + + 1 + 0.8 + 4 + + true + + + + + 10 + false + Sound + false + 1 + false + 0 + null + + rbxasset://sounds/unsheath.wav + + + 0 + 1 + 10000 + 10 + true + + + + + + 10 + false + Sound + false + 1 + false + 0 + null + + rbxasset://sounds/swordlunge.wav + + + 0 + 0.6 + 10000 + 10 + true + + + + + + 10 + false + Sound + false + 1 + false + 0 + null + + rbxasset://sounds/swordslash.wav + + + 0 + 0.7 + 10000 + 10 + true + + + + + + 2 + 2 + + rbxasset://fonts/sword.mesh + + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + rbxasset://textures/SwordTexture.png + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Timebomb.rbxmx b/Tools/Models/Timebomb.rbxmx new file mode 100644 index 0000000..58ac51c --- /dev/null +++ b/Tools/Models/Timebomb.rbxmx @@ -0,0 +1,141 @@ + + + + + true + true + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + + false + Timebomb + true + + + rbxasset://Textures/Bomb.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 400.0722 + 6.221753 + 383.565 + -0.9999679 + -0.007971467 + -6.34748E-06 + -3.721468E-12 + -0.0007962743 + 0.9999996 + -0.007971469 + 0.9999677 + 0.0007962488 + + true + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 0 + + 2 + 2 + 2 + + true + + + + + 2 + 2 + + rbxasset://fonts/timebomb.mesh + + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + rbxasset://textures/bombtex.png + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Models/Trowel.rbxmx b/Tools/Models/Trowel.rbxmx new file mode 100644 index 0000000..4a24a36 --- /dev/null +++ b/Tools/Models/Trowel.rbxmx @@ -0,0 +1,163 @@ + + + + + true + true + + 0 + -1.3 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + Trowel + true + + + rbxasset://Textures/Wall.png + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 452.9303 + 2.522889 + 429.0599 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + 0 + + true + true + 0 + 4292330906 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 2 + 1 + + 1 + 4.4 + 1 + + true + + + + + 10 + false + BuildSound + false + 1 + false + 0 + null + + rbxasset://sounds//bass.wav + + + 0 + 1 + 10000 + 10 + true + + + + + + 2 + 2 + + rbxasset://fonts/trowel.mesh + + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + rbxasset://textures/TrowelTexture.png + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Scripts/GravityHammer/GravityHammer.rbxmx b/Tools/Scripts/GravityHammer/GravityHammer.rbxmx new file mode 100644 index 0000000..7de8632 --- /dev/null +++ b/Tools/Scripts/GravityHammer/GravityHammer.rbxmx @@ -0,0 +1,163 @@ + + + + + false + true + + 0 + 0 + -3.25 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + 0 + + false + GravityHammer + true + + + http://www.roblox.com/asset/?id=1256305 + + + true + + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 433.6435 + 11.72512 + 424.1967 + -0.9932989 + 0.114088 + 0.01847253 + 0.01858202 + -0.0001038264 + 0.9998273 + 0.1140701 + 0.9934707 + -0.002016852 + + true + true + 0 + 4284702562 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + Handle + 0.4 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 2 + 1 + + 1 + 0.8 + 10 + + true + + + + + 10 + false + Sound + false + 1 + false + 0 + null + + http://www.roblox.com/asset/?id=1255794 + + + 0 + 1 + 10000 + 10 + true + + + + + + 2 + 2 + + http://www.roblox.com/asset/?id=1256290 + + 5 + Mesh + + 0 + 0 + 0 + + + 0.05 + 0.05 + 0.05 + + + + http://www.roblox.com/asset/?id=1256283 + + + 1 + 1 + 1 + + true + + + + + \ No newline at end of file diff --git a/Tools/Scripts/GravityHammer/SwordScript.server.lua b/Tools/Scripts/GravityHammer/SwordScript.server.lua new file mode 100644 index 0000000..53b34a6 --- /dev/null +++ b/Tools/Scripts/GravityHammer/SwordScript.server.lua @@ -0,0 +1,158 @@ +--Made by Luckymaxer + +Tool = script.Parent +Handle = Tool:WaitForChild("Handle") + +Sound = Handle:WaitForChild("Sound") + +Players = game:GetService("Players") +Debris = game:GetService("Debris") + +Debounce = false + +Tool.Enabled = true + +local function spawnSound(s) + local sound = s:Clone() + sound.Parent = s.Parent + sound:Play() + sound.Ended:Connect(function () + sound:Destroy() + end) +end +function TagHumanoid(humanoid, player) + local Creator_Tag = Instance.new("ObjectValue") + Creator_Tag.Name = "creator" + Creator_Tag.Value = player + Debris:AddItem(Creator_Tag, 2) + Creator_Tag.Parent = humanoid +end + +function UntagHumanoid(humanoid) + for i, v in pairs(humanoid:GetChildren()) do + if v:IsA("ObjectValue") and v.Name == "creator" then + v:Destroy() + end + end +end + +function FindCharacterAncestor(Parent) + if Parent and Parent ~= game:GetService("Workspace") then + local humanoid = Parent:FindFirstChild("Humanoid") + if humanoid then + return Parent, humanoid + else + return FindCharacterAncestor(Parent.Parent) + end + end + return nil +end + +function Blow(Hit) + RightGrip = RightGrip:Clone() + if Hit and Hit.Parent then + local humanoid = Hit.Parent:FindFirstChild("Humanoid") + if humanoid == Humanoid then + return + end + if humanoid then + Propel(Hit) + UntagHumanoid(humanoid) + TagHumanoid(humanoid, Player) + humanoid.Health = humanoid.Health - 49 + else + Explode(Hit) + end + end +end + +function Propel(Part) + if not Part or not Part.Parent or Part.Anchored then + return + end + local character, humanoid = FindCharacterAncestor(Part) + if character == Character then + return + end + local Direction = (Part.Position - Torso.Position).unit + Direction = Direction + Vector3.new(0, 1, 0) + Direction = Direction * 200 + Part.Velocity = Part.Velocity + Direction +end + +function Explode(Part) + if not Part or not Part.Parent or Debounce then + return + end + Debounce = true + local Direction = (Part.Position - Torso.Position).unit + local Position = Direction * 12 + Torso.Position + local Explosion = Instance.new("Explosion") + Explosion.ExplosionType = Enum.ExplosionType.NoCraters + Explosion.BlastRadius = 4 + Explosion.BlastPressure = 1 + Explosion.Position = Position + Explosion.Hit:connect(function(Part, Distance) + Propel(Part) + end) + local owner = Instance.new("ObjectValue") + owner.Name = "Owner" + owner.Value = Player + owner.Parent = Explosion + Explosion.Parent = game:GetService("Workspace") + wait(0.1) + local GripClone = RightGrip:Clone() + GripClone.Parent = RightArm + Debounce = false +end + +function Attack() + spawnSound(Sound) + local Anim = Instance.new("StringValue") + Anim.Name = "toolanim" + Anim.Value = "Slash" + Debris:AddItem(Anim, 2) + Anim.Parent = Tool +end + +function Lunge() + Attack() + local Force = Instance.new("BodyPosition") + Force.maxForce = Vector3.new(1e+005, 1e+004, 1e+005) + local Direction = Humanoid.targetPoint + if ((Direction - Handle.Position).magnitude > 15) then + return + end + Force.position = Direction + Debris:AddItem(Force, 0.25) + Force.Parent = Handle +end + +function Activated() + if not Tool.Enabled or not Humanoid.Parent or Humanoid.Health == 0 or not Torso.Parent or not RightArm.Parent or not RightGrip then + return + end + Tool.Enabled = false + connection = Handle.Touched:connect(Blow) + Lunge() + wait(0.4) + connection:disconnect() + Tool.Enabled = true +end + +function Equipped() + Character = Tool.Parent + Player = Players:GetPlayerFromCharacter(Character) + Humanoid = Character:FindFirstChild("Humanoid") + Torso = Character:FindFirstChild("Torso") + RightArm = Character:FindFirstChild("Right Arm") + if RightArm then + RightGrip = RightArm:WaitForChild("RightGrip",1) + end + if not Player or not Humanoid or Humanoid.Health == 0 or not Torso or not RightArm or not RightGrip then + return + end +end + +Tool.Activated:connect(Activated) +Tool.Equipped:connect(Equipped) \ No newline at end of file diff --git a/Tools/Scripts/JetBoots/Jetboots.server.lua b/Tools/Scripts/JetBoots/Jetboots.server.lua new file mode 100644 index 0000000..2de58f6 --- /dev/null +++ b/Tools/Scripts/JetBoots/Jetboots.server.lua @@ -0,0 +1,76 @@ +print("Jet Boots loaded") + +bin = script.Parent + +walking = false +reloadtime = 0 + +local thrust = Instance.new("BodyVelocity") +local velocity = 0 +local max_velocity = 30 +local flight_time = 6 +local localPlayer + + + +function onStart() + local char = localPlayer.Character + local head = char:WaitForChild("Head") + + print("start walking") + walking = true + reloadtime = 8.0 + + thrust.Parent = head + + thrust.velocity = Vector3.new(0,velocity,0) + thrust.maxForce = Vector3.new(0,4e+003,0) + + local sound = head:findFirstChild("JetbootSound") + if sound == nil then + sound = Instance.new("Sound") + sound.Name = "JetbootSound" + sound.SoundId = "rbxasset://sounds\\Rocket whoosh 01.wav" + sound.Looped = true + sound.Parent = head + end + sound:play() + +end + +function onDeactivated() + print("stop walking") + local char = localPlayer.Character + local head = char:WaitForChild("Head") + walking = false + thrust.Parent = nil + local sound = head:findFirstChild("JetbootSound") + if sound ~= nil then sound:stop() end + bin.Enabled = false + wait(reloadtime) + bin.Enabled = true + reloadtime = 0 +end + +function onActivated() + local char = bin.Parent + localPlayer = game.Players:GetPlayerFromCharacter(char) + if not localPlayer then return end + if reloadtime > 0 then return end + if walking then return end + + onStart() + + local time = 0 + while walking do + wait(.2) + time = time + .2 + velocity = (max_velocity * (time / flight_time)) + 3 + thrust.velocity = Vector3.new(0,velocity,0) + + if time > flight_time then onDeactivated() end + end +end + +bin.Activated:Connect(onActivated) +bin.Deactivated:Connect(onDeactivated) \ No newline at end of file diff --git a/Tools/Scripts/Multirocket/RocketScript.server.lua b/Tools/Scripts/Multirocket/RocketScript.server.lua new file mode 100644 index 0000000..b2678fa --- /dev/null +++ b/Tools/Scripts/Multirocket/RocketScript.server.lua @@ -0,0 +1,71 @@ +r = game:service("RunService") + +shaft = script.Parent +position = Vector3.new(0,0,0) +debris = game:GetService("Debris") + +function tagHumanoid(humanoid) + -- todo: make tag expire + local tag = shaft:findFirstChild("creator") + if tag ~= nil then + -- kill all other tags + while(humanoid:findFirstChild("creator") ~= nil) do + humanoid:findFirstChild("creator").Parent = nil + end + + local new_tag = tag:clone() + new_tag.Parent = humanoid + debris:AddItem(new_tag, 1) + end +end + +local function onExplosionHit(hit) + local char = hit.Parent + if char then + local humanoid = char:FindFirstChild("Humanoid") + if humanoid then + tagHumanoid(humanoid) + end + end +end + +function fly() + direction = shaft.CFrame.lookVector + position = position + direction + error = position - shaft.Position + shaft.Velocity = 7*error +end + +function blow() + swoosh:Stop() + explosion = Instance.new("Explosion") + explosion.Position = shaft.Position + explosion.Parent = game.Workspace + explosion.Hit:Connect(onExplosionHit) + connection:disconnect() + shaft.Explosion:Play() + shaft.Anchored = true + shaft.CanCollide = false + shaft.Transparency = 1 + + shaft.Explosion:Play() + shaft.Explosion.Ended:Wait() + shaft:Destroy() +end + +t, s = r.Stepped:wait() + +swoosh = script.Parent.Swoosh +swoosh:Play() + +position = shaft.Position +d = t + 10.0 - s +connection = shaft.Touched:connect(blow) + +while t < d do + fly() + t = r.Stepped:wait() +end + +swoosh:Stop() +shaft:remove() diff --git a/Tools/Scripts/Multirocket/ServerLauncher.server.lua b/Tools/Scripts/Multirocket/ServerLauncher.server.lua new file mode 100644 index 0000000..d01eb1c --- /dev/null +++ b/Tools/Scripts/Multirocket/ServerLauncher.server.lua @@ -0,0 +1,93 @@ +local Rocket = Instance.new("Part") +local Tool = script.Parent + +Rocket.Locked = true +Rocket.BackSurface = 3 +Rocket.BottomSurface = 3 +Rocket.FrontSurface = 3 +Rocket.LeftSurface = 3 +Rocket.RightSurface = 3 +Rocket.TopSurface = 3 +Rocket.Size = Vector3.new(1,1,4) +Rocket.BrickColor = BrickColor.Red() + +Tool.RocketScript:clone().Parent = Rocket +Tool.Explosion:clone().Parent = Rocket +Tool.Swoosh:clone().Parent = Rocket + + +function fire(vTarget) + + local vCharacter = Tool.Parent; + + local vHandle = vCharacter:findFirstChild("Head") + if vHandle == nil then + print("Handle not found") + return + end + + local dir = vTarget - vHandle.Position + + dir = computeDirection(dir) + + local missile = Rocket:clone() + + local pos = vHandle.Position + (dir * 6) + + --missile.Position = pos + missile.CFrame = CFrame.new(pos, pos + dir) + + local creator_tag = Instance.new("ObjectValue") + + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + if vPlayer == nil then + print("Player not found") + else + if (vPlayer.Neutral == false) then -- nice touch + missile.BrickColor = vPlayer.TeamColor + end + end + + creator_tag.Value =vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = missile + + missile.RocketScript.Disabled = false + + missile.Parent = game.Workspace +end + +function computeDirection(vec) + local lenSquared = vec.magnitude * vec.magnitude + local invSqrt = 1 / math.sqrt(lenSquared) + return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt) +end + +Tool.Enabled = true +function onActivated() + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local targetPos = humanoid.TargetPoint + + fire(targetPos) + + wait(1) + + Tool.Enabled = true +end + + +script.Parent.Activated:connect(onActivated) + diff --git a/Tools/Scripts/PaintballGun/BrickCleanup.server.lua b/Tools/Scripts/PaintballGun/BrickCleanup.server.lua new file mode 100644 index 0000000..5bec096 --- /dev/null +++ b/Tools/Scripts/PaintballGun/BrickCleanup.server.lua @@ -0,0 +1,4 @@ +-- this script removes its parent from the workspace after 120 seconds + +wait(120) +script.Parent.Parent = nil diff --git a/Tools/Scripts/PaintballGun/Paintball.server.lua b/Tools/Scripts/PaintballGun/Paintball.server.lua new file mode 100644 index 0000000..e03adf0 --- /dev/null +++ b/Tools/Scripts/PaintballGun/Paintball.server.lua @@ -0,0 +1,83 @@ +ball = script.Parent +damage = 20 + +function onTouched(hit) + if not (hit.CanCollide and hit.Parent) then + return + end + + local humanoid = hit.Parent:findFirstChild("Humanoid") + + if hit:getMass() < 1.2 * 200 then + hit.BrickColor = ball.BrickColor + end + + -- make a splat + for i = 1, 3 do + local s = Instance.new("Part") + s.Shape = 1 -- block + s.formFactor = 2 -- plate + s.Size = Vector3.new(1,.4,1) + s.BrickColor = ball.BrickColor + + local v = Vector3.new(math.random(-1,1), math.random(0,1), math.random(-1,1)) + s.Velocity = 15 * v + s.CFrame = CFrame.new(ball.Position + v, v) + + ball.BrickCleanup:clone().Parent = s + + s.BrickCleanup.Disabled = false + s.Parent = game.Workspace + end + + + if humanoid ~= nil then + local canDamage = true + local tag = ball:FindFirstChild("creator") + local char = humanoid:FindFirstAncestorWhichIsA("Model") + + if tag and char then + local creator = tag.Value + local player = game.Players:GetPlayerFromCharacter(char) + if creator and player then + if creator.Team and player.Team and creator.Team == player.Team then + canDamage = false + end + end + end + + if canDamage then + tagHumanoid(humanoid) + humanoid:TakeDamage(damage) + wait(2) + untagHumanoid(humanoid) + end + end + + connection:disconnect() + ball.Parent = nil +end + +function tagHumanoid(humanoid) + -- todo: make tag expire + local tag = ball:findFirstChild("creator") + if tag ~= nil then + local new_tag = tag:clone() + new_tag.Parent = humanoid + end +end + + +function untagHumanoid(humanoid) + if humanoid ~= nil then + local tag = humanoid:findFirstChild("creator") + if tag ~= nil then + tag.Parent = nil + end + end +end + +connection = ball.Touched:connect(onTouched) + +wait(8) +ball.Parent = nil diff --git a/Tools/Scripts/PaintballGun/PaintballShooter.server.lua b/Tools/Scripts/PaintballGun/PaintballShooter.server.lua new file mode 100644 index 0000000..4f6a199 --- /dev/null +++ b/Tools/Scripts/PaintballGun/PaintballShooter.server.lua @@ -0,0 +1,85 @@ +Tool = script.Parent + +colors = {45, 119, 21, 24, 23, 105, 104} + +function fire(v) + + Tool.Handle.Fire:play() + + + local vCharacter = Tool.Parent + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + local missile = Instance.new("Part") + + + + local spawnPos = vCharacter.PrimaryPart.Position + + + + spawnPos = spawnPos + (v * 8) + + missile.Position = spawnPos + missile.Size = Vector3.new(1,1,1) + missile.Velocity = v * 100 + missile.BrickColor = BrickColor.new(colors[math.random(1, #colors)]) + missile.Shape = 0 + missile.BottomSurface = 0 + missile.TopSurface = 0 + missile.Name = "Paintball" + missile.Elasticity = 0 + missile.Reflectance = 0 + missile.Friction = .9 + + local force = Instance.new("BodyForce") + force.force = Vector3.new(0,45,0) + force.Parent = missile + + Tool.BrickCleanup:clone().Parent = missile + + local new_script = script.Parent.Paintball:clone() + new_script.Disabled = false + new_script.Parent = missile + + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = missile + + + + missile.Parent = game.Workspace + missile:SetNetworkOwner(vPlayer) +end + + + +Tool.Enabled = true +function onActivated() + + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local targetPos = humanoid.TargetPoint + local lookAt = (targetPos - character.Head.Position).unit + + fire(lookAt) + + wait(.5) + + Tool.Enabled = true +end + + +script.Parent.Activated:connect(onActivated) diff --git a/Tools/Scripts/Plane/ControlScheme.lua b/Tools/Scripts/Plane/ControlScheme.lua new file mode 100644 index 0000000..327c155 --- /dev/null +++ b/Tools/Scripts/Plane/ControlScheme.lua @@ -0,0 +1,32 @@ +return +{ + ActivateContext = "Steer Plane"; + Buttons = + { + ["Y"] = + { + Label = "Start Engine"; + XboxButton = "ButtonY"; + }; + ["X"] = + { + Label = "Stop Engine"; + XboxButton = "ButtonB"; + }; + ["F"] = + { + Label = "Fire Weapon"; + XboxButton = "ButtonL2"; + }; + ["G"] = + { + Label = "Barrel Roll"; + XboxButton = "ButtonL1"; + }; + ["T"] = + { + Label = "Stunt Roll"; + XboxButton = "ButtonR1"; + } + } +} \ No newline at end of file diff --git a/Tools/Scripts/Plane/IconOverride.txt b/Tools/Scripts/Plane/IconOverride.txt new file mode 100644 index 0000000..8de79c4 --- /dev/null +++ b/Tools/Scripts/Plane/IconOverride.txt @@ -0,0 +1 @@ +rbxassetid://1067894989 \ No newline at end of file diff --git a/Tools/Scripts/Plane/PlaneTool/FlyScript.server.lua b/Tools/Scripts/Plane/PlaneTool/FlyScript.server.lua new file mode 100644 index 0000000..fcc310d --- /dev/null +++ b/Tools/Scripts/Plane/PlaneTool/FlyScript.server.lua @@ -0,0 +1,19 @@ +local engine = script.Parent.Parent.Engine +local speed = 90 +if engine:FindFirstChild("EngineSpeed") then + speed = engine.EngineSpeed.Value +end + +local bv = engine:FindFirstChild("EngineForce") +if not bv then + bv = Instance.new("BodyVelocity") + bv.Name = "EngineForce" + bv.MaxForce = Vector3.new(10e7,10e7,10e7) + bv.Velocity = Vector3.new() + bv.Parent = engine +end + +while true do + wait(.1) + bv.Velocity = engine.CFrame.lookVector * speed +end diff --git a/Tools/Scripts/Plane/PlaneTool/init.server.lua b/Tools/Scripts/Plane/PlaneTool/init.server.lua new file mode 100644 index 0000000..9b9b97c --- /dev/null +++ b/Tools/Scripts/Plane/PlaneTool/init.server.lua @@ -0,0 +1,311 @@ +local Players = game:GetService("Players") + +local tool = script.Parent +local plane = nil +local hold = false +local debounce = false +local planedebounce = false +local stuntdebounce = false +local controlling = false +local player + +local rocket = tool:WaitForChild("Rocket") +rocket.Parent = nil + +local function fireRocket(pln,spn) + local missile = rocket:Clone() + missile.CFrame = spn.CFrame * CFrame.new(0, 0, -35) + missile.Anchored = false + + missile.RocketScript.Disabled = false + missile.Parent = workspace + + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = player + creator_tag.Name = "creator" + creator_tag.Parent = missile + + missile.Owner.Value = pln +end + +local function fireDeathLaser(engine) + local dir = engine.CFrame.lookVector + for i = 1, 50 do + local ex = Instance.new("Explosion") + ex.BlastRadius = 6 + ex.BlastPressure = 8000000 + ex.Position = engine.Position + (dir * 50) + (dir * i * 12) + ex.Parent = workspace + end + if engine:FindFirstChild("DeathLaser") then + engine.DeathLaser:Play() + end +end + +local function computeDirection(vec) + local lenSquared = vec.magnitude * vec.magnitude + local invSqrt = 1 / math.sqrt(lenSquared) + return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt) +end + +local function move(target, engine) + local bg = engine:findFirstChild("BodyGyro") + if bg then + local origincframe = bg.cframe + local dir = (target - engine.Position).unit + local spawnPos = engine.Position + + local pos = spawnPos + (dir * 1) + + bg.maxTorque = Vector3.new(900000, 900000, 900000) + bg.cframe = CFrame.new(pos, pos + dir) + wait(0.1) + bg.maxTorque = Vector3.new(0, 0, 0) + bg.cframe = origincframe + end +end + +function findPlane(char) + local player = Players:GetPlayerFromCharacter(char) + local humanoid = char:FindFirstChildWhichIsA("Humanoid") + local plane = char:FindFirstChildWhichIsA("Model") + if plane and plane.Name == "Plane" then + local color_tag = plane:FindFirstChild("PlaneColor") + if color_tag then + color_tag.Value = player.TeamColor + end + local seat = plane:FindFirstChildWhichIsA("Seat",true) + if seat then + local occupant = seat.Occupant + if humanoid == occupant then + return plane + end + end + end +end + +local function onActivated() + local char = tool.Parent + local humanoid = char:FindFirstChildWhichIsA("Humanoid") + if humanoid then + local vehicle = findPlane(char) + if vehicle ~= nil and debounce == false and planedebounce == false and stuntdebounce == false then + debounce = true + player = Players:GetPlayerFromCharacter(char) + controlling = true + + local engine = vehicle.Parts.Engine + + while wait() do + local target = humanoid.TargetPoint + if engine:FindFirstChild("FlyScript") ~= nil then + move(target, engine) + end + if planedebounce or not controlling then + break + end + end + + wait(.1) + debounce = false + end + end +end + +local function onDeactivated() + controlling = false +end + +local function onKeyDown(key) + if (key~=nil) then + key = key:lower() + local char = tool.Parent + local player = game.Players:GetPlayerFromCharacter(char) + if player==nil then return end + local vehicle = findPlane(char) + if (vehicle==nil) then return end + plane = vehicle.Parts + local engine = vehicle.Parts.Engine + if (key=="f") and tool.Enabled then + local engine = plane.Engine + if engine:FindFirstChild("DeathLaserMode") and engine.DeathLaserMode.Value then + fireDeathLaser(engine) + else + fireRocket(vehicle,plane.Gun1) + fireRocket(vehicle,plane.Gun2) + end + tool.Enabled = false + wait(1) + tool.Enabled = true + end + if (key=="x") and not planedebounce then + local power = plane.Engine:FindFirstChild("FlyScript") + if (power ~= nil) then + power:Destroy() + tool.Enabled = false + for _,v in pairs(vehicle:GetDescendants()) do + if v:IsA("ParticleEmitter") and v.Name == "EngineSparkles" then + v.Enabled = false + elseif v:IsA("BodyVelocity") and v.Name == "EngineForce" then + v:Destroy() + end + end + end + end + if (key=="y") then + local power = plane.Engine:FindFirstChild("FlyScript") + if not power then + local fly = script.FlyScript:Clone() + fly.Disabled = false + fly.Parent = plane.Engine + tool.Enabled = true + for _,v in pairs(vehicle:GetDescendants()) do + if v:IsA("ParticleEmitter") and v.Name == "EngineSparkles" then + v.Enabled = true + elseif v:IsA("BasePart") and v:CanSetNetworkOwnership() then + v:SetNetworkOwner(player) + end + end + end + end + if (key=="k") and not planedebounce then + planedebounce = true + for i = 1,4 do + wait() + engine.RotVelocity = engine.RotVelocity + Vector3.new(0, -0.7, 0) + end + planedebounce = false + end + if (key=="h") and not planedebounce then + planedebounce = true + for i = 1,4 do + wait() + engine.RotVelocity = engine.RotVelocity + Vector3.new(0, 0.7, 0) + end + end + if (key=="j") and not planedebounce then + local body = plane.Engine.BodyGyro + body.maxTorque = Vector3.new(9000, 9000, 9000) + + local position = engine.CFrame * Vector3.new(0, 0.5, -4) + local dir = position - engine.Position + + dir = computeDirection(dir) + + local spawnPos = engine.Position + + local pos = spawnPos + (dir * 8) + + body.cframe = CFrame.new(pos, pos + dir) + wait(.2) + body.maxTorque = Vector3.new(0, 0, 0) + end + if (key=="l") and planedebounce == false then + local body = plane.Engine.BodyGyro + body.maxTorque = Vector3.new(9000, 0, 0) + local frame = plane:FindFirstChild("OriginCFrame") + if frame ~= nil then + body.cframe = frame.Value + end + wait(0.1) + body.maxTorque = Vector3.new(0, 0, 0) + end + if (key=="u") and planedebounce == false then + local body = plane.Engine.BodyGyro + body.maxTorque = Vector3.new(9000, 9000, 9000) + + local position = engine.CFrame * Vector3.new(0, -0.5, -4) + local dir = position - engine.Position + + dir = computeDirection(dir) + + local spawnPos = engine.Position + + local pos = spawnPos + (dir * 8) + + body.cframe = CFrame.new(pos, pos + dir) + wait(.2) + body.maxTorque = Vector3.new(0, 0, 0) + end + if (key=="g") and planedebounce == false and stuntdebounce == false then + planedebounce = true + stuntdebounce = true + plane.Parent.Stunt.Value = 1 + local body = plane.Engine.BodyGyro + body.maxTorque = Vector3.new(9000, 9000, 9000) + + local currentframe = plane.Engine.CFrame + + for i = 1,6 do + body.cframe = plane.Engine.CFrame * CFrame.fromEulerAnglesXYZ(0, 0, 30) + wait(.2) + end + + body.cframe = currentframe + wait(.6) + + body.maxTorque = Vector3.new(0, 0, 0) + planedebounce = false + plane.Parent.Stunt.Value = 0 + wait(3) + stuntdebounce = false + end + if (key=="t") and planedebounce == false and stuntdebounce == false then + planedebounce = true + stuntdebounce = true + plane.Parent.Stunt.Value = 1 + local body = plane.Engine.BodyGyro + body.maxTorque = Vector3.new(9000, 9000, 9000) + + local currentframe = plane.Engine.CFrame + local valy = 30 + local valz = 30 + + for i = 1,8 do + body.cframe = currentframe * CFrame.fromEulerAnglesXYZ(0, valy, valz) + valy = valy +50 + valz = valz +100 + wait(.1) + end + + body.cframe = currentframe * CFrame.fromEulerAnglesXYZ(0, 600, 0) + + wait(.5) + + body.maxTorque = Vector3.new(0, 0, 0) + planedebounce = false + plane.Parent.Stunt.Value = 0 + wait(4) + stuntdebounce = false + end + end +end + +spawn(function () + local iconOverride = tool:WaitForChild("IconOverride") + while wait(.25) do + local isToolInactive = true + local char = tool.Parent + if char and char:IsA("Model") then + local plane = findPlane(char) + if plane then + if plane.Parts.Engine:FindFirstChild("FlyScript") then + isToolInactive = false + end + end + end + iconOverride.Parent = isToolInactive and tool or nil + end +end) + +local keyEvent = tool:WaitForChild("KeyEvent",99999) + +local function onKeyEvent(key,down) + if down then + onKeyDown(key) + end +end + +tool.Activated:Connect(onActivated) +tool.Deactivated:Connect(onDeactivated) +keyEvent.Event:Connect(onKeyEvent) \ No newline at end of file diff --git a/Tools/Scripts/Plane/Rocket/RocketScript.server.lua b/Tools/Scripts/Plane/Rocket/RocketScript.server.lua new file mode 100644 index 0000000..965b584 --- /dev/null +++ b/Tools/Scripts/Plane/Rocket/RocketScript.server.lua @@ -0,0 +1,95 @@ +r = game:service("RunService") + +shaft = script.Parent +position = shaft.Position + +function fly() + direction = shaft.CFrame.lookVector + position = position + 35*direction + error = position - shaft.Position + shaft.Velocity = 5*error +end + +function blow() + swoosh:stop() + explosion = Instance.new("Explosion") + explosion.Position = shaft.Position + explosion.BlastRadius = 10 + + -- find instigator tag + local creator = script.Parent:findFirstChild("creator") + if creator ~= nil then + explosion.Hit:connect(function(part, distance) onPlayerBlownUp(part, distance, creator) end) + end + + explosion.Parent = game.Workspace + connection:disconnect() + wait(.1) + shaft:remove() +end + +function onTouch(hit) + if hit.Name == "Building" or + hit.Name == "Safe" then + swoosh:stop() + shaft:remove() + return end + + local parent = hit.Parent.Parent + local owner = shaft.Owner + if owner ~= nil then + if parent ~= nil and owner.Value ~= nil then + if parent ~= owner.Value then + local stunt = parent:FindFirstChild("Stunt") + if stunt ~= nil then + if stunt.Value ~= 1 then + blow() + end + else + blow() + end + end + end + end +end + +function onPlayerBlownUp(part, distance, creator) + if part.Name == "Head" then + local humanoid = part.Parent:findFirstChild("Humanoid") + tagHumanoid(humanoid, creator) + end +end + +function tagHumanoid(humanoid, creator) + if creator ~= nil then + local new_tag = creator:clone() + new_tag.Parent = humanoid + end +end + +function untagHumanoid(humanoid) + if humanoid ~= nil then + local tag = humanoid:findFirstChild("creator") + if tag ~= nil then + tag.Parent = nil + end + end +end + +t, s = r.Stepped:wait() + +swoosh = script.Parent.Swoosh +swoosh:play() + +d = t + 4.0 - s +connection = shaft.Touched:connect(onTouch) + +while t < d do + fly() + t = r.Stepped:wait() +end + +-- at max range +script.Parent.Explosion.PlayOnRemove = false +swoosh:stop() +shaft:remove() diff --git a/Tools/Scripts/Reset/IconOverride.txt b/Tools/Scripts/Reset/IconOverride.txt new file mode 100644 index 0000000..60cec04 --- /dev/null +++ b/Tools/Scripts/Reset/IconOverride.txt @@ -0,0 +1 @@ +rbxassetid://1000000 \ No newline at end of file diff --git a/Tools/Scripts/Reset/Reset.server.lua b/Tools/Scripts/Reset/Reset.server.lua new file mode 100644 index 0000000..56b07f3 --- /dev/null +++ b/Tools/Scripts/Reset/Reset.server.lua @@ -0,0 +1,13 @@ +local tool = script.Parent + +local function onActivated() + local char = tool.Parent + if char then + local humanoid = char:FindFirstChild("Humanoid") + if humanoid then + humanoid.Health = 0 + end + end +end + +tool.Activated:Connect(onActivated) \ No newline at end of file diff --git a/Tools/Scripts/RocketLauncher/RocketScript.server.lua b/Tools/Scripts/RocketLauncher/RocketScript.server.lua new file mode 100644 index 0000000..16f685a --- /dev/null +++ b/Tools/Scripts/RocketLauncher/RocketScript.server.lua @@ -0,0 +1,91 @@ +r = game:service("RunService") + +shaft = script.Parent +position = Vector3.new(0,0,0) +debris = game:GetService("Debris") + +function tagHumanoid(humanoid) + -- todo: make tag expire + local tag = shaft:findFirstChild("creator") + if tag ~= nil then + -- kill all other tags + while(humanoid:findFirstChild("creator") ~= nil) do + humanoid:findFirstChild("creator").Parent = nil + end + + local new_tag = tag:clone() + new_tag.Parent = humanoid + debris:AddItem(new_tag, 1) + end +end + +local function onExplosionHit(hit) + local char = hit:FindFirstAncestorWhichIsA("Model") + if char then + local humanoid = char:FindFirstChild("Humanoid") + if humanoid then + tagHumanoid(humanoid) + end + end +end + +function fly() + local direction = shaft.CFrame.lookVector + position = position + direction + shaft.Velocity = position - shaft.Position +end + +function blow(hit) + local canExplode = true + local char = hit:FindFirstAncestorWhichIsA("Model") + + if char then + local humanoid = char:FindFirstChild("Humanoid") + if humanoid then + local tag = shaft:FindFirstChild("creator") + local player = game.Players:GetPlayerFromCharacter(char) + if tag and player and tag.Value == player then + canExplode = false + end + end + end + + if canExplode then + local tag = shaft:FindFirstChild("creator") + swoosh:Stop() + + if tag then + local explosion = Instance.new("Explosion") + explosion.Position = shaft.Position + tag:Clone().Parent = explosion + explosion.Parent = workspace + explosion.Hit:Connect(onExplosionHit) + connection:disconnect() + shaft.Explosion:Play() + shaft.Anchored = true + shaft.CanCollide = false + shaft.Transparency = 1 + + shaft.Explosion:Play() + shaft.Explosion.Ended:Wait() + shaft:Destroy() + end + end +end + +t, s = r.Stepped:wait() + +swoosh = script.Parent.Swoosh +swoosh:Play() + +position = shaft.Position +d = t + 10.0 - s +connection = shaft.Touched:connect(blow) + +while t < d do + fly() + t = r.Stepped:wait() +end + +swoosh:Stop() +shaft:remove() diff --git a/Tools/Scripts/RocketLauncher/ServerLauncher.server.lua b/Tools/Scripts/RocketLauncher/ServerLauncher.server.lua new file mode 100644 index 0000000..9999d8a --- /dev/null +++ b/Tools/Scripts/RocketLauncher/ServerLauncher.server.lua @@ -0,0 +1,93 @@ +local Rocket = Instance.new("Part") +local Tool = script.Parent + +Rocket.Locked = true +Rocket.BackSurface = 3 +Rocket.BottomSurface = 3 +Rocket.FrontSurface = 3 +Rocket.LeftSurface = 3 +Rocket.RightSurface = 3 +Rocket.TopSurface = 3 +Rocket.Size = Vector3.new(1,1,4) +Rocket.BrickColor = BrickColor.new(23) + +Tool.RocketScript:clone().Parent = Rocket +Tool.Explosion:clone().Parent = Rocket +Tool.Swoosh:clone().Parent = Rocket + + +function fire(vTarget) + + local vCharacter = Tool.Parent; + + local vHandle = Tool:findFirstChild("Handle") + if vHandle == nil then + print("Handle not found") + return + end + + local dir = vTarget - vHandle.Position + + dir = computeDirection(dir) + + local missile = Rocket:clone() + + local pos = vHandle.Position + (dir * 8) + + --missile.Position = pos + missile.CFrame = CFrame.new(pos, pos + dir) + + local creator_tag = Instance.new("ObjectValue") + + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + if vPlayer == nil then + print("Player not found") + else + if (vPlayer.Neutral == false) then -- nice touch + missile.BrickColor = vPlayer.TeamColor + end + end + + creator_tag.Value =vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = missile + + missile.RocketScript.Disabled = false + + missile.Parent = game.Workspace +end + +function computeDirection(vec) + local lenSquared = vec.magnitude * vec.magnitude + local invSqrt = 1 / math.sqrt(lenSquared) + return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt) +end + +Tool.Enabled = true +function onActivated() + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local targetPos = humanoid.TargetPoint + + fire(targetPos) + + wait(3) + + Tool.Enabled = true +end + + +script.Parent.Activated:connect(onActivated) + diff --git a/Tools/Scripts/Slingshot/PelletScript.server.lua b/Tools/Scripts/Slingshot/PelletScript.server.lua new file mode 100644 index 0000000..0cc2030 --- /dev/null +++ b/Tools/Scripts/Slingshot/PelletScript.server.lua @@ -0,0 +1,63 @@ +local debris = game:service("Debris") +pellet = script.Parent +damage = 8 + +local allowTeamDamage = false +local ServerStorage = game:GetService("ServerStorage") +if ServerStorage:FindFirstChild("TeamDamage") then + allowTeamDamage = ServerStorage.TeamDamage.Value +end + +function tagHumanoid(humanoid) + -- todo: make tag expire + local tag = pellet:findFirstChild("creator") + if tag ~= nil then + -- kill all other tags + while(humanoid:findFirstChild("creator") ~= nil) do + humanoid:findFirstChild("creator").Parent = nil + end + + local new_tag = tag:clone() + new_tag.Parent = humanoid + debris:AddItem(new_tag, 1) + end +end + +function onTouched(hit) + local hitChar = hit:FindFirstAncestorWhichIsA("Model") + local humanoid = hitChar:FindFirstChild("Humanoid") + if humanoid ~= nil then + local canDamage = true + local tag = pellet:FindFirstChild("creator") + if tag then + local creator = tag.Value + local player = game.Players:GetPlayerFromCharacter(hitChar) + if creator and player then + if creator.Team and player.Team and creator.Team == player.Team then + canDamage = allowTeamDamage + end + end + end + if canDamage then + tagHumanoid(humanoid) + humanoid:TakeDamage(damage) + end + else + damage = damage / 2 + if damage < 1 then + connection:disconnect() + pellet.Parent = nil + end + end +end + +connection = pellet.Touched:connect(onTouched) + +r = game:service("RunService") +t, s = r.Stepped:wait() +d = t + 2.0 - s +while t < d do + t = r.Stepped:wait() +end + +pellet.Parent = nil diff --git a/Tools/Scripts/Slingshot/Slingshot.server.lua b/Tools/Scripts/Slingshot/Slingshot.server.lua new file mode 100644 index 0000000..d649ad7 --- /dev/null +++ b/Tools/Scripts/Slingshot/Slingshot.server.lua @@ -0,0 +1,138 @@ +Tool = script.Parent +VELOCITY = 85 -- constant + +local Pellet = Instance.new("Part") +Pellet.Locked = true +Pellet.BottomSurface = 0 +Pellet.TopSurface = 0 +Pellet.Shape = 0 +Pellet.Size = Vector3.new(1,1,1) +Pellet.BrickColor = BrickColor.new(2) + +Tool.PelletScript:clone().Parent = Pellet + +function spawnSound(sound) + local s = sound:clone() + s.Parent = sound.Parent + s:Play() + s.Ended:connect(function () + s:Destroy() + end) +end + +function fire(mouse_pos) + + spawnSound(Tool.Handle.SlingshotSound) + +-- find player's head pos + + local vCharacter = Tool.Parent + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + local head = vCharacter:findFirstChild("Head") + if head == nil then return end + + local dir = mouse_pos - head.Position + dir = computeDirection(dir) + + local launch = head.Position + 5 * dir + + local delta = mouse_pos - launch + + local dy = delta.y + + local new_delta = Vector3.new(delta.x, 0, delta.z) + delta = new_delta + + local dx = delta.magnitude + local unit_delta = delta.unit + + -- acceleration due to gravity in RBX units + local g = (-9.81 * 20) + + local theta = computeLaunchAngle( dx, dy, g) + + local vy = math.sin(theta) + local xz = math.cos(theta) + local vx = unit_delta.x * xz + local vz = unit_delta.z * xz + + + local missile = Pellet:clone() + + + + + missile.Position = launch + missile.Velocity = Vector3.new(vx,vy,vz) * VELOCITY + + missile.PelletScript.Disabled = false + + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = missile + + missile.Parent = game.Workspace + missile:SetNetworkOwner(vPlayer) +end + + +function computeLaunchAngle(dx,dy,grav) + -- arcane + -- http://en.wikipedia.org/wiki/Trajectory_of_a_projectile + + local g = math.abs(grav) + local inRoot = (VELOCITY*VELOCITY*VELOCITY*VELOCITY) - (g * ((g*dx*dx) + (2*dy*VELOCITY*VELOCITY))) + if inRoot <= 0 then + return .25 * math.pi + end + local root = math.sqrt(inRoot) + local inATan1 = ((VELOCITY*VELOCITY) + root) / (g*dx) + + local inATan2 = ((VELOCITY*VELOCITY) - root) / (g*dx) + local answer1 = math.atan(inATan1) + local answer2 = math.atan(inATan2) + if answer1 < answer2 then return answer1 end + return answer2 +end + +function computeDirection(vec) + local lenSquared = vec.magnitude * vec.magnitude + local invSqrt = 1 / math.sqrt(lenSquared) + return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt) +end + + + + +Tool.Enabled = true +function onActivated() + + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + if humanoid.Health <= 0 then + return + end + + local targetPos = humanoid.TargetPoint + + fire(targetPos) + + wait(.2) + + Tool.Enabled = true +end + +script.Parent.Activated:connect(onActivated) diff --git a/Tools/Scripts/Superball/CannonBall.server.lua b/Tools/Scripts/Superball/CannonBall.server.lua new file mode 100644 index 0000000..af2d435 --- /dev/null +++ b/Tools/Scripts/Superball/CannonBall.server.lua @@ -0,0 +1,79 @@ +local Ball = script.Parent +local damage = 35 + +local r = game:service("RunService") +local debris = game:GetService("Debris") + +local last_sound_time = r.Stepped:wait() + +local allowTeamDamage = false +local ServerStorage = game:GetService("ServerStorage") +if ServerStorage:FindFirstChild("TeamDamage") then + allowTeamDamage = ServerStorage.TeamDamage.Value +end + +function onTouched(hit) + local hitChar = hit:FindFirstAncestorWhichIsA("Model") + local humanoid = hitChar:FindFirstChild("Humanoid") + if humanoid ~=nil then + local canDamage = true + local tag = Ball:FindFirstChild("creator") + if tag then + local creator = tag.Value + local player = game.Players:GetPlayerFromCharacter(hitChar) + if creator and player then + if creator.Team and player.Team and creator.Team == player.Team then + canDamage = allowTeamDamage + end + if creator == player then + canDamage = true + end + end + end + + if canDamage then + if connection then + connection:disconnect() + end + Ball.Boing:play() + tagHumanoid(humanoid) + humanoid:TakeDamage(damage) + if humanoid.RootPart then + local apply = (Ball.Position - humanoid.RootPart.Position).unit * (Ball.Velocity/4) + humanoid.RootPart.Velocity = humanoid.RootPart.Velocity + apply + humanoid.RootPart.RotVelocity = humanoid.RootPart.RotVelocity + apply + end + humanoid.PlatformStand = true + wait(.1) + humanoid.PlatformStand = false + end + else + local now = tick() + if (now - last_sound_time > .1) then + Ball.Boing:play() + last_sound_time = now + damage = damage / 2 + if damage < 2 then + if connection then + connection:disconnect() + end + end + end + end +end + +function tagHumanoid(humanoid) + local tag = Ball:findFirstChild("creator") + if tag ~= nil then + local new_tag = tag:clone() + new_tag.Parent = humanoid + debris:AddItem(new_tag, 4) + end +end + + +connection = Ball.Touched:connect(onTouched) + +wait(5) + +Ball:Destroy() \ No newline at end of file diff --git a/Tools/Scripts/Superball/CannonScript.server.lua b/Tools/Scripts/Superball/CannonScript.server.lua new file mode 100644 index 0000000..fe44f0a --- /dev/null +++ b/Tools/Scripts/Superball/CannonScript.server.lua @@ -0,0 +1,65 @@ +local Tool = script.Parent +local Ball = Tool.Handle + +function fire(direction) + + Tool.Handle.Boing:Play() + + local vCharacter = Tool.Parent + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + local missile = Instance.new("Part") + + local spawnPos = vCharacter.PrimaryPart.Position + + spawnPos = spawnPos + (direction * 5) + + missile.Position = spawnPos + missile.Size = Vector3.new(2,2,2) + missile.Velocity = direction * 200 + missile.BrickColor = BrickColor.random() + missile.Shape = 0 + missile.BottomSurface = 0 + missile.TopSurface = 0 + missile.Name = "Cannon Shot" + missile.Reflectance = .2 + missile.CustomPhysicalProperties = PhysicalProperties.new(1,0,1) + Tool.Handle.Boing:clone().Parent = missile + + local new_script = script.Parent.CannonBall:clone() + new_script.Disabled = false + new_script.Parent = missile + + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = missile + + missile.Parent = game.Workspace + missile:SetNetworkOwner(nil) +end + + + +Tool.Enabled = true +function onActivated() + if not Tool.Enabled then + return + end + Tool.Enabled = false + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + local targetPos = humanoid.TargetPoint + local lookAt = (targetPos - character.Head.Position).unit + fire(lookAt) + wait(2) + Tool.Enabled = true +end + + +Tool.Activated:connect(onActivated) + diff --git a/Tools/Scripts/Sword/SwordScript.server.lua b/Tools/Scripts/Sword/SwordScript.server.lua new file mode 100644 index 0000000..d14b07f --- /dev/null +++ b/Tools/Scripts/Sword/SwordScript.server.lua @@ -0,0 +1,181 @@ +-------- OMG HAX + +r = game:service("RunService") + + +local damage = 5 + + +local slash_damage = 10 +local lunge_damage = 30 + +local Debris = game:GetService("Debris") + +sword = script.Parent.Handle +Tool = script.Parent + + +local SlashSound = Instance.new("Sound") +SlashSound.SoundId = "rbxasset://sounds\\swordslash.wav" +SlashSound.Parent = sword +SlashSound.Volume = .7 + +local LungeSound = Instance.new("Sound") +LungeSound.SoundId = "rbxasset://sounds\\swordlunge.wav" +LungeSound.Parent = sword +LungeSound.Volume = .6 + +local UnsheathSound = Instance.new("Sound") +UnsheathSound.SoundId = "rbxasset://sounds\\unsheath.wav" +UnsheathSound.Parent = sword +UnsheathSound.Volume = 1 + + +function tagHumanoid(humanoid, player) + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = player + creator_tag.Name = "creator" + creator_tag.Parent = humanoid + Debris:AddItem(creator_tag,1) +end + +function spawnSound(sound) + local s = sound:clone() + s.Parent = sound.Parent + s:Play() + s.Ended:connect(function () + s:Destroy() + end) +end + +function blow(hit) + if (hit.Parent == nil) then return end -- happens when bullet hits sword + + local humanoid = hit.Parent:findFirstChild("Humanoid") + local vCharacter = Tool.Parent + local vPlayer = game.Players:playerFromCharacter(vCharacter) + local hum = vCharacter:findFirstChild("Humanoid") -- non-nil if tool held by a character + if humanoid~=nil and humanoid ~= hum and hum ~= nil then + -- final check, make sure sword is in-hand + + local right_arm = vCharacter:FindFirstChild("Right Arm") + if (right_arm ~= nil) then + local joint = right_arm:FindFirstChild("RightGrip") + if (joint ~= nil and (joint.Part0 == sword or joint.Part1 == sword)) then + local canDamage = true + local victim = game.Players:GetPlayerFromCharacter(humanoid.Parent) + if victim then + if vPlayer.Team and victim.Team and vPlayer.Team == victim.Team then + canDamage = false + end + end + if canDamage then + local damageDone = damage + local amplify = vCharacter:FindFirstChild("DamageAmplifier") + if amplify then + damageDone = damageDone * amplify.Value + end + tagHumanoid(humanoid, vPlayer) + humanoid:TakeDamage(damageDone) + end + end + end + + + end +end + +function attack() + damage = slash_damage + spawnSound(SlashSound) + local anim = Instance.new("StringValue") + anim.Name = "toolanim" + anim.Value = "Slash" + anim.Parent = Tool +end + +function lunge() + damage = lunge_damage + + spawnSound(LungeSound) + + local anim = Instance.new("StringValue") + anim.Name = "toolanim" + anim.Value = "Lunge" + anim.Parent = Tool + + + local force = Instance.new("BodyVelocity") + force.Velocity = Vector3.new(0,3,0) --Tool.Parent.Torso.CFrame.lookVector * 80 + force.MaxForce = Vector3.new(0,4000,0) + force.Parent = Tool.Parent.Torso + wait(.25) + swordOut() + wait(.25) + force.Parent = nil + wait(.5) + swordUp() + + damage = slash_damage +end + +function swordUp() + Tool.GripForward = Vector3.new(-1,0,0) + Tool.GripRight = Vector3.new(0,1,0) + Tool.GripUp = Vector3.new(0,0,1) +end + +function swordOut() + Tool.GripForward = Vector3.new(0,0,1) + Tool.GripRight = Vector3.new(0,-1,0) + Tool.GripUp = Vector3.new(-1,0,0) +end + +function swordAcross() + -- parry +end + + +Tool.Enabled = true +local last_attack = 0 +function onActivated() + + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local t = tick() + + if (t - last_attack < .2) then + lunge() + else + attack() + end + + last_attack = t + + --wait(.5) + + Tool.Enabled = true +end + + +function onEquipped() + UnsheathSound:play() +end + + +script.Parent.Activated:connect(onActivated) +script.Parent.Equipped:connect(onEquipped) + + +connection = sword.Touched:connect(blow) \ No newline at end of file diff --git a/Tools/Scripts/Timebomb/Bomb.server.lua b/Tools/Scripts/Timebomb/Bomb.server.lua new file mode 100644 index 0000000..3589dfb --- /dev/null +++ b/Tools/Scripts/Timebomb/Bomb.server.lua @@ -0,0 +1,83 @@ +local updateInterval = .4 + +local currentColor = 1 +local colors = {26, 21} + +local bomb = script.Parent +local debris = game:GetService("Debris") + +local ticksound = Instance.new("Sound") +ticksound.SoundId = "rbxasset://sounds\\clickfast.wav" +ticksound.Parent = bomb + +local function update() + updateInterval = updateInterval * .9 + script.Parent.BrickColor = BrickColor.new(colors[currentColor]) + currentColor = currentColor + 1 + if (currentColor > 2) then currentColor = 1 end +end + +local function spawnSound(sound) + local s = sound:clone() + s.Parent = sound.Parent + s:Play() + s.Ended:connect(function () + s:Destroy() + end) +end + +function tagHumanoid(humanoid) + -- todo: make tag expire + local tag = bomb:findFirstChild("creator") + if tag ~= nil then + -- kill all other tags + while(humanoid:findFirstChild("creator") ~= nil) do + humanoid:findFirstChild("creator").Parent = nil + end + + local new_tag = tag:clone() + new_tag.Parent = humanoid + debris:AddItem(new_tag, 1) + end +end + +local function onExplosionHit(hit) + local char = hit:FindFirstAncestorWhichIsA("Model") + if char then + local humanoid = char:FindFirstChild("Humanoid") + if humanoid then + tagHumanoid(humanoid) + end + end +end + +while updateInterval > .1 do + wait(updateInterval) + update() + spawnSound(ticksound) +end + +local sound = Instance.new("Sound") +sound.SoundId = "rbxasset://sounds\\Rocket shot.wav" +sound.Parent = script.Parent +sound.Volume = 1 +sound:Play() + +local explosion = Instance.new("Explosion") +explosion.BlastRadius = 12 +explosion.BlastPressure = 1000000 -- these are really wussy units +explosion.Hit:Connect(onExplosionHit) + +local creator = bomb:FindFirstChild("creator") +if creator then + creator:Clone().Parent = explosion +end + +explosion.Position = bomb.Position +explosion.Parent = workspace + +bomb.Transparency = 1 +bomb.Anchored = true +bomb.CanCollide = false +sound.Ended:wait() +bomb:Destroy() \ No newline at end of file diff --git a/Tools/Scripts/Timebomb/PlantBomb.server.lua b/Tools/Scripts/Timebomb/PlantBomb.server.lua new file mode 100644 index 0000000..485df6d --- /dev/null +++ b/Tools/Scripts/Timebomb/PlantBomb.server.lua @@ -0,0 +1,69 @@ +local bombScript = script.Parent.Bomb +local Tool = script.Parent +local Bomb = Tool.Handle + +function plant() + local bomb2 = Instance.new("Part") + + local vCharacter = Tool.Parent + local vPlayer = game.Players:playerFromCharacter(vCharacter) + + local spawnPos = Bomb.Position + + bomb2.Position = Vector3.new(spawnPos.x, spawnPos.y+3, spawnPos.z) + bomb2.Size = Vector3.new(2,2,2) + + bomb2.BrickColor = BrickColor.new(21) + bomb2.Shape = 0 + bomb2.BottomSurface = 0 + bomb2.TopSurface = 0 + bomb2.Reflectance = 0.2 + bomb2.Name = "TimeBomb" + bomb2.Locked = true + + local creator_tag = Instance.new("ObjectValue") + creator_tag.Value = vPlayer + creator_tag.Name = "creator" + creator_tag.Parent = bomb2 + + bomb2.Parent = game.Workspace + bomb2:SetNetworkOwner(vPlayer) + local new_script = bombScript:clone() + new_script.Disabled = false + new_script.Parent = bomb2 +end + + +Tool.Enabled = true +function onActivated() + + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local targetPos = humanoid.TargetPoint + Bomb.Transparency = 1.0 + + plant() + + wait(6) + Bomb.Transparency = 0.0 + + Tool.Enabled = true +end + +function onUnequipped() +end + + +Tool.Activated:connect(onActivated) +Tool.Unequipped:connect(onUnequipped) \ No newline at end of file diff --git a/Tools/Scripts/Trowel/BrickCleanup.server.lua b/Tools/Scripts/Trowel/BrickCleanup.server.lua new file mode 100644 index 0000000..5f2dd3e --- /dev/null +++ b/Tools/Scripts/Trowel/BrickCleanup.server.lua @@ -0,0 +1,4 @@ +-- this script removes its parent from the workspace after 24 seconds + +wait(24) +script.Parent.Parent = nil diff --git a/Tools/Scripts/Trowel/WallMaker.server.lua b/Tools/Scripts/Trowel/WallMaker.server.lua new file mode 100644 index 0000000..e6fc5bc --- /dev/null +++ b/Tools/Scripts/Trowel/WallMaker.server.lua @@ -0,0 +1,96 @@ +local wallHeight = 4 +local brickSpeed = 0.04 +local wallWidth = 12 + +local Tool = script.Parent + +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local brickColors = require(ReplicatedStorage:WaitForChild("BrickColors")) + + +-- places a brick at pos and returns the position of the brick's opposite corner +function placeBrick(cf, pos, color) + local brick = Instance.new("Part") + brick.BrickColor = color + brick.CFrame = cf * CFrame.new(pos + brick.Size / 2) + script.Parent.BrickCleanup:Clone().Parent = brick -- attach cleanup script to this brick + brick.BrickCleanup.Disabled = false + brick.Parent = game.Workspace + return brick, pos + brick.Size +end + +function buildWall(cf) + + local color = BrickColor.new(brickColors[math.random(1,#brickColors)]) + local bricks = {} + + assert(wallWidth>0) + local y = 0 + while y < wallHeight do + local p + local x = -wallWidth/2 + while x < wallWidth/2 do + local brick + brick, p = placeBrick(cf, Vector3.new(x, y, 0), color) + x = p.x + table.insert(bricks, brick) + brick:MakeJoints() + wait(brickSpeed) + end + y = p.y + end + + --workspace:UnjoinFromOutsiders(bricks) + return bricks + +end + + +function snap(v) + if math.abs(v.x)>math.abs(v.z) then + if v.x>0 then + return Vector3.new(1,0,0) + else + return Vector3.new(-1,0,0) + end + else + if v.z>0 then + return Vector3.new(0,0,1) + else + return Vector3.new(0,0,-1) + end + end +end + + +Tool.Enabled = true +function onActivated() + + if not Tool.Enabled then + return + end + + Tool.Enabled = false + + local character = Tool.Parent; + local humanoid = character.Humanoid + if humanoid == nil then + print("Humanoid not found") + return + end + + local targetPos = humanoid.TargetPoint + local lookAt = snap( (targetPos - character.Head.Position).unit ) + local cf = CFrame.new(targetPos, targetPos + lookAt) + + Tool.Handle.BuildSound:play() + + buildWall(cf) + + wait(5) + + Tool.Enabled = true +end + +script.Parent.Activated:connect(onActivated) + diff --git a/UI/Backpack/SlotTemp.rbxmx b/UI/Backpack/SlotTemp.rbxmx new file mode 100644 index 0000000..ab23d35 --- /dev/null +++ b/UI/Backpack/SlotTemp.rbxmx @@ -0,0 +1,650 @@ + + + + true + + 0 + 0 + + + false + true + + 0.7058824 + 0.7058824 + 0.7058824 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 3 + 0 + 1 + false + SlotTemp + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + + + 0.1058824 + 0.1647059 + 0.2078432 + + false + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + false + 2 + 1 + false + 1 + true + + + + true + + 0 + 1 + + + true + + 0.6666667 + 0.6666667 + 0.6666667 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + Index + null + null + null + null + + 0.03 + 2 + 0.97 + -2 + + null + 0 + false + null + + 0.2 + 0 + 0.2 + 0 + + 2 + + 1 + + 1 + 1 + 1 + + true + 14 + + 1 + 1 + 1 + + 0.8 + 0 + 0 + true + 2 + 1 + true + 3 + true + + + + + 20 + 1 + UITextSizeConstraint + + true + + + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + SelectionOutline + null + null + null + null + + 0 + -1 + 0 + -1 + + null + 0 + false + null + + 1 + 2 + 1 + 2 + + 0 + 0 + + false + 1 + true + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Outline + null + null + null + null + + 0 + 0 + 0.97 + 0 + + null + 0 + false + null + + 1 + 0 + 0.03 + 0 + + 0 + 0 + + true + 3 + true + + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Outline + null + null + null + null + + 0.97 + 0 + 0 + 0 + + null + 0 + false + null + + 0.03 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + true + + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Outline + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.03 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + true + + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + Outline + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.03 + 0 + + 0 + 0 + + true + 3 + true + + + + + + false + + 0 + 0 + + + true + + 0.7058824 + 0.7058824 + 0.7058824 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + TextHover + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + false + 3 + true + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + + + + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + ToolIcon + null + null + null + null + + 0.15 + 0 + 0.15 + 0 + + null + 0 + 0 + false + null + + 0.7 + 0 + 0.7 + 0 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 4 + true + + + + + true + + 0 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + ToolName + null + null + null + null + + 0.1 + 0 + 0.475 + 0 + + null + 0 + false + null + + 2 + 0 + 0.17 + 0 + + 0 + + Tool + + 1 + 1 + 1 + + true + 100 + + 0.4980392 + 0.4980392 + 0.4980392 + + 0.5 + 0.2 + 0 + true + 0 + 1 + true + 4 + true + + + + \ No newline at end of file diff --git a/UI/Backpack/init.client.lua b/UI/Backpack/init.client.lua new file mode 100644 index 0000000..6be5ed8 --- /dev/null +++ b/UI/Backpack/init.client.lua @@ -0,0 +1,300 @@ +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- @CloneTrooper1019, 2015 +-- Backpack +-- Simulates the 2008 backpack from scratch. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Setup + +local ui = script.Parent +local rootFrame = ui:WaitForChild("RootFrame") + +local self = rootFrame:WaitForChild("Backpack") +local slotTemp = script:WaitForChild("SlotTemp") + +local backdrop = self:WaitForChild("Backdrop") +local slotsBin = self:WaitForChild("Slots") + +local player = game.Players.LocalPlayer +local UserInputService = game:GetService("UserInputService") + +local toolIndex = 0 + +local tools = {} +local slots = {} +local tokens = +{ + One = 1; + Two = 2; + Three = 3; + Four = 4; + Five = 5; + Six = 6; + Seven = 7; + Eight = 8; + Nine = 9; + Zero = 10; -- shhh not a hack +} + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Key Hookup + +local eNumPress = Instance.new("BindableEvent") +local numPress = eNumPress.Event + +-- Hack to work around the inputs being overridden while the Plane tool is active. +local function allowGameProcessedBypassHack() + local lastInputType = UserInputService:GetLastInputType() + if lastInputType.Name == "Gamepad1" then + local char = player.Character + if char then + local tool = char:FindFirstChildWhichIsA("Tool") + if tool and not tool.Enabled then + return true + end + end + end + return false +end + +local function onInputBegan(input,gameProcessed) + if not gameProcessed or allowGameProcessedBypassHack() then + local name = input.UserInputType.Name + local keyCode = input.KeyCode.Name + if name == "Keyboard" then + local toIndex = tokens[keyCode] + if toIndex then + eNumPress:Fire(toIndex) + end + elseif name == "Gamepad1" then + if keyCode == "ButtonL1" or keyCode == "ButtonR1" then + local nextIndex = toolIndex + if keyCode == "ButtonL1" then + nextIndex = nextIndex - 1 + elseif keyCode == "ButtonR1" then + nextIndex = nextIndex + 1 + end + print(nextIndex,#tools) + if nextIndex > 0 and nextIndex <= #tools then + eNumPress:Fire(nextIndex) + else + eNumPress:Fire(toolIndex) + end + end + end + end +end + +UserInputService.InputBegan:connect(onInputBegan) + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local function resortSlots() + for index,tool in ipairs(tools) do + local slot = slots[tool] + slot.Index.Text = index + slot.LayoutOrder = index + slot.Visible = true + end + backdrop.Size = UDim2.new(#tools,0,1,0) +end + +local function createSlot(tool) + if not slots[tool] then + local index = #tools+1 + tools[index] = tool + + local slot = slotTemp:clone() + slot.Name = tool.Name + slot.Parent = slotsBin + + local textHover = slot:WaitForChild("TextHover") + local selectionOutline = slot:WaitForChild("SelectionOutline") + local toolIcon = slot:WaitForChild("ToolIcon") + local indexLbl = slot:WaitForChild("Index") + local toolName = slot:WaitForChild("ToolName") + + local isHovering = false + local isDown = false + + local backpack = player:WaitForChild("Backpack") + local char = player.Character or player.CharacterAdded:Wait() + + local humanoid = char:WaitForChild("Humanoid") + local conReg = {} + + local function killTool() + local currentIndex = tonumber(indexLbl.Text) + table.remove(tools, currentIndex) + + for _,con in pairs(conReg) do + con:disconnect() + end + + slots[tool] = nil + slot:Destroy() + + resortSlots() + end + + local function checkParent() + if tool.Parent == char then + selectionOutline.Visible = true + elseif tool.Parent == backpack then + selectionOutline.Visible = false + else + killTool() + end + end + + local function toggleTool() + if tool.Parent == char then + humanoid:UnequipTools() + else + toolIndex = tonumber(indexLbl.Text) + humanoid:EquipTool(tool) + end + end + + local function renderUpdate() + if tool.TextureId ~= "" then + toolName.Visible = false + toolIcon.Visible = true + toolIcon.Image = tool.TextureId + else + toolIcon.Visible = false + toolName.Visible = true + toolName.Text = tool.Name + end + if tool.TextureId ~= "" then + textHover.Visible = false + if isHovering then + toolIcon.BackgroundTransparency = 0 + if isDown then + toolIcon.BackgroundColor3 = Color3.new(0,0,1) + else + toolIcon.BackgroundColor3 = Color3.new(1,1,0) + end + else + toolIcon.BackgroundTransparency = 1 + end + else + textHover.Visible = true + if isHovering then + textHover.BackgroundTransparency = 0 + if isDown then + textHover.BackgroundColor3 = Color3.new(1,1,0) + else + textHover.BackgroundColor3 = Color3.new(0.706,0.706,0.706) + end + else + textHover.BackgroundTransparency = 1 + end + end + end + + local function onInputBegan(input) + if input.UserInputType.Name == "MouseButton1" then + isDown = true + elseif input.UserInputType.Name == "MouseMovement" or input.UserInputType.Name == "Touch" then + isHovering = true + end + renderUpdate() + end + + local function onInputEnded(input) + if input.UserInputType.Name == "MouseButton1" then + isDown = false + if isHovering then + toggleTool() + end + elseif input.UserInputType.Name == "MouseMovement" then + isHovering = false + elseif input.UserInputType.Name == "Touch" then + isHovering = false + if humanoid.MoveDirection == Vector3.new() then + toggleTool() + end + end + + renderUpdate() + end + + local function onNumDown(num) + local currentIndex = tonumber(indexLbl.Text) + + if num == currentIndex then + toggleTool() + end + end + + local function onToolChanged(property) + if property == "TextureId" or property == "Name" then + renderUpdate() + elseif property == "Parent" then + checkParent() + end + end + + local eventMounts = + { + [numPress] = onNumDown; + [tool.Changed] = onToolChanged; + [slot.InputBegan] = onInputBegan; + [slot.InputEnded] = onInputEnded; + [humanoid.Died] = killTool; + } + + renderUpdate() + checkParent() + + for event, func in pairs(eventMounts) do + local connection = event:Connect(func) + table.insert(conReg, connection) + end + + slots[tool] = slot + resortSlots() + end +end + +local currentChar + +local function onCharacterAdded(char) + if currentChar ~= char then + currentChar = char + + for _,v in pairs(slots) do + v:Destroy() + end + + slots = {} + tools = {} + + local function onChildAdded(child) + if child:IsA("Tool") then + createSlot(child) + end + end + + local backpack = player:WaitForChild("Backpack") + + for _,v in pairs(backpack:GetChildren()) do + onChildAdded(v) + end + + for _,v in pairs(char:GetChildren()) do + onChildAdded(v) + end + + char.ChildAdded:connect(onChildAdded) + backpack.ChildAdded:connect(onChildAdded) + end +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:connect(onCharacterAdded) + +game.StarterGui.ResetPlayerGuiOnSpawn = false \ No newline at end of file diff --git a/UI/Chat/GetCoreGateway.lua b/UI/Chat/GetCoreGateway.lua new file mode 100644 index 0000000..96af2a6 --- /dev/null +++ b/UI/Chat/GetCoreGateway.lua @@ -0,0 +1,96 @@ +local ChatConnections = {} + +local function AddObjects(bindableClass,targetName,...) + local target = ChatConnections[targetName] + if not target then + target = {} + ChatConnections[targetName] = target + end + local names = {...} + for _,name in pairs(names) do + local signal = Instance.new(bindableClass) + signal.Name = targetName .. "_" .. name + signal.Parent = script + target[name] = signal + end +end + +AddObjects("BindableEvent","ChatWindow", + --------------------------- + -- Fired from the CoreGui + --------------------------- + "ToggleVisibility", -- Fired when the CoreGui chat button is pressed. + "SetVisible", -- Fired when the CoreGui wants to directly change the visiblity state of the chat window. + "FocusChatBar", -- Fired when the CoreGui wants to capture the Chatbar's Focus. + "TopbarEnabledChanged", -- Fired when the visibility of the Topbar is changed. + "SpecialKeyPressed", -- Fired when the reserved ChatHotkey is pressed. + "CoreGuiEnabled", -- Fired when a user changes the SetCoreGuiEnabled state of the Chat Gui. + + --------------------------- + -- Fired to the CoreGui + --------------------------- + "ChatBarFocusChanged", + -- ^ Fire this with 'true' when you want to assure the CoreGui that the ChatBar is being focused on. + + "VisibilityStateChanged", + -- ^ Fire this with 'true' when the user shows or hides the chat. + + "MessagesChanged", + -- ^ Fire this with a number to change the number of messages that have been recorded by the chat window. + -- If the CoreGui thinks the chat window isn't visible, it will display the recorded difference between + -- the number of messages that was displayed when it was visible, and the number you supply. + + "MessagePosted" + -- ^ Fire this to make the player directly chat under ROBLOX's C++ API. + -- This will fire the LocalPlayer's Chatted event. + -- Please only fire this on the player's behalf. If you attempt to spoof a player's chat + -- to get them in trouble, you could face serious moderation action. +) + +AddObjects("BindableFunction","ChatWindow", + "IsFocused" -- This will be invoked by the CoreGui when it wants to check if the chat window is active. +) + +-- The following events are fired if the user calls StarterGui:SetCore(string name, Variant data) +-- Note that you can only hook onto these ones specifically. +AddObjects("BindableEvent","SetCore", + "ChatMakeSystemMessage", + "ChatWindowPosition", + "ChatWindowSize", + "ChatBarDisabled" +) + +-- The following functions are invoked if the user calls StarterGui:GetCore(string name) +-- Note that you can only hook onto these ones specifically. +AddObjects("BindableFunction","GetCore", + "ChatWindowPosition", -- Should return a UDim2 representing the position of the chat window. + "ChatWindowSize", -- Should return a UDim2 representing the size of the chat window. + "ChatBarDisabled" -- Should return true if the chat bar is currently disabled. +) + +-- Connect ChatConnections to the CoreGui. +local StarterGui = game:GetService("StarterGui") +local GuiService = game:GetService("GuiService") + +if not GuiService:IsTenFootInterface() then + local tries = 0 + local maxAttempts = 30 + + while (tries < maxAttempts) do + local success,result = pcall(function () + StarterGui:SetCore("CoreGuiChatConnections", ChatConnections) + end) + if success then + break + else + tries = tries + 1 + if tries == maxAttempts then + error("Error calling SetCore CoreGuiChatConnections: " .. result) + else + wait() + end + end + end +end + +return ChatConnections \ No newline at end of file diff --git a/UI/Chat/LinkedList.lua b/UI/Chat/LinkedList.lua new file mode 100644 index 0000000..26faa79 --- /dev/null +++ b/UI/Chat/LinkedList.lua @@ -0,0 +1,84 @@ +local LinkedList = {} +LinkedList.__index = LinkedList + +function LinkedList:Add(data) + local node = {} + node.data = data + node.id = tostring(node):sub(8) + + local back = self.back + if back then + back.next = node + node.prev = back + end + + if not self.front then + self.front = node + end + + self.back = node + self.size = self.size + 1 + + self.nodes[node.id] = node + self.lookup[data] = node + + return node.id +end + +function LinkedList:Get(id) + local node = self.nodes[id] + if node then + return node.data + end +end + +function LinkedList:Remove(id) + local node = self.nodes[id] + + if node then + if node.prev then + node.prev.next = node.next + end + + if node.next then + node.next.prev = node.prev + end + + if node == self.front then + self.front = node.next + end + + if node == self.back then + self.back = node.prev + end + + if node.data then + node.data = nil + end + + self.size = self.size - 1 + end +end + +function LinkedList:GetEnumerator() + return coroutine.wrap(function () + local node = self.front + while node ~= nil do + coroutine.yield(node.id, node.data) + node = node.next + end + end) +end + +function LinkedList.new() + local list = + { + nodes = {}; + lookup = {}; + size = 0; + } + + return setmetatable(list, LinkedList) +end + +return LinkedList \ No newline at end of file diff --git a/UI/Chat/MessageTemplate.rbxmx b/UI/Chat/MessageTemplate.rbxmx new file mode 100644 index 0000000..92651ad --- /dev/null +++ b/UI/Chat/MessageTemplate.rbxmx @@ -0,0 +1,220 @@ + + + + false + + 0 + 0 + + + true + + 0.6 + 0.6 + 0.6 + + 0.6 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + MessageTemplate + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 0 + 16 + + 0 + 0 + + true + 1 + true + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 1 + 1 + Message + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + + + + 1 + 1 + 1 + + false + 16 + + 1 + 1 + 1 + + 0.9 + 0 + 0 + false + 0 + 1 + true + 1 + true + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + PlayerName + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + + + + 0 + 0 + 0 + + false + 16 + + 0 + 0 + 0 + + 0.9 + 0 + 0 + false + 0 + 1 + true + 1 + true + + + + + + 0 + 1 + AutoLayout + + 0 + 0 + + 2 + + 1 + true + + + + \ No newline at end of file diff --git a/UI/Chat/init.client.lua b/UI/Chat/init.client.lua new file mode 100644 index 0000000..422089b --- /dev/null +++ b/UI/Chat/init.client.lua @@ -0,0 +1,181 @@ +-------------------------------------------------------------------------------------------- +-- Constants +-------------------------------------------------------------------------------------------- + +local Debris = game:GetService("Debris") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local RunService = game:GetService("RunService") +local TextService = game:GetService("TextService") +local UserInputService = game:GetService("UserInputService") + +local LinkedList = require(script:WaitForChild("LinkedList")) + +local ui = script.Parent +local rootFrame = ui:WaitForChild("RootFrame") + +local chat = rootFrame:WaitForChild("Chat") +local chatBar = chat:WaitForChild("ChatBar") +local chatOutput = chat:WaitForChild("ChatOutput") +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") + +local focusBackdrop = chatBar:WaitForChild("FocusBackdrop") +local mainBackdrop = chat:WaitForChild("MainBackdrop") +local messageTemplate = script:WaitForChild("MessageTemplate") + +local hasCoreGateway, coreGateway = pcall(function () + local getCoreGateway = script:WaitForChild("GetCoreGateway") + return require(getCoreGateway) +end) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Colors +-------------------------------------------------------------------------------------------------------------------------------------- + +local PLAYER_COLORS = +{ + [0] = Color3.fromRGB(173, 35, 35); -- red + [1] = Color3.fromRGB( 42, 75, 215); -- blue + [2] = Color3.fromRGB( 29, 105, 20); -- green + [3] = Color3.fromRGB(129, 38, 192); -- purple + [4] = Color3.fromRGB(255, 146, 51); -- orange + [5] = Color3.fromRGB(255, 238, 51); -- yellow + [6] = Color3.fromRGB(255, 205, 243); -- pink + [7] = Color3.fromRGB(233, 222, 187); -- tan +} + +local function computePlayerColor(player) + if player.Team then + return player.TeamColor.Color + else + local pName = player.Name + local length = #pName + + local oddShift = (1 - (length % 2)) + local value = 0 + + for i = 1,length do + local char = pName:sub(i, i):byte() + local rev = (length - i) + oddShift + + if (rev % 4) >= 2 then + value = value - char + else + value = value + char + end + end + + return PLAYER_COLORS[value % 8] + end +end + +-------------------------------------------------------------------------------------------- +-- Chat Input +-------------------------------------------------------------------------------------------- + +local function beginChatting() + focusBackdrop.Visible = true + + if not chatBar:IsFocused() then + chatBar.TextTransparency = 1 + chatBar:CaptureFocus() + wait() + chatBar.Text = "" + chatBar.TextTransparency = 0 + end +end + +local function onInputBegan(input, processed) + if not processed and input.UserInputType == Enum.UserInputType.Keyboard then + if input.KeyCode == Enum.KeyCode.Slash then + beginChatting() + end + end +end + +local function onChatFocusLost(enterPressed) + local msg = chatBar.Text + + if enterPressed and #msg > 0 then + if #msg > 128 then + msg = msg:sub(1, 125) .. "..." + end + + chatRemote:FireServer(msg) + + if hasCoreGateway then + coreGateway.ChatWindow.MessagePosted:Fire(msg) + end + end + + chatBar.Text = "" + focusBackdrop.Visible = false +end + +UserInputService.InputBegan:Connect(onInputBegan) + +chatBar.Focused:Connect(beginChatting) +chatBar.FocusLost:Connect(onChatFocusLost) + +-------------------------------------------------------------------------------------------- +-- Chat Output +-------------------------------------------------------------------------------------------- + +local messageId = 0 +local blank_v2 = Vector2.new() +local chatQueue = LinkedList.new() + +local function computeTextBounds(label) + local bounds = TextService:GetTextSize(label.Text, label.TextSize, label.Font, blank_v2) + return UDim2.new(0, bounds.X, 0, bounds.Y) +end + +local function getMessageId() + messageId = messageId + 1 + return messageId +end + +local function onReceiveChat(player, message, wasFiltered) + -- Process the message + if message:sub(1, 1) == "%" then + message = "(TEAM) " .. message:sub(2) + end + + if wasFiltered then + message = message:gsub("#[# ]+#", "[ Content Deleted ]") + end + + -- Create the message + local msg = messageTemplate:Clone() + + local playerLbl = msg:WaitForChild("PlayerName") + playerLbl.TextColor3 = computePlayerColor(player) + playerLbl.TextStrokeColor3 = playerLbl.TextColor3 + playerLbl.Text = player.Name .. "; " + playerLbl.Size = computeTextBounds(playerLbl) + + local msgLbl = msg:WaitForChild("Message") + msgLbl.Text = message + msgLbl.Size = computeTextBounds(msgLbl) + + local width = playerLbl.AbsoluteSize.X + msgLbl.AbsoluteSize.X + + msg.Size = msg.Size + UDim2.new(0, width, 0, 0) + msg.LayoutOrder = getMessageId() + + msg.Name = "Message" .. msg.LayoutOrder + msg.Parent = chatOutput + + if chatQueue.size == 6 then + local front = chatQueue.front + front.data:Destroy() + + chatQueue:Remove(front.id) + end + + chatQueue:Add(msg) + Debris:AddItem(msg, 60) +end + +chatRemote.OnClientEvent:Connect(onReceiveChat) + +-------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/UI/Health.client.lua b/UI/Health.client.lua new file mode 100644 index 0000000..bca252c --- /dev/null +++ b/UI/Health.client.lua @@ -0,0 +1,32 @@ +local StarterGui = game:GetService("StarterGui") +StarterGui:SetCoreGuiEnabled("All",false) + +local health = script.Parent +local redBar = health:WaitForChild("RedBar") +local greenBar = redBar:WaitForChild("GreenBar") + +local player = game.Players.LocalPlayer +local c = workspace.CurrentCamera + +if c.ViewportSize.Y < 600 then + local scale = Instance.new("UIScale") + scale.Scale = 0.6 + scale.Parent = health +end + +local function onCharacterAdded(char) + local humanoid = char:WaitForChild("Humanoid") + + local function updateHealth(health) + greenBar.Size = UDim2.new(1, 0, health / humanoid.MaxHealth, 0) + end + + updateHealth(humanoid.MaxHealth) + humanoid.HealthChanged:Connect(updateHealth) +end + +if player.Character then + onCharacterAdded(player.Character) +end + +player.CharacterAdded:Connect(onCharacterAdded) \ No newline at end of file diff --git a/UI/Messages/Hint.rbxmx b/UI/Messages/Hint.rbxmx new file mode 100644 index 0000000..0df6cbc --- /dev/null +++ b/UI/Messages/Hint.rbxmx @@ -0,0 +1,76 @@ + + + + false + + 0 + 1 + + + true + + 0 + 0 + 0 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + Hint + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 0 + 20 + + 0 + + + + 0.882353 + 0.882353 + 0.882353 + + false + 16 + + 0.7843138 + 0.7843138 + 0.7843138 + + 0.9 + 0 + 0 + false + 2 + 2 + true + 1 + true + + + \ No newline at end of file diff --git a/UI/Messages/Message.rbxmx b/UI/Messages/Message.rbxmx new file mode 100644 index 0000000..0b5c0b5 --- /dev/null +++ b/UI/Messages/Message.rbxmx @@ -0,0 +1,76 @@ + + + + false + + 0 + 0 + + + true + + 0.4980392 + 0.4980392 + 0.4980392 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + Message + null + null + null + null + + 0 + 0 + 0 + -36 + + null + 0 + false + null + + 1 + 0 + 1 + 36 + + 0 + + + + 1 + 1 + 1 + + false + 18 + + 0 + 0 + 0 + + 0.1 + 0.1 + 0 + true + 2 + 1 + false + 1 + true + + + \ No newline at end of file diff --git a/UI/Messages/Player.rbxmx b/UI/Messages/Player.rbxmx new file mode 100644 index 0000000..55f856e --- /dev/null +++ b/UI/Messages/Player.rbxmx @@ -0,0 +1,76 @@ + + + + false + + 0 + 0 + + + true + + 0.5882353 + 0.5882353 + 0.5882353 + + 0.5 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 9 + 0 + 1 + Player + null + null + null + null + + 0 + 32 + 0 + 5 + + null + 0 + false + null + + 0.25 + 0 + 0.25 + 0 + + 0 + + Test + + 1 + 1 + 1 + + false + 18 + + 0 + 0 + 0 + + 0.1 + 0.1 + 0 + true + 2 + 1 + true + 10 + true + + + \ No newline at end of file diff --git a/UI/Messages/init.client.lua b/UI/Messages/init.client.lua new file mode 100644 index 0000000..e2371f2 --- /dev/null +++ b/UI/Messages/init.client.lua @@ -0,0 +1,92 @@ +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") + +local gui = script.Parent +local player = Players.LocalPlayer + +local hintBin = Instance.new("Folder") +local msgNameFmt = "MsgLbl_%s [%s]" + +local function addMessage(sourceMsg,msgType) + local isInPlayer = (sourceMsg.Parent == player) + local msgType = sourceMsg.ClassName + + if msgType == "Message" and isInPlayer then + msgType = "Player" + end + + local msgTemp = script:WaitForChild(msgType) + + local msg = msgTemp:Clone() + msg.Name = msgNameFmt:format(msgType, sourceMsg:GetFullName()) + + local textUpdater = sourceMsg:GetPropertyChangedSignal("Text") + local isUpdating = false + + local function updateText() + if not isUpdating then + isUpdating = true + + msg.Text = sourceMsg.Text + sourceMsg.Text = "" + + if msgType ~= "Hint" then + msg.Visible = (#msg.Text > 0) + end + + isUpdating = false + end + end + + local function onAncestryChanged() + local desiredAncestor + + if msgType == "Hint" then + desiredAncestor = hintBin + elseif isInPlayer then + desiredAncestor = player + else + desiredAncestor = workspace + end + + if not sourceMsg:IsDescendantOf(desiredAncestor) then + msg:Destroy() + end + end + + --[[ + I have to parent the Hint somewhere where it won't render since it + draws even if the Hint has no text. The server will remove the object + by it's reference address even if I change the parent, so this isn't a + problem online. But I can't rely on this in a non-network scenario so + regular Hints will still be visible offline if they're in the Workspace :( + --]] + + if msgType == "Hint" then + wait() + sourceMsg.Parent = hintBin + end + + updateText() + textUpdater:Connect(updateText) + sourceMsg.AncestryChanged:Connect(onAncestryChanged) + + msg.Parent = gui +end + +local function registerMessage(obj) + if obj:IsA("Message") then + addMessage(obj) + end +end + +for _,v in pairs(workspace:GetDescendants()) do + registerMessage(v) +end + +for _,v in pairs(player:GetChildren()) do + registerMessage(v) +end + +player.ChildAdded:Connect(registerMessage) +workspace.DescendantAdded:Connect(registerMessage) \ No newline at end of file diff --git a/UI/PlayerList/BaseGroup.rbxmx b/UI/PlayerList/BaseGroup.rbxmx new file mode 100644 index 0000000..df3cd29 --- /dev/null +++ b/UI/PlayerList/BaseGroup.rbxmx @@ -0,0 +1,362 @@ + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + -9999 + BaseGroup + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 999999999 + Footer + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.165 + 0 + + 0 + 0 + + false + 1 + true + + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + -9999999 + Header + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.333 + 0 + + 0 + 0 + + true + 1 + true + + + + false + + 1 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + Title + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + Player List + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + true + + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 0 + Stats + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.75 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + TeamUnderline + null + null + null + null + + -1 + 2 + 0.875 + 0 + + null + 0 + false + null + + 1 + -4 + 0 + 1 + + 0 + 0 + + false + 2 + true + + + + + + + 1 + 1 + ListLayout + + 0 + 0 + + 2 + + 1 + true + + + + \ No newline at end of file diff --git a/UI/PlayerList/BasePlayerLbl.rbxmx b/UI/PlayerList/BasePlayerLbl.rbxmx new file mode 100644 index 0000000..43e1a1d --- /dev/null +++ b/UI/PlayerList/BasePlayerLbl.rbxmx @@ -0,0 +1,184 @@ + + + + false + + 0 + 0 + + + true + + 0 + 1 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 0 + BasePlayerLbl + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 0.3333 + 0 + + 0 + 0 + + true + 1 + true + + + + false + + 1 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + PlayerName + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + OnlyTwentyCharacters + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + true + + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 0 + Stats + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0.75 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + true + + + + \ No newline at end of file diff --git a/UI/PlayerList/BaseStat.rbxmx b/UI/PlayerList/BaseStat.rbxmx new file mode 100644 index 0000000..bcbd2ef --- /dev/null +++ b/UI/PlayerList/BaseStat.rbxmx @@ -0,0 +1,76 @@ + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 9 + 0 + 1 + BaseStat + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + + 0 + + 1 + 1 + 1 + + true + 14 + + 0 + 0 + 0 + + 1 + 0 + 0 + true + 0 + 1 + true + 2 + true + + + \ No newline at end of file diff --git a/UI/PlayerList/init.client.lua b/UI/PlayerList/init.client.lua new file mode 100644 index 0000000..e3685ce --- /dev/null +++ b/UI/PlayerList/init.client.lua @@ -0,0 +1,632 @@ +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local Teams = game:GetService("Teams") + +spawn(function () + local StarterGui = game:GetService("StarterGui") + StarterGui:SetCoreGuiEnabled("PlayerList", false) + + local player = Players.LocalPlayer + + local playerGui = player:WaitForChild("PlayerGui") + playerGui:SetTopbarTransparency(1) +end) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Setup +-------------------------------------------------------------------------------------------------------------------------------------- + +local playerStates = {} +local teamGroups = {} + +local statLookup = {} +local statNames = {} + +local inTeamMode = false + +local basePlayerLbl = script:WaitForChild("BasePlayerLbl") +local baseGroup = script:WaitForChild("BaseGroup") +local baseStat = script:WaitForChild("BaseStat") + +local playerList = script.Parent +local backdrop = playerList:WaitForChild("Backdrop") +local container = playerList:WaitForChild("Container") + +local coreGroup = baseGroup:Clone() +coreGroup.Name = "Default" +coreGroup.Parent = container + +local coreFooter = coreGroup.Footer +local coreHeader = coreGroup.Header + +local eUpdateStatLayout = Instance.new("BindableEvent") +local updateStatLayout = eUpdateStatLayout.Event + +local eUpdateTeamTotal = Instance.new("BindableEvent") +local updateTeamTotal = eUpdateTeamTotal.Event + +local ePlayerTeamChanged = Instance.new("BindableEvent") +local playerTeamChanged = ePlayerTeamChanged.Event + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Colors +-------------------------------------------------------------------------------------------------------------------------------------- + +local PLAYER_COLORS = +{ + [0] = Color3.fromRGB(173, 35, 35); -- red + [1] = Color3.fromRGB( 42, 75, 215); -- blue + [2] = Color3.fromRGB( 29, 105, 20); -- green + [3] = Color3.fromRGB(129, 38, 192); -- purple + [4] = Color3.fromRGB(255, 146, 51); -- orange + [5] = Color3.fromRGB(255, 238, 51); -- yellow + [6] = Color3.fromRGB(255, 205, 243); -- pink + [7] = Color3.fromRGB(233, 222, 187); -- tan +} + +local function computePlayerColor(player) + local pName = player.Name + local length = #pName + local oddShift = (1 - (length % 2)) + local value = 0 + + for i = 1,length do + local char = pName:sub(i,i):byte() + local rev = (length - i) + oddShift + if (rev % 4) >= 2 then + value = value - char + else + value = value + char + end + end + + return PLAYER_COLORS[value % 8] +end + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Backdrop Handler +-------------------------------------------------------------------------------------------------------------------------------------- + +local isTeamMode = false +local hasStats = false + +local size1x1 = Vector2.new(1,1) +local rawGroups = {} + +local function onContainerChildAdded(child) + if child:IsA("Frame") then + local listLayout = child:WaitForChild("ListLayout",2) + if listLayout then + rawGroups[child] = listLayout + end + end +end + +local function onContainerChildRemoved(child) + if rawGroups[child] then + rawGroups[child] = nil + end +end + +local function sortGroups(a,b) + if a == coreGroup then + return true + elseif b == coreGroup then + return false + else + local orderA,orderB = a.LayoutOrder,b.LayoutOrder + if orderA == orderB then + return a.Name < b.Name + else + return orderA < orderB + end + end +end + +local function updateBackdrop() + local groups = {} + local at = 1 + + for group in pairs(rawGroups) do + if group.Visible then + groups[at] = group + at = at + 1 + end + end + + local height = 0 + table.sort(groups,sortGroups) + + for i = 1,#groups do + local group = groups[i] + local layout = rawGroups[group] + group.Position = UDim2.new(0,0,0,height) + height = height + layout.AbsoluteContentSize.Y + end + + if #statNames > 0 and not hasStats then + hasStats = true + container.AnchorPoint = Vector2.new(1,0) + for _,group in pairs(groups) do + group.Header.TeamUnderline.Size = UDim2.new(2,-4,0,1) + end + eUpdateStatLayout:Fire() + elseif #statNames == 0 and hasStats then + hasStats = false + container.AnchorPoint = Vector2.new(0,0) + for _,group in pairs(groups) do + group.Header.TeamUnderline.Size = UDim2.new(1,-4,0,1) + end + eUpdateStatLayout:Fire() + end + + if isTeamMode then + height = height + coreHeader.AbsoluteSize.Y + end + + local width = container.AbsoluteSize.X * (container.AnchorPoint.X+1) + backdrop.Size = UDim2.new(0,width,0,height) +end + +for _,child in pairs(container:GetChildren()) do + onContainerChildAdded(child) +end + +container.ChildAdded:Connect(onContainerChildAdded) +container.ChildRemoved:Connect(onContainerChildRemoved) +RunService.Heartbeat:Connect(updateBackdrop) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Header Size Stuff +-------------------------------------------------------------------------------------------------------------------------------------- + +local function switchHeaderMode(isTeamMode) + if isTeamMode then + coreHeader.Size = UDim2.new(1,0,1/3,0) + coreHeader.Stats.Size = UDim2.new(0.75,0,1,0) + coreHeader.Title.Size = UDim2.new(1,0,1,0) + else + coreHeader.Size = UDim2.new(1,0,0.4,0) + coreHeader.Stats.Size = UDim2.new(0.75,0,0.85,0) + coreHeader.Title.Size = UDim2.new(1,0,0.85,0) + end +end + +switchHeaderMode(false) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player Stats +-------------------------------------------------------------------------------------------------------------------------------------- + +local function incrementStat(statName) + if not statLookup[statName] then + statLookup[statName] = 1 + table.insert(statNames,statName) + else + statLookup[statName] = statLookup[statName] + 1 + end + eUpdateStatLayout:Fire() +end + +local function decrementStat(statName) + if statLookup[statName] then + statLookup[statName] = statLookup[statName] - 1 + + if statLookup[statName] == 0 then + statLookup[statName] = nil + for i,name in ipairs(statNames) do + if name == statName then + table.remove(statNames,i) + break + end + end + end + + eUpdateStatLayout:Fire() + end +end + +local function getPlayerStateFromStat(stat) + local leaderstats = stat.Parent + if leaderstats then + local player = leaderstats.Parent + if player then + return playerStates[player] + end + end +end + +local function refreshTeamStats() + for _,team in pairs(Teams:GetTeams()) do + eUpdateTeamTotal:Fire(team) + end +end + +local function onStatRemoved(stat,statName) + if stat.ClassName == "IntValue" then + local statName = statName or stat.Name + local playerState = getPlayerStateFromStat(stat) + if playerState and playerState.Stats[statName] then + playerState.Stats[statName]:Destroy() + playerState.Stats[statName] = nil + end + decrementStat(statName) + refreshTeamStats() + end +end + +local function onStatAdded(stat) + if stat.ClassName == "IntValue" then + local statName = stat.Name + local playerState = getPlayerStateFromStat(stat) + if playerState then + local changeSignal + + if not playerState.Stats[statName] then + local statLbl = baseStat:Clone() + statLbl.Name = statName + + local function updateStat() + statLbl.Text = stat.Value + if isTeamMode then + local team = playerState.Player.Team + if team then + eUpdateTeamTotal:Fire(team) + end + end + end + + updateStat() + changeSignal = stat.Changed:Connect(updateStat) + + statLbl.Parent = playerState.Label.Stats + playerState.Stats[statName] = statLbl + end + + local nameSignal do + local function onNameChanged() + if changeSignal then + changeSignal:Disconnect() + changeSignal = nil + end + nameSignal:Disconnect() + nameSignal = nil + + -- Rebuild the stat + onStatRemoved(stat,statName) + onStatAdded(stat) + end + + nameSignal = stat:GetPropertyChangedSignal("Name"):Connect(onNameChanged) + end + end + + incrementStat(statName) + refreshTeamStats() + end +end + +local function onPlayerChildAdded(leaderstats) + if leaderstats.Name == "leaderstats" then + local player = leaderstats.Parent + local playerState = playerStates[player] + if playerState and not playerState.leaderstats then + playerState.leaderstats = leaderstats + for _,stat in pairs(leaderstats:GetChildren()) do + onStatAdded(stat) + end + leaderstats.ChildAdded:Connect(onStatAdded) + leaderstats.ChildRemoved:Connect(onStatRemoved) + end + end +end + +local function onPlayerChildRemoved(child) + if child.Name == "leaderstats" then + for _,stat in pairs(child:GetChildren()) do + onStatRemoved(stat) + end + for player,playerState in pairs(playerStates) do + if playerState.leaderstats == child then + playerState.leaderstats = nil + break + end + end + end +end + +local function updateStatLbl(statLbl,index) + statLbl.Size = UDim2.new(1/#statNames,0,1,0) + statLbl.Position = UDim2.new((index-1)/#statNames) +end + +local function onUpdateStatLayout() + local statBin = coreHeader.Stats + + for _,statLbl in pairs(statBin:GetChildren()) do + if statLbl:IsA("TextLabel") and not statLookup[statLbl.Name] then + statLbl:Destroy() + end + end + + for i,statName in pairs(statNames) do + local statLbl = statBin:FindFirstChild(statName) + if not statLbl then + statLbl = baseStat:Clone() + statLbl.Name = statName + statLbl.Text = statName + statLbl.Parent = statBin + end + updateStatLbl(statLbl,i) + end + + for player,playerState in pairs(playerStates) do + for statName,statLbl in pairs(playerState.Stats) do + if not statLookup[statName] then + statLbl:Destroy() + playerState.Stats[statName] = nil + end + end + + for i,statName in pairs(statNames) do + local statLbl = playerState.Stats[statName] + if statLbl then + if player.Team then + statLbl.TextColor = player.Team.TeamColor + else + statLbl.TextColor3 = Color3.new(1,1,1) + end + updateStatLbl(statLbl,i) + end + end + end + + isTeamMode = (#Teams:GetTeams() > 0) + + if isTeamMode then + coreHeader.Visible = hasStats + coreHeader.Title.Text = "Team" + else + coreHeader.Visible = true + if hasStats then + coreHeader.Title.Text = "Players" + else + coreHeader.Title.Text = "Player List" + end + end + + switchHeaderMode(isTeamMode) +end + +updateStatLayout:Connect(onUpdateStatLayout) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Player States +-------------------------------------------------------------------------------------------------------------------------------------- + +local function onPlayerAdded(player) + local playerState = {} + local name = player.Name + + local lbl = basePlayerLbl:Clone() + lbl.Name = name + lbl.PlayerName.Text = name + lbl.PlayerName.TextColor3 = computePlayerColor(player) + lbl.Parent = coreGroup + + playerState.Player = player + playerState.Label = lbl + playerState.Stats = {} + playerStates[player] = playerState + + for _,child in pairs(player:GetChildren()) do + onPlayerChildAdded(child) + end + + player.ChildAdded:Connect(onPlayerChildAdded) + player.ChildRemoved:Connect(onPlayerChildRemoved) + + player.Changed:Connect(function (property) + if property == "Team" then + ePlayerTeamChanged:Fire(player) + end + end) + + ePlayerTeamChanged:Fire(player) +end + +local function onPlayerRemoved(player) + local state = playerStates[player] + playerStates[player] = nil + + if state and state.Label then + state.Label:Destroy() + end +end + +for _,player in pairs(Players:GetPlayers()) do + onPlayerAdded(player) +end + +Players.PlayerAdded:Connect(onPlayerAdded) +Players.PlayerRemoving:Connect(onPlayerRemoved) + +-------------------------------------------------------------------------------------------------------------------------------------- +-- Teams +-------------------------------------------------------------------------------------------------------------------------------------- + +local function neutralizePlayer(player) + local playerState = playerStates[player] + if playerState then + local playerLbl = playerState.Label + playerLbl.PlayerName.Text = player.Name + playerLbl.PlayerName.TextColor3 = computePlayerColor(player) + playerLbl.PlayerName.Position = UDim2.new(0,0,0,0) + for stat,statLbl in pairs(playerState.Stats) do + statLbl.TextColor3 = Color3.new(1,1,1) + end + playerLbl.Visible = (not isTeamMode) + playerLbl.Parent = coreGroup + end +end + +local function onPlayerAddedToTeam(player) + local team = player.Team + local group = teamGroups[team] + if group then + local playerState = playerStates[player] + if playerState then + local playerLbl = playerState.Label + playerLbl.PlayerName.TextColor = team.TeamColor + playerLbl.PlayerName.Position = UDim2.new(0,4,0,0) + for stat,statLbl in pairs(playerState.Stats) do + statLbl.TextColor = team.TeamColor + end + playerLbl.Parent = group + playerLbl.Visible = true + eUpdateStatLayout:Fire() + refreshTeamStats() + end + end +end + +local function onPlayerRemovedFromTeam(player) + if not player.Team then + neutralizePlayer(player) + refreshTeamStats() + end +end + +local function onUpdateTeamTotal(team) + local teamGroup = teamGroups[team] + if teamGroup then + local teamStats = teamGroup.Header.Stats + local totals = {} + + for i,statName in ipairs(statNames) do + local total = totals[i] + if not total then + total = { Name = statName, Value = 0 } + totals[i] = total + end + for _,player in pairs(team:GetPlayers()) do + local playerState = playerStates[player] + if playerState then + local leaderstats = playerState.leaderstats + if leaderstats then + local stat = leaderstats:FindFirstChild(statName) + if stat then + total.Value = total.Value + stat.Value + end + end + end + end + end + + local numStats = #statNames + + for i,statRecord in ipairs(totals) do + local statName = statRecord.Name + local statLbl = teamStats:FindFirstChild(statName) + if not statLbl then + statLbl = baseStat:Clone() + statLbl.Name = statName + statLbl.TextColor = team.TeamColor + statLbl.TextStrokeTransparency = 0.5 + statLbl.Parent = teamStats + end + statLbl.Text = statRecord.Value + updateStatLbl(statLbl,i) + end + + for _,statLbl in pairs(teamStats:GetChildren()) do + if not statLookup[statLbl.Name] then + statLbl:Destroy() + end + end + end +end + +local function onTeamAdded(team) + if team.ClassName == "Team" then + local teamGroup = baseGroup:Clone() + teamGroup.Name = team.Name + teamGroup.Footer.Visible = true + + local teamHeader = teamGroup.Header + + local teamUnderline = teamHeader.TeamUnderline + teamUnderline.Visible = true + teamUnderline.BackgroundColor = team.TeamColor + + if hasStats then + teamUnderline.Size = teamUnderline.Size + UDim2.new(1,0,0,0) + end + + local teamTitle = teamHeader.Title + teamTitle.Text = team.Name + teamTitle.TextColor = team.TeamColor + teamTitle.TextStrokeTransparency = 0.5 + + teamGroup.Parent = container + teamGroups[team] = teamGroup + + for _,player in pairs(team:GetPlayers()) do + onPlayerAddedToTeam(player) + end + + eUpdateTeamTotal:Fire(team) + eUpdateStatLayout:Fire() + end + if #Teams:GetTeams() > 0 and not isTeamMode then + isTeamMode = true + for _,player in pairs(Players:GetPlayers()) do + if not player.Team then + neutralizePlayer(player) + end + end + end +end + +local function onTeamRemoved(team) + if teamGroups[team] then + for _,player in pairs(Players:GetPlayers()) do + if player.TeamColor == team.TeamColor then + neutralizePlayer(player) + end + end + teamGroups[team]:Destroy() + teamGroups[team] = nil + eUpdateStatLayout:Fire() + end + if #Teams:GetTeams() == 0 then + isTeamMode = false + for _,player in pairs(Players:GetPlayers()) do + neutralizePlayer(player) + end + end +end + +local function onPlayerTeamChange(player) + local team = player.Team + if team then + onPlayerAddedToTeam(player) + else + onPlayerRemovedFromTeam(player) + end +end + +for _,team in pairs(Teams:GetTeams()) do + onTeamAdded(team) +end + +for _,player in pairs(Players:GetPlayers()) do + onPlayerTeamChange(player) +end + +Teams.ChildAdded:Connect(onTeamAdded) +Teams.ChildRemoved:Connect(onTeamRemoved) +updateTeamTotal:Connect(onUpdateTeamTotal) +playerTeamChanged:Connect(onPlayerTeamChange) + +-------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/UI/RootFrame.rbxmx b/UI/RootFrame.rbxmx new file mode 100644 index 0000000..56eebe1 --- /dev/null +++ b/UI/RootFrame.rbxmx @@ -0,0 +1,1790 @@ + + true + null + nil + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 0 + RootFrame + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + + ChatPadding + + 0 + 20 + + + 0 + 0 + + + 0 + 0 + + + 0 + 0 + + + + + + + false + + 0.5 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + rbxassetid://334630296 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + ClassicMouse + null + null + null + null + + 0.5 + 0 + 0.5 + 0 + + null + 0 + 0 + false + null + + 0 + 80 + 0 + 80 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + true + 10 + + + + + true + + 0 + 1 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + + rbxassetid://991182833 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + SafeChat + null + null + null + null + + 0 + 22 + 0.75 + 0 + + + null + 0 + 0 + true + false + null + + 0 + 32 + 0 + 30 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + false + + 0.5 + 0.75 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + rbxasset://textures/ui/Settings/Help/XButtonDark@2x.png + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + GamepadHint + null + null + null + null + + 1 + 5 + 0 + 0 + + null + 0 + 0 + false + null + + 0.75 + 0 + 0.75 + 0 + + 2 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 1 + + + + + + false + + 1 + 1 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 0 + ZoomControls + null + null + null + null + + 1 + 0 + 1 + 0 + + null + 0 + false + null + + 0 + 70 + 0 + 70 + + 0 + 0 + + true + 1 + + + + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + + rbxassetid://598662248 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + RotateUp + null + null + null + null + + 0 + 0 + 0 + 0 + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + + rbxassetid://598662248 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + RotateDown + null + null + null + null + + 0 + 0 + 0 + 35 + + + null + -180 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + + rbxassetid://598663795 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + ZoomIn + null + null + null + null + + 0 + 35 + 0 + 0 + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0.5 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Lock + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 35 + 0 + 35 + + 0 + 0 + + false + 3 + + + + + + true + + 0 + 0 + + + true + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + + rbxassetid://598665130 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + false + ZoomOut + null + null + null + null + + 0 + 35 + 0 + 35 + + + null + 0 + 0 + true + false + null + + 0 + 35 + 0 + 35 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + 0 + + + 1 + 0 + 1 + 0 + + true + 2 + + + + + false + + 1 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + rbxassetid://598702035 + + 1 + 1 + 1 + + + 0 + 0 + + + 0 + 0 + + 0 + 0 + FirstPersonIndicator + null + null + null + null + + 1 + 0 + 0 + -97 + + null + 0 + 0 + false + null + + 0 + 168 + 0 + 42 + + 0 + + + 0 + 0 + + + 0 + 0 + + + 1 + + + 1 + 0 + 1 + 0 + + false + 2 + + + + + + false + + 1 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Health + null + null + null + null + + 1 + -31 + 0.5 + 0 + + null + 0 + false + null + + 0 + 66 + 0 + 137 + + 0 + 0 + + true + 1 + + + + false + + 0.5 + 0 + + + true + + 1 + 0 + 0 + + 0 + + 1 + 0 + 0 + + 0 + 0 + false + false + 0 + RedBar + null + null + null + null + + 0.5 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 12 + 0 + 112 + + 0 + 0 + + true + 2 + + + + false + + 0.5 + 1 + + + true + + 0.505882382 + 0.772549093 + 0.0862745121 + + 0 + + 0.505882382 + 0.772549093 + 0.0862745121 + + 0 + 0 + false + false + 0 + GreenBar + null + null + null + null + + 0.5 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 3 + + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 9 + 0 + 1 + HealthLbl + null + null + null + null + + 0 + 0 + 1 + -24 + + null + 0 + false + null + + 1 + 0 + 0 + 24 + + 0 + + Health + + 0 + 0 + 1 + + true + 18 + + 0 + 0 + 1 + + 0.899999976 + 0 + 0 + true + 2 + 1 + true + 2 + + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 0 + Chat + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + true + + 1 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.168627501 + 0.168627501 + 0.168627501 + + 0 + 0 + true + false + false + 4 + 0 + 1 + false + ChatBar + null + null + null + null + + 1 + 1 + 0.784313798 + + To chat click here or press the "/" key + + 1 + 0 + 1 + 0 + + null + 0 + true + null + true + + 1 + -3 + 0 + 15 + + 0 + + + + 0 + 0 + 0 + + true + false + 15 + + 0 + 0 + 0 + + 1 + 0 + 0 + false + 0 + 1 + true + 3 + + + + false + + 1 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + FocusBackdrop + null + null + null + null + + 1 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 3 + 1 + 0 + + 0 + 0 + + false + 2 + + + + + + false + + 0 + 0 + + + true + + 0.250980407 + 0.250980407 + 0.250980407 + + 0 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + MainBackdrop + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 0 + 20 + + 0 + 0 + + true + 1 + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + true + false + 0 + ChatOutput + null + null + null + null + + 0 + 23 + 0 + 29 + + null + 0 + false + null + + 1 + 0 + 0 + 96 + + 0 + 0 + + true + 1 + + + + + 1 + 1 + Stream + + 0 + 0 + + 2 + + 2 + + + + + + + true + + 0 + 1 + + + true + + 0.498039186 + 0.498039186 + 0.498039186 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Backpack + null + null + null + null + + 0 + 0 + 1 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 2 + 0 + + true + 1 + + + + + UIScale + 0.133000001 + + + + + + false + + 0 + 0 + + + true + + 0.70588237 + 0.70588237 + 0.70588237 + + 0.5 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Backdrop + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 1 + 0 + + 0 + 0 + + true + 2 + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 0 + Slots + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 1 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + + 0 + 1 + UIListLayout + + 0 + 0 + + 2 + + 1 + + + + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 1 + false + false + 0 + PlayerList + null + null + null + null + + 0 + 0 + 0 + -36 + + null + 0 + false + null + + 1 + 0 + 1 + 36 + + 0 + 0 + + true + 1 + + + + false + + 1 + 0 + + + true + + 0.600000024 + 0.600000024 + 0.600000024 + + 0.400000006 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Backdrop + null + null + null + null + + 1 + -10 + 0 + 10 + + null + 0 + false + null + + 0 + 10 + 0 + 10 + + 0 + 0 + + true + 1 + + + + + false + + 0 + 0 + + + true + + 0 + 0 + 0 + + 1 + + 0.105882399 + 0.164705902 + 0.207843199 + + 0 + 0 + false + false + 0 + Container + null + null + null + null + + 1 + -10 + 0 + 10 + + null + 0 + false + null + + 0.165000007 + 0 + 1 + 0 + + 0 + 0 + + true + 1 + + + + 3 + 0 + + 0 + AspectRatio + + + + + + + \ No newline at end of file diff --git a/UI/SafeChat/Click.rbxmx b/UI/SafeChat/Click.rbxmx new file mode 100644 index 0000000..66db075 --- /dev/null +++ b/UI/SafeChat/Click.rbxmx @@ -0,0 +1,24 @@ + + + + + 10 + false + Click + false + 1 + false + 0 + null + + rbxasset://sounds/switch.mp3 + + + 0 + 0.5 + 10000 + 10 + true + + + \ No newline at end of file diff --git a/UI/SafeChat/NullSelectionImageObject.rbxmx b/UI/SafeChat/NullSelectionImageObject.rbxmx new file mode 100644 index 0000000..6373a95 --- /dev/null +++ b/UI/SafeChat/NullSelectionImageObject.rbxmx @@ -0,0 +1,56 @@ + + + + false + + 0 + 0 + + + true + + 1 + 1 + 1 + + 0 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 0 + false + false + 0 + NullSelectionImageObject + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + false + null + + 0 + 0 + 0 + 0 + + 0 + 0 + + true + 1 + true + + + \ No newline at end of file diff --git a/UI/SafeChat/TempBranch.rbxmx b/UI/SafeChat/TempBranch.rbxmx new file mode 100644 index 0000000..d353cc0 --- /dev/null +++ b/UI/SafeChat/TempBranch.rbxmx @@ -0,0 +1,72 @@ + + + + false + + 0 + 0.5 + + + true + + 1 + 1 + 1 + + 1 + + 0.1058824 + 0.1647059 + 0.2078432 + + 0 + 1 + false + false + 0 + TempBranch + null + null + null + null + + 1 + 5 + 0.5 + 0 + + null + 0 + false + null + + 0 + 140 + 0 + 24 + + 0 + 0 + + false + 2 + true + + + + + 1 + 1 + UIListLayout + + 0 + 5 + + 2 + + 0 + true + + + + \ No newline at end of file diff --git a/UI/SafeChat/TempButton.rbxmx b/UI/SafeChat/TempButton.rbxmx new file mode 100644 index 0000000..5346add --- /dev/null +++ b/UI/SafeChat/TempButton.rbxmx @@ -0,0 +1,80 @@ + + + + true + + 0 + 0 + + + false + true + + 1 + 1 + 1 + + 0 + + 0.2470588 + 0.2470588 + 0.2470588 + + 0 + 1 + false + false + 9 + 0 + 1 + false + TempButton + null + null + null + null + + 0 + 0 + 0 + 0 + + null + 0 + true + false + null + + 0 + 140 + 0 + 24 + + 0 + 0 + + ROOT + + 0 + 0 + 0 + + false + 12 + + 0 + 0 + 0 + + 0.95 + 0.25 + 0 + false + 2 + 1 + true + 2 + true + + + \ No newline at end of file diff --git a/UI/SafeChat/init.client.lua b/UI/SafeChat/init.client.lua new file mode 100644 index 0000000..08aac35 --- /dev/null +++ b/UI/SafeChat/init.client.lua @@ -0,0 +1,204 @@ +local UserInputService = game:GetService("UserInputService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local GuiService = game:GetService("GuiService") + +local c = workspace.CurrentCamera +local resUpdate = c:GetPropertyChangedSignal("ViewportSize") +local safeChat = script.Parent +local click = script:WaitForChild("Click") + +local IMG_CHAT = "rbxassetid://991182833" +local IMG_CHAT_DN = "rbxassetid://991182832" +local IMG_CHAT_OVR = "rbxassetid://991182834" + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Fetch Tree Data + +local mSafeChatTree = ReplicatedStorage:WaitForChild("SafeChatTree") +local safeChatTree = require(mSafeChatTree) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Button Positioning + +local IS_PHONE = c.ViewportSize.Y < 600 + +local function onResolutionUpdate() + local viewPort = c.ViewportSize + local chatX = math.min(25,viewPort.Y/40) + local chatY = (viewPort.X/viewPort.Y) * (viewPort.Y * 0.225) + safeChat.Position = UDim2.new(0,chatX,1,-chatY) +end + +onResolutionUpdate() +resUpdate:Connect(onResolutionUpdate) + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Safe Chat Tree + +local chatRemote = ReplicatedStorage:WaitForChild("ChatRemote") +local tempBranch = script:WaitForChild("TempBranch") +local tempButton = script:WaitForChild("TempButton") +local isActivated = false +local rootTree + +local function recursivelyDeactivateTree(obj) + if obj:IsA("Frame") then + obj.Visible = false + elseif obj:IsA("TextButton") then + obj.BackgroundColor3 = Color3.new(1,1,1) + end + for _,v in pairs(obj:GetChildren()) do + recursivelyDeactivateTree(v) + end +end + +local function deactivateRootTree() + isActivated = false + safeChat.Image = IMG_CHAT + recursivelyDeactivateTree(rootTree) + + if GuiService.SelectedObject then + GuiService.SelectedObject = nil + GuiService:RemoveSelectionGroup("SafechatNav") + end +end + +local function activateRootTree() + isActivated = true + rootTree.Visible = true + safeChat.Image = IMG_CHAT_DN + + if UserInputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then + GuiService:AddSelectionParent("SafechatNav",safeChat) + GuiService.SelectedObject = safeChat + end +end + +local function assembleTree(tree) + local treeFrame = tempBranch:Clone() + treeFrame.Name = "Branches" + + local currentBranch + + for i,branch in ipairs(tree.Branches) do + local label = branch.Label + local branches = branch.Branches + local button = tempButton:Clone() + button.Name = label + button.Text = label + button.LayoutOrder = i + local branchFrame = assembleTree(branch) + branchFrame.Parent = button + button.Parent = treeFrame + + local function onEnter() + if currentBranch then + recursivelyDeactivateTree(currentBranch) + end + currentBranch = button + button.BackgroundColor3 = Color3.new(0.7,0.7,0.7) + branchFrame.Visible = true + end + + local function onActivate() + local submit = true + if UserInputService.TouchEnabled then + if not branchFrame.Visible and #branchFrame:GetChildren() > 1 then + branchFrame.Visible = true + submit = false + end + end + if submit then + deactivateRootTree() + chatRemote:FireServer(label) + click:Play() + end + end + + button.MouseEnter:Connect(onEnter) + button.SelectionGained:Connect(onEnter) + button.MouseButton1Down:Connect(onActivate) + end + + return treeFrame +end + +rootTree = assembleTree(safeChatTree) +rootTree.Parent = safeChat + +if IS_PHONE then + local uiScale = Instance.new("UIScale") + uiScale.Parent = rootTree + uiScale.Scale = 0.7 +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Button State + +local isActivated = false +local isHovering = false + +do + local function onMouseEnter() + if not isActivated then + safeChat.Image = IMG_CHAT_OVR + end + isHovering = true + end + + local function onMouseLeave() + if not isActivated then + safeChat.Image = IMG_CHAT + end + isHovering = false + end + + local function onMouseDown() + safeChat.Image = IMG_CHAT_DN + end + + local function onMouseUp() + if isHovering then + activateRootTree() + end + end + + local function onInputBegan(input,gameProcessed) + if input.UserInputType == Enum.UserInputType.MouseButton1 and not gameProcessed and isActivated then + deactivateRootTree() + end + end + + safeChat.MouseEnter:Connect(onMouseEnter) + safeChat.MouseLeave:Connect(onMouseLeave) + safeChat.MouseButton1Down:Connect(onMouseDown) + safeChat.MouseButton1Up:Connect(onMouseUp) + + UserInputService.InputBegan:Connect(onInputBegan) +end + +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Gamepad Stuff +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +local gamepadHint = safeChat:WaitForChild("GamepadHint") + +if GuiService:IsTenFootInterface() then + gamepadHint.Visible = true +else + local function onLastInputTypeChanged(inputType) + gamepadHint.Visible = (inputType.Name == "Gamepad1") + end + + onLastInputTypeChanged(UserInputService:GetLastInputType()) + UserInputService.LastInputTypeChanged:Connect(onLastInputTypeChanged) +end + + +local function onInputBegan(input) + if input.KeyCode == Enum.KeyCode.ButtonX then + activateRootTree() + end +end + +UserInputService.InputBegan:Connect(onInputBegan) \ No newline at end of file diff --git a/UI/ZoomControls.client.lua b/UI/ZoomControls.client.lua new file mode 100644 index 0000000..36fcd84 --- /dev/null +++ b/UI/ZoomControls.client.lua @@ -0,0 +1,112 @@ +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +if GuiService:IsTenFootInterface() then + return +end + +local IS_TOUCH = UserInputService.TouchEnabled + +local player = game.Players.LocalPlayer +local playerScripts = player:WaitForChild("PlayerScripts") +local passCameraEvent = playerScripts:WaitForChild("PassCameraEvent") + +local self = script.Parent +local zoomIn = self:WaitForChild("ZoomIn") +local zoomLock = zoomIn:WaitForChild("Lock") +local firstPersonIndicator = self:WaitForChild("FirstPersonIndicator") + +local yellow = Color3.new(1,1,0) +local cyan = Color3.new(0,1,1) +local white = Color3.new(1,1,1) + +local c = workspace.CurrentCamera +local currentlyDown + +local function updateCameraStatus() + local dist = (c.Focus.p - c.CFrame.p).magnitude + firstPersonIndicator.Visible = (dist <= 1.5) + zoomLock.Visible = (dist <= 1) +end + +local function setupButton(btn) + local isDown = false + local inBounds = false + local lock = btn:FindFirstChild("Lock") + local mouse = player:GetMouse() + btn.MouseEnter:connect(function () + if (lock == nil or not lock.Visible) then + if (currentlyDown == nil or currentlyDown == btn) then + inBounds = true + if isDown then + btn.ImageColor3 = yellow + else + btn.ImageColor3 = cyan + end + end + end + end) + btn.MouseLeave:connect(function () + if (lock == nil or not lock.Visible) then + inBounds = false + if isDown then + btn.ImageColor3 = cyan + else + btn.ImageColor3 = white + end + end + end) + btn.MouseButton1Down:connect(function () + if (lock == nil or not lock.Visible) then + isDown = true + currentlyDown = btn + btn.ImageColor3 = yellow + end + end) + btn.MouseButton1Click:connect(function () + if (lock == nil or not lock.Visible) then + isDown = false + currentlyDown = nil + inBounds = false + passCameraEvent:Fire(btn.Name) + if IS_TOUCH then + btn.ImageColor3 = white + end + end + end) + mouse.Button1Up:connect(function () + if (lock == nil or not lock.Visible) then + if isDown then + isDown = false + currentlyDown = nil + if inBounds then + inBounds = false + passCameraEvent:Fire(btn.Name) + end + end + end + btn.ImageColor3 = white + end) + if lock then + lock.Changed:connect(function () + if lock.Visible then + btn.ImageColor3 = white + isDown = false + if currentlyDown == btn then + currentlyDown = nil + end + end + end) + end + if IS_TOUCH then + btn.Modal = true + end +end + +for _,v in pairs(script.Parent:GetChildren()) do + if v:IsA("ImageButton") then + setupButton(v) + end +end + +c.Changed:connect(updateCameraStatus) \ No newline at end of file diff --git a/default.project.json b/default.project.json new file mode 100644 index 0000000..b4629f7 --- /dev/null +++ b/default.project.json @@ -0,0 +1,54 @@ +{ + "name": "MainModule", + + "tree": + { + "$path": "main.lua", + + "ReplicatedFirst": + { + "$className": "Folder", + + "JoinScript": + { + "$path": "Resources/GameJoin" + } + }, + + "ReplicatedStorage": + { + "$className": "Folder", + + "SafeChatTree": + { + "$path": "Resources/SafeChat" + } + }, + + "StarterGui": + { + "$className": "Folder", + + "UI": + { + "$className": "ScreenGui", + "$path": "UI" + } + }, + + "ServerScriptService": + { + "$path": "Server" + }, + + "StarterPlayerScripts": + { + "$path": "Client" + }, + + "StarterCharacterScripts": + { + "$path": "Character" + } + } +} \ No newline at end of file diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..5d44be5 --- /dev/null +++ b/main.lua @@ -0,0 +1,174 @@ +local gameInst = game.JobId +local isOnline = (gameInst ~= "") + +if isOnline and game.GameId ~= 123949867 then + script:Destroy() + return +end + +local dataModel = script:WaitForChild("DataModel") +local framework = script:WaitForChild("Framework") + +local Chat = game:GetService("Chat") +local InsertService = game:GetService("InsertService") +local Lighting = game:GetService("Lighting") +local Players = game:GetService("Players") +local ServerStorage = game:GetService("ServerStorage") +local StarterGui = game:GetService("StarterGui") +local StarterPlayer = game:GetService("StarterPlayer") +local TeleportService = game:GetService("TeleportService") + +local initMsg = Instance.new("Message") +initMsg.Text = "INITIALIZING..." +initMsg.Parent = workspace + +if not workspace.FilteringEnabled then + initMsg.Text = "FATAL: Workspace.FilteringEnabled MUST be set to true!!!" + return 0 +end + +local override = ServerStorage:FindFirstChild("LocalGameImport") + +if override then + if isOnline then + warn("WARNING: Dev framework is present in a networked game, and it shouldn't be!!!") + override:Destroy() + elseif override ~= script then + initMsg:Destroy() + require(override) + return 1 + end +end + +-- Standard Forced Settings +Lighting.Outlines = false +Players.CharacterAutoLoads = false +StarterGui.ShowDevelopmentGui = false + +local sky = Lighting:FindFirstChildOfClass("Sky") + +if not sky then + local skyProps = {"Bk", "Dn", "Ft", "Lf", "Rt", "Up"} + local skyId = "rbxasset://Sky/null_plainsky512_%s.jpg" + + sky = Instance.new("Sky") + + for _,prop in pairs(skyProps) do + sky["Skybox"..prop] = skyId:format(prop:lower()) + end + + sky.Parent = Lighting +end + +sky.SunAngularSize = 14 +sky.MoonAngularSize = 6 + +local devProps = +{ + DevComputerMovementMode = "KeyboardMouse"; + DevComputerCameraMovementMode = "Classic"; + DevTouchMovementMode = "UserChoice"; + DevTouchCameraMovementMode = "Classic"; +} + +StarterPlayer.LoadCharacterAppearance = false +StarterPlayer.EnableMouseLockOption = false + +for prop,value in pairs(devProps) do + StarterPlayer[prop] = value +end + +for _,player in pairs(Players:GetPlayers()) do + local char = player.Character + + if char and char:IsDescendantOf(workspace) then + char:Destroy() + player.Character = nil + end + + for prop,value in pairs(devProps) do + StarterPlayer[prop] = value + end +end + +-- Import the shared universe assets (scripts and stuff shared between both the main menu and the actual places) +require(ServerStorage:FindFirstChild("LocalSharedImport") or 1027421176) + +-- Load Scripts +for _,desc in pairs(dataModel:GetDescendants()) do + if desc:IsA("StringValue") and desc.Name:sub(1,9) == "ScriptRef" then + local scriptName = desc.Name:gsub("ScriptRef%[(.+)%]","%1") + local scriptPath = desc.Value + local scriptRef = framework + + local gotScript = true + + for path in scriptPath:gmatch("[^/]+") do + scriptRef = scriptRef:WaitForChild(path, 1) + + if not scriptRef then + gotScript = false + + warn("WARNING: Failed to load ScriptRef for", desc:GetFullName()) + warn(" got stuck at:", path) + + break + end + end + + if gotScript then + local newScript = scriptRef:Clone() + newScript.Name = scriptName + + if newScript:IsA("BaseScript") then + newScript.Disabled = false + end + + for _,child in pairs(desc:GetChildren()) do + child.Parent = newScript + end + + newScript.Parent = desc.Parent + end + + desc:Destroy() + end +end + +-- Load DataModel + +for _,rep in pairs(dataModel:GetChildren()) do + local real = game:FindFirstChildWhichIsA(rep.Name, true) + + if not real then -- Hopefully a service that doesn't exist yet? + real = game:GetService(rep.Name) + end + + for _,child in pairs(rep:GetChildren()) do + local existing = real:FindFirstChild(child.Name) + + if existing then + existing:Destroy() + end + + child.Parent = real + end +end + +-- Reconnect any players that may have joined during initialization. +-- (or restart the PlayerScripts manually if I'm offline testing) + +local StarterPlayerScripts = StarterPlayer:WaitForChild("StarterPlayerScripts") + +if isOnline then + for _,player in pairs(Players:GetPlayers()) do + TeleportService:TeleportToPlaceInstance(game.PlaceId, gameInst, player) + end +end + +if Chat.LoadDefaultChat then + warn("Chat.LoadDefaultChat should be set to false!") +end + +initMsg:Destroy() +return 0 \ No newline at end of file diff --git a/place.project.json b/place.project.json new file mode 100644 index 0000000..aaab7bb --- /dev/null +++ b/place.project.json @@ -0,0 +1,38 @@ +{ + "name": "Roblox-PNG-Library", + + "tree": + { + "$className": "DataModel", + + "ReplicatedStorage": + { + "$className": "ReplicatedStorage", + + "PNG": + { + "$path": "init.lua", + + "Chunks": + { + "$path": "Chunks" + }, + + "BinaryReader": + { + "$path": "Modules/BinaryReader.lua" + }, + + "Deflate": + { + "$path": "Modules/Deflate.lua" + }, + + "Unfilter": + { + "$path": "Modules/Unfilter.lua" + } + } + } + } +} \ No newline at end of file diff --git a/rojo-build.bat b/rojo-build.bat new file mode 100644 index 0000000..dcab747 --- /dev/null +++ b/rojo-build.bat @@ -0,0 +1,4 @@ +@echo off +rojo build -o Test.rbxmx + +pause \ No newline at end of file diff --git a/rojo-build.sh b/rojo-build.sh new file mode 100644 index 0000000..16c7e99 --- /dev/null +++ b/rojo-build.sh @@ -0,0 +1 @@ +rojo build -o PNG.rbxm diff --git a/rojo-serve.bat b/rojo-serve.bat new file mode 100644 index 0000000..4cb5052 --- /dev/null +++ b/rojo-serve.bat @@ -0,0 +1,4 @@ +@echo off +rojo serve place.project.json + +pause \ No newline at end of file diff --git a/rojo-serve.sh b/rojo-serve.sh new file mode 100644 index 0000000..75bc9c9 --- /dev/null +++ b/rojo-serve.sh @@ -0,0 +1 @@ +rojo serve place.project.json