1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Ride into the sunset with the 32nd Modeling Contest.
    Dismiss Notice
  5. This adventure has come to an end. Congratulate our heroes in the 16th Mini Mapping Contest Results.
    Dismiss Notice
  6. From the gates of hell, the 5th Special Effect Contest Results have emerged.
    Dismiss Notice
  7. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Combined Camera Slider System

Submitted by Sabe
This bundle is marked as pending. It has not been reviewed by a staff member yet.
Combined Camera Slider System

What is it?

Combined Camera Slider System (CCSS) is a system that combines all needs for a camera system: it allows you to modify all of the camera properties easily and GUI-friendly. It doesn't require any complex knowledge of JASS or even triggers in general for that matter. It even allows you to make a 3rd Person Camera easily in just a couple of clicks.

Why CCSS? (What does it do?)

CCSS is more capable (or at least simpler and easier) than any camera system you've come across with before (thanks to the fairly new JASS natives, that allow to make UI elements).

* Adjust all essential elements of a camera with a slide of a slider (distance, angle, rotation, height)
* All players can modify their own camera to their liking without a single chat command
* Awesome, sleek and neat-looking UI, that fits Warcraft 3, like it had been there from the start
* Set the settings to your personal and map's needs; you have the total control over how much players playing your map can adjust the camera
* Creating a 3rd or 1st Person Camera easier than ever before!
* Arrow key functions for rotating the camera in 3rd Person Mode already built-in
* Use WASD or Numpad keys to move the unit

Video preview:


How to install?

Step 0: Make sure you have "Automatically create unknown variables while pasting trigger data" ticked under World Editor's File -> Preferences...

Step 1: Open Combined Camera Slider System demo map
Step 2: Export the templates.toc file from the Import Manager (F12)
Step 3: Copy the "Combined Camera Slider System" trigger folder from the Trigger Editor.
Step 4: Paste the trigger folder to your own map
Step 5: Import the templates.toc file to your own map
Step 6: Done. Now set the settings the way you like on the "Combine Camera Sliders System Settings" trigger and go!​

How to use?

Basically, it's all ready to use as is. Of course, you can make your own modification within the Settings trigger.

Settings
  • Combined Camera Slider System Settings
    • -------- ===================================================================== --------
    • -------- --------
    • Set CCSS_CamUpdateInterval = 0.10
    • -------- The interval of how often the camera is updated. Smaller number will make the controls more responsive, but may have an effect on performance with many players. --------
    • -------- Default value: 0.10 --------
    • -------- --------
    • -------- --------
    • -------- CHECK BOX --------
    • -------- --------
    • Set CCSS_CheckBoxShow = True
    • -------- Whether to show the check box in-game at all. For example, you could prevent players themselves from changing the camera settings. --------
    • -------- --------
    • -------- Position: --------
    • Set CCSS_PositionCheckBoxX = 3.71
    • -------- X is the horizontal position. X is between 0.00 and 8.00. Default value: 3.71 --------
    • -------- 0.00 = the left edge of the screen 8.00 = the right side of the screen --------
    • -------- --------
    • Set CCSS_PositionCheckBoxY = 5.62
    • -------- Y is the horizontal position. Y is between 0.00 and 6.00. Default value: 5.62 --------
    • -------- 0.00 = bottom of the screen 6.00 = top edge of the screen --------
    • -------- --------
    • -------- Text: --------
    • Set CCSS_CheckBoxTextOnLeft = True
    • -------- Alignment on the left - If TRUE the text will be on the left side of the box. If FALSE, the text will be on the right side of the box. --------
    • -------- --------
    • Set CCSS_CheckBoxText = Camera Settings
    • -------- This is the actual text that is going to read next to the box. --------
    • -------- --------
    • -------- --------
    • -------- ===================================================================== --------
    • -------- --------
    • -------- --------
    • -------- SLIDERS --------
    • -------- --------
    • Set CCSS_ShowValues = True
    • -------- Set TRUE if you want the the exact values to be shown the next to the sliders. --------
    • -------- --------
    • -------- --------
    • -------- Slider settings: --------
    • -------- Show: Determines whether the slider is shown at all. --------
    • -------- Enabled: If set to TRUE all players can adjust them for their own liking. If FALSE, the slider will be locked. This setting can be changed any time during the game. --------
    • -------- Default: Default is the starting value and also the value the camera resets to when the button is pressed. --------
    • -------- Min: The minimum value for the slider. --------
    • -------- Max: The maximum value for the slider. --------
    • -------- Step: Determines in how large steps the value changes. For example, 15 step for Rotation means that you can change the rotation in steps of 15 degrees. --------
    • -------- --------
    • -------- --------
    • -------- Distance / Zoom --------
    • Set CCSS_DistanceShow = True
    • Set CCSS_DistanceEnabled = True
    • Set CCSS_DistanceDefault = 1650.00
    • Set CCSS_DistanceMin = 400.00
    • Set CCSS_DistanceMax = 3400.00
    • Set CCSS_DistanceStep = 5.00
    • -------- --------
    • -------- --------
    • -------- Angle --------
    • Set CCSS_AngleOfAttackShow = True
    • Set CCSS_AngleOfAttackEnabled = True
    • Set CCSS_AngleOfAttackDefault = 304.00
    • Set CCSS_AngleOfAttackMin = 270.00
    • Set CCSS_AngleOfAttackMax = 359.00
    • Set CCSS_AngleOfAttackStep = 0.50
    • -------- --------
    • -------- --------
    • -------- Rotation --------
    • Set CCSS_RotationShow = True
    • Set CCSS_RotationEnabled = True
    • Set CCSS_RotationDefault = 0.00
    • Set CCSS_RotationMin = -180.00
    • Set CCSS_RotationMax = 180.00
    • Set CCSS_RotationStep = 15.00
    • -------- --------
    • -------- --------
    • -------- Height --------
    • Set CCSS_HeightShow = True
    • Set CCSS_HeightEnabled = True
    • Set CCSS_HeightDefault = 0.00
    • Set CCSS_HeightMin = -200.00
    • Set CCSS_HeightMax = 400.00
    • Set CCSS_HeightStep = 1.00
    • -------- --------
    • -------- --------
    • -------- Positions: --------
    • Set CCSS_PositionSlidersX = 0.00
    • -------- X is the horizontal position. X is between 0.00 and 8.00. Default value: 0.00 --------
    • -------- 0.00 = the left edge of the screen 8.00 = the right side of the screen --------
    • -------- --------
    • Set CCSS_PositionSlidersY = 5.50
    • -------- Y is the horizontal position. Y is between 0.00 and 6.00. Default value: 5.50 --------
    • -------- 0.00 = bottom of the screen 6.00 = top edge of the screen --------
    • -------- --------
    • Set CCSS_AlignmentLeft = True
    • -------- Alignment Left: If TRUE, the sliders' texts will be on the right side of the sliders and reset buttons will be aligned to the left. If FALSE, texts will be on the left side and reset button is aligned to the right. --------
    • -------- --------
    • -------- --------
    • -------- Slider Gap: --------
    • Set CCSS_SliderGap = 0.05
    • -------- Determines how large the gap between sliders is. Default value: 0.05. --------
    • -------- --------
    • -------- --------
    • -------- ===================================================================== --------
    • -------- --------
    • -------- --------
    • -------- RESET BUTTON --------
    • -------- --------
    • -------- Size: --------
    • Set CCSS_ResetButtonSizeX = 1.10
    • -------- Horizontal size. Default value: 1.10 --------
    • -------- --------
    • Set CCSS_ResetButtonSizeY = 0.30
    • -------- Vertical size. Default value: 0.30 --------
    • -------- --------
    • -------- --------
    • -------- Text --------
    • Set CCSS_ResetButtonText = Reset Camera
    • -------- The text that will read on the button --------
    • -------- --------
    • -------- --------
    • -------- ===================================================================== --------
    • -------- --------
    • -------- --------
    • -------- THIRD PERSON CAMERA MODE --------
    • -------- --------
    • Set CCSS_3rdPersonCamMode = True
    • -------- Set TRUE if you want to allow a third person camera. See the trigger SET TARGET UNIT for more info. --------
    • -------- --------
    • -------- --------
    • Set CCSS_AddUnitHeightToCamera = True
    • -------- If TRUE, the Target Unit's height (flying units) will affect the camera's height as well. --------
    • -------- --------
    • -------- --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- Arrow Key settings: --------
    • -------- --------
    • Set CCSS_UseArrowKeys = True
    • -------- If TRUE, players can look around (turn the camera) with arrow keys. --------
    • -------- --------
    • -------- --------
    • Set CCSS_HorizontalSpeed = 10.00
    • -------- Sets the speed at which rate the camera rotates horizontally. Default value: 10.00 --------
    • -------- --------
    • Set CCSS_HorizontalArrowMoveLimit = 180.00
    • -------- Sets the limit to how far the horizontal rotation goes, so it won't just roll around the Target Unit forever. Default value: 180.00 --------
    • -------- --------
    • Set CCSS_InvertHorizontalMovement = False
    • -------- Inverts the direction of the left and right arrow keys. --------
    • -------- --------
    • -------- --------
    • Set CCSS_VerticalSpeed = 6.00
    • -------- Sets the speed at which rate the camera changes angle vertically. Default value: 6.00 --------
    • -------- --------
    • Set CCSS_InvertVerticalMovement = False
    • -------- Inverts the direction of the up and down arrow keys. --------
    • -------- --------
    • -------- --------
    • Set CCSS_HorizontalReturnSpeed = 1.50
    • Set CCSS_VerticalReturnSpeed = 1.50
    • -------- Return Speed will determine the speed at which rate the camera resets back to normal view after releasing the arrow keys. --------
    • -------- 0.00 = The camera won't return automatically --------
    • -------- 1.00 = Camera will return the same speed as it moves with arrow keys --------
    • -------- 2.00 = Camera returns twice the speed it moves with arrow keys, and so on. --------
    • -------- --------
    • -------- --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- WASD key settings: --------
    • -------- --------
    • Set CCSS_UseWASDKeys = True
    • -------- If TRUE, players can move and turn the unit in 3rd person mode with WASD keys --------
    • -------- --------
    • Set CCSS_UseNumpadKeys = False
    • -------- Use the Numpad instead of WASD for moving --------
    • -------- --------
    • -------- --------
    • Set CCSS_WASDMoveOrderInterval = 0.25
    • -------- Higher number will cause the unit to be ordered to move more often. Default value: 0.25 --------
    • -------- DECREASE if unit animation stutters --------
    • -------- --------
    • Set CCSS_WASDMoveMinDistance = 130.00
    • -------- The minimum distance the unit moves with one push of W or Numpad_8 button. Default value: 130 --------
    • -------- INCREASE if slow units stop even if forward button is hold down --------
    • -------- --------
    • Set CCSS_WASDMoveSpeedModifier = 2.25
    • -------- Counts the minimum distance for one move interval depending on unit's movement speed. Default value: 2.25 --------
    • -------- DECREASE if fast units stop even if forward button is hold down --------
    • -------- --------
    • -------- --------
    • Set CCSS_WASDTurnSpeed = 40.00
    • -------- Set the speed at which rate the unit turns with A and D keys. Default value: 40.00 --------
    • -------- Note, that the unit's own turn rate will have the last say on the actualy turn speed --------
    • -------- --------
    • Set CCSS_WASDStationaryTurnSpeed = 16.00
    • -------- The speed the unit turns when turning while not moving. Default value: 16.00 --------
    • -------- --------
    • -------- --------
    • Set CCSS_SButton180Turn = False
    • -------- If TRUE, the unit will make a 180 turn when S or Numpad_5 is pressed while not moving --------
    • -------- --------
    • Set CCSS_XButton180Turn = True
    • -------- If TRUE, the unit will make a 180 turn when X or Numpad_2 is pressed while not moving --------
    • -------- --------
    • Set CCSS_SButtonOrder = stop
    • -------- Order which is given to the unit when the S or Numpad_5 button is pressed down --------
    • -------- --------
    • -------- --------
    • -------- ===================================================================== --------
    • -------- --------
    • -------- --------
    • -------- --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- ------------------------------------------------------------------------------------------------------------------------------------------ --------
    • -------- This will run the script. It is essential that this is ran after all the other setting variables are set. --------
    • Custom script: call CreateCamControl()


For setting up a Third or First Person Camera, only two lines of code are actually required. Although you might want to make up a bit more specific conditions or perhaps set one specific unit for each player.

For the camera rotation:
1. Set CCSS_TargetUnit[(Player number of the player who follows this unit)] to the unit to be followed
To lock the camera position to the unit, use the normal GUI function:
2. Camera - Lock Camera Target to Unit
Here is a simple example:

Setting Up 3rdPC
  • Set Target Unit
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
      • Player - Player 2 (Blue) skips a cinematic sequence
    • Conditions
    • Actions
      • -------- This is an example trigger how to assign the target unit a player's camera will follow in Third Person Camera mode. --------
      • -------- ---------------------------------------------------------------------- --------
      • -------- This IF is just used to also break the connection with a player and a unit. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • CCSS_TargetUnit[(Player number of (Triggering player))] Equal to No unit
        • Then - Actions
          • -------- These two actions are basically all you need. Of course you might want to give it some conditions, but just to show an example. --------
          • -------- (Also, ignore all the leaks for simplicity's sake) --------
          • -------- --------
          • -------- The first line locks the rotation to the unit. --------
          • Set CCSS_TargetUnit[(Player number of (Triggering player))] = (Random unit from (Units currently selected by (Triggering player)))
          • -------- Use the normal GUI function to lock the camera position to the unit. --------
          • Camera - Lock camera target for (Triggering player) to CCSS_TargetUnit[(Player number of (Triggering player))], offset by (0.00, 0.00) using Default rotation
          • -------- --------
        • Else - Actions
          • -------- This is an example how you can break the Third Person Camera mode --------
          • -------- Remember to also free the camera from the unit lock: --------
          • -------- --------
          • Set CCSS_TargetUnit[(Player number of (Triggering player))] = No unit
          • Camera - Reset camera for (Triggering player) to standard game-view over 0.00 seconds
          • -------- --------


Here's a look to the whole code, if you're interested:
(In fact, I'm not any kind of master in JASS coding, so all hints and tips are most welcome!)

Code
Code (vJASS):
library CombinedCameraSliderSystem
   
    //----------------------------------------------\\
    //                                              \\
    //  Version 1.2                                 \\
    //  Written by Sabe / Sabeximus#2923            \\
    //                                              \\
    //----------------------------------------------\\
   
   
    globals
        private framehandle      sliderDistance
        private framehandle      sliderDistanceLabel
        private framehandle      sliderAngleOfAttack
        private framehandle      sliderAngleOfAttackLabel
        private framehandle      sliderRotation
        private framehandle      sliderRotationLabel
        private framehandle      sliderHeight
        private framehandle      sliderHeightLabel
        private framehandle      resetButton
        private framehandle      sliderAbove
       
        private framepointtype   framepointVerticalMain
        private framepointtype   framepointVerticalSecondary
        private framepointtype   framepointCornerMain
       
        private framepointtype   framepointCheckboxMain
        private framepointtype   framepointCheckboxSecondary
       
        private boolean  array   leftArrowIsDown
        private boolean  array   upArrowIsDown
        private boolean  array   downArrowIsDown
        private boolean  array   rightArrowIsDown
        private boolean  array   wKeyIsDown
        private boolean  array   aKeyIsDown
        private boolean  array   sKeyIsDown
        private boolean  array   dKeyIsDown
        private boolean  array   xKeyIsDown
        private real     array   horizontalChange
        private real     array   verticalChange

        private real     array   xTarget
        private real     array   yTarget
        private real     array   forward
        private real     array   sideways
        private real     array   orderDelay
        private real     array   fullTurnDelay
        private boolean          debugMode                    = false
    endglobals
   
    private function LoadToc takes string s returns nothing
        if not BlzLoadTOCFile(s) then
            call BJDebugMsg("|cffff0000Failed to Load: " + s + "|r \nYou need to import the |cffffcc00templates.toc|r file.")
        endif  
    endfunction

    private function UpdateCam takes nothing returns nothing
        local integer i = GetPlayerId(GetEnumPlayer())
        local unit u = udg_CCSS_TargetUnit[i + 1]
        local real facing = GetUnitFacing(u)
        local real moveSpeed = GetUnitMoveSpeed(u)
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real hDir = 0
        local real vDir = 0
        call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_TARGET_DISTANCE, BlzFrameGetValue(sliderDistance), udg_CCSS_CamUpdateInterval)
       
        if (udg_CCSS_3rdPersonCamMode) then // Check if Third Person Camera mode is enabled
            if (((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys)) and (u != null)) then // Unit WASD control. Obviously, run these only if the WASD keys are enabled and there is a Target Unit
                if (wKeyIsDown[i]) then
                    set forward[i] = 1
                else
                    set forward[i] = 0
                endif

                if (aKeyIsDown[i]) then
                    set sideways[i] = sideways[i] - 1
                endif

                if (dKeyIsDown[i]) then
                    set sideways[i] = sideways[i] + 1
                endif

                set xTarget[i] = x
                set yTarget[i] = y

                if ((moveSpeed / udg_CCSS_WASDMoveSpeedModifier) < udg_CCSS_WASDMoveMinDistance) then
                    set moveSpeed = udg_CCSS_WASDMoveMinDistance
                else
                    set moveSpeed = moveSpeed / udg_CCSS_WASDMoveSpeedModifier
                endif

                if (forward[i] == 1) then
                    set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing)) * (moveSpeed)
                    set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing)) * (moveSpeed)

                    if (sideways[i] < 0) then
                        set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
                        set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
                        call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
                        set sideways[i] = 0
                    endif
               
                    if (sideways[i] > 0) then
                        set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
                        set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
                        call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
                        set sideways[i] = 0
                    endif
                else
                    if (sideways[i] == -1) then
                        call SetUnitFacing(u, facing + (udg_CCSS_WASDStationaryTurnSpeed))
                        set sideways[i] = 0
                    endif

                    if (sideways[i] == 1) then
                        call SetUnitFacing(u, facing - (udg_CCSS_WASDStationaryTurnSpeed))
                        set sideways[i] = 0
                    endif

                    if (udg_CCSS_SButtonOrder != "") then
                        if (sKeyIsDown[i]) then
                            call IssueImmediateOrder(u, udg_CCSS_SButtonOrder)
                        endif
                    endif

                    set fullTurnDelay[i] = fullTurnDelay[i] - udg_CCSS_CamUpdateInterval
                    if (fullTurnDelay[i] <= 0) then
                        if (udg_CCSS_SButton180Turn) then
                            if (sKeyIsDown[i]) then
                                set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
                                call SetUnitFacing(u, facing - 180)
                            endif
                        endif

                        if (udg_CCSS_XButton180Turn) then
                            if (xKeyIsDown[i]) then
                                set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
                                call SetUnitFacing(u, facing - 180)
                            endif
                        endif
                    endif
                endif

                set orderDelay[i] = orderDelay[i] - udg_CCSS_WASDMoveOrderInterval
                if (orderDelay[i] <= 0) then
                    set orderDelay[i] = 1
                    if ((forward[i] != 0) or (sideways[i] != 0)) then
                        call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
                        set sideways[i] = 0
                    endif
                endif
            endif

            if (udg_CCSS_UseArrowKeys) then // Only run these if the Arrow Keys are used
               
                // Horizontal Key Register
                if (leftArrowIsDown[i]) then
                    if (udg_CCSS_InvertHorizontalMovement) then
                        if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
                            set hDir = hDir - 1
                        endif
                    else
                        if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
                            set hDir = hDir + 1
                        endif
                    endif
                endif
                if (rightArrowIsDown[i]) then
                    if (udg_CCSS_InvertHorizontalMovement) then
                        if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
                            set hDir = hDir + 1
                        endif
                    else
                        if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
                            set hDir = hDir - 1
                        endif
                    endif
                endif
               
                set horizontalChange[i] = horizontalChange[i] + (hDir * udg_CCSS_HorizontalSpeed)
                if ((hDir == 0) and (horizontalChange[i] != 0)) then
                    if (horizontalChange[i] > 0) then
                        set horizontalChange[i] = horizontalChange[i] - (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
                        if (horizontalChange[i] < udg_CCSS_HorizontalSpeed) then
                            set horizontalChange[i] = 0
                        endif
                    else
                        set horizontalChange[i] = horizontalChange[i] + (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
                        if (horizontalChange[i] > udg_CCSS_HorizontalSpeed) then
                            set horizontalChange[i] = 0
                        endif
                    endif
                endif

                // Vertical Key Register
                if (upArrowIsDown[i]) then
                    if (udg_CCSS_InvertVerticalMovement) then
                        if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
                            set vDir = vDir - 1
                        endif
                    else
                        if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then // Don't allow the number to grow if camera had stopped at the limit
                            set vDir = vDir + 1
                        endif
                    endif
                endif
                if (downArrowIsDown[i]) then
                    if (udg_CCSS_InvertVerticalMovement) then
                        if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then
                            set vDir = vDir + 1
                        endif
                    else
                        if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
                            set vDir = vDir - 1
                        endif
                    endif
                endif

                set verticalChange[i] = verticalChange[i] + (vDir * udg_CCSS_VerticalSpeed)
                if ((vDir == 0) and (verticalChange[i] != 0)) then
                    if (verticalChange[i] > 0) then
                        set verticalChange[i] = verticalChange[i] - (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
                        if (verticalChange[i] < udg_CCSS_VerticalSpeed) then
                            set verticalChange[i] = 0
                        endif
                    else
                        set verticalChange[i] = verticalChange[i] + (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
                        if (verticalChange[i] > udg_CCSS_VerticalSpeed) then
                            set verticalChange[i] = 0
                        endif
                    endif
                endif

               
            endif
           
            // Apply arrow key changes
            if (u != null) then // Check if our player has a Target Unit
                // Horizontal
                if (horizontalChange[i] > udg_CCSS_HorizontalArrowMoveLimit) then
                    call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval) // Prevent camera from rolling around the unit forever
                else
                    if (horizontalChange[i] < -udg_CCSS_HorizontalArrowMoveLimit) then
                        call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing - udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval)
                    else
                        call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + horizontalChange[i], udg_CCSS_CamUpdateInterval)
                    endif
                endif
               
                if (GetLocalPlayer() == Player(i)) then // Lock the rotation bar. Purely cosmetic, can be removed if, for example, causes desync problems. (The bar won't affect rotation even if not locked)
                     call BlzFrameSetEnable(sliderRotation, false)
                endif

                // Vertical
                if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) > (udg_CCSS_AngleOfAttackMax)) then // Prevent camera from overstepping angle of attack slider maximum and minimum.
                    call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMax, udg_CCSS_CamUpdateInterval)
                else
                    if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) < (udg_CCSS_AngleOfAttackMin)) then
                        call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMin, udg_CCSS_CamUpdateInterval)
                    else
                        call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i], udg_CCSS_CamUpdateInterval)
                    endif
                endif

                // Add Unit Height to Camera
                if (udg_CCSS_AddUnitHeightToCamera) then
                    call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight) + GetUnitFlyHeight(u), udg_CCSS_CamUpdateInterval)
                endif

            else                // If doesn't have Target Unit
                // Horizontal
                call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 Because I want the default rotation angle (90) to be zero for simplicity's sake
               
                if ((GetLocalPlayer() == GetEnumPlayer()) and (udg_CCSS_RotationEnabled)) then
                    call BlzFrameSetEnable(sliderRotation, true)
                endif

                // Vertical
                call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)

                // Height
                call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
            endif
        else // Only run this if 3rdPC mode is not used
            call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 so that 0 on the slider is the default WC3 angle
            call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)
            call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
        endif

        set u = null
    endfunction

    private function HumanPlayersPlaying takes nothing returns boolean
        if (GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER) and (GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING) then
            return true
        else
            return false
        endif
    endfunction

    private function PreUpdateCam takes nothing returns nothing
        local force f = GetPlayersMatching(Condition(function HumanPlayersPlaying)) // No point in picking computer players
        call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
        call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
        call BlzFrameSetEnable(sliderRotation, udg_CCSS_DistanceEnabled)
        call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
       
        if (udg_CCSS_ShowValues) then
            call BlzFrameSetText(sliderDistanceLabel, "Distance: " + R2SW(BlzFrameGetValue(sliderDistance), 1, 1))
            call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle: " + R2SW(BlzFrameGetValue(sliderAngleOfAttack), 1, 1))
            call BlzFrameSetText(sliderRotationLabel, "Rotation: " + R2SW(BlzFrameGetValue(sliderRotation), 1, 1))
            call BlzFrameSetText(sliderHeightLabel, "Height: " + R2SW(BlzFrameGetValue(sliderHeight), 1, 1))
        else
            call BlzFrameSetText(sliderDistanceLabel, "Distance")
            call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle")
            call BlzFrameSetText(sliderRotationLabel, "Rotation")
            call BlzFrameSetText(sliderHeightLabel, "Height")
        endif
       
        call ForForce(f, function UpdateCam)
        call DestroyForce(f)
    endfunction

    private function CreateSliders takes nothing returns nothing
        local real labelGap
        set sliderDistance = BlzCreateFrame("EscMenuSliderTemplate",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        set sliderDistanceLabel = BlzCreateFrame("EscMenuLabelTextTemplate",  sliderDistance, 0, 0)
        set sliderAngleOfAttack = BlzCreateFrame("EscMenuSliderTemplate",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 1)
        set sliderAngleOfAttackLabel = BlzCreateFrame("EscMenuLabelTextTemplate",  sliderAngleOfAttack, 0, 0)
        set sliderRotation = BlzCreateFrame("EscMenuSliderTemplate",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 2)
        set sliderRotationLabel = BlzCreateFrame("EscMenuLabelTextTemplate",  sliderRotation, 0, 0)
        set sliderHeight = BlzCreateFrame("EscMenuSliderTemplate",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 3)
        set sliderHeightLabel = BlzCreateFrame("EscMenuLabelTextTemplate",  sliderHeight, 0, 0)
        set sliderAbove = null
       
        if (udg_CCSS_PositionSlidersX >= 8) then
            set udg_CCSS_PositionSlidersX = 0.8
        else
            if (udg_CCSS_PositionSlidersX < 0) then
                set udg_CCSS_PositionSlidersX = 0
            else
                set udg_CCSS_PositionSlidersX = udg_CCSS_PositionSlidersX / 10 // GUI only allows 2 decimals for reals, so this way I can get 3 decimals for JASS
            endif
        endif

        if (udg_CCSS_PositionSlidersY >= 6) then
            set udg_CCSS_PositionSlidersY = 0.6
        else
            if (udg_CCSS_PositionSlidersY < 0) then
                set udg_CCSS_PositionSlidersY = 0
            else
                set udg_CCSS_PositionSlidersY = udg_CCSS_PositionSlidersY / 10
            endif
        endif
       
        set udg_CCSS_SliderGap = udg_CCSS_SliderGap / 10
       
        if (udg_CCSS_AlignmentLeft) then
            set framepointVerticalMain = FRAMEPOINT_LEFT
            set framepointVerticalSecondary = FRAMEPOINT_RIGHT
            set framepointCornerMain = FRAMEPOINT_TOPLEFT
            set labelGap = 0.005
        else
            set framepointVerticalMain = FRAMEPOINT_RIGHT
            set framepointVerticalSecondary = FRAMEPOINT_LEFT
            set framepointCornerMain = FRAMEPOINT_TOPRIGHT
            set labelGap = -0.005
        endif

        //Distance Slider options
        call BlzFrameSetAbsPoint(sliderDistance, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
        call BlzFrameSetPoint(sliderDistanceLabel, framepointVerticalMain, sliderDistance, framepointVerticalSecondary, labelGap, 0)
        call BlzFrameSetMinMaxValue(sliderDistance, udg_CCSS_DistanceMin, udg_CCSS_DistanceMax)
        call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
        call BlzFrameSetStepSize(sliderDistance, udg_CCSS_DistanceStep)
        call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
        if (udg_CCSS_DistanceShow) then
            set sliderAbove = sliderDistance
        endif
        call BlzFrameSetVisible(sliderDistance, false)

        //Angle of Attack Slider options
        if (sliderAbove != null) then
            call BlzFrameSetPoint(sliderAngleOfAttack, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
        else
            call BlzFrameSetAbsPoint(sliderAngleOfAttack, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
        endif
        call BlzFrameSetPoint(sliderAngleOfAttackLabel, framepointVerticalMain, sliderAngleOfAttack, framepointVerticalSecondary, labelGap, 0)
        call BlzFrameSetMinMaxValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackMin, udg_CCSS_AngleOfAttackMax)
        call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
        call BlzFrameSetStepSize(sliderAngleOfAttack, udg_CCSS_AngleOfAttackStep)
        call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
        if (udg_CCSS_AngleOfAttackShow) then
            set sliderAbove = sliderAngleOfAttack
        endif
        call BlzFrameSetVisible(sliderAngleOfAttack, false)
       
        //Rotation Slider options
        if (sliderAbove != null) then
            call BlzFrameSetPoint(sliderRotation, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
        else
            call BlzFrameSetAbsPoint(sliderRotation, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
        endif
        call BlzFrameSetPoint(sliderRotationLabel, framepointVerticalMain, sliderRotation, framepointVerticalSecondary, labelGap, 0)
        call BlzFrameSetMinMaxValue(sliderRotation, udg_CCSS_RotationMin, udg_CCSS_RotationMax)
        call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
        call BlzFrameSetStepSize(sliderRotation, udg_CCSS_RotationStep)
        call BlzFrameSetEnable(sliderRotation, udg_CCSS_RotationEnabled)
        if (udg_CCSS_RotationShow) then
            set sliderAbove = sliderRotation
        endif
        call BlzFrameSetVisible(sliderRotation, false)
       
        //Height Slider options
        if (sliderAbove != null) then
            call BlzFrameSetPoint(sliderHeight, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
        else
            call BlzFrameSetAbsPoint(sliderHeight, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
        endif
        call BlzFrameSetPoint(sliderHeightLabel, framepointVerticalMain, sliderHeight, framepointVerticalSecondary, labelGap, 0)
        call BlzFrameSetMinMaxValue(sliderHeight, udg_CCSS_HeightMin, udg_CCSS_HeightMax)
        call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
        call BlzFrameSetStepSize(sliderHeight, udg_CCSS_HeightStep)
        call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
        if (udg_CCSS_HeightShow) then
            set sliderAbove = sliderHeight
        endif
        call BlzFrameSetVisible(sliderHeight, false)
    endfunction

    private function ResetSliders takes nothing returns nothing
        if GetLocalPlayer() == GetTriggerPlayer() then
            call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
            call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
            call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
            call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
        endif
       
        call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
        call BlzFrameSetEnable(BlzGetTriggerFrame(), true)
    endfunction

    private function CreateResetButton takes nothing returns nothing
        local trigger t = CreateTrigger()
        set resetButton = BlzCreateFrame("ScriptDialogButton",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        set udg_CCSS_ResetButtonSizeX = udg_CCSS_ResetButtonSizeX / 10
        set udg_CCSS_ResetButtonSizeY = udg_CCSS_ResetButtonSizeY / 10
       
        if (sliderAbove != null) then
            call BlzFrameSetPoint(resetButton, framepointCornerMain, sliderAbove, framepointVerticalMain, 0, -(udg_CCSS_SliderGap * 2))
        else
            call BlzFrameSetAbsPoint(resetButton, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
        endif
        call BlzFrameSetSize(resetButton, udg_CCSS_ResetButtonSizeX, udg_CCSS_ResetButtonSizeY)
        call BlzFrameSetText(resetButton, udg_CCSS_ResetButtonText)
        call BlzFrameSetVisible(resetButton, false)
       
        call TriggerAddAction(t, function ResetSliders)
        call BlzTriggerRegisterFrameEvent(t, resetButton, FRAMEEVENT_CONTROL_CLICK)
    endfunction

    private function CheckBoxLockSliders takes nothing returns nothing
        local boolean b = (BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED)
        if GetLocalPlayer() == GetTriggerPlayer() then
            if (udg_CCSS_DistanceShow) then
                call BlzFrameSetVisible(sliderDistance, b)
            endif
            if (udg_CCSS_AngleOfAttackShow) then
                call BlzFrameSetVisible(sliderAngleOfAttack, b)
            endif
            if (udg_CCSS_RotationShow) then
                call BlzFrameSetVisible(sliderRotation, b)
            endif
            if (udg_CCSS_HeightShow) then
                call BlzFrameSetVisible(sliderHeight, b)
            endif
            call BlzFrameSetVisible(resetButton, b)
        endif  
    endfunction

    private function CreateCheckbox takes nothing returns nothing
        local trigger t = CreateTrigger()
        local framehandle fh = BlzCreateFrame("QuestCheckBox",  BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        local framehandle label = BlzCreateFrame("EscMenuLabelTextTemplate",  fh, 0, 0)
        local real labelGap
       
        if (udg_CCSS_PositionCheckBoxX >= 8) then
            set udg_CCSS_PositionCheckBoxX = 0.8
        else
            if (udg_CCSS_PositionCheckBoxX < 0) then
                set udg_CCSS_PositionCheckBoxX = 0
            else
                set udg_CCSS_PositionCheckBoxX = udg_CCSS_PositionCheckBoxX / 10
            endif
        endif

        if (udg_CCSS_PositionCheckBoxY >= 6) then
            set udg_CCSS_PositionCheckBoxY = 0.6
        else
            if (udg_CCSS_PositionCheckBoxY < 0) then
                set udg_CCSS_PositionCheckBoxY = 0
            else
                set udg_CCSS_PositionCheckBoxY = udg_CCSS_PositionCheckBoxY / 10
            endif
        endif
       
        if (udg_CCSS_CheckBoxTextOnLeft) then
            set framepointCheckboxMain = FRAMEPOINT_RIGHT
            set framepointCheckboxSecondary = FRAMEPOINT_LEFT
            set labelGap = -0.005
        else
            set framepointCheckboxMain = FRAMEPOINT_LEFT
            set framepointCheckboxSecondary = FRAMEPOINT_RIGHT
            set labelGap = 0.005
        endif
       
        call BlzFrameSetPoint(label, framepointCheckboxMain, fh, framepointCheckboxSecondary, labelGap, 0)
        call BlzFrameSetAbsPoint(fh, framepointCheckboxMain, udg_CCSS_PositionCheckBoxX, udg_CCSS_PositionCheckBoxY)  
        call BlzFrameSetText(label, udg_CCSS_CheckBoxText)
        call BlzFrameSetVisible(fh, udg_CCSS_CheckBoxShow)
       
        call TriggerAddAction(t, function CheckBoxLockSliders)
        call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_CHECKED)
        call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_UNCHECKED)
    endfunction
   
    // Arrow keys
   
    private function LeftArrowPress takes nothing returns nothing
        set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
    endfunction
   
    private function LeftArrowRelease takes nothing returns nothing
        set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
    endfunction
   
    private function UpArrowPress takes nothing returns nothing
        set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
    endfunction
   
    private function UpArrowRelease takes nothing returns nothing
        set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
    endfunction
   
    private function DownArrowPress takes nothing returns nothing
        set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
    endfunction
   
    private function DownArrowRelease takes nothing returns nothing
        set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
    endfunction
   
    private function RightArrowPress takes nothing returns nothing
        set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
    endfunction
   
    private function RightArrowRelease takes nothing returns nothing
        set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
    endfunction

    private function ArrowKeyListeners takes nothing returns nothing
        local trigger tLp = CreateTrigger()
        local trigger tUp = CreateTrigger()
        local trigger tDp = CreateTrigger()
        local trigger tRp = CreateTrigger()
        local trigger tLr = CreateTrigger()
        local trigger tUr = CreateTrigger()
        local trigger tDr = CreateTrigger()
        local trigger tRr = CreateTrigger()
        local integer i
       
        set i = 0
        loop
            call TriggerRegisterPlayerKeyEventBJ(tLp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_LEFT)
            call TriggerRegisterPlayerKeyEventBJ(tLr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_LEFT)
            call TriggerRegisterPlayerKeyEventBJ(tUp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_UP)
            call TriggerRegisterPlayerKeyEventBJ(tUr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_UP)
            call TriggerRegisterPlayerKeyEventBJ(tDp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_DOWN)
            call TriggerRegisterPlayerKeyEventBJ(tDr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_DOWN)
            call TriggerRegisterPlayerKeyEventBJ(tRp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_RIGHT)
            call TriggerRegisterPlayerKeyEventBJ(tRr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_RIGHT)
            set i = i + 1
            exitwhen i > bj_MAX_PLAYER_SLOTS
        endloop
       
        call TriggerAddAction(tLp, function LeftArrowPress)
        call TriggerAddAction(tLr, function LeftArrowRelease)
        call TriggerAddAction(tUp, function UpArrowPress)
        call TriggerAddAction(tUr, function UpArrowRelease)
        call TriggerAddAction(tDp, function DownArrowPress)
        call TriggerAddAction(tDr, function DownArrowRelease)
        call TriggerAddAction(tRp, function RightArrowPress)
        call TriggerAddAction(tRr, function RightArrowRelease)
    endfunction

    // WASD keys

    private function WKey takes nothing returns nothing
        set wKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
        if (debugMode) then
            if BlzGetTriggerPlayerIsKeyDown() then
                call BJDebugMsg("W is pressed")
            else
                call BJDebugMsg("W is released")
            endif
        endif
    endfunction
   
    private function AKey takes nothing returns nothing
        set aKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
        if (debugMode) then
            if BlzGetTriggerPlayerIsKeyDown() then
                call BJDebugMsg("A is pressed")
            else
                call BJDebugMsg("A is released")
            endif
        endif
    endfunction
   
    private function SKey takes nothing returns nothing
        set sKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
        if (debugMode) then
            if BlzGetTriggerPlayerIsKeyDown() then
                call BJDebugMsg("S is pressed")
            else
                call BJDebugMsg("S is released")
            endif
        endif
    endfunction
   
    private function DKey takes nothing returns nothing
        set dKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
        if (debugMode) then
            if BlzGetTriggerPlayerIsKeyDown() then
                call BJDebugMsg("D is pressed")
            else
                call BJDebugMsg("D is released")
            endif
        endif
    endfunction

    private function XKey takes nothing returns nothing
        set xKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
        if (debugMode) then
            if BlzGetTriggerPlayerIsKeyDown() then
                call BJDebugMsg("X is pressed")
            else
                call BJDebugMsg("X is released")
            endif
        endif
    endfunction

    private function WASDKeyListeners takes nothing returns nothing
        local trigger tWp = CreateTrigger()
        local trigger tAp = CreateTrigger()
        local trigger tSp = CreateTrigger()
        local trigger tDp = CreateTrigger()
        local trigger tWr = CreateTrigger()
        local trigger tAr = CreateTrigger()
        local trigger tSr = CreateTrigger()
        local trigger tDr = CreateTrigger()
        local trigger tXp = CreateTrigger()
        local trigger tXr = CreateTrigger()
        local integer i
       
        set i = 0
        loop
            if (udg_CCSS_UseNumpadKeys) then
                call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_NUMPAD8, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_NUMPAD8, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_NUMPAD4, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_NUMPAD4, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_NUMPAD5, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_NUMPAD5, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_NUMPAD6, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_NUMPAD6, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_NUMPAD2, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_NUMPAD2, 0, false)
            else
                call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_W, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_W, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_A, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_A, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_S, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_S, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_D, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_D, 0, false)
                call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_X, 0, true)
                call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_X, 0, false)
            endif

            set orderDelay[i] = 0
            set fullTurnDelay[i] = 0
            set i = i + 1
            exitwhen i > bj_MAX_PLAYER_SLOTS
        endloop
       
        call TriggerAddAction(tWp, function WKey)
        call TriggerAddAction(tWr, function WKey)
        call TriggerAddAction(tAp, function AKey)
        call TriggerAddAction(tAr, function AKey)
        call TriggerAddAction(tSp, function SKey)
        call TriggerAddAction(tSr, function SKey)
        call TriggerAddAction(tDp, function DKey)
        call TriggerAddAction(tDr, function DKey)
        call TriggerAddAction(tXp, function XKey)
        call TriggerAddAction(tXr, function XKey)
    endfunction
   
   
//=============================================================================
    function CreateCamControl takes nothing returns nothing
        call LoadToc("war3mapimported\\templates.toc")
        call CreateSliders()
        call CreateCheckbox()
        call CreateResetButton()
        if ((udg_CCSS_3rdPersonCamMode) and (udg_CCSS_UseArrowKeys)) then // If 3rd Person Cam and Arrow keys aren't enabled, don't bother to create triggers for listening the keys
            call ArrowKeyListeners()
        endif
        if ((udg_CCSS_3rdPersonCamMode) and ((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys))) then
            call WASDKeyListeners()
        endif
        call TimerStart(CreateTimer(), udg_CCSS_CamUpdateInterval, true, function PreUpdateCam)

        set debugMode = false // Turn true for testing purposes
    endfunction
endlibrary




Known issues:

- For units with Collision size from 16 to 31 the camera rotates slightly off the center position of the unit for some unknown reason. Not game-breaking, but can be slightly annoying. (Can be seen in the review video, when a Footman is the 3rd Person Camera Target Unit.)



Credits:

@Tasyen - This seriously could not have been possible without you! Thank you for your personal help and awesome tutorials that got me into JASS coding.



Changelog
Update: v.1.2.18
- Camera should be now a lot smoother even with slower update intervals. Faster cam update will now make moving with WASD keys a bit more responsive, but even a 0.1 sec update speed should be perfectly fine.

Update: v1.1.19

- WASD and Numpad unit moving now built-in as well
Contents

CCSS v1.2.18 (Map)

  1. Swatosj

    Swatosj

    Joined:
    Jun 12, 2018
    Messages:
    133
    Resources:
    0
    Resources:
    0
    Glad to see you are also working on vJass scripts :) I'm learning it too and it find it quite friendly after spending couple hours.

    This is a useful GUI system that can be used on many maps, I'll dig the code to inspire myself learning custom UI !

    Documentation is clear and code looks clean to me.
     
  2. Sabe

    Sabe

    Joined:
    Jul 30, 2018
    Messages:
    431
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Thanks! :)
     
  3. Wrda

    Wrda

    Joined:
    Nov 18, 2012
    Messages:
    1,243
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Every variables in caps lock, known as constants, should have the constant keyword.
    I see you have some variables lowercase on first letter and then rest uppercase on each word and others uppercase on first letter and then uppercase next words, for a matter of coherence, make up your mind :p
    This is quite great.
     
  4. Sabe

    Sabe

    Joined:
    Jul 30, 2018
    Messages:
    431
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Thanks for the reply!

    And good point! I went through it again and it should be a bit more consistent now. :)
     
  5. BrothForMyPeople

    BrothForMyPeople

    Joined:
    Jul 9, 2017
    Messages:
    284
    Resources:
    0
    Resources:
    0
    World of Warcraft making of :)
    Huge piece of great job.
     
  6. DrTema

    DrTema

    Joined:
    Dec 31, 2013
    Messages:
    111
    Resources:
    0
    Resources:
    0
    So this is reforged only verion?
     
  7. Sabe

    Sabe

    Joined:
    Jul 30, 2018
    Messages:
    431
    Resources:
    1
    Spells:
    1
    Resources:
    1
    It requires 1.31 or later version, since that's when the UI elements were introduced.