├── .gitattributes ├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keys └── AdvancedTrainSimulator.bikey ├── libs └── PBOGradlePlugin.jar ├── logo.paa ├── logo.png ├── logo.psd ├── mod.cpp ├── screenshots ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── track_placement_1.jpg └── track_placement_2.jpg ├── src └── addons │ └── ats │ └── core │ ├── $PBOPREFIX$ │ ├── config.cpp │ ├── functions │ ├── camera │ │ ├── camera.h │ │ ├── fn_cameraMouseMoveHandler.sqf │ │ ├── fn_cameraMouseZoomHandler.sqf │ │ ├── fn_cameraUpdatePosition.sqf │ │ ├── fn_disable3rdPersonCamera.sqf │ │ └── fn_enable3rdPersonCamera.sqf │ ├── common │ │ ├── fn_RemoteExec.sqf │ │ ├── fn_RemoteExecServer.sqf │ │ ├── fn_addEventHandler.sqf │ │ ├── fn_getTypeOf.sqf │ │ ├── fn_hidePlayerObjectGlobal.sqf │ │ ├── fn_rebuildArrayLookupIndexes.sqf │ │ ├── fn_removeAllEventHandlers.sqf │ │ └── fn_removeEventHandler.sqf │ ├── debugging │ │ ├── fn_createMarker.sqf │ │ ├── fn_getProfile.sqf │ │ ├── fn_initTrackTestAction.sqf │ │ ├── fn_printProfiles.sqf │ │ ├── fn_profileInit.sqf │ │ ├── fn_profileMethodStart.sqf │ │ ├── fn_profileMethodStop.sqf │ │ └── fn_resetProfile.sqf │ ├── fn_init.sqf │ ├── server │ │ ├── fn_attachTrainToTrackMap.sqf │ │ ├── fn_initServer.sqf │ │ ├── fn_registerTrainAndDriver.sqf │ │ ├── fn_requestATSInstall.sqf │ │ ├── fn_serverEventHandlerLoop.sqf │ │ ├── fn_unregisterTrainAndDriver.sqf │ │ ├── fn_updateServerTrackMap.sqf │ │ └── fn_updateTrackMap.sqf │ ├── sound │ │ ├── fn_attachSoundSource.sqf │ │ ├── fn_createSoundSource.sqf │ │ ├── fn_deleteSoundSource.sqf │ │ ├── fn_detatchSoundSource.sqf │ │ ├── fn_enableSoundSource.sqf │ │ ├── fn_getSoundSourcePositionASL.sqf │ │ ├── fn_getSoundSourceVolume.sqf │ │ ├── fn_initSound.sqf │ │ ├── fn_nearbySoundSourceHandler.sqf │ │ ├── fn_setSoundSourcePositionASL.sqf │ │ ├── fn_setSoundSourceVolume.sqf │ │ ├── fn_soundSourceAttachedTo.sqf │ │ └── fn_soundSourceSimulationHandler.sqf │ ├── track │ │ ├── fn_addWorldPaths.sqf │ │ ├── fn_buildTrackMap.sqf │ │ ├── fn_findAlignedTrackWorldPath.sqf │ │ ├── fn_findConnectedTrackNodes.sqf │ │ ├── fn_getTrackDefinition.sqf │ │ ├── fn_getTrackMapConnection.sqf │ │ ├── fn_getTrackUnderTrain.sqf │ │ ├── fn_getTrackWorldPaths.sqf │ │ ├── fn_getTracksAtPosition.sqf │ │ ├── fn_initTracks.sqf │ │ ├── fn_lookupTrackMapPosition.sqf │ │ └── fn_preloadAllTracksNearEditorPlacedConnections.sqf │ └── train │ │ ├── common │ │ ├── fn_calculateTrainAlignment.sqf │ │ ├── fn_getNearestTrainCar.sqf │ │ ├── fn_getPositionAndDirectionOnPath.sqf │ │ ├── fn_getTrainAtPosition.sqf │ │ ├── fn_getTrainDefinition.sqf │ │ ├── fn_getTrainPositionAndDirection.sqf │ │ ├── fn_getTrainUnderPlayer.sqf │ │ ├── fn_hideTrainObject.sqf │ │ ├── fn_hideTrainObjectGlobal.sqf │ │ ├── fn_hideTrainObjectLocal.sqf │ │ ├── fn_hideTrainReplaceWithNew.sqf │ │ ├── fn_initTrainObject.sqf │ │ ├── fn_isPassengerMoving.sqf │ │ └── fn_isTrainLocal.sqf │ │ ├── controls │ │ ├── fn_attachToTrainCar.sqf │ │ ├── fn_disableTrainInputHandlers.sqf │ │ ├── fn_disableTrainPassengerInputHandlers.sqf │ │ ├── fn_enableTrainInputHandlers.sqf │ │ ├── fn_enableTrainPassengerInputHandlers.sqf │ │ ├── fn_exitTrain.sqf │ │ ├── fn_exitTrainPassenger.sqf │ │ ├── fn_getInTrain.sqf │ │ ├── fn_getInTrainPassenger.sqf │ │ ├── fn_managePlayerTrainActions.sqf │ │ ├── fn_passengerMoveInputHandler.sqf │ │ ├── fn_rideOnTrain.sqf │ │ ├── fn_rideOnTrainEventHandler.sqf │ │ ├── fn_toggleCruiseControl.sqf │ │ ├── fn_toggleLights.sqf │ │ └── fn_trainInputHandler.sqf │ │ ├── fn_initTrains.sqf │ │ ├── hud │ │ ├── fn_disableHud.sqf │ │ └── fn_enableHud.sqf │ │ ├── simulation │ │ ├── fn_cleanUpNodePath.sqf │ │ ├── fn_drawEventHandler.sqf │ │ ├── fn_drawTrain.sqf │ │ ├── fn_handleSimulationNetworkUpdates.sqf │ │ ├── fn_handleVelocityNetworkUpdates.sqf │ │ ├── fn_setWheelSpeed.sqf │ │ ├── fn_simulateTrain.sqf │ │ ├── fn_simulateTrainAttachment.sqf │ │ ├── fn_simulateTrainParticleEffects.sqf │ │ └── fn_simulateTrainVelocity.sqf │ │ └── sound │ │ ├── fn_addTrainSoundDefinition.sqf │ │ ├── fn_getTrainSoundDefinition.sqf │ │ ├── fn_initTrainSound.sqf │ │ └── fn_simulateTrainSounds.sqf │ └── sounds │ ├── horn_end.ogg │ ├── horn_middle1.ogg │ ├── horn_middle2.ogg │ ├── horn_start.ogg │ ├── train_bell.ogg │ ├── train_engine.ogg │ ├── train_engine_idle.ogg │ ├── train_horn.ogg │ ├── train_steam_engine.ogg │ ├── train_steam_engine_idle.ogg │ └── train_track.ogg ├── steamLogo.jpg └── steamLogo.psd /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | *.sqf eol=crlf 20 | *.sqm eol=crlf 21 | *.ext eol=crlf 22 | *.hpp eol=crlf 23 | *.cpp eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | *.pbo 49 | .gradle 50 | build 51 | a3 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Train Simulator (ATS) 2 | 3 | ![](https://github.com/sethduda/AdvancedTrainSimulator/blob/master/steamLogo.jpg?raw=true) 4 | 5 | **Features:** 6 | 7 | - Drive and ride on trains in Arma 3! 8 | - Supports all existing trains and tracks on Tanoa. 9 | - Create custom tracks by placing APEX track objects in the editor (see directions below). 10 | - Multiplayer support. Mod only required to be installed on server. 11 | - Supports APEX and CUPS train models. 12 | - Supports APEX tracks (CUPS tracks still in the works!). 13 | 14 | **Directions:** 15 | 16 | While outside of a train, there are a few actions you can perform. Look directly at the train to get these possible actions: 17 | 18 | - Get in Train as Driver: When looking at a train engine, you'll get this option to become the driver of the train. See train driver controls below. 19 | - Disconnect Car: When looking at a car connected to a train, you'll get this option. This will disconnect the car from the train. The train cannot be moving. 20 | - Ride Train: When looking at a train car (attached to a train someone else is driving) you'll get this option to ride the train. See train passenger controls below. 21 | 22 | Train Driver Controls: 23 | 24 | - Move Forward (defaults to W key): Speed up the train 25 | - Move Backward (defaults to S key): Slow down the train 26 | - Turn Left (defaults to A key): Controls track switching. Hold "Move Left" as you pass an intersection to direct the train down the left-most path. 27 | - Turn Right (defaults to D key): Controls track switching. Hold "Move Right" as you pass an intersection to direct the train down the right-most path. 28 | - Enabled / Disable Cruise Control (C key): When enabled, the train will maintain its current speed automatically (even if you jump out of the train - runaway train!) 29 | - Break (B key): A faster way to slow down your train besides holding down the Move Backwards key 30 | - Exit Train (delete key): Exit the current train. 31 | - First Person / 3rd Person View (numpad-enter key): Toggles between first and 3rd person in the train. You can also use the mouse wheel to zoom into 1st person. 32 | - Horn (H key): Train horn (hold for longer horn) 33 | - Bells (G key): Train bells (hold for longer bells) 34 | - Turn off Engine (E key): Turn off engine when train isn't moving 35 | 36 | Note: If you don't hold left or right while passing an intersection, the train will choose the path that requires the least amount of turning. 37 | 38 | Train Passenger Controls: 39 | 40 | - Exit Train (delete key): Exit the current train 41 | - First Person / 3rd Person View (numpad-enter key): Toggles between first and 3rd person in the train. You can also use the mouse wheel to zoom into 1st person. 42 | 43 | Train Placement 44 | 45 | Train objects can be placed on any tracks, including custom tracks. The train must be placed on top of the track. It's not important that the train object lines up perfectly. As long as it's on top of the track, it will work. All existing trains on the Tanoa map will work as-is. Currently, all of the train objects from APEX and CUPS are supported. 46 | 47 | Track Placement 48 | 49 | Custom track objects can be placed via the editor on any map. They can also connect on to the existing tracks placed on Tanoa. Only the track objects included with APEX are supported. 50 | 51 | 1. All tracks must be terminated with the track termination object. If you don't do this, the train won't be able to follow your track that has no termination. 52 | 53 | ![](https://github.com/sethduda/AdvancedTrainSimulator/blob/master/screenshots/track_placement_1.jpg?raw=true) 54 | 55 | 2. Intersections must use the intersection track objects. Intersection track objects can be place on top of other tracks. You cannot create intersections using straight or curved tracks. 56 | 57 | ![](https://github.com/sethduda/AdvancedTrainSimulator/blob/master/screenshots/track_placement_2.jpg?raw=true) 58 | 59 | **Installation:** 60 | 61 | 1. Subscribe via steam: xxxxxx or download latest release from https://github.com/sethduda/AdvancedTrainSimulator/releases 62 | 2. If installing this on a server, add the addon to the -serverMod command line option. It's required on the server side and is not required for clients. 63 | 64 | **FAQ** 65 | 66 | *Battleye kicks me when I try to do xyz. What do I do?* 67 | 68 | You need to configure Battleye rules on your server. Below are the files you need to configure: 69 | 70 | setvariable.txt 71 | 72 | Add the following exclusions to the end of all lines starting with 4, 5, 6, or 7 if they contain "" (meaning applies to all values): 73 | 74 | !"ATRAIN_" 75 | 76 | setvariableval.txt 77 | 78 | If you have any lines starting with 4, 5, 6, or 7 and they contain "" (meaning applies to all values) it's not going to work. Either remove the line or explicitly define the values you want to kick. Since the values of the variables above can vary, I don't know of a good way to define an exclusion rule. 79 | 80 | Also, it's possible there are other battleye filter files that can cause issues. If you check your battleye logs you can figure out which file is causing a problem. 81 | 82 | *My server is blocking script remote executions. How do I fix this?* 83 | 84 | Most likely your server is setup with a white list for remote executions. In order to fix this, you need to modify your mission's description.ext file, adding the following CfgRemoteExec rules. If using InfiStar you should edit your cfgremoteexec.hpp instead of the description.ext file. See https://community.bistudio.com/wiki/Arma_3_Remote_Execution for more details on CfgRemoteExec. 85 | 86 | ``` 87 | class CfgRemoteExec 88 | { 89 | class Functions 90 | { 91 | class ATRAIN_fnc_unregisterTrainAndDriver { allowedTargets=2; }; 92 | class ATRAIN_fnc_registerTrainAndDriver { allowedTargets=2; }; 93 | class ATRAIN_fnc_updateTrackMap { allowedTargets=2; }; 94 | class ATRAIN_fnc_hideTrainObjectGlobal { allowedTargets=2; }; 95 | class ATRAIN_fnc_hidePlayerObjectGlobal { allowedTargets=2; }; 96 | class ATRAIN_fnc_requestATSInstall { allowedTargets=2; }; 97 | }; 98 | }; 99 | ``` 100 | 101 | **Issues & Feature Requests** 102 | 103 | https://github.com/sethduda/AdvancedTrainSimulator/issues 104 | 105 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath files('libs/PBOGradlePlugin.jar') 7 | classpath group: 'commons-io', name: 'commons-io', version: '2.5' 8 | } 9 | } 10 | 11 | apply plugin: 'duda.a3.pbo' 12 | 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 13 18:09:31 EDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /keys/AdvancedTrainSimulator.bikey: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/keys/AdvancedTrainSimulator.bikey -------------------------------------------------------------------------------- /libs/PBOGradlePlugin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/libs/PBOGradlePlugin.jar -------------------------------------------------------------------------------- /logo.paa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/logo.paa -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/logo.png -------------------------------------------------------------------------------- /logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/logo.psd -------------------------------------------------------------------------------- /mod.cpp: -------------------------------------------------------------------------------- 1 | name = "Advanced Train Simulator"; 2 | picture = "logo.paa"; 3 | description = "Advanced Train Simulator"; 4 | logo = "logo.paa"; 5 | logoOver = "logo.paa"; 6 | tooltip = "Advanced Train Simulator"; 7 | tooltipOwned = "Advanced Train Simulator Owned"; 8 | overview = "Advanced Train Simulator"; 9 | author = "[SA] Duda"; 10 | overviewPicture = "logo.paa"; 11 | overviewText = "Advanced Train Simulator"; 12 | overviewFootnote = ""; -------------------------------------------------------------------------------- /screenshots/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/1.jpg -------------------------------------------------------------------------------- /screenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/2.jpg -------------------------------------------------------------------------------- /screenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/3.jpg -------------------------------------------------------------------------------- /screenshots/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/4.jpg -------------------------------------------------------------------------------- /screenshots/track_placement_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/track_placement_1.jpg -------------------------------------------------------------------------------- /screenshots/track_placement_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/screenshots/track_placement_2.jpg -------------------------------------------------------------------------------- /src/addons/ats/core/$PBOPREFIX$: -------------------------------------------------------------------------------- 1 | ats\core -------------------------------------------------------------------------------- /src/addons/ats/core/config.cpp: -------------------------------------------------------------------------------- 1 | #define private 0 2 | #define protected 1 3 | #define public 2 4 | 5 | class CfgPatches 6 | { 7 | class ATS_Core 8 | { 9 | units[] = {}; 10 | weapons[] = {}; 11 | requiredVersion = 0.1; 12 | requiredAddons[] = {}; 13 | }; 14 | }; 15 | 16 | class CfgNetworkMessages 17 | { 18 | 19 | class AdvancedTrainSimulatorRemoteExecClient 20 | { 21 | module = "AdvancedTrainSimulator"; 22 | parameters[] = {"ARRAY","STRING","OBJECT","BOOL"}; 23 | }; 24 | 25 | class AdvancedTrainSimulatorRemoteExecServer 26 | { 27 | module = "AdvancedTrainSimulator"; 28 | parameters[] = {"ARRAY","STRING","BOOL"}; 29 | }; 30 | 31 | }; 32 | 33 | class CfgFunctions 34 | { 35 | class ATS 36 | { 37 | tag = "ATRAIN"; 38 | 39 | class Main 40 | { 41 | file = "ats\core\functions"; 42 | class init{postInit=1;}; 43 | }; 44 | 45 | class Camera 46 | { 47 | file = "ats\core\functions\camera"; 48 | class cameraMouseMoveHandler {}; 49 | class cameraMouseZoomHandler {}; 50 | class cameraUpdatePosition {}; 51 | class disable3rdPersonCamera {}; 52 | class enable3rdPersonCamera {}; 53 | }; 54 | 55 | class Common 56 | { 57 | file = "ats\core\functions\common"; 58 | class addEventHandler {}; 59 | class getTypeOf {}; 60 | class hidePlayerObjectGlobal {}; 61 | class rebuildArrayLookupIndexes {}; 62 | class RemoteExec {}; 63 | class RemoteExecServer {}; 64 | class removeAllEventHandlers {}; 65 | class removeEventHandler {}; 66 | }; 67 | 68 | class Debugging 69 | { 70 | file = "ats\core\functions\debugging"; 71 | class createMarker {}; 72 | class getProfile {}; 73 | class initTrackTestAction {}; 74 | class printProfiles {}; 75 | class profileInit {}; 76 | class profileMethodStart {}; 77 | class profileMethodStop {}; 78 | class resetProfile {}; 79 | }; 80 | 81 | class Server 82 | { 83 | file = "ats\core\functions\server"; 84 | class attachTrainToTrackMap {}; 85 | class initServer {}; 86 | class registerTrainAndDriver {}; 87 | class serverEventHandlerLoop {}; 88 | class unregisterTrainAndDriver {}; 89 | class updateServerTrackMap {}; 90 | class updateTrackMap {}; 91 | class requestATSInstall {}; 92 | }; 93 | 94 | class Track 95 | { 96 | file = "ats\core\functions\track"; 97 | class addWorldPaths {}; 98 | class buildTrackMap {}; 99 | class findAlignedTrackWorldPath {}; 100 | class findConnectedTrackNodes {}; 101 | class getTrackDefinition {}; 102 | class getTrackMapConnection {}; 103 | class getTracksAtPosition {}; 104 | class getTrackUnderTrain {}; 105 | class getTrackWorldPaths {}; 106 | class initTracks {}; 107 | class lookupTrackMapPosition {}; 108 | class preloadAllTracksNearEditorPlacedConnections {}; 109 | }; 110 | 111 | class Train 112 | { 113 | file = "ats\core\functions\train"; 114 | class initTrains {}; 115 | }; 116 | 117 | class TrainCommon 118 | { 119 | file = "ats\core\functions\train\common"; 120 | class calculateTrainAlignment {}; 121 | class getPositionAndDirectionOnPath {}; 122 | class getTrainAtPosition {}; 123 | class getTrainDefinition {}; 124 | class getTrainPositionAndDirection {}; 125 | class getTrainUnderPlayer {}; 126 | class hideTrainObject {}; 127 | class hideTrainObjectGlobal {}; 128 | class hideTrainObjectLocal {}; 129 | class hideTrainReplaceWithNew {}; 130 | class initTrainObject {}; 131 | class isPassengerMoving {}; 132 | class isTrainLocal {}; 133 | class getNearestTrainCar {}; 134 | }; 135 | 136 | class TrainControls 137 | { 138 | file = "ats\core\functions\train\controls"; 139 | class attachToTrainCar {}; 140 | class disableTrainInputHandlers {}; 141 | class disableTrainPassengerInputHandlers {}; 142 | class enableTrainInputHandlers {}; 143 | class enableTrainPassengerInputHandlers {}; 144 | class exitTrain {}; 145 | class exitTrainPassenger {}; 146 | class getInTrain {}; 147 | class getInTrainPassenger {}; 148 | class managePlayerTrainActions {}; 149 | class passengerMoveInputHandler {}; 150 | class rideOnTrain {}; 151 | class rideOnTrainEventHandler {}; 152 | class toggleCruiseControl {}; 153 | class trainInputHandler {}; 154 | class toggleLights {}; 155 | }; 156 | 157 | class TrainHud 158 | { 159 | file = "ats\core\functions\train\hud"; 160 | class disableHud {}; 161 | class enableHud {}; 162 | }; 163 | 164 | class TrainSimulation 165 | { 166 | file = "ats\core\functions\train\simulation"; 167 | class cleanUpNodePath {}; 168 | class drawEventHandler {}; 169 | class drawTrain {}; 170 | class handleSimulationNetworkUpdates {}; 171 | class handleVelocityNetworkUpdates {}; 172 | class setWheelSpeed {}; 173 | class simulateTrain {}; 174 | class simulateTrainAttachment {}; 175 | class simulateTrainParticleEffects {}; 176 | class simulateTrainVelocity {}; 177 | }; 178 | 179 | class TrainSound 180 | { 181 | file = "ats\core\functions\train\sound"; 182 | class addTrainSoundDefinition {}; 183 | class getTrainSoundDefinition {}; 184 | class initTrainSound {}; 185 | class simulateTrainSounds {}; 186 | }; 187 | 188 | class Sound 189 | { 190 | file = "ats\core\functions\sound"; 191 | class attachSoundSource {}; 192 | class createSoundSource {}; 193 | class deleteSoundSource {}; 194 | class detatchSoundSource {}; 195 | class enableSoundSource {}; 196 | class getSoundSourcePositionASL {}; 197 | class getSoundSourceVolume {}; 198 | class initSound {}; 199 | class nearbySoundSourceHandler {}; 200 | class setSoundSourcePositionASL {}; 201 | class setSoundSourceVolume {}; 202 | class soundSourceAttachedTo {}; 203 | class soundSourceSimulationHandler {}; 204 | }; 205 | 206 | }; 207 | }; 208 | 209 | class CfgSounds 210 | { 211 | class ATS_Train_Track_Sound 212 | { 213 | name = ""; 214 | sound[] = {"\ats\core\sounds\train_track.ogg", db-5, 1}; 215 | titles[] = {0,""}; 216 | }; 217 | class ATS_Train_Engine_Sound 218 | { 219 | name = ""; 220 | sound[] = {"\ats\core\sounds\train_engine.ogg", db-12, 1}; 221 | titles[] = {0,""}; 222 | }; 223 | class ATS_Train_Engine_Idle_Sound 224 | { 225 | name = ""; 226 | sound[] = {"\ats\core\sounds\train_engine_idle.ogg", db-4, 1}; 227 | titles[] = {0,""}; 228 | }; 229 | class ATS_Train_Steam_Engine_Sound 230 | { 231 | name = ""; 232 | sound[] = {"\ats\core\sounds\train_steam_engine.ogg", db-0, 1}; 233 | titles[] = {0,""}; 234 | }; 235 | class ATS_Train_Steam_Engine_Idle_Sound 236 | { 237 | name = ""; 238 | sound[] = {"\ats\core\sounds\train_steam_engine_idle.ogg", db-4, 1}; 239 | titles[] = {0,""}; 240 | }; 241 | class ATS_Train_Bell_Sound 242 | { 243 | name = ""; 244 | sound[] = {"\ats\core\sounds\train_bell.ogg", db-0, 1}; 245 | titles[] = {0,""}; 246 | }; 247 | class ATSHornStart 248 | { 249 | name = ""; 250 | sound[] = {"\ats\core\sounds\horn_start.ogg", db+5, 1}; 251 | titles[] = {0,""}; 252 | }; 253 | class ATSHornMiddle1 254 | { 255 | name = ""; 256 | sound[] = {"\ats\core\sounds\horn_middle1.ogg", db+5, 1}; 257 | titles[] = {0,""}; 258 | }; 259 | class ATSHornMiddle2 260 | { 261 | name = ""; 262 | sound[] = {"\ats\core\sounds\horn_middle2.ogg", db+5, 1}; 263 | titles[] = {0,""}; 264 | }; 265 | class ATSHornEnd 266 | { 267 | name = ""; 268 | sound[] = {"\ats\core\sounds\horn_end.ogg", db+5, 1}; 269 | titles[] = {0,""}; 270 | }; 271 | }; 272 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/camera.h: -------------------------------------------------------------------------------- 1 | #define ATRAIN_FNC_CAMERA_DISTANCE (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Distance",8]) 2 | #define ATRAIN_FNC_CAMERA (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera",objNull]) 3 | #define ATRAIN_FNC_CAMERA_TARGET (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Target",objNull]) 4 | #define ATRAIN_FNC_CAMERA_X_TOTAL (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_X_Move_Total",-90]) 5 | #define ATRAIN_FNC_CAMERA_Y_TOTAL (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Y_Move_Total",60]) 6 | #define ATRAIN_FNC_CAMERA_Y_TOTAL_PRIOR (missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Y_Move_Total_Prior",ATRAIN_FNC_CAMERA_Y_TOTAL]) 7 | #define ATRAIN_FNC_CAMERA_REL_POSITION [ATRAIN_FNC_CAMERA_DISTANCE * (cos ATRAIN_FNC_CAMERA_X_TOTAL) * (sin ATRAIN_FNC_CAMERA_Y_TOTAL), ATRAIN_FNC_CAMERA_DISTANCE * (sin ATRAIN_FNC_CAMERA_X_TOTAL) * (sin ATRAIN_FNC_CAMERA_Y_TOTAL), ATRAIN_FNC_CAMERA_DISTANCE * (cos ATRAIN_FNC_CAMERA_Y_TOTAL)] 8 | #define ATRAIN_FNC_1ST_PERSON_ENABLED (ATRAIN_FNC_CAMERA_DISTANCE <= 3) -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/fn_cameraMouseMoveHandler.sqf: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | private ["_cam","_distance","_target"]; 3 | private _factor = 0.2; 4 | if(ATRAIN_FNC_CAMERA_DISTANCE == 3) then { 5 | _factor = 0.4; 6 | }; 7 | ATRAIN_3rd_Person_Camera_X_Move_Total = ATRAIN_FNC_CAMERA_X_TOTAL + (-(_this select 1)*_factor); 8 | ATRAIN_3rd_Person_Camera_Y_Move_Total = ATRAIN_FNC_CAMERA_Y_TOTAL + (-(_this select 2)*_factor); 9 | if(ATRAIN_FNC_1ST_PERSON_ENABLED) then { 10 | ATRAIN_3rd_Person_Camera_Y_Move_Total = ATRAIN_FNC_CAMERA_Y_TOTAL max 40 min 160; 11 | } else { 12 | ATRAIN_3rd_Person_Camera_Y_Move_Total = ATRAIN_FNC_CAMERA_Y_TOTAL max 20 min 160; 13 | }; 14 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/fn_cameraMouseZoomHandler.sqf: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | private ["_mouseZoom","_distance"]; 3 | _mouseZoom = (_this select 1); 4 | if(_mouseZoom > 0) then { 5 | _mouseZoom = 1; 6 | } else { 7 | _mouseZoom = -1; 8 | }; 9 | _distance = ATRAIN_FNC_CAMERA_DISTANCE; 10 | ATRAIN_3rd_Person_Camera_Distance = (_distance - _mouseZoom) max 3 min 60; 11 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/fn_cameraUpdatePosition.sqf: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | private _cam = ATRAIN_FNC_CAMERA; 3 | if(!isNil "_cam") then { 4 | private _targetObject = vehicle ATRAIN_FNC_CAMERA_TARGET; 5 | private _bbr = boundingBoxReal _targetObject; 6 | private _p1 = _bbr select 0; 7 | private _p2 = _bbr select 1; 8 | private _maxHeight = abs ((_p2 select 2) - (_p1 select 2)); 9 | private _targetModelPosition = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0,0,_maxHeight * 0.5]; 10 | private _targetPosition = AGLToASL (_targetObject modelToWorldVisual _targetModelPosition); 11 | private _cameraPosition = AGLToASL (_targetObject modelToWorldVisual (ATRAIN_FNC_CAMERA_REL_POSITION vectorAdd _targetModelPosition)); 12 | if((ASLToATL _cameraPosition) select 2 < 0) then { 13 | ATRAIN_3rd_Person_Camera_Y_Move_Total = ATRAIN_FNC_CAMERA_Y_TOTAL min ATRAIN_FNC_CAMERA_Y_TOTAL_PRIOR; 14 | _cameraPosition = ATRAIN_FNC_CAMERA_REL_POSITION vectorAdd _targetPosition; 15 | }; 16 | private _lookVector = _cameraPosition vectorFromTo _targetPosition; 17 | private _cameraUpVector = (_lookVector vectorCrossProduct [0,0,1]) vectorCrossProduct _lookVector; 18 | if(ATRAIN_FNC_1ST_PERSON_ENABLED) then { 19 | _cam setPosASL _targetPosition; 20 | } else { 21 | _cam setPosASL _cameraPosition; 22 | }; 23 | 24 | _cam setVectorDirAndUp [_lookVector,_cameraUpVector]; 25 | 26 | ATRAIN_3rd_Person_Camera_Y_Move_Total_Prior = ATRAIN_FNC_CAMERA_Y_TOTAL; 27 | ATRAIN_3rd_Person_Camera_Last_Position = _cameraPosition; 28 | }; 29 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/fn_disable3rdPersonCamera.sqf: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | if(!isNull ATRAIN_FNC_CAMERA) then { 3 | 4 | removeMissionEventHandler ["EachFrame", ATRAIN_3rd_Person_Camera_Frame_Handler]; 5 | ["MAIN_DISPLAY","MouseMoving", ATRAIN_Mouse_Move_Handler] call ATRAIN_fnc_removeEventHandler; 6 | ["MAIN_DISPLAY","MouseZChanged", ATRAIN_Mouse_Zoom_Handler] call ATRAIN_fnc_removeEventHandler; 7 | ["MAIN_DISPLAY","KeyDown", ATRAIN_3rd_Person_Camera_Map_Handler1] call ATRAIN_fnc_removeEventHandler; 8 | ["MAIN_DISPLAY","MouseButtonDown", ATRAIN_3rd_Person_Camera_Map_Handler2] call ATRAIN_fnc_removeEventHandler; 9 | 10 | ATRAIN_FNC_CAMERA cameraEffect ["Terminate", "Back"]; 11 | camDestroy ATRAIN_FNC_CAMERA; 12 | 13 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Distance",nil]; 14 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera",nil]; 15 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_X_Move_Total",nil]; 16 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Y_Move_Total",nil]; 17 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Y_Move_Total_Prior",nil]; 18 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Last_Position",nil]; 19 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Frame_Handler",nil]; 20 | missionNamespace setVariable ["ATRAIN_Mouse_Move_Handler",nil]; 21 | missionNamespace setVariable ["ATRAIN_Mouse_Zoom_Handler",nil]; 22 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Map_Handler1",nil]; 23 | missionNamespace setVariable ["ATRAIN_3rd_Person_Camera_Map_Handler2",nil]; 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/camera/fn_enable3rdPersonCamera.sqf: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | _this spawn { 3 | params ["_object",["_modelPosition",[0,0,0]]]; 4 | waitUntil {time > 0}; 5 | showCinemaBorder false; 6 | ATRAIN_3rd_Person_Camera_Target = _object; 7 | ATRAIN_3rd_Person_Camera_Target_Model_Position = _modelPosition; 8 | ATRAIN_3rd_Person_Camera = "camera" camCreate (_object modelToWorldVisual _modelPosition); 9 | ATRAIN_3rd_Person_Camera cameraEffect ["internal", "BACK"]; 10 | ATRAIN_3rd_Person_Camera camSetFocus [-1, -1]; 11 | ATRAIN_3rd_Person_Camera camCommit 0; 12 | ATRAIN_Mouse_Move_Handler = ["MAIN_DISPLAY","MouseMoving", "_this call ATRAIN_fnc_cameraMouseMoveHandler"] call ATRAIN_fnc_addEventHandler; 13 | ATRAIN_Mouse_Zoom_Handler = ["MAIN_DISPLAY","MouseZChanged", "_this call ATRAIN_fnc_cameraMouseZoomHandler"] call ATRAIN_fnc_addEventHandler; 14 | ATRAIN_3rd_Person_Camera_Frame_Handler = addMissionEventHandler ["EachFrame", {[] call ATRAIN_fnc_cameraUpdatePosition; false}]; 15 | 16 | ATRAIN_fnc_remoteCameraMapHandler = { 17 | if(visibleMap) exitWith {}; 18 | private ["_event","_eventParams","_actionKeys"]; 19 | _event = param [0]; 20 | _eventParams = param [1]; 21 | _actionKeys = actionKeys "ShowMap"; 22 | if(_event == "KeyDown" || _event == "MouseButtonDown") then { 23 | if( (_eventParams select 1) in _actionKeys || (65536 + (_eventParams select 1)) in _actionKeys ) then { 24 | [] spawn { 25 | ATRAIN_FNC_CAMERA cameraEffect ["Terminate", "Back"]; 26 | openMap true; 27 | waitUntil {!visibleMap}; 28 | if(!isNil "ATRAIN_3rd_Person_Camera") then { 29 | ATRAIN_3rd_Person_Camera cameraEffect ["internal", "BACK"]; 30 | }; 31 | }; 32 | }; 33 | }; 34 | 35 | /* 36 | 37 | Used for finding driver/rider positions 38 | 39 | if(_eventParams select 1 in (actionKeys "MoveBack")) then { 40 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0,0,-0.1]; 41 | }; 42 | if(_eventParams select 1 in (actionKeys "MoveForward")) then { 43 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0,0,0.1]; 44 | }; 45 | if(_eventParams select 1 in (actionKeys "TurnRight")) then { 46 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0,0.1,0]; 47 | }; 48 | if(_eventParams select 1 in (actionKeys "TurnLeft")) then { 49 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0,-0.1,0]; 50 | }; 51 | if(_eventParams select 1 == 35) then { //H 52 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [0.1,0,0]; 53 | }; 54 | if(_eventParams select 1 == 34) then { //G 55 | ATRAIN_3rd_Person_Camera_Target_Model_Position = ATRAIN_3rd_Person_Camera_Target_Model_Position vectorAdd [-0.1,0,0]; 56 | }; 57 | copyToClipboard (str ATRAIN_3rd_Person_Camera_Target_Model_Position); 58 | 59 | */ 60 | 61 | 62 | }; 63 | 64 | ATRAIN_3rd_Person_Camera_Map_Handler1 = ["MAIN_DISPLAY","KeyDown", "[""KeyDown"",_this] call ATRAIN_fnc_remoteCameraMapHandler"] call ATRAIN_fnc_addEventHandler; 65 | ATRAIN_3rd_Person_Camera_Map_Handler2 = ["MAIN_DISPLAY","MouseButtonDown", "[""MouseButtonDown"",_this] call ATRAIN_fnc_remoteCameraMapHandler"] call ATRAIN_fnc_addEventHandler; 66 | 67 | waitUntil {isNull ATRAIN_FNC_CAMERA || isNull _object}; 68 | [] call ATRAIN_fnc_disable3rdPersonCamera; 69 | }; 70 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_RemoteExec.sqf: -------------------------------------------------------------------------------- 1 | params ["_params","_functionName","_target",["_isCall",false]]; 2 | if(!isNil "ExileClient_system_network_send") then { 3 | ["AdvancedTrainSimulatorRemoteExecClient",[_params,_functionName,_target,_isCall]] call ExileClient_system_network_send; 4 | } else { 5 | if(_isCall) then { 6 | _params remoteExecCall [_functionName, _target]; 7 | } else { 8 | _params remoteExec [_functionName, _target]; 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_RemoteExecServer.sqf: -------------------------------------------------------------------------------- 1 | params ["_params","_functionName",["_isCall",false]]; 2 | if(!isNil "ExileClient_system_network_send") then { 3 | ["AdvancedTrainSimulatorRemoteExecServer",[_params,_functionName,_isCall]] call ExileClient_system_network_send; 4 | } else { 5 | if(_isCall) then { 6 | _params remoteExecCall [_functionName, 2]; 7 | } else { 8 | _params remoteExec [_functionName, 2]; 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_addEventHandler.sqf: -------------------------------------------------------------------------------- 1 | #define ATRAIN_MAP_CONTROL (findDisplay 12 displayCtrl 51) 2 | #define ATRAIN_MAP_DISPLAY (findDisplay 12) 3 | #define ATRAIN_MAIN_DISPLAY (findDisplay 46) 4 | 5 | params ["_handlerType","_eventType","_eventScript"]; 6 | 7 | waitUntil {!isNull ATRAIN_MAP_CONTROL && !isNull ATRAIN_MAIN_DISPLAY && !isNull ATRAIN_MAP_DISPLAY}; 8 | 9 | private _allEventHandlers = uiNamespace getVariable ["ATRAIN_All_Event_Handlers",[]]; 10 | 11 | private _eventId = -1; 12 | if(_handlerType == "MAIN_DISPLAY") then { 13 | _eventId = ATRAIN_MAIN_DISPLAY displayAddEventHandler [_eventType, _eventScript + "; false"]; 14 | }; 15 | if(_handlerType == "MAP_DISPLAY") then { 16 | _eventId = ATRAIN_MAP_DISPLAY displayAddEventHandler [_eventType, _eventScript+ "; false"]; 17 | }; 18 | if(_handlerType == "MAP_CONTROL") then { 19 | _eventId = ATRAIN_MAP_CONTROL ctrlAddEventHandler [_eventType, _eventScript+ "; false"]; 20 | }; 21 | 22 | _allEventHandlers pushBack [_handlerType, _eventType, _eventId]; 23 | uiNamespace setVariable ["ATRAIN_All_Event_Handlers",_allEventHandlers]; 24 | 25 | _eventId; 26 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_getTypeOf.sqf: -------------------------------------------------------------------------------- 1 | params ["_object"]; 2 | private _typeOfArray = [typeOf _object,false]; 3 | if( (_typeOfArray select 0) != "" ) exitWith { _typeOfArray }; 4 | private _modelName = ((str _object) splitString ": ") param [1, ""]; 5 | private _modelToTypeMapIndex = ATRAIN_Object_Model_To_Type_Map_Index find (toLower _modelName); 6 | if(_modelToTypeMapIndex >= 0) then { 7 | _typeOfArray = (ATRAIN_Object_Model_To_Type_Map select _modelToTypeMapIndex) select 1; 8 | }; 9 | _typeOfArray; 10 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_hidePlayerObjectGlobal.sqf: -------------------------------------------------------------------------------- 1 | params ["_player","_hide"]; 2 | if(isPlayer _player) then { 3 | if(isServer) then { 4 | _player hideObjectGlobal _hide; 5 | } else { 6 | _player hideObject _hide; 7 | [_this, "ATRAIN_fnc_hidePlayerObjectGlobal"] call ATRAIN_fnc_RemoteExecServer; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_rebuildArrayLookupIndexes.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_Track_Definitions_Index = []; 2 | ATRAIN_Track_Definitions = missionNamespace getVariable ["ATRAIN_Track_Definitions",[]]; 3 | { 4 | ATRAIN_Track_Definitions_Index pushBack (toLower (_x select 0)); 5 | } forEach ATRAIN_Track_Definitions; 6 | ATRAIN_Train_Definitions_Index = []; 7 | ATRAIN_Train_Definitions = missionNamespace getVariable ["ATRAIN_Train_Definitions",[]]; 8 | { 9 | ATRAIN_Train_Definitions_Index pushBack (toLower (_x select 0)); 10 | } forEach ATRAIN_Train_Definitions; 11 | ATRAIN_Object_Model_To_Type_Map_Index = []; 12 | ATRAIN_Object_Model_To_Type_Map = missionNamespace getVariable ["ATRAIN_Object_Model_To_Type_Map",[]]; 13 | { 14 | ATRAIN_Object_Model_To_Type_Map_Index pushBack (toLower (_x select 0)); 15 | } forEach ATRAIN_Object_Model_To_Type_Map; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_removeAllEventHandlers.sqf: -------------------------------------------------------------------------------- 1 | private _allEventHandlers = uiNamespace getVariable ["ATRAIN_All_Event_Handlers",[]]; 2 | { 3 | _x call ATRAIN_fnc_removeEventHandler; 4 | } forEach _allEventHandlers; 5 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/common/fn_removeEventHandler.sqf: -------------------------------------------------------------------------------- 1 | #define ATRAIN_MAP_CONTROL (findDisplay 12 displayCtrl 51) 2 | #define ATRAIN_MAP_DISPLAY (findDisplay 12) 3 | #define ATRAIN_MAIN_DISPLAY (findDisplay 46) 4 | 5 | params ["_handlerType","_eventType","_eventHandlerId"]; 6 | 7 | waitUntil {!isNull ATRAIN_MAP_CONTROL && !isNull ATRAIN_MAIN_DISPLAY && !isNull ATRAIN_MAP_DISPLAY}; 8 | 9 | if(_eventHandlerId >= 0) then { 10 | if(_handlerType == "MAIN_DISPLAY") then { 11 | ATRAIN_MAIN_DISPLAY displayRemoveEventHandler [_eventType, _eventHandlerId]; 12 | }; 13 | if(_handlerType == "MAP_DISPLAY") then { 14 | ATRAIN_MAP_DISPLAY displayRemoveEventHandler [_eventType, _eventHandlerId]; 15 | }; 16 | if(_handlerType == "MAP_CONTROL") then { 17 | ATRAIN_MAP_CONTROL ctrlRemoveEventHandler [_eventType, _eventHandlerId]; 18 | }; 19 | 20 | private _allEventHandlers = uiNamespace getVariable ["ATRAIN_All_Event_Handlers",[]]; 21 | private _newAllEventHandlers = []; 22 | { 23 | if( _x select 0 != _handlerType || _x select 1 != _eventType || _x select 2 != _eventHandlerId ) then { 24 | _newAllEventHandlers pushBack _x; 25 | }; 26 | } forEach _allEventHandlers; 27 | uiNamespace setVariable ["ATRAIN_All_Event_Handlers",_newAllEventHandlers]; 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_createMarker.sqf: -------------------------------------------------------------------------------- 1 | private ["_markerPosition","_markerColor","_markerName","_markerText"]; 2 | if( isNil "createDotMarker_id" ) then { 3 | createDotMarker_id = 0; 4 | } else { 5 | createDotMarker_id = createDotMarker_id + 1; 6 | }; 7 | _markerPosition = [_this, 0] call BIS_fnc_param; 8 | _markerColor = [_this, 1, "Default"] call BIS_fnc_param; 9 | _markerText = [_this, 2, ""] call BIS_fnc_param; 10 | _markerName = format ["createDotMarker_%1", createDotMarker_id]; 11 | _markerName = createMarker [_markerName,_markerPosition]; 12 | _markerName setMarkerShape "ICON"; 13 | _markerName setMarkerType "mil_dot"; 14 | _markerName setMarkerColor _markerColor; 15 | _markerName setMarkerText _markerText; 16 | _markerName; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_getProfile.sqf: -------------------------------------------------------------------------------- 1 | params ["_profileName"]; 2 | private _profile = []; 3 | private _profileIndex = -1; 4 | { 5 | if(_x select 0 == _profileName) exitWith { 6 | _profile = _x; 7 | _profileIndex = _forEachIndex; 8 | }; 9 | } forEach ATRAIN_Profiles; 10 | [_profileIndex,_profile]; 11 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_initTrackTestAction.sqf: -------------------------------------------------------------------------------- 1 | ARROWS = []; 2 | player addAction ["Test Track", { 3 | 4 | _timeStart2 = 0; 5 | _timeEnd2 = 0; 6 | _timeStart = diag_tickTime; 7 | { 8 | deleteVehicle _x; 9 | } forEach ARROWS; 10 | private _tracks = [getPosASL player,player] call ATRAIN_fnc_getTracksAtPosition; 11 | if(count _tracks > 0) then { 12 | private _track = _tracks select 0; 13 | 14 | _map = [_track] call ATRAIN_fnc_buildTrackMap; 15 | _totalDistance = 0; 16 | { 17 | private _node = _x; 18 | //diag_log str ["NODE",_x select 0]; 19 | private _nodeConnections = _node select 1; 20 | { 21 | //diag_log str [_x select 0, _x select 2]; 22 | private _connectionPath = _x select 1; 23 | private _connectionDistance = _x select 2; 24 | _totalDistance = _totalDistance + (_connectionDistance / 2); 25 | //{ 26 | // //diag_log _x; 27 | //} forEach _connectionPath; 28 | } forEach _nodeConnections; 29 | } forEach _map; 30 | hint ("DONE" + str _totalDistance); 31 | 32 | private _nodes = [_track] call ATRAIN_fnc_findConnectedTrackNodes; 33 | 34 | { 35 | private _path = _x select 1; 36 | { 37 | _arrow = "Sign_Arrow_F" createVehicle [0,0,0]; 38 | _arrow setPosASL _x; 39 | ARROWS pushBack _arrow; 40 | } forEach _path; 41 | } forEach _nodes; 42 | }; 43 | //[] call ATRAIN_fnc_printProfiles; 44 | //_timeEnd = diag_tickTime; 45 | //hintSilent str [(_timeEnd - _timeStart),(_timeEnd2 - _timeStart2),ATRAIN_COUNT,ATRAIN_TIME]; 46 | }]; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_printProfiles.sqf: -------------------------------------------------------------------------------- 1 | { 2 | diag_log str _x; 3 | } forEach ATRAIN_Profiles; 4 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_profileInit.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_Method_Stack = []; 2 | ATRAIN_Profiles = []; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_profileMethodStart.sqf: -------------------------------------------------------------------------------- 1 | params ["_methodName",["_time",diag_tickTime]]; 2 | ATRAIN_Method_Stack pushBack [_methodName,_time]; 3 | //////diag_log (str "Start " + _methodName + ": " + str ATRAIN_Method_Stack); 4 | ([_methodName] call ATRAIN_fnc_getProfile) params ["_profileIndex","_profile"]; 5 | if(_profileIndex == -1) then { 6 | ATRAIN_Profiles pushBack [_methodName,0,0,0]; 7 | }; 8 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_profileMethodStop.sqf: -------------------------------------------------------------------------------- 1 | params [["_time",diag_tickTime]]; 2 | private _stackElement = ATRAIN_Method_Stack deleteAt ((count ATRAIN_Method_Stack) - 1); 3 | _stackElement params ["_methodName","_startTime"]; 4 | ([_methodName] call ATRAIN_fnc_getProfile) params ["_profileIndex","_profile"]; 5 | private _totalTime = (_time - _startTime); 6 | _profile params ["_pName","_pCount","_pTotal","_pSelf"]; 7 | _profile set [1,_pCount + 1]; 8 | _profile set [2,_pTotal + _totalTime]; 9 | _profile set [3,_pSelf + _totalTime]; 10 | ATRAIN_Profiles set [_profileIndex,_profile]; 11 | if(count ATRAIN_Method_Stack > 0) then { 12 | private _caller = ATRAIN_Method_Stack select ((count ATRAIN_Method_Stack) - 1); 13 | _caller params ["_callerMethodName","_callerStartTime"]; 14 | ([_callerMethodName] call ATRAIN_fnc_getProfile) params ["_callerProfileIndex","_callerProfile"]; 15 | _callerProfile params ["_cName","_cCount","_cTotal","_cSelf"]; 16 | _callerProfile set [3,_cSelf - _totalTime]; 17 | ATRAIN_Profiles set [_callerProfileIndex,_callerProfile]; 18 | }; 19 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/debugging/fn_resetProfile.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_Method_Stack = []; 2 | ATRAIN_Profiles = []; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/fn_init.sqf: -------------------------------------------------------------------------------- 1 | 2 | diag_log "Advanced Train Simulator (ATS) Loading..."; 3 | 4 | if(hasInterface) then { 5 | [] call ATRAIN_fnc_removeAllEventHandlers; 6 | }; 7 | 8 | [] call ATRAIN_fnc_initTracks; 9 | 10 | [] call ATRAIN_fnc_initTrains; 11 | 12 | [] call ATRAIN_fnc_initServer; 13 | 14 | [] call ATRAIN_fnc_initSound; 15 | 16 | diag_log "Advanced Train Simulator (ATS) Loaded"; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_attachTrainToTrackMap.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | //diag_log "Attaching Train to Track Map"; 3 | private _nodePath = _train getVariable ["ATRAIN_Local_Node_Path",[]]; 4 | // Exit if train already attached to the track 5 | if(count _nodePath > 0) exitWith {true}; 6 | private _localTrain = _train getVariable ["ATRAIN_Local_Copy",_train]; 7 | private _trackMapPosition = [_localTrain] call ATRAIN_fnc_lookupTrackMapPosition; 8 | if(count _trackMapPosition == 0) exitWith { false }; 9 | _trackMapPosition params ["_startNodeIndex","_endNodeIndex","_distanceFromStart","_trackDistance"]; 10 | _train setVariable ["ATRAIN_Local_Node_Path",[_startNodeIndex, _endNodeIndex],true]; 11 | _train setVariable ["ATRAIN_Local_Distance_From_Front",_distanceFromStart,true]; 12 | _train setVariable ["ATRAIN_Local_Node_Path_Distance",_trackDistance,true]; 13 | true; 14 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_initServer.sqf: -------------------------------------------------------------------------------- 1 | if(isServer) then { 2 | 3 | ATRAIN_Server_Events = []; 4 | 5 | [] spawn ATRAIN_fnc_serverEventHandlerLoop; 6 | 7 | // Remotely installs ATS (if clients doesn't have it installed) 8 | [[], { 9 | if(isNil "ATRAIN_fnc_init") then { 10 | if(!isNil "ExileClient_system_network_send") then { 11 | ["AdvancedTrainSimulatorRemoteExecServer",[[clientOwner],"ATRAIN_fnc_requestATSInstall",false]] call ExileClient_system_network_send; 12 | } else { 13 | [clientOwner] remoteExec ["ATRAIN_fnc_requestATSInstall", 2]; 14 | }; 15 | }; 16 | }] remoteExec ["spawn", -2, true]; 17 | 18 | // Adds support for exile network calls (Only used when running exile) // 19 | 20 | ExileServer_AdvancedTrainSimulator_network_AdvancedTrainSimulatorRemoteExecServer = { 21 | params ["_sessionId", "_messageParameters",["_isCall",false]]; 22 | _messageParameters params ["_params","_functionName"]; 23 | if(_isCall) then { 24 | _params call (missionNamespace getVariable [_functionName,{}]); 25 | } else { 26 | _params spawn (missionNamespace getVariable [_functionName,{}]); 27 | }; 28 | }; 29 | 30 | ExileServer_AdvancedTrainSimulator_network_AdvancedTrainSimulatorRemoteExecClient = { 31 | params ["_sessionId", "_messageParameters"]; 32 | _messageParameters params ["_params","_functionName","_target",["_isCall",false]]; 33 | if(_isCall) then { 34 | _params remoteExecCall [_functionName, _target]; 35 | } else { 36 | _params remoteExec [_functionName, _target]; 37 | }; 38 | }; 39 | 40 | }; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_registerTrainAndDriver.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_driver"]; 2 | if(!isServer) exitWith { [_this, "ATRAIN_fnc_registerTrainAndDriver"] call ATRAIN_fnc_RemoteExecServer }; 3 | ATRAIN_Server_Events pushBack ["REGISTER",_train,_driver]; 4 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_requestATSInstall.sqf: -------------------------------------------------------------------------------- 1 | params ["_clientId"]; 2 | 3 | if(!isServer) exitWith {}; 4 | 5 | // Find and cache all functions to remotely install 6 | if(isNil "ATRAIN_Functions_To_Install") then { 7 | ATRAIN_Functions_To_Install = []; 8 | private _cfg = "true" configClasses (configFile >> 'CfgFunctions' >> 'ATS'); 9 | { 10 | _cfgFunctions = "true" configClasses (configFile >> 'CfgFunctions' >> 'ATS' >> (configName _x)); 11 | { 12 | ATRAIN_Functions_To_Install pushBack (format['ATRAIN_fnc_%1', configName _x]); 13 | } forEach _cfgFunctions; 14 | } forEach _cfg; 15 | }; 16 | 17 | if( count ATRAIN_Functions_To_Install > 0 ) then { 18 | 19 | // Remotely install all functions 20 | { 21 | _clientId publicVariableClient _x; 22 | } forEach ATRAIN_Functions_To_Install; 23 | 24 | // Remotely init ATS 25 | [[ATRAIN_Functions_To_Install], { 26 | params ["_functionsToInstall"]; 27 | { waitUntil { !isNil _x } } forEach _functionsToInstall; 28 | [] spawn ATRAIN_fnc_init; 29 | }] remoteExec ["spawn", _clientId]; 30 | 31 | }; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_serverEventHandlerLoop.sqf: -------------------------------------------------------------------------------- 1 | if(!isServer) exitWith {}; 2 | while {true} do { 3 | if(count ATRAIN_Server_Events > 0) then { 4 | private _event = ATRAIN_Server_Events deleteAt 0; 5 | private _action = _event select 0; 6 | if(_action == "REGISTER") then { 7 | _event params ["_action","_train","_driver"]; 8 | if([_train] call ATRAIN_fnc_attachTrainToTrackMap) then { 9 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 10 | _registeredTrains pushBackUnique _train; 11 | _train setVariable ["ATRAIN_Remote_Driver", _driver, true]; 12 | _train setVariable ["ATRIAN_Current_Train", _train, true]; 13 | missionNamespace setVariable ["ATRAIN_Registered_Trains",_registeredTrains,true]; 14 | } else { 15 | [[_train, _driver], { 16 | params ["_train", "_driver"]; 17 | //diag_log str ["START",_this]; 18 | if(_train getVariable ["ATRAIN_Loaded_Track_Map",false]) exitWith {}; 19 | _train setVariable ["ATRAIN_Loaded_Track_Map",true]; 20 | private _track = [_train] call ATRAIN_fnc_getTrackUnderTrain; 21 | //diag_log str ["TRACK",_track]; 22 | if(isNull _track) exitWith {}; 23 | ["Loading Advanced Train Simulator (ATS)",0,0,99,2,0,3000] spawn bis_fnc_dynamicText; 24 | private _trackMap = [_track] call ATRAIN_fnc_buildTrackMap; 25 | [_trackMap] call ATRAIN_fnc_updateTrackMap; 26 | [_train, _driver] call ATRAIN_fnc_registerTrainAndDriver; 27 | ["",0,0,1,0,0,3000] spawn bis_fnc_dynamicText; 28 | ["",0,0,1,0,0,3001] spawn bis_fnc_dynamicText; 29 | }] remoteExec ["spawn", _driver]; 30 | }; 31 | }; 32 | if(_action == "UNREGISTER") then { 33 | _event params ["_action","_train","_driver"]; 34 | _train setVariable ["ATRAIN_Remote_Driver", nil, true]; 35 | }; 36 | if(_action == "UPDATETRACKMAP") then { 37 | _event params ["_action","_trackMap"]; 38 | //diag_log str ["HANDLING TRACK MAP UPDATE"]; 39 | [_trackMap] call ATRAIN_fnc_updateServerTrackMap; 40 | }; 41 | }; 42 | sleep 0.1; 43 | }; 44 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_unregisterTrainAndDriver.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_driver"]; 2 | if(!isServer) exitWith { [_this, "ATRAIN_fnc_unregisterTrainAndDriver"] call ATRAIN_fnc_RemoteExecServer }; 3 | ATRAIN_Server_Events pushBack ["UNREGISTER",_train,_driver]; 4 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_updateServerTrackMap.sqf: -------------------------------------------------------------------------------- 1 | params ["_trackMap"]; 2 | private _trackMapUpdated = false; 3 | private _trackMapNodesToUpdate = []; 4 | { 5 | private _nodeTrack = _x select 0; 6 | if!(_nodeTrack in ATRAIN_Nodes) then { 7 | ATRAIN_Nodes pushBack _nodeTrack; 8 | ATRAIN_Map pushBack []; 9 | _trackMapNodesToUpdate pushBack _x; 10 | _trackMapUpdated = true; 11 | //diag_log str _x; 12 | }; 13 | } forEach _trackMap; 14 | 15 | { 16 | private _nodeTrack = _x select 0; 17 | private _nodeConnections = _x select 1; 18 | private _nodeIndex = ATRAIN_Nodes find _nodeTrack; 19 | if(_nodeIndex >= 0) then { 20 | private _mapConnections = []; 21 | { 22 | private _connectionNodeTrack = _x select 0; 23 | private _connectionNodeIndex = ATRAIN_Nodes find _connectionNodeTrack; 24 | private _connectionPath = _x select 1; 25 | private _connectionDistance = _x select 2; 26 | private _connectionTracks = _x select 3; 27 | if(_connectionNodeIndex >= 0) then { 28 | _mapConnections pushBack [_connectionNodeIndex, _connectionDistance, _connectionPath]; 29 | { 30 | private _connectionTrackObj = _x select 0; 31 | private _connectionTrackDirection = _x select 1; 32 | ATRAIN_Track_Node_Lookup pushBack [_connectionTrackObj, _connectionTrackDirection, _connectionNodeIndex, _nodeIndex ]; 33 | } forEach _connectionTracks; 34 | }; 35 | } forEach _nodeConnections; 36 | ATRAIN_Map set [_nodeIndex, _mapConnections]; 37 | }; 38 | } forEach _trackMapNodesToUpdate; 39 | if(_trackMapUpdated) then { 40 | publicVariable "ATRAIN_Map"; 41 | }; 42 | 43 | _trackMapUpdated; 44 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/server/fn_updateTrackMap.sqf: -------------------------------------------------------------------------------- 1 | params ["_trackMap"]; 2 | if(!isServer) exitWith { [_this, "ATRAIN_fnc_updateTrackMap"] call ATRAIN_fnc_RemoteExecServer }; 3 | ATRAIN_Server_Events pushBack ["UPDATETRACKMAP",_trackMap]; 4 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_attachSoundSource.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource", "_attachToObject", ["_modelPosition",[0,0,0]]]; 2 | _soundSource setVariable ["attachedTo", [_attachToObject, _modelPosition]]; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_createSoundSource.sqf: -------------------------------------------------------------------------------- 1 | params ["_sound",["_maxDistance",250],["_repeat",true],["_repeatLength",10],["_pitch",1]]; 2 | private _soundSource = "Building" createVehicleLocal [-1000,-1000,-1000]; 3 | _soundSource setVariable ["maxDistance", _maxDistance]; 4 | _soundSource setVariable ["repeatLength", _repeatLength]; 5 | _soundSource setVariable ["sound", _sound]; 6 | _soundSource setVariable ["pitch", _pitch]; 7 | _soundSource setVariable ["repeat", _repeat]; 8 | _soundSource setVariable ["lastPlayTime",0]; 9 | [_soundSource, false] call ATRAIN_fnc_enableSoundSource; 10 | ATRAIN_Sound_Sources pushBack _soundSource; 11 | _soundSource; 12 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_deleteSoundSource.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource"]; 2 | if(!isNull _soundSource) then { 3 | ATRAIN_Sound_Sources = ATRAIN_Sound_Sources - [_soundSource]; 4 | ATRAIN_Sound_Sources_Near = ATRAIN_Sound_Sources_Near - [_soundSource]; 5 | deleteVehicle _soundSource; 6 | }; 7 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_detatchSoundSource.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource"]; 2 | _soundSource setVariable ["attachedTo", nil]; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_enableSoundSource.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource","_isEnabled"]; 2 | _soundSource setVariable ["enabled", _isEnabled]; 3 | if(!_isEnabled) then { 4 | _soundSource setPosASL [-1000,-1000,-1000]; 5 | _soundSource spawn { 6 | sleep 0.1; // Repeat 0.1 seconds later to avoid concurrency issues 7 | _this setPosASL [-1000,-1000,-1000]; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_getSoundSourcePositionASL.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource"]; 2 | private _soundSourcePositionASL = _soundSource getVariable ["positionASL", [0,0,0]];; 3 | private _attachedTo = [_soundSource] call ATRAIN_fnc_soundSourceAttachedTo; 4 | _attachedTo params [["_attachedToObject",objNull], ["_attachedToModelPosition",[0,0,0]]]; 5 | if(!isNull _attachedToObject) then { 6 | _soundSourcePositionASL = AGLToASL (_attachedToObject modelToWorldVisual _attachedToModelPosition); 7 | }; 8 | _soundSourcePositionASL; 9 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_getSoundSourceVolume.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource"]; 2 | ((_soundSource getVariable ["volume", 1]) min 1) max 0; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_initSound.sqf: -------------------------------------------------------------------------------- 1 | if(!isNil "ATRAIN_Sound_Source_Init") exitWith {}; 2 | ATRAIN_Sound_Source_Init = true; 3 | ATRAIN_Sound_Sources = missionNamespace getVariable ["ATRAIN_Sound_Sources",[]]; 4 | ATRAIN_Sound_Sources_Near = missionNamespace getVariable ["ATRAIN_Sound_Sources_Near",[]]; 5 | // Start loop to detect, track and show nearby sound sources 6 | [] spawn ATRAIN_fnc_nearbySoundSourceHandler; 7 | // Start loop to handle sound source simulation (volume + attachments) 8 | [] spawn ATRAIN_fnc_soundSourceSimulationHandler; 9 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_nearbySoundSourceHandler.sqf: -------------------------------------------------------------------------------- 1 | while {true} do { 2 | { 3 | private _soundSource = _x; 4 | private _soundSourcePositionASL = [_soundSource] call ATRAIN_fnc_getSoundSourcePositionASL; 5 | private _cameraPositionASL = AGLToASL (positionCameraToWorld [0,0,0]); 6 | private _maxDistance = _soundSource getVariable "maxDistance"; 7 | if(_cameraPositionASL distance _soundSourcePositionASL < _maxDistance * 2) then { 8 | if!( _soundSource in ATRAIN_Sound_Sources_Near) then { 9 | ATRAIN_Sound_Sources_Near pushBack _soundSource; 10 | }; 11 | } else { 12 | if( _soundSource in ATRAIN_Sound_Sources_Near) then { 13 | ATRAIN_Sound_Sources_Near = ATRAIN_Sound_Sources_Near - [_soundSource]; 14 | _soundSource setPosASL [-1000,-1000,-1000]; 15 | _soundSource spawn { 16 | sleep 0.1; // Repeat 0.1 seconds later to avoid concurrency issues 17 | _this setPosASL [-1000,-1000,-1000]; 18 | }; 19 | }; 20 | }; 21 | } forEach ATRAIN_Sound_Sources; 22 | sleep 3; 23 | }; 24 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_setSoundSourcePositionASL.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource","_positionASL"]; 2 | _soundSource setVariable ["positionASL", _positionASL]; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_setSoundSourceVolume.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource", "_volume"]; 2 | _soundSource setVariable ["volume", _volume]; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_soundSourceAttachedTo.sqf: -------------------------------------------------------------------------------- 1 | params ["_soundSource"]; 2 | _soundSource getVariable ["attachedTo", []]; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/sound/fn_soundSourceSimulationHandler.sqf: -------------------------------------------------------------------------------- 1 | while {true} do { 2 | { 3 | private _tickTime = diag_tickTime; 4 | private _soundSource = _x; 5 | if(_soundSource getVariable "enabled") then { 6 | 7 | // Set sound source position 8 | private _cameraPositionASL = AGLToASL (positionCameraToWorld [0,0,0]); 9 | private _soundSourcePositionASL = [_soundSource] call ATRAIN_fnc_getSoundSourcePositionASL; 10 | private _volume = [_soundSource] call ATRAIN_fnc_getSoundSourceVolume; 11 | private _maxDistance = _soundSource getVariable "maxDistance"; 12 | if(_volume < 1) then { 13 | // Move sound source further away from position to simulate volume 14 | _soundSourcePositionASL = _soundSourcePositionASL vectorAdd ((_cameraPositionASL vectorFromTo _soundSourcePositionASL) vectorMultiply (((-_volume)+1) * (_maxDistance))); 15 | }; 16 | _soundSource setPosASL _soundSourcePositionASL; 17 | 18 | // Play sound source sound 19 | private _lastPlayTime = _soundSource getVariable "lastPlayTime"; 20 | private _repeatLength = _soundSource getVariable "repeatLength"; 21 | private _repeat = _soundSource getVariable "repeat"; 22 | private _sound = _soundSource getVariable "sound"; 23 | private _pitch = _soundSource getVariable "pitch"; 24 | if( (_repeat || _lastPlayTime == 0) && _tickTime - _lastPlayTime > (_repeatLength) ) then { 25 | _soundSource say3D [_sound, _maxDistance, _pitch]; 26 | _soundSource setVariable ["lastPlayTime", _tickTime]; 27 | }; 28 | 29 | }; 30 | } forEach ATRAIN_Sound_Sources_Near; 31 | sleep 0.1; 32 | }; 33 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_addWorldPaths.sqf: -------------------------------------------------------------------------------- 1 | params ["_path", "_addPath",["_replaceOverlapWithAddedPath",false]]; 2 | 3 | if(count _addPath < 2) exitWith { 0; }; 4 | private _distanceAddedToPath = 0; 5 | private _pathSize = count _path; 6 | 7 | // Initialize path if it contains no points 8 | if(_pathSize == 0) exitWith { 9 | private _lastSeenPathPointPositionASL = _addPath select 0; 10 | { 11 | _path pushBack _x; 12 | _distanceAddedToPath = _distanceAddedToPath + (_lastSeenPathPointPositionASL distance _x); 13 | _lastSeenPathPointPositionASL = _x; 14 | } forEach _addPath; 15 | _distanceAddedToPath; 16 | }; 17 | 18 | private _lastPathPointPosASL = _path select (_pathSize - 1); 19 | private _secondToLastPathPointPosASL = _path select (_pathSize - 2); 20 | private _pathUnitVectorDir = _secondToLastPathPointPosASL vectorFromTo _lastPathPointPosASL; 21 | 22 | // Align direction of paths 23 | private _addPathFirstPointPosASL = _addPath select 0; 24 | private _addPathSecondPointPosASL = _addPath select 1; 25 | private _addPathVectorDir = _addPathFirstPointPosASL vectorFromTo _addPathSecondPointPosASL; 26 | private _pathDotProduct = _pathUnitVectorDir vectorDotProduct _addPathVectorDir; 27 | if( _pathDotProduct < 0 ) then { 28 | reverse _addPath; 29 | }; 30 | 31 | // Remove overlapping points from path before adding new path (if requested) 32 | if(_replaceOverlapWithAddedPath) then { 33 | private _resizeTo = _pathSize; 34 | private _addPathFirstPointPosASL = _addPath select 0; 35 | for [{_i=_pathSize-1}, {_i > 1}, {_i=_i-1}] do 36 | { 37 | private _pathPointPosASL = (_path select _i); 38 | private _priorPathPointPosASL = (_path select _i - 1); 39 | private _pathUnitVectorDir = _priorPathPointPosASL vectorFromTo _pathPointPosASL; 40 | private _unitVectorDirToNewPathPoint = _pathPointPosASL vectorFromTo _addPathFirstPointPosASL; 41 | if( _pathUnitVectorDir vectorDotProduct _unitVectorDirToNewPathPoint <= 0 ) then { 42 | _resizeTo = _resizeTo - 1; 43 | _distanceAddedToPath = _distanceAddedToPath - (_priorPathPointPosASL distance _pathPointPosASL); 44 | } else { 45 | _i = 0; 46 | }; 47 | }; 48 | if(_resizeTo < _pathSize) then { 49 | _path resize _resizeTo; 50 | _pathSize = _resizeTo; 51 | }; 52 | _lastPathPointPosASL = (_path select (_pathSize - 1)); 53 | }; 54 | 55 | // Add the the new path onto the existing path 56 | { 57 | private _unitVectorDirToNewPathPoint = _lastPathPointPosASL vectorFromTo _x; 58 | if( _pathUnitVectorDir vectorDotProduct _unitVectorDirToNewPathPoint > 0 ) then { 59 | // Merges points together (reduces number of points slightly) 60 | /*if(_pathUnitVectorDir vectorDotProduct _unitVectorDirToNewPathPoint == 1 && !_replaceOverlapWithAddedPath && _pathSize > 2) then { 61 | _pathSize = (_pathSize-1); 62 | _path resize _pathSize; 63 | };*/ 64 | _path pushBack _x; 65 | _distanceAddedToPath = _distanceAddedToPath + (_lastPathPointPosASL distance _x); 66 | _lastPathPointPosASL = _x; 67 | }; 68 | } forEach _addPath; 69 | _distanceAddedToPath; 70 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_buildTrackMap.sqf: -------------------------------------------------------------------------------- 1 | params ["_track"]; 2 | private _startNodes = [_track] call ATRAIN_fnc_findConnectedTrackNodes; 3 | if(count _startNodes == 0) exitWith {[]}; 4 | private _firstStartNode = _startNodes select 0; 5 | private _firstStartNodeTrack = _firstStartNode select 0; 6 | private _nodesToProcess = [[_firstStartNodeTrack]]; 7 | private _nodeMap = []; 8 | while { count _nodesToProcess > 0 } do { 9 | private _currentNodeToProcess = _nodesToProcess deleteAt 0; 10 | private _currentNodeTrack = _currentNodeToProcess select 0; 11 | private _nodeSeen = false; 12 | { 13 | if(_x select 0 == _currentNodeTrack) exitWith { 14 | _nodeSeen = true; 15 | }; 16 | } forEach _nodeMap; 17 | if(!_nodeSeen) then { 18 | private _connectedNodes = _currentNodeToProcess call ATRAIN_fnc_findConnectedTrackNodes; 19 | _nodeMap pushBack [_currentNodeTrack,_connectedNodes]; 20 | { 21 | private _connectedNodeTrack = _x select 0; 22 | private _reversePathCopy = ((_x select 1) + []); 23 | reverse _reversePathCopy; 24 | private _pathDistance = _x select 2; 25 | private _connectionTracks = []; 26 | { 27 | _connectionTracks pushBack [_x select 0, (_x select 1) vectorMultiply -1]; 28 | } forEach (_x select 3); 29 | _nodesToProcess pushBack [_connectedNodeTrack,[_currentNodeTrack,_reversePathCopy,_pathDistance,_connectionTracks]]; 30 | if(missionNamespace getVariable ["ATRAIN_Track_Debug_Enabled",false]) then { 31 | private _path = _x select 1; 32 | { 33 | [_x] call ATRAIN_fnc_createMarker; 34 | } forEach _path; 35 | }; 36 | } forEach _connectedNodes; 37 | }; 38 | }; 39 | _nodeMap; 40 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_findAlignedTrackWorldPath.sqf: -------------------------------------------------------------------------------- 1 | params ["_track","_approachPosVectorDir"]; 2 | private _worldPaths = [_track] call ATRAIN_fnc_getTrackWorldPaths; 3 | private _bestTrackPathDotProduct = -1; 4 | private _bestTrackWorldPath = []; 5 | { 6 | private _pathPosition0ASL = (_x select 0); 7 | private _pathPosition1ASL = (_x select 1); 8 | private _pathVectorDir = _pathPosition0ASL vectorFromTo _pathPosition1ASL; 9 | private _pathDotProduct = _approachPosVectorDir vectorDotProduct _pathVectorDir; 10 | if( _pathDotProduct > _bestTrackPathDotProduct || _bestTrackPathDotProduct == -1 ) then { 11 | _bestTrackPathDotProduct = _pathDotProduct; 12 | _bestTrackWorldPath = _x; 13 | }; 14 | } forEach _worldPaths; 15 | _bestTrackWorldPath; 16 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_findConnectedTrackNodes.sqf: -------------------------------------------------------------------------------- 1 | params ["_track",["_sourceConnection",[]]]; 2 | private _trackWorldPaths = [_track] call ATRAIN_fnc_getTrackWorldPaths; 3 | private _connectedTrackNodes = []; 4 | { 5 | private _trackWorldPath = _x; 6 | private _pathToNode = []; 7 | reverse _trackWorldPath; 8 | private _trackDistance = [_pathToNode, _trackWorldPath] call ATRAIN_fnc_addWorldPaths; 9 | private _pathToNodeCount = count _pathToNode; 10 | private _lastPathPosASL = _pathToNode select (_pathToNodeCount-1); 11 | private _secondToLastPathPosASL = _pathToNode select (_pathToNodeCount-2); 12 | private _trackDir = _secondToLastPathPosASL vectorFromTo _lastPathPosASL; 13 | private _tracksInPath = [[_track,_trackDir]]; 14 | private _distanceFromFront = 0; 15 | private _lastSeenTrack = _track; 16 | private _trackNodeFound = false; 17 | private _trackNode = objNull; 18 | private _sourceConnectionUsed = false; 19 | private _lastCameraPreloadLocation = [0,0,0]; 20 | 21 | // Check to see if the path is heading back in the direction of the path we just followed 22 | // If it is, use the source connection path instead of retracing the steps back 23 | if(count _sourceConnection > 0) then { 24 | private _sourceConnectionPath = _sourceConnection select 1; 25 | private _sourceConnectionPathSecondPosition = _sourceConnectionPath select 1; 26 | private _currentPathSecondPosition = _pathToNode select 1; 27 | if( _sourceConnectionPathSecondPosition distance _currentPathSecondPosition == 0) then { 28 | _connectedTrackNodes pushBack _sourceConnection; 29 | _sourceConnectionUsed = true; 30 | }; 31 | }; 32 | 33 | private _priorPositionOnPath = ([_pathToNode,_distanceFromFront + 2] call ATRAIN_fnc_getPositionAndDirectionOnPath) select 0; 34 | 35 | while {true && !_sourceConnectionUsed} do { 36 | 37 | private _positionOnPath = ([_pathToNode,_distanceFromFront] call ATRAIN_fnc_getPositionAndDirectionOnPath) select 0; 38 | private _directionOnPath = _priorPositionOnPath vectorFromTo _positionOnPath; 39 | private _tracksAtPosition = [_positionOnPath,_lastSeenTrack,_directionOnPath] call ATRAIN_fnc_getTracksAtPosition; 40 | _priorPositionOnPath = _positionOnPath; 41 | 42 | if(missionNamespace getVariable ["ATRAIN_Track_Debug_Enabled",false]) then { 43 | _arrow = "Sign_Arrow_F" createVehicle [0,0,0]; 44 | _arrow setPosASL _positionOnPath; 45 | }; 46 | 47 | scopeName "ATRAIN_fnc_findConnectedTrackNodes_0"; 48 | { 49 | if(_x != _lastSeenTrack) then { 50 | private _trackDef = [_x] call ATRAIN_fnc_getTrackDefinition; 51 | _trackDef params ["_className","_modelPaths","_isSplitTrack","_isEndTrack"]; 52 | private _trackWorldPath = ([_x] call ATRAIN_fnc_getTrackWorldPaths) select 0; 53 | if(_isSplitTrack || _isEndTrack) then { 54 | _trackWorldPath = [_x,_directionOnPath] call ATRAIN_fnc_findAlignedTrackWorldPath; 55 | }; 56 | _lastTrackSeen = _x; 57 | if(_isSplitTrack || _isEndTrack) then { 58 | private _distanceAdded = [_pathToNode, _trackWorldPath, true] call ATRAIN_fnc_addWorldPaths; 59 | private _pathToNodeCount = count _pathToNode; 60 | private _lastPathPosASL = _pathToNode select (_pathToNodeCount-1); 61 | private _secondToLastPathPosASL = _pathToNode select (_pathToNodeCount-2); 62 | private _trackDir = _secondToLastPathPosASL vectorFromTo _lastPathPosASL; 63 | _tracksInPath pushBack [_x,_trackDir]; 64 | _trackDistance = _trackDistance + _distanceAdded; 65 | _distanceFromFront = _distanceFromFront + _distanceAdded; 66 | _trackNodeFound = true; 67 | _trackNode = _x; 68 | breakTo "ATRAIN_fnc_findConnectedTrackNodes_0"; 69 | }; 70 | if(_x == _track) then { 71 | // Prevents endless track loops 72 | _trackNodeFound = false; 73 | _trackNode = objNull; 74 | breakTo "ATRAIN_fnc_findConnectedTrackNodes_0"; 75 | }; 76 | private _distanceAdded = [_pathToNode, _trackWorldPath, false] call ATRAIN_fnc_addWorldPaths; 77 | private _pathToNodeCount = count _pathToNode; 78 | private _lastPathPosASL = _pathToNode select (_pathToNodeCount-1); 79 | private _secondToLastPathPosASL = _pathToNode select (_pathToNodeCount-2); 80 | private _trackDir = _secondToLastPathPosASL vectorFromTo _lastPathPosASL; 81 | _tracksInPath pushBack [_x,_trackDir]; 82 | _trackDistance = _trackDistance + _distanceAdded; 83 | _distanceFromFront = _distanceFromFront + _distanceAdded; 84 | _lastSeenTrack = _x; 85 | }; 86 | } forEach _tracksAtPosition; 87 | 88 | // Force objects to load on map as we search for tracks (does not work on dedicated server) 89 | if(count _tracksAtPosition == 0 && _distanceFromFront < -10) then { 90 | if(_lastCameraPreloadLocation distance _positionOnPath > 100 ) then { 91 | private _posAGL = [_positionOnPath select 0, _positionOnPath select 1, 0]; 92 | { 93 | _posAGL nearObjects [_x select 0, 300]; 94 | } forEach ATRAIN_Train_Definitions; 95 | _distanceFromFront = 0; 96 | _lastCameraPreloadLocation = _positionOnPath; 97 | }; 98 | }; 99 | 100 | // Track node found or no valid node found ( will search 10m beyond end of track ) 101 | if(_trackNodeFound || _distanceFromFront < -10) exitWith {}; 102 | 103 | if(_distanceFromFront > 0 && !(_lastSeenTrack in ATRAIN_TRACKS_NEAR_EDITOR_PLACED_CONNECTIONS)) then { 104 | _distanceFromFront = 0; 105 | } else { 106 | _distanceFromFront = _distanceFromFront - 1.1; 107 | }; 108 | 109 | }; 110 | 111 | if(!isNull _trackNode) then { 112 | _connectedTrackNodes pushBack [_trackNode,_pathToNode,_trackDistance,_tracksInPath]; 113 | }; 114 | 115 | } forEach _trackWorldPaths; 116 | _connectedTrackNodes; 117 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_getTrackDefinition.sqf: -------------------------------------------------------------------------------- 1 | params ["_track"]; 2 | private _trackType = [_track] call ATRAIN_fnc_getTypeOf; 3 | private _trackDef = []; 4 | private _trackDefIndex = ATRAIN_Track_Definitions_Index find toLower (_trackType select 0); 5 | if(_trackDefIndex >= 0) then { 6 | _trackDef = ATRAIN_Track_Definitions select _trackDefIndex; 7 | }; 8 | _trackDef; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_getTrackMapConnection.sqf: -------------------------------------------------------------------------------- 1 | params ["_startNodeIndex","_connectionNodeIndex"]; 2 | private _foundConnection = []; 3 | private _mapStartNode = ATRAIN_Map select _startNodeIndex; 4 | { 5 | if((_x select 0) == _connectionNodeIndex) exitWith { _foundConnection = _x }; 6 | } forEach _mapStartNode; 7 | _foundConnection; 8 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_getTrackUnderTrain.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainPositionASL = getPosASLVisual _train; 3 | private _trainVectorDir = vectorDir _train; 4 | private _offset = _train getVariable ["ATRAIN_Remote_Position_Offset",[0,0,0]]; 5 | _trainPositionASL = _trainPositionASL vectorAdd (_offset vectorMultiply -1); 6 | private _tracks = [_trainPositionASL,_train,_trainVectorDir] call ATRAIN_fnc_getTracksAtPosition; 7 | private _foundTrack = objNull; 8 | if(count _tracks > 0) then { 9 | _foundTrack = _tracks select 0; 10 | }; 11 | _foundTrack; 12 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_getTrackWorldPaths.sqf: -------------------------------------------------------------------------------- 1 | params ["_track"]; 2 | private _trackDef = [_track] call ATRAIN_fnc_getTrackDefinition; 3 | if(count _trackDef == 0) exitWith {[];}; 4 | _trackDef params ["_className","_centerOffset","_isIntersection","_isTermination",["_heightOffset",0]]; 5 | private _map1 = _track selectionPosition "map1"; 6 | _map1 = _map1 vectorAdd [0,0,_heightOffset]; 7 | private _map2 = _track selectionPosition "map2"; 8 | _map2 = _map2 vectorAdd [0,0,_heightOffset]; 9 | private _map3 = _track selectionPosition "map3"; 10 | _map3 = _map3 vectorAdd [0,0,_heightOffset]; 11 | 12 | private _trackWorldPaths = []; 13 | 14 | if(!_isIntersection && !_isTermination) then { 15 | private _worldPath = []; 16 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_map1))); 17 | private _trackPosition = _track selectionPosition "track1"; 18 | if(_trackPosition distance [0,0,0] != 0) then { 19 | private _trackIndex = 1; 20 | while {_trackPosition distance [0,0,0] != 0} do { 21 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_trackPosition))); 22 | _trackIndex = _trackIndex + 1; 23 | _trackPosition = _track selectionPosition (format ["track%1", _trackIndex]); 24 | }; 25 | } else { 26 | if(_centerOffset != 0) then { 27 | private _pathMidpoint = _map1 vectorAdd ((_map2 vectorDiff _map1) vectorMultiply 0.5); 28 | _pathMidpoint = _pathMidpoint vectorAdd (((vectorUp _track) vectorCrossProduct (_map1 vectorFromTo _map2)) vectorMultiply _centerOffset); 29 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_pathMidpoint))); 30 | }; 31 | }; 32 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_map2))); 33 | _trackWorldPaths pushBack _worldPath; 34 | }; 35 | 36 | if(_isTermination) then { 37 | private _pathMidpoint = _map1 vectorAdd ((_map2 vectorDiff _map1) vectorMultiply 0.5); 38 | _trackWorldPaths pushBack [AGLtoASL (_track modelToWorld (_map1)), AGLtoASL (_track modelToWorld (_pathMidpoint))]; 39 | _trackWorldPaths pushBack [AGLtoASL (_track modelToWorld (_map2)), AGLtoASL (_track modelToWorld (_pathMidpoint))]; 40 | }; 41 | 42 | if(_isIntersection) then { 43 | private _pathMidpoint = _map1 vectorAdd ((_map2 vectorDiff _map1) vectorMultiply 0.9); 44 | _trackWorldPaths pushBack [AGLtoASL (_track modelToWorld (_map1)), AGLtoASL (_track modelToWorld (_pathMidpoint))]; 45 | _trackWorldPaths pushBack [AGLtoASL (_track modelToWorld (_map2)), AGLtoASL (_track modelToWorld (_pathMidpoint))]; 46 | private _worldPath = []; 47 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_map3))); 48 | private _pathMidpoint2 = _map3 vectorAdd ((_pathMidpoint vectorDiff _map3) vectorMultiply 0.5); 49 | _pathMidpoint2 = _pathMidpoint2 vectorAdd (((vectorUp _track) vectorCrossProduct (_map3 vectorFromTo _pathMidpoint)) vectorMultiply _centerOffset); 50 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_pathMidpoint2))); 51 | _worldPath pushBack (AGLtoASL (_track modelToWorld (_pathMidpoint))); 52 | _trackWorldPaths pushBack _worldPath; 53 | }; 54 | _trackWorldPaths; 55 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_getTracksAtPosition.sqf: -------------------------------------------------------------------------------- 1 | params ["_positionASL",["_ignoreObject",objNull],["_approachDirectionVector",[0,0,0]]]; 2 | private _intersectStartASL = _positionASL vectorAdd [0,0,2] vectorAdd (_approachDirectionVector vectorMultiply -4); 3 | private _intersectEndASL = _positionASL vectorAdd [0,0,-2] vectorAdd (_approachDirectionVector vectorMultiply 4); 4 | private _objects = lineIntersectsWith [_intersectStartASL,_intersectEndASL,_ignoreObject]; 5 | private _foundTracks = []; 6 | private _didFindTracks = false; 7 | private _trackDef = []; 8 | { 9 | private _object = _x; 10 | if(!isNull _object) then { 11 | _trackDef = [_object] call ATRAIN_fnc_getTrackDefinition; 12 | if(count _trackDef > 0) then { 13 | _foundTracks pushBack _object; 14 | _didFindTracks = true; 15 | }; 16 | }; 17 | } forEach _objects; 18 | _foundTracks; 19 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_initTracks.sqf: -------------------------------------------------------------------------------- 1 | 2 | ATRAIN_Track_Definitions = missionNamespace getVariable ["ATRAIN_Track_Definitions",[]]; 3 | 4 | // [Class Name, Center Point Offset, Is Split Track, Is End Track,Memory Point Height Offset] 5 | ATRAIN_Track_Definitions append [ 6 | ["Land_Track_01_3m_F",0,false,false], 7 | ["Land_Track_01_7deg_F",0.15,false,false], 8 | ["Land_Track_01_10m_F",0,false,false], 9 | ["Land_Track_01_15deg_F",0.3,false,false], 10 | ["Land_Track_01_20m_F",0,false,false], 11 | ["Land_Track_01_30deg_F",0.6,false,false], 12 | ["Land_Track_01_bridge_F",0,false,false], 13 | ["Land_Track_01_bumper_F",0,false,true], 14 | ["Land_Track_01_turnout_left_F",0.55,true,false], 15 | ["Land_Track_01_turnout_right_F",-0.55,true,false], 16 | ["ATS_Tracks_Cable_Wire",0,false,false], 17 | ["ATS_Tracks_Cable_Wire_50",0,false,false], 18 | ["ATS_Tracks_Cable_Wire_Stop",0,false,true], 19 | ["ATS_Tracks_Cable_Pole",0,false,false], 20 | // Test Tracks Below 21 | ["Land_straight40",0,false,false,0.06], 22 | ["Land_left_turn",1,true,false,0.06], 23 | ["Land_right_turn",-1,true,false,0.06], 24 | ["Land_straight25",0,false,false,0.06], 25 | ["Land_Bridge",0,false,false,0.06], 26 | ["Land_terminator_concrete",0,false,true,0.06], 27 | ["Land_straight_down40",0,false,false,0.06], 28 | ["Land_stonebridge",0,false,false,0.06], 29 | ["Land_Bridgehalf",0,false,false,0.06], 30 | ["Land_road_xing_25",0,false,false,0.06], 31 | ["Land_xroad_10",0,false,false,0.06], 32 | ["Land_xroad_25",0,false,false,0.06], 33 | ["Land_curveR25_5",0.3,false,false,0.06], 34 | ["Land_curveL30_20",0.3,false,false,0.06], 35 | ["Land_curveL25_10",0.3,false,false,0.06], 36 | ["Land_curveL25_5",0.3,false,false,0.06] 37 | ]; 38 | 39 | 40 | ATRAIN_Object_Model_To_Type_Map = missionNamespace getVariable ["ATRAIN_Object_Model_To_Type_Map",[]]; 41 | 42 | ATRAIN_Object_Model_To_Type_Map append [ 43 | ["track_01_3m_f.p3d",["Land_Track_01_3m_F",true]], 44 | ["track_01_7deg_f.p3d",["Land_Track_01_7deg_F",true]], 45 | ["track_01_10m_f.p3d",["Land_Track_01_10m_F",true]], 46 | ["track_01_15deg_f.p3d",["Land_Track_01_15deg_F",true]], 47 | ["track_01_20m_f.p3d",["Land_Track_01_20m_F",true]], 48 | ["track_01_30deg_f.p3d",["Land_Track_01_30deg_F",true]], 49 | ["track_01_bridge_f.p3d",["Land_Track_01_bridge_F",true]], 50 | ["track_01_bumper_f.p3d",["Land_Track_01_bumper_F",true]], 51 | ["track_01_turnout_left_f.p3d",["Land_Track_01_turnout_left_F",true]], 52 | ["track_01_turnout_right_f.p3d",["Land_Track_01_turnout_right_F",true]], 53 | ["ats_tracks_cable_pole.p3d",["ATS_Tracks_Cable_Pole",true]], 54 | ["ats_tracks_cable_wire.p3d",["ATS_Tracks_Cable_Wire",true]], 55 | ["ats_tracks_cable_wire_50.p3d",["ATS_Tracks_Cable_Wire_50",true]], 56 | ["ats_tracks_cable_wire_stop.p3d",["ATS_Tracks_Cable_Wire_Stop",true]], 57 | // Test Objects Below 58 | ["straight40.p3d",["Land_straight40",true]], 59 | ["right_turn.p3d",["Land_left_turn",true]], 60 | ["right_turn.p3d",["Land_right_turn",true]], 61 | ["straight25.p3d",["Land_straight25",true]], 62 | ["Bridge.p3d",["Land_Bridge",true]], 63 | ["straight_down40.p3d",["Land_terminator_concrete",true]], 64 | ["terminator_concrete.p3d",["Land_straight_down40",true]], 65 | ["stonebridge.p3d",["Land_stonebridge",true]], 66 | ["Bridgehalf.p3d",["Land_Bridgehalf",true]], 67 | ["road_xing_25.p3d",["Land_road_xing_25",true]], 68 | ["xroad_10.p3d",["Land_xroad_10",true]], 69 | ["xroad_25.p3d",["Land_xroad_25",true]], 70 | ["curveR25_5.p3d",["Land_curveR25_5",true]], 71 | ["curveL30_20.p3d",["Land_curveL30_20",true]], 72 | ["curveL25_10.p3d",["Land_curveL25_10",true]], 73 | ["curveL25_5.p3d",["Land_curveL25_5",true]] 74 | ]; 75 | 76 | 77 | [] call ATRAIN_fnc_rebuildArrayLookupIndexes; 78 | 79 | [] call ATRAIN_fnc_preloadAllTracksNearEditorPlacedConnections; 80 | 81 | /* 82 | [ 83 | [Track, Track Vector Dir, Start Node Track, End Node Track], 84 | ... 85 | ] 86 | */ 87 | ATRAIN_Track_Node_Lookup = missionNamespace getVariable ["ATRAIN_Track_Node_Lookup",[]]; 88 | 89 | 90 | /* 91 | [ 92 | Track Object, 93 | ... 94 | ] 95 | */ 96 | ATRAIN_Nodes = missionNamespace getVariable ["ATRAIN_Nodes",[]]; 97 | 98 | /* 99 | Map: [ 100 | Node: [ 101 | Connection: [ 102 | Node Index, 103 | Distance, 104 | Path: [ 105 | Point: [Pos, Dir, Up], ... 106 | ] 107 | ], 108 | ... 109 | ], 110 | ... 111 | ] 112 | */ 113 | ATRAIN_Map = missionNamespace getVariable ["ATRAIN_Map",[]]; 114 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_lookupTrackMapPosition.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _track = [_train] call ATRAIN_fnc_getTrackUnderTrain; 3 | if(isNull _track) exitWith {[]}; 4 | //diag_log str ["LOOKUP", _track]; 5 | private _trackMapPosition = []; 6 | private _foundTrackLookup = []; 7 | scopeName "ATRAIN_fnc_lookupTrackMapPosition_0"; 8 | { 9 | if(_x select 0 == _track) then { 10 | if( vectorDir _train vectorDotProduct (_x select 1) > 0 ) then { 11 | _foundTrackLookup = _x; 12 | breakTo "ATRAIN_fnc_lookupTrackMapPosition_0"; 13 | }; 14 | }; 15 | } forEach ATRAIN_Track_Node_Lookup; 16 | 17 | ////diag_log str ATRAIN_Track_Node_Lookup; 18 | 19 | if(count _foundTrackLookup > 0) then { 20 | _foundTrackLookup params ["_track","_direction","_startNodeIndex","_endNodeIndex"]; 21 | private _connection = [_startNodeIndex, _endNodeIndex] call ATRAIN_fnc_getTrackMapConnection; 22 | private _connectionDistance = _connection select 1; 23 | private _connectionPath = _connection select 2; 24 | private _distanceFromStart = 0; 25 | private _foundDistanceFromStart = 0; 26 | private _lastPathPointPosASL = []; 27 | private _trianPositionASL = getPosASL _train; 28 | scopeName "ATRAIN_fnc_lookupTrackMapPosition_1"; 29 | { 30 | private _currentPathPointPosASL = _x; 31 | if( count _lastPathPointPosASL > 0 ) then { 32 | private _positionDotProduct = (_trianPositionASL vectorFromTo _lastPathPointPosASL) vectorDotProduct (_trianPositionASL vectorFromTo _currentPathPointPosASL); 33 | if(_positionDotProduct <= 0) then { 34 | _foundDistanceFromStart = _distanceFromStart + (_lastPathPointPosASL distance _trianPositionASL); 35 | breakTo "ATRAIN_fnc_lookupTrackMapPosition_1"; 36 | }; 37 | _distanceFromStart = _distanceFromStart + (_lastPathPointPosASL distance _currentPathPointPosASL); 38 | }; 39 | _lastPathPointPosASL = _currentPathPointPosASL; 40 | } forEach _connectionPath; 41 | _trackMapPosition = [_startNodeIndex, _endNodeIndex, _foundDistanceFromStart, _connectionDistance]; 42 | }; 43 | // [Start Node Index, End Node Index, Distance From Start, Total Distance] 44 | _trackMapPosition; 45 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/track/fn_preloadAllTracksNearEditorPlacedConnections.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_TRACKS_NEAR_EDITOR_PLACED_CONNECTIONS = []; 2 | { 3 | private _isSplitTrack = _x select 2; 4 | private _isEndTrack = _x select 3; 5 | private _trackClassName = _x select 0; 6 | if(_isSplitTrack || _isEndTrack) then { 7 | // Loop over every mission object of that class 8 | private _missionTrackObjects = allMissionObjects _trackClassName; 9 | { 10 | // Loop over every path in the track object 11 | private _track = _x; 12 | private _trackWorldPaths = [_track] call ATRAIN_fnc_getTrackWorldPaths; 13 | { 14 | // Find tracks under the track path's end points 15 | private _positionASL = _x select 0; 16 | private _tracksAtPosition = [_positionASL,_track] call ATRAIN_fnc_getTracksAtPosition; 17 | { 18 | private _trackType = [_x] call ATRAIN_fnc_getTypeOf; 19 | _trackType params ["_className","_isStatic"]; 20 | if(_isStatic) then { 21 | ATRAIN_TRACKS_NEAR_EDITOR_PLACED_CONNECTIONS pushBackUnique _x; 22 | }; 23 | } forEach _tracksAtPosition 24 | } forEach _trackWorldPaths; 25 | } forEach _missionTrackObjects; 26 | }; 27 | } forEach ATRAIN_Track_Definitions; 28 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_calculateTrainAlignment.sqf: -------------------------------------------------------------------------------- 1 | params ["_trainEngine","_trainCar","_trainDistanceFromFront"]; 2 | private _carLength = _trainCar getVariable ["ATRAIN_Remote_Car_Length",6]; 3 | private _carFrontPositionAndDirection = [_trainEngine, _trainCar, _trainDistanceFromFront - (_carLength * 0.4)] call ATRAIN_fnc_getTrainPositionAndDirection; 4 | private _carBackPositionAndDirection = [_trainEngine, _trainCar, _trainDistanceFromFront + (_carLength * 0.4)] call ATRAIN_fnc_getTrainPositionAndDirection; 5 | [_carFrontPositionAndDirection, _carBackPositionAndDirection]; 6 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getNearestTrainCar.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | 3 | private _currentCar = player getVariable ["ATRAIN_Current_Train_Car",objNull]; 4 | if(isNull _currentCar) then { 5 | _currentCar = player getVariable ["ATRAIN_Current_Train_Passenger_Car",objNull]; 6 | }; 7 | 8 | // If player is in the engine or passenger car, return it 9 | if(!isNull _currentCar) exitWith { _currentCar }; 10 | 11 | // Otherwise, find the train car closest to the player's camera 12 | 13 | private _minDistance = 0; 14 | private _closestCar = objNull; 15 | private _cameraPositionASL = AGLToASL (positionCameraToWorld [0,0,0]); 16 | private _cars = _train getVariable ["ATRAIN_Remote_Cars",[_train]]; 17 | { 18 | private _localCar = _x getVariable ["ATRAIN_Local_Copy",_x]; 19 | if( isNull _closestCar || (visiblePositionASL _localCar) distance _cameraPositionASL < _minDistance) then { 20 | _minDistance = (visiblePositionASL _localCar) distance _cameraPositionASL; 21 | _closestCar = _x; 22 | }; 23 | } forEach _cars; 24 | 25 | _closestCar; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getPositionAndDirectionOnPath.sqf: -------------------------------------------------------------------------------- 1 | #define CALC_POS_AND_DIR_FROM_START(trackStartASL, trackEndASL, distanceFromStart) [(trackStartASL vectorAdd ( ( trackStartASL vectorFromTo trackEndASL ) vectorMultiply distanceFromStart)), trackEndASL vectorFromTo trackStartASL] 2 | 3 | params ["_path","_distanceFromFront",["_frontIsFirstElement",false],["_pathId",""],["_objectBeingPositioned",objNull]]; 4 | 5 | private _positionAndDirectionOnPath = []; 6 | 7 | // Lookup Position Cache Data (To speed up position lookup) 8 | private ["_lastPathId","_lastPathIndex","_lastPathDistance","_lastPathCount"]; 9 | if(isNull _objectBeingPositioned) then { 10 | _lastPathId = missionNamespace getVariable ["ATRAIN_Position_Cache_Path_id",""]; 11 | _lastPathIndex = missionNamespace getVariable ["ATRAIN_Position_Cache_Path_Index",0]; 12 | _lastPathDistance = missionNamespace getVariable ["ATRAIN_Position_Cache_Path_Distance",0]; 13 | _lastPathCount = missionNamespace getVariable ["ATRAIN_Position_Cache_Path_Count",0]; 14 | } else { 15 | _lastPathId = _objectBeingPositioned getVariable ["ATRAIN_Position_Cache_Path_id",""]; 16 | _lastPathIndex = _objectBeingPositioned getVariable ["ATRAIN_Position_Cache_Path_Index",0]; 17 | _lastPathDistance = _objectBeingPositioned getVariable ["ATRAIN_Position_Cache_Path_Distance",0]; 18 | _lastPathCount = _objectBeingPositioned getVariable ["ATRAIN_Position_Cache_Path_Count",0]; 19 | }; 20 | 21 | if(_lastPathId == _pathId && _pathId != "") then { 22 | 23 | // Lookup path position using cached data (much faster) 24 | 25 | if(_frontIsFirstElement) then { 26 | if( _distanceFromFront < _lastPathDistance ) then { 27 | if(_lastPathIndex == 0) then { 28 | private _pointPositionASL = (_path select 0); 29 | private _priorPointPositionASL = (_path select 1); 30 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 31 | } else { 32 | private _distanceSeen = _lastPathDistance; 33 | for [{_i=_lastPathIndex}, {_i > 0}, {_i=_i-1}] do 34 | { 35 | private _pointPositionASL = (_path select (_i-1)); 36 | private _priorPointPositionASL = (_path select _i); 37 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 38 | _distanceSeen = _distanceSeen - _distanceBetweenPathPositions; 39 | if(_distanceSeen <= _distanceFromFront || _i == 1) then { 40 | _lastPathIndex = _i-1; 41 | _lastPathDistance = _distanceSeen; 42 | _distanceFromFront = _distanceFromFront - _distanceSeen; 43 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 44 | _i = 0; 45 | }; 46 | }; 47 | }; 48 | } else { 49 | if(_lastPathIndex == _lastPathCount - 1) then { 50 | private _pointPositionASL = (_path select _lastPathCount-2); 51 | private _priorPointPositionASL = (_path select _lastPathCount-1); 52 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 53 | _distanceFromFront = (_distanceFromFront - _lastPathDistance) + _distanceBetweenPathPositions; 54 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 55 | } else { 56 | private _distanceSeen = _lastPathDistance; 57 | for [{_i=_lastPathIndex+1}, {_i < _lastPathCount}, {_i=_i+1}] do 58 | { 59 | private _pointPositionASL = (_path select (_i-1)); 60 | private _priorPointPositionASL = (_path select _i); 61 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 62 | _distanceSeen = _distanceSeen + _distanceBetweenPathPositions; 63 | if(_distanceSeen >= _distanceFromFront || _i == _lastPathCount - 1) then { 64 | _lastPathIndex = _i-1; 65 | _lastPathDistance = _distanceSeen - _distanceBetweenPathPositions; 66 | _distanceFromFront = _distanceFromFront - (_distanceSeen - _distanceBetweenPathPositions); 67 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 68 | _i = _lastPathCount; 69 | }; 70 | }; 71 | }; 72 | }; 73 | } else { 74 | if( _distanceFromFront < _lastPathDistance ) then { 75 | if(_lastPathIndex == _lastPathCount - 1) then { 76 | private _pointPositionASL = (_path select _lastPathCount-1); 77 | private _priorPointPositionASL = (_path select _lastPathCount-2); 78 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 79 | } else { 80 | private _distanceSeen = _lastPathDistance; 81 | for [{_i=_lastPathIndex+1}, {_i < _lastPathCount}, {_i=_i+1}] do 82 | { 83 | private _pointPositionASL = (_path select _i); 84 | private _priorPointPositionASL = (_path select (_i-1)); 85 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 86 | _distanceSeen = _distanceSeen - _distanceBetweenPathPositions; 87 | if(_distanceSeen <= _distanceFromFront || _i == _lastPathCount - 1) then { 88 | _lastPathIndex = _i; 89 | _lastPathDistance = _distanceSeen; 90 | _distanceFromFront = _distanceFromFront - _distanceSeen; 91 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 92 | _i = _lastPathCount; 93 | }; 94 | }; 95 | }; 96 | } else { 97 | if(_lastPathIndex == 0) then { 98 | private _pointPositionASL = (_path select 1); 99 | private _priorPointPositionASL = (_path select 2); 100 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 101 | _distanceFromFront = (_distanceFromFront - _lastPathDistance) + _distanceBetweenPathPositions; 102 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 103 | } else { 104 | private _distanceSeen = _lastPathDistance; 105 | for [{_i=_lastPathIndex}, {_i > 0}, {_i=_i-1}] do 106 | { 107 | private _pointPositionASL = (_path select _i); 108 | private _priorPointPositionASL = (_path select (_i-1)); 109 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 110 | _distanceSeen = _distanceSeen + _distanceBetweenPathPositions; 111 | if(_distanceSeen >= _distanceFromFront || _i == 1) then { 112 | _lastPathIndex = _i; 113 | _lastPathDistance = _distanceSeen - _distanceBetweenPathPositions; 114 | _distanceFromFront = _distanceFromFront - (_distanceSeen - _distanceBetweenPathPositions); 115 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 116 | _i = 0; 117 | }; 118 | }; 119 | }; 120 | }; 121 | }; 122 | 123 | } else { 124 | 125 | // Cannot use position cache data since path has changed 126 | 127 | private _pointCount = count _path; 128 | private _distanceSeen = 0; 129 | private _priorPoint = []; 130 | if(_frontIsFirstElement) then { 131 | for [{_i=1}, {_i < _pointCount}, {_i=_i+1}] do 132 | { 133 | private _pointPositionASL = (_path select (_i-1)); 134 | private _priorPointPositionASL = (_path select _i); 135 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 136 | _distanceSeen = _distanceSeen + _distanceBetweenPathPositions; 137 | if(_distanceSeen >= _distanceFromFront || _i == _pointCount - 1) then { 138 | _lastPathIndex = _i-1; 139 | _lastPathDistance = _distanceSeen - _distanceBetweenPathPositions; 140 | _distanceFromFront = _distanceFromFront - (_distanceSeen - _distanceBetweenPathPositions); 141 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 142 | _i = _pointCount; 143 | }; 144 | }; 145 | } else { 146 | for [{_i=_pointCount-1}, {_i > 0}, {_i=_i-1}] do 147 | { 148 | private _pointPositionASL = (_path select _i); 149 | private _priorPointPositionASL = (_path select (_i-1)); 150 | private _distanceBetweenPathPositions = (_pointPositionASL distance _priorPointPositionASL); 151 | _distanceSeen = _distanceSeen + _distanceBetweenPathPositions; 152 | if(_distanceSeen >= _distanceFromFront || _i == 1) then { 153 | _lastPathIndex = _i; 154 | _lastPathDistance = _distanceSeen - _distanceBetweenPathPositions; 155 | _distanceFromFront = _distanceFromFront - (_distanceSeen - _distanceBetweenPathPositions); 156 | _positionAndDirectionOnPath = CALC_POS_AND_DIR_FROM_START(_pointPositionASL, _priorPointPositionASL, _distanceFromFront); 157 | _i = 0; 158 | }; 159 | }; 160 | }; 161 | 162 | _lastPathCount = _pointCount; 163 | 164 | }; 165 | 166 | // Cache position data to speed up the next lookup 167 | 168 | if(isNull _objectBeingPositioned) then { 169 | missionNamespace setVariable ["ATRAIN_Position_Cache_Path_id",_pathId]; 170 | missionNamespace setVariable ["ATRAIN_Position_Cache_Path_Index",_lastPathIndex]; 171 | missionNamespace setVariable ["ATRAIN_Position_Cache_Path_Distance",_lastPathDistance]; 172 | missionNamespace setVariable ["ATRAIN_Position_Cache_Path_Count",_lastPathCount]; 173 | } else { 174 | _objectBeingPositioned setVariable ["ATRAIN_Position_Cache_Path_id",_pathId]; 175 | _objectBeingPositioned setVariable ["ATRAIN_Position_Cache_Path_Index",_lastPathIndex]; 176 | _objectBeingPositioned setVariable ["ATRAIN_Position_Cache_Path_Distance",_lastPathDistance]; 177 | _objectBeingPositioned setVariable ["ATRAIN_Position_Cache_Path_Count",_lastPathCount]; 178 | }; 179 | 180 | _positionAndDirectionOnPath; 181 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getTrainAtPosition.sqf: -------------------------------------------------------------------------------- 1 | params ["_positionASL",["_ignoreObject",objNull]]; 2 | private _intersectStartASL = _positionASL vectorAdd [0,0,2]; 3 | private _intersectEndASL = _positionASL vectorAdd [0,0,-2]; 4 | private _objects = lineIntersectsWith [_intersectStartASL,_intersectEndASL,_ignoreObject]; 5 | private _foundTrain = objNull; 6 | { 7 | private _object = _x; 8 | if(!isNull _object) then { 9 | _trainDef = [_object] call ATRAIN_fnc_getTrainDefinition; 10 | if(count _trainDef > 0) then { 11 | _foundTrain = _object; 12 | }; 13 | }; 14 | } forEach _objects; 15 | _foundTrain; 16 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getTrainDefinition.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainDef = []; 3 | private _trainType = [_train] call ATRAIN_fnc_getTypeOf; 4 | private _trainDefIndex = ATRAIN_Train_Definitions_Index find toLower (_trainType select 0); 5 | if(_trainDefIndex >= 0) then { 6 | _trainDef = ATRAIN_Train_Definitions select _trainDefIndex; 7 | }; 8 | _trainDef; 9 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getTrainPositionAndDirection.sqf: -------------------------------------------------------------------------------- 1 | params ["_trainEngine","_trainCar","_trainDistanceFromFront"]; 2 | private _nodePath = _trainEngine getVariable ["ATRAIN_Local_Node_Path",[]]; 3 | private _nodePathCount = count _nodePath; 4 | if(_nodePathCount == 2) exitWith { 5 | private _startNodeIndex = _nodePath select 0; 6 | private _endNodeIndex = _nodePath select 1; 7 | private _mapConnection = [_startNodeIndex, _endNodeIndex] call ATRAIN_fnc_getTrackMapConnection; 8 | [_mapConnection select 2, _trainDistanceFromFront, true, (str _startNodeIndex + "-" + str _endNodeIndex), _trainCar] call ATRAIN_fnc_getPositionAndDirectionOnPath; 9 | }; 10 | private _distanceSeen = 0; 11 | private _priorNodeIndex = -1; 12 | private _positioning = []; 13 | for [{_i=0}, {_i < _nodePathCount}, {_i=_i+1}] do 14 | { 15 | private _currentNodeIndex = _nodePath select _i; 16 | if(_priorNodeIndex >= 0) then { 17 | private _mapConnection = [_priorNodeIndex, _currentNodeIndex] call ATRAIN_fnc_getTrackMapConnection; 18 | private _distanceBetweeNodes = _mapConnection select 1; 19 | _distanceSeen = _distanceSeen + _distanceBetweeNodes; 20 | if((_trainDistanceFromFront < _distanceSeen) || ((_nodePathCount-1) == _i)) then { 21 | private _distanceFromStartNode = _trainDistanceFromFront - (_distanceSeen - _distanceBetweeNodes); 22 | _positioning = [_mapConnection select 2, _distanceFromStartNode, true, (str _priorNodeIndex + "-" + str _currentNodeIndex), _trainCar] call ATRAIN_fnc_getPositionAndDirectionOnPath; 23 | _i = _nodePathCount; 24 | }; 25 | }; 26 | _priorNodeIndex = _currentNodeIndex; 27 | }; 28 | _positioning; 29 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_getTrainUnderPlayer.sqf: -------------------------------------------------------------------------------- 1 | params ["_player"]; 2 | [getPosASLVisual _player,_player] call ATRAIN_fnc_getTrainAtPosition; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_hideTrainObject.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_hide","_hideGlobal"]; 2 | if(_hideGlobal) then { 3 | _this call ATRAIN_fnc_hideTrainObjectGlobal; 4 | } else { 5 | _this call ATRAIN_fnc_hideTrainObjectLocal; 6 | }; 7 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_hideTrainObjectGlobal.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_hide"]; 2 | if(isServer) then { 3 | private _trainDef = [_train] call ATRAIN_fnc_getTrainDefinition; 4 | if(count _trainDef > 0) then { 5 | _train hideObjectGlobal _hide; 6 | }; 7 | } else { 8 | _this call ATRAIN_fnc_hideTrainObjectLocal; 9 | [_this, "ATRAIN_fnc_hideTrainObjectGlobal"] call ATRAIN_fnc_RemoteExecServer; 10 | }; 11 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_hideTrainObjectLocal.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_hide"]; 2 | private _trainDef = [_train] call ATRAIN_fnc_getTrainDefinition; 3 | if(count _trainDef > 0) then { 4 | _train hideObject _hide; 5 | }; 6 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_hideTrainReplaceWithNew.sqf: -------------------------------------------------------------------------------- 1 | //added killed eventhandler, epe contact eventhandlers, lock 2 2 | params ["_train",["_oldObjectIsHiddenGlobal",true],["_newObjectIsGlobal",true]]; 3 | private _newTrain = objNull; 4 | private _trainType = [_train] call ATRAIN_fnc_getTypeOf; 5 | _trainType params ["_className","_isStatic"]; 6 | [_train, true, _oldObjectIsHiddenGlobal] call ATRAIN_fnc_hideTrainObject; 7 | private _waitStartTime = diag_tickTime; 8 | 9 | ATS_canDestruct = { 10 | params ["_train"]; 11 | if (alive _train) then { 12 | true 13 | } else { 14 | false 15 | }; 16 | }; 17 | 18 | ATS_trainDestroyed = { 19 | params ["_train"]; 20 | private _remoteTrainCarKilled = _train getVariable ["ATRAIN_Remote_Copy",_trainCarKilled]; 21 | if(!isNull _remoteTrainCarKilled) then { 22 | _remoteTrainCarKilled setVariable ["ATRAIN_Remote_Killed", true, true]; 23 | }; 24 | [] call ATRAIN_fnc_exitTrain; 25 | [] call ATRAIN_fnc_exitTrainPassenger; 26 | _train removeEventHandler ["Killed",0]; 27 | /*_train removeEventHandler ["EpeContact",0]; 28 | _train removeEventHandler ["EpeContactStart",0]; 29 | _train removeEventHandler ["EpeContactEnd",0];*/ 30 | }; 31 | 32 | waitUntil { 33 | if (diag_tickTime - _waitStartTime > 10) exitWith {true}; 34 | if (isNull _train) exitWith {true}; 35 | isObjectHidden _train; 36 | }; 37 | if(isObjectHidden _train) then {//should always be true, triggered after the waituntil isObjectHidden _train 38 | if(_newObjectIsGlobal) then { 39 | _newTrain = createVehicle [_className, ASLToAGL getPosASLVisual _train, [], 0, "CAN_COLLIDE"]; 40 | } else { 41 | _newTrain = _className createVehicleLocal ASLToAGL (getPosASLVisual _train); 42 | }; 43 | _newTrain setVectorDirAndUp [vectorDir _train, vectorUp _train]; 44 | _newTrain setPosASL (getPosASLVisual _train); 45 | 46 | if ([_newTrain] call ATS_canDestruct) then { 47 | /*_newTrain addEventHandler 48 | ["EpeContact", 49 | { 50 | params ["_obj1","_obj2","_sel1","_sel2","_force"]; 51 | _obj1 setdammage ATRAIN_TEMPDAMAGE_OBJ1; 52 | _obj2 setdammage ATRAIN_TEMPDAMAGE_OBJ2; 53 | } 54 | ]; 55 | _newTrain addEventHandler 56 | ["EpeContactStart", 57 | { 58 | params ["_obj1","_obj2","_sel1","_sel2","_force"]; 59 | _obj1 allowDamage false; 60 | _obj2 allowDamage false; 61 | _obj1 globalChat "DAMAGE FALSE"; 62 | } 63 | ]; 64 | _newTrain addEventHandler 65 | ["EpeContactEnd", 66 | { 67 | params ["_obj1","_obj2","_sel1","_sel2","_force"]; 68 | _obj1 allowDamage true; 69 | _obj2 allowDamage true; 70 | _obj1 globalChat "DAMAGE true"; 71 | } 72 | ];*/ 73 | _newTrain addEventHandler ["Killed", {[_this select 0] call ATS_trainDestroyed}]; 74 | _newTrain lock 2; 75 | }; 76 | }; 77 | _newTrain; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_initTrainObject.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainType = [_train] call ATRAIN_fnc_getTypeOf; 3 | _trainType params ["_className","_isStatic"]; 4 | if(_isStatic) then { 5 | _train = [_train] call ATRAIN_fnc_hideTrainReplaceWithNew; 6 | }; 7 | private _trainDef = [_train] call ATRAIN_fnc_getTrainDefinition; 8 | _trainDef params ["_className", "_isDrivable", "_isRideable", "_carLength", "_maxSpeed", "_positionOffset","_animateTrain", "_isModelReversed", "_particleEffects", "_isCableCar", "_firstPersonPosition"]; 9 | _train setVariable ["ATRAIN_Remote_Car_Length",_carLength,true]; 10 | _train setVariable ["ATRAIN_Remote_Train_Max_Velocity",_maxSpeed,true]; 11 | _train setVariable ["ATRAIN_Remote_Position_Offset",_positionOffset,true]; 12 | _train setVariable ["ATRAIN_Remote_Animate_Train",_animateTrain,true]; 13 | _train setVariable ["ATRAIN_Remote_Is_Model_Reversed",_isModelReversed,true]; 14 | _train setVariable ["ATRAIN_Remote_Particle_Effects",_particleEffects,true]; 15 | _train setVariable ["ATRAIN_Remote_Is_Cable_Car",_isCableCar,true]; 16 | _train setVariable ["ATRAIN_Remote_First_Person_Position",_firstPersonPosition,true]; 17 | _train enableSimulation false; 18 | 19 | _train; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_isPassengerMoving.sqf: -------------------------------------------------------------------------------- 1 | params ["_player"]; 2 | (_player getVariable ["ATRAIN_Passenger_Forward", 0]) + (_player getVariable ["ATRAIN_Passenger_Backward", 0]) + (_player getVariable ["ATRAIN_Passenger_Right", 0]) + (_player getVariable ["ATRAIN_Passenger_Left", 0]) > 0; 3 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/common/fn_isTrainLocal.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _driver = _train getVariable ["ATRAIN_Remote_Driver", objNull]; 3 | if(isServer && isNull _driver) exitWith {true}; 4 | if(!isNull _driver && local _driver) exitWith {true}; 5 | false; 6 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_attachToTrainCar.sqf: -------------------------------------------------------------------------------- 1 | params ["_object","_trainCar","_attachmentPosition"]; 2 | _trainCar = _trainCar getVariable ["ATRAIN_Remote_Copy",_trainCar]; 3 | private _attachments = _trainCar getVariable ["ATRAIN_Attachments",[]]; 4 | _attachments pushBack [_object,_attachmentPosition]; 5 | _trainCar setVariable ["ATRAIN_Attachments",_attachments,true]; 6 | _object attachTo [_trainCar, _attachmentPosition]; 7 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_disableTrainInputHandlers.sqf: -------------------------------------------------------------------------------- 1 | private _inputHandlers = player getVariable ["ATRAIN_Input_Handlers", []]; 2 | { 3 | _x call ATRAIN_fnc_removeEventHandler; 4 | } forEach _inputHandlers; 5 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_disableTrainPassengerInputHandlers.sqf: -------------------------------------------------------------------------------- 1 | private _inputHandlers = player getVariable ["ATRAIN_Passenger_Input_Handlers", []]; 2 | { 3 | _x call ATRAIN_fnc_removeEventHandler; 4 | } forEach _inputHandlers; 5 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_enableTrainInputHandlers.sqf: -------------------------------------------------------------------------------- 1 | //added onMouseButtonDown/onMouseButtonClick events, made keydown/up events return appropriately 2 | //disabled delete key to exit 3 | private _inputHandlers = []; 4 | _inputHandlers pushBack ["MAIN_DISPLAY","KeyDown",(["MAIN_DISPLAY","KeyDown", "[""KeyDown"",_this] call ATRAIN_fnc_trainInputHandler"] call ATRAIN_fnc_addEventHandler)]; 5 | _inputHandlers pushBack ["MAIN_DISPLAY","KeyUp",(["MAIN_DISPLAY","KeyUp", "[""KeyUp"",_this] call ATRAIN_fnc_trainInputHandler"] call ATRAIN_fnc_addEventHandler)]; 6 | player setVariable ["ATRAIN_Input_Handlers", _inputHandlers]; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_enableTrainPassengerInputHandlers.sqf: -------------------------------------------------------------------------------- 1 | 2 | player setVariable ["ATRAIN_Passenger_Forward", 0]; 3 | player setVariable ["ATRAIN_Passenger_Backward", 0]; 4 | player setVariable ["ATRAIN_Passenger_Right", 0]; 5 | player setVariable ["ATRAIN_Passenger_Left", 0]; 6 | 7 | private _inputHandlers = []; 8 | _inputHandlers pushBack ["MAIN_DISPLAY","KeyDown",(["MAIN_DISPLAY","KeyDown", "[""KeyDown"",_this] call ATRAIN_fnc_passengerMoveInputHandler"] call ATRAIN_fnc_addEventHandler)]; 9 | _inputHandlers pushBack ["MAIN_DISPLAY","KeyUp",(["MAIN_DISPLAY","KeyUp", "[""KeyUp"",_this] call ATRAIN_fnc_passengerMoveInputHandler"] call ATRAIN_fnc_addEventHandler)]; 10 | player setVariable ["ATRAIN_Passenger_Input_Handlers", _inputHandlers]; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_exitTrain.sqf: -------------------------------------------------------------------------------- 1 | //added setdir +180, removeeventhandler "killed" 2 | private _train = player getVariable ["ATRAIN_Current_Train",objNull]; 3 | private _trainCar = player getVariable ["ATRAIN_Current_Train_Car",objNull]; 4 | 5 | ATS_checkSimulation = { 6 | params ["_train"]; 7 | if !(simulationEnabled _train) then { 8 | _train enableSimulation true; 9 | }; 10 | }; 11 | 12 | 13 | if(!isNull _train) then { 14 | player setVariable ["ATRAIN_Current_Train", nil]; 15 | player setVariable ["ATRAIN_Current_Train_Car", nil]; 16 | [_train,player] call ATRAIN_fnc_unregisterTrainAndDriver; 17 | [] call ATRAIN_fnc_disableTrainInputHandlers; 18 | _localCopy = _trainCar getVariable ["ATRAIN_Local_Copy",_trainCar]; 19 | private _trainPos = getPos _localCopy; 20 | private _trainVectorDir = vectorDir _localCopy; 21 | private _trainVectorUp = vectorUp _localCopy; 22 | private _trainVectorLeft = _trainVectorDir vectorCrossProduct _trainVectorUp; 23 | private _exitPos = _trainPos vectorAdd (_trainVectorLeft vectorMultiply 3); 24 | _exitPos set [2,0]; 25 | player setPos _exitPos; 26 | player setdir (getdir player + 180); 27 | [player,false] call ATRAIN_fnc_hidePlayerObjectGlobal; 28 | player enableSimulation true; 29 | player allowDamage true; 30 | [] call ATRAIN_fnc_disable3rdPersonCamera; 31 | [] spawn ATRAIN_fnc_disableHud; 32 | _localCopy removeEventHandler ["Killed", 0]; 33 | 34 | if (isEngineOn _train) then { 35 | [_train] call ATS_checkSimulation; 36 | _localCopy engineOn false; 37 | }; 38 | 39 | true //return for keyhandler 40 | }; 41 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_exitTrainPassenger.sqf: -------------------------------------------------------------------------------- 1 | private _trainCar = player getVariable ["ATRAIN_Current_Train_Passenger_Car",objNull]; 2 | if(!isNull _trainCar) then { 3 | player setVariable ["ATRAIN_Current_Train_Passenger_Car", nil]; 4 | [] call ATRAIN_fnc_disableTrainPassengerInputHandlers; 5 | _localCopy = _trainCar getVariable ["ATRAIN_Local_Copy",_trainCar]; 6 | private _trainPos = getPos _localCopy; 7 | private _trainVectorDir = vectorDir _localCopy; 8 | private _trainVectorUp = vectorUp _localCopy; 9 | private _trainVectorLeft = _trainVectorDir vectorCrossProduct _trainVectorUp; 10 | private _exitPos = _trainPos vectorAdd (_trainVectorLeft vectorMultiply 3); 11 | _exitPos set [2,0]; 12 | player setPos _exitPos; 13 | [player,false] call ATRAIN_fnc_hidePlayerObjectGlobal; 14 | player enableSimulation true; 15 | player allowDamage true; 16 | [] call ATRAIN_fnc_disable3rdPersonCamera; 17 | }; 18 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_getInTrain.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_trainCar"]; 2 | private _trainAndCarSame = _train == _trainCar; 3 | _train = _train getVariable ["ATRAIN_Remote_Copy",_train]; 4 | _train = [_train] call ATRAIN_fnc_initTrainObject; 5 | if(_trainAndCarSame) then { 6 | _trainCar = _train; 7 | }; 8 | 9 | ATS_checkSimulation = { 10 | params ["_train"]; 11 | if !(simulationEnabled _train) then { 12 | _train enableSimulation true; 13 | }; 14 | }; 15 | 16 | player setVariable ["ATRAIN_Current_Train",_train]; 17 | player setVariable ["ATRAIN_Current_Train_Car",_trainCar]; 18 | [_train,player] call ATRAIN_fnc_registerTrainAndDriver; 19 | [player,true] call ATRAIN_fnc_hidePlayerObjectGlobal; 20 | player enableSimulation false; 21 | player allowDamage false; 22 | private _localTrainCar = _trainCar getVariable ["ATRAIN_Local_Copy",_trainCar]; 23 | [_localTrainCar, _trainCar getVariable "ATRAIN_Remote_First_Person_Position"] call ATRAIN_fnc_enable3rdPersonCamera; 24 | [] call ATRAIN_fnc_enableTrainInputHandlers; 25 | [] spawn ATRAIN_fnc_enableHud; 26 | ["Press [delete] to exit train",0.02,0.9,5,2,0,3001] spawn bis_fnc_dynamicText; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_getInTrainPassenger.sqf: -------------------------------------------------------------------------------- 1 | params ["_trainCar"]; 2 | player setVariable ["ATRAIN_Current_Train_Passenger_Car",_trainCar]; 3 | private _localTrainCar = _trainCar getVariable ["ATRAIN_Local_Copy",_trainCar]; 4 | [player,true] call ATRAIN_fnc_hidePlayerObjectGlobal; 5 | player enableSimulation false; 6 | player allowDamage false; 7 | [_localTrainCar, _trainCar getVariable "ATRAIN_Remote_First_Person_Position"] call ATRAIN_fnc_enable3rdPersonCamera; 8 | [] call ATRAIN_fnc_enableTrainPassengerInputHandlers; 9 | ["Press [delete] to exit train",0.02,0.9,5,2,0,3001] spawn bis_fnc_dynamicText; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_managePlayerTrainActions.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_Player_Actions = missionNamespace getVariable ["ATRAIN_Player_Actions",[]]; 2 | // start a player's eyes 3 | private _searchStartPointASL = eyePos player; 4 | // end 2 meters in front of where player is looking 5 | private _searchEndPointASL = _searchStartPointASL vectorAdd ((_searchStartPointASL vectorFromTo (ATLtoASL screenToWorld [0.5,0.5])) vectorMultiply 2); 6 | private _objects = lineIntersectsWith [_searchStartPointASL,_searchEndPointASL]; 7 | private _trainFound = objNull; 8 | { 9 | if(count ([_x] call ATRAIN_fnc_getTrainDefinition) > 0) exitWith { 10 | _trainFound = _x; 11 | }; 12 | } forEach _objects; 13 | 14 | if(!isNull _trainFound && count ATRAIN_Player_Actions == 0) then { 15 | _trainFound = _trainFound getVariable ["ATRAIN_Remote_Copy",_trainFound]; 16 | private _trainDef = [_trainFound] call ATRAIN_fnc_getTrainDefinition; 17 | _trainDef params ["_className", "_isDrivable", "_isRideable"]; 18 | 19 | // Add actions 20 | if(_isDrivable) then { 21 | private _mainEngine = _trainFound getVariable ["ATRIAN_Current_Train", _trainFound]; 22 | private _currentDriver = _mainEngine getVariable ["ATRAIN_Remote_Driver", objNull]; 23 | if(isNull _currentDriver || !alive _currentDriver || _currentDriver == player) then { 24 | private _driveAction = player addAction ["Get in Train as Driver", { 25 | (_this select 3) params ["_mainEngine","_trainCar"]; 26 | private _currentDriver = _mainEngine getVariable ["ATRAIN_Remote_Driver", objNull]; 27 | if(isNull _currentDriver || !alive _currentDriver || _currentDriver == player) then { 28 | [_mainEngine,_trainCar] call ATRAIN_fnc_getInTrain; 29 | }; 30 | },[_mainEngine,_trainFound]]; 31 | ATRAIN_Player_Actions pushBack _driveAction; 32 | }; 33 | }; 34 | 35 | private _currentTrain = _trainFound getVariable ["ATRIAN_Current_Train", objNull]; 36 | if(!isNull _currentTrain && (_currentTrain getVariable ["ATRAIN_Local_Velocity",0]) == 0 && _currentTrain != _trainFound) then { 37 | private _disconnectAction = player addAction ["Disconnect Car", { 38 | 39 | private _trainCar = _this select 3; 40 | private _localTrainCar = _trainCar getVariable ["ATRAIN_Local_Copy", _trainCar]; 41 | private _currentTrain = _trainCar getVariable ["ATRIAN_Current_Train", objNull]; 42 | 43 | private _carsInRear = _currentTrain getVariable ["ATRAIN_Remote_Cars_In_Rear",[]]; 44 | private _carsInFront = _currentTrain getVariable ["ATRAIN_Remote_Cars_In_Front",[]]; 45 | private _allCars = _currentTrain getVariable ["ATRAIN_Remote_Cars",[]]; 46 | 47 | private _rearCarSeen = false; 48 | private _newCarsInRear = []; 49 | { 50 | if(_x == _trainCar && !_rearCarSeen) then { 51 | _rearCarSeen = true; 52 | }; 53 | if(_rearCarSeen) then { 54 | _x setVariable ["ATRIAN_Current_Train",nil,true]; 55 | _x setVariable ["ATRIAN_Remote_Is_Backwards", nil, true]; 56 | _x setPosASL (getPosASLVisual _localTrainCar); 57 | _x setVectorDirAndUp [vectorDir _localTrainCar, vectorUp _localTrainCar]; 58 | _allCars = _allCars - [_x]; 59 | } else { 60 | _newCarsInRear pushBack _x; 61 | }; 62 | } forEach _carsInRear; 63 | _currentTrain setVariable ["ATRAIN_Remote_Cars_In_Rear",_newCarsInRear,true]; 64 | 65 | 66 | 67 | private _frontCarSeen = false; 68 | private _newCarsInFront = []; 69 | { 70 | if(_x == _trainCar && !_frontCarSeen) then { 71 | _frontCarSeen = true; 72 | }; 73 | if(_frontCarSeen) then { 74 | _x setVariable ["ATRIAN_Current_Train",nil,true]; 75 | _x setVariable ["ATRIAN_Remote_Is_Backwards", nil, true]; 76 | _x setPosASL (getPosASLVisual _localTrainCar); 77 | _x setVectorDirAndUp [vectorDir _localTrainCar, vectorUp _localTrainCar]; 78 | _allCars = _allCars - [_x]; 79 | } else { 80 | _newCarsInFront pushBack _x; 81 | }; 82 | } forEach _carsInFront; 83 | _currentTrain setVariable ["ATRAIN_Remote_Cars_In_Front",_newCarsInFront,true]; 84 | 85 | _currentTrain setVariable ["ATRAIN_Remote_Cars",_allCars,true]; 86 | 87 | },_trainFound]; 88 | ATRAIN_Player_Actions pushBack _disconnectAction; 89 | 90 | }; 91 | 92 | if(_isRideable) then { 93 | private _currentTrain = _trainFound getVariable ["ATRIAN_Current_Train", objNull]; 94 | private _currentDriver = _currentTrain getVariable ["ATRAIN_Remote_Driver", objNull]; 95 | if(!isNull _currentTrain && _currentTrain != _trainFound && _currentDriver != player) then { 96 | private _rideAction = player addAction ["Ride Train", { 97 | [_this select 3] call ATRAIN_fnc_getInTrainPassenger; 98 | },_trainFound]; 99 | ATRAIN_Player_Actions pushBack _rideAction; 100 | }; 101 | }; 102 | }; 103 | 104 | if(isNull _trainFound && count ATRAIN_Player_Actions > 0) then { 105 | { 106 | player removeAction _x; 107 | } forEach ATRAIN_Player_Actions; 108 | ATRAIN_Player_Actions = []; 109 | }; 110 | 111 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_passengerMoveInputHandler.sqf: -------------------------------------------------------------------------------- 1 | params ["_event","_eventParams"]; 2 | 3 | if(_event == "KeyDown") then { 4 | if(_eventParams select 1 in (actionKeys "MoveBack")) then { 5 | player setVariable ["ATRAIN_Passenger_Forward", 1]; 6 | }; 7 | if(_eventParams select 1 in (actionKeys "MoveForward")) then { 8 | player setVariable ["ATRAIN_Passenger_Backward", 1]; 9 | }; 10 | if(_eventParams select 1 in (actionKeys "TurnRight")) then { 11 | player setVariable ["ATRAIN_Passenger_Right", 1]; 12 | }; 13 | if(_eventParams select 1 in (actionKeys "TurnLeft")) then { 14 | player setVariable ["ATRAIN_Passenger_Left", 1]; 15 | }; 16 | if(_eventParams select 1 == 211) then { // Delete 17 | [] call ATRAIN_fnc_exitTrainPassenger; 18 | }; 19 | if(_eventParams select 1 == 156) then { //Numpad Enter 20 | if(missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Distance",8] == 3) then { 21 | ATRAIN_3rd_Person_Camera_Distance = 8; 22 | } else { 23 | ATRAIN_3rd_Person_Camera_Distance = 3; 24 | }; 25 | }; 26 | }; 27 | 28 | if(_event == "KeyUp") then { 29 | if(_eventParams select 1 in (actionKeys "MoveBack")) then { 30 | player setVariable ["ATRAIN_Passenger_Forward", 0]; 31 | }; 32 | if(_eventParams select 1 in (actionKeys "MoveForward")) then { 33 | player setVariable ["ATRAIN_Passenger_Backward", 0]; 34 | }; 35 | if(_eventParams select 1 in (actionKeys "TurnRight")) then { 36 | player setVariable ["ATRAIN_Passenger_Right", 0]; 37 | }; 38 | if(_eventParams select 1 in (actionKeys "TurnLeft")) then { 39 | player setVariable ["ATRAIN_Passenger_Left", 0]; 40 | }; 41 | }; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_rideOnTrain.sqf: -------------------------------------------------------------------------------- 1 | params ["_player","_train"]; 2 | 3 | [] call ATRAIN_fnc_enableTrainPassengerInputHandlers; 4 | 5 | player setVariable ["ATRAIN_Riding_On_Train_Last_Train_Position_ASL", getPosASLVisual _train]; 6 | player setVariable ["ATRAIN_Riding_On_Train_Last_Train_Dir", getDir _train]; 7 | 8 | player setVariable ["ATRAIN_Riding_On_Train_Last_Player_Position_Model", _train worldToModelVisual (ASLToAGL getPosASLVisual _player) ]; 9 | 10 | ATRAIN_RIDE_ON_TRAIN_EVENT_HANDLER_PARAMS = _this; 11 | private _rideEventHandlerId = addMissionEventHandler ["EachFrame", {call ATRAIN_fnc_rideOnTrainEventHandler}]; 12 | 13 | while {true} do { 14 | private _currentTrain = [_player] call ATRAIN_fnc_getTrainUnderPlayer; 15 | private _currentPassengerCar = _player getVariable ["ATRAIN_Current_Train_Passenger_Car",objNull]; 16 | if(isNull _currentTrain || _currentTrain != _train || !isNull _currentPassengerCar || !alive _player) exitWith {}; 17 | sleep 0.1; 18 | }; 19 | _player setVariable ["ATRAIN_Riding_On_Train", nil]; 20 | removeMissionEventHandler ["EachFrame", _rideEventHandlerId]; 21 | [] call ATRAIN_fnc_disableTrainPassengerInputHandlers; 22 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_rideOnTrainEventHandler.sqf: -------------------------------------------------------------------------------- 1 | ATRAIN_RIDE_ON_TRAIN_EVENT_HANDLER_PARAMS params ["_player","_train"]; 2 | 3 | private _remoteTrain = _train getVariable ["ATRAIN_Remote_Copy",_train]; 4 | private _mainEngine = _remoteTrain getVariable ["ATRIAN_Current_Train", _remoteTrain]; 5 | 6 | private _currentTrainPositionASL = getPosASLVisual _train; 7 | private _lastTrainPositionASL = _player getVariable ["ATRAIN_Riding_On_Train_Last_Train_Position_ASL", _currentTrainPositionASL]; 8 | private _currentTrainDir = getDir _train; 9 | private _lastTrainDir = _player getVariable ["ATRAIN_Riding_On_Train_Last_Train_Dir", _currentTrainDir]; 10 | 11 | _player setVariable ["ATRAIN_Riding_On_Train_Last_Train_Position_ASL", _currentTrainPositionASL]; 12 | _player setVariable ["ATRAIN_Riding_On_Train_Last_Train_Dir", _currentTrainDir]; 13 | 14 | private _isPlayerMoving = [_player] call ATRAIN_fnc_isPassengerMoving; 15 | 16 | if(_isPlayerMoving) then { 17 | _player setVariable ["ATRAIN_Riding_On_Train_Last_Player_Position_Model", _train worldToModelVisual (ASLToAGL getPosASLVisual vehicle _player) ]; 18 | }; 19 | 20 | private _lastPlayerPositionModel = _player getVariable ["ATRAIN_Riding_On_Train_Last_Player_Position_Model", _train worldToModelVisual (ASLToAGL getPosASLVisual vehicle _player)]; 21 | 22 | if(_currentTrainPositionASL distance _lastTrainPositionASL > 0) then { 23 | 24 | if(!_isPlayerMoving) then { 25 | (vehicle _player) setVelocity [0,0,0]; 26 | }; 27 | 28 | (vehicle _player) setDir (getDir _player + _currentTrainDir - _lastTrainDir); 29 | (vehicle _player) setPosASL (AGLtoASL (_train modelToWorldVisual _lastPlayerPositionModel)); 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_toggleCruiseControl.sqf: -------------------------------------------------------------------------------- 1 | private _train = player getVariable ["ATRAIN_Current_Train",objNull]; 2 | if(!isNull _train) then { 3 | private _cruiseControlEnabled = _train getVariable ["ATRAIN_Remote_Cruise_Control_Enabled", false]; 4 | _train setVariable ["ATRAIN_Remote_Cruise_Control_Enabled", !_cruiseControlEnabled, true]; 5 | }; 6 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_toggleLights.sqf: -------------------------------------------------------------------------------- 1 | private _train = player getVariable ["ATRAIN_Current_Train",objNull]; 2 | if(!isNull _train) then { 3 | private _lightsEnabled = _train getVariable ["ATRAIN_Remote_Lights_Enabled", false]; 4 | _train setVariable ["ATRAIN_Remote_Lights_Enabled", !_lightsEnabled, true]; 5 | }; 6 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/controls/fn_trainInputHandler.sqf: -------------------------------------------------------------------------------- 1 | params ["_event","_eventParams"]; 2 | 3 | if(_event == "KeyDown") then { 4 | if(_eventParams select 1 in (actionKeys "MoveBack")) then { 5 | player setVariable ["ATRAIN_Remote_Movement_Direction", -1, true]; 6 | }; 7 | if(_eventParams select 1 in (actionKeys "MoveForward")) then { 8 | player setVariable ["ATRAIN_Remote_Movement_Direction", 1, true]; 9 | }; 10 | if(_eventParams select 1 in (actionKeys "TurnRight")) then { 11 | player setVariable ["ATRAIN_Remote_Turn_Direction", 1, true]; 12 | }; 13 | if(_eventParams select 1 in (actionKeys "TurnLeft")) then { 14 | player setVariable ["ATRAIN_Remote_Turn_Direction", -1, true]; 15 | }; 16 | if((_eventParams select 1 == 48) or (_eventParams select 1 in (actionKeys "carHandBrake"))) then { //B 17 | player setVariable ["ATRAIN_Remote_Break_Enabled", true, true]; 18 | }; 19 | if(_eventParams select 1 == 35) then { //H 20 | player setVariable ["ATRAIN_Remote_Horn_Enabled", true, true]; 21 | }; 22 | if(_eventParams select 1 == 34) then { //G 23 | player setVariable ["ATRAIN_Remote_Bell_Enabled", true, true]; 24 | }; 25 | if((_eventParams select 1 == 156) or (_eventParams select 1 in (actionKeys "personView"))) then { //Numpad Enter 26 | if(missionNamespace getVariable ["ATRAIN_3rd_Person_Camera_Distance",8] == 3) then { 27 | ATRAIN_3rd_Person_Camera_Distance = 8; 28 | } else { 29 | ATRAIN_3rd_Person_Camera_Distance = 3; 30 | }; 31 | }; 32 | if(_eventParams select 1 == 18) then { //E 33 | // Toggle engine on/off when not moving 34 | private _train = player getVariable ["ATRAIN_Current_Train",objNull]; 35 | if(!isNull _train) then { 36 | private _trainSpeed = abs (_train getVariable ["ATRAIN_Local_Velocity",0]); 37 | if(_trainSpeed == 0) then { 38 | private _enginedEnabled = _train getVariable ["ATRAIN_Remote_Engine_Enabled", true]; 39 | _train setVariable ["ATRAIN_Remote_Engine_Enabled", !_enginedEnabled, true]; 40 | }; 41 | }; 42 | }; 43 | }; 44 | 45 | if(_event == "KeyUp") then { 46 | if(_eventParams select 1 in (actionKeys "Headlights")) then { 47 | [] call ATRAIN_fnc_toggleLights; 48 | }; 49 | if(_eventParams select 1 in (actionKeys "MoveBack")) then { 50 | player setVariable ["ATRAIN_Remote_Movement_Direction", 0, true]; 51 | }; 52 | if(_eventParams select 1 in (actionKeys "MoveForward")) then { 53 | player setVariable ["ATRAIN_Remote_Movement_Direction", 0, true]; 54 | }; 55 | if(_eventParams select 1 in (actionKeys "TurnRight")) then { 56 | player setVariable ["ATRAIN_Remote_Turn_Direction", 0, true]; 57 | }; 58 | if(_eventParams select 1 in (actionKeys "TurnLeft")) then { 59 | player setVariable ["ATRAIN_Remote_Turn_Direction", 0, true]; 60 | }; 61 | if(_eventParams select 1 == 46) then { // C 62 | [] call ATRAIN_fnc_toggleCruiseControl; 63 | }; 64 | if((_eventParams select 1 == 48) or (_eventParams select 1 in (actionKeys "carHandBrake"))) then { //B 65 | player setVariable ["ATRAIN_Remote_Break_Enabled", false, true]; 66 | }; 67 | if((_eventParams select 1 == 211) or (_eventParams select 1 in (actionKeys "GetOut"))) then { // Delete 68 | [] call ATRAIN_fnc_exitTrain; 69 | }; 70 | if(_eventParams select 1 == 35) then { //H 71 | player setVariable ["ATRAIN_Remote_Horn_Enabled", false, true]; 72 | }; 73 | if(_eventParams select 1 == 34) then { //G 74 | player setVariable ["ATRAIN_Remote_Bell_Enabled", false, true]; 75 | }; 76 | }; 77 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/fn_initTrains.sqf: -------------------------------------------------------------------------------- 1 | 2 | ATRAIN_Train_Definitions = missionNamespace getVariable ["ATRAIN_Train_Definitions",[]]; 3 | 4 | // [Class Name, Is Drivable, Is Rideable, Length In Meters, maxspeed, Model Position Offset, Animate Train, Is Direction Reversed, Particle Effects, Is Cable Car] 5 | ATRAIN_Train_Definitions append [ 6 | ["ATS_Trains_A2Locomotive_Driveable_Blue", true, false, 13.5, 47.22, [0,0,0],true,false, [], false, [0,0,0]], 7 | ["ATS_Trains_A2Locomotive_Driveable_Red", true, false, 13.5, 47.22, [0,0,0],true,false, [], false, [0,0,0]], 8 | ["Land_Locomotive_01_v1_F", true, false, 5.3, 12, [0,0,0.052],true,false, [], false, [1.2,-0.8,-0.6]], 9 | ["Land_Locomotive_01_v2_F", true, false, 5.3, 12, [0,0,0.052],true,false, [], false, [1.2,-0.8,-0.6]], 10 | ["Land_Locomotive_01_v3_F", true, false, 5.3, 12, [0,0,0.052],true,false, [], false, [1.2,-0.8,-0.6]], 11 | ["Land_RailwayCar_01_passenger_F", false, true, 5.5, 12, [0,0,0.06],true,false, [], false, [-0.6,1.3,-1]], 12 | ["Land_RailwayCar_01_sugarcane_empty_F", false, true, 3.2, 12, [0,0,0.052],true,false, [], false, [0,0,0]], 13 | ["Land_RailwayCar_01_sugarcane_F", false, false, 3.2, 12, [0,0,0.052],true,false, [], false, [0,0,0]], 14 | ["Land_RailwayCar_01_tank_F", false, false, 5.5, 12, [0,0,0.08],true,false, [], false, [0,0,0]], 15 | ["Land_loco_742_blue", true, false, 13.5, 19.4, [0,0.05,-0.14],false,false, [], false, [1.1,-3.4,-1.3]], 16 | ["Land_loco_742_red", true, false, 13.5, 19.4, [0,0.05,-0.14],false,false, [], false, [1.1,-3.4,-1.3]], 17 | ["Land_wagon_box", false, true, 12, 19.4, [0,-0.43,0.02],false,false, [], false, [-0.8,0.1,-0.9]], 18 | ["Land_wagon_flat", false, true, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0.5]], 19 | ["Land_wagon_tanker", false, false, 11.5, 19.4, [0,-0.05,0.02],false,false, [], false, [0,0,0]], 20 | ["ATS_Trains_Steam_Small", true, false, 12, 19.4, [0,0,0],false,false, [["steam","steam"]], false, [0.6,0,-1.1] ], 21 | ["ATS_Trains_Steam_Large", true, false, 12.5, 19.4, [0,0,0],false,false, [["steam","steam"]], false , [1,-2.3,-1.2]], 22 | ["ATS_Trains_Cable_Car", true, true, 2, 8, [0,0,-7.32],true,false, [], true, [0,0,0]], 23 | ["ATS_Trains_AE_Engine", true, false, 19.6, 40, [0,0,0],false,false, [], false, [0.5,6.8,-1.3] ], 24 | ["ATS_Trains_AE_Wagon", false, true, 24, 40, [0,0,0],false,false, [], false, [-0.9,-0.2,-1.8] ], 25 | ["ATS_Trains_SD60_Engine", true, false, 20, 31.1, [0,0,0],false,false, [], false, [1.8,7.4,-1.3] ], 26 | ["ATS_Trains_SD60_Flatbed", false, true, 17.25, 31.1, [0,0,0],false,false, [], false, [0,0,0] ], 27 | ["ATS_Trains_SD60_Oil_Tank", false, false, 17.5, 31.1, [0,0,0],false,false, [], false, [0,0,0] ], 28 | ["ATS_Trains_SD60_Open_Wagon", false, true, 16, 31.1, [0,0,0],false,false, [], false, [1.1,0.1,0.2] ], 29 | ["ATS_Trains_SD60_Covered_Wagon", false, true, 18, 31.1, [0,0,0],false,false, [], false, [2,0,-1.8] ], 30 | ["ATS_Trains_SD60_Covered_Wagon_Black", false, true, 18, 31.1, [0,0,0],false,false, [], false, [2,0,-1.8] ], 31 | ["ATS_Trains_SD60_Covered_Wagon_Blue", false, true, 18, 31.1, [0,0,0],false,false, [], false, [2,0,-1.8] ], 32 | ["ATS_Trains_SD60_Covered_Wagon_Green", false, true, 18, 31.1, [0,0,0],false,false, [], false, [2,0,-1.8] ], 33 | ["ATS_Trains_SD60_Covered_Wagon_Grey", false, true, 18, 31.1, [0,0,0],false,false, [], false, [2,0,-1.8] ], 34 | ["ATS_Trains_VL_Elgolova", true, true, 18.8, 19.4, [0,0,0],false,true, [], false, [0.7,-7.89999,-2]], 35 | ["ATS_Trains_VL_EW", true, true, 18.8, 19.4, [0,0,0],false,true, [], false, [-1,-1.7,-1.5]], 36 | ["ATS_Trains_VL_EE", true, true, 18.8, 19.4, [0,0,0],false,true, [], false, [-1,-1.7,-3.1]], 37 | ["ATS_Trains_VL_M62", true, true, 17.35, 19.4, [0,0,0],false,true, [], false, [-0.9,-6.9,-1.6]], 38 | ["ATS_Trains_VL_VL10", true, false, 16, 19.4, [0,0,0],false,true, [], false, [0.9,-6.4,-2.9]], 39 | ["ATS_Trains_VL_TVZ", true, true, 23.5, 19.4, [0,0,0],false,true, [], false, [1.1,0.3,-2]], 40 | ["ATS_Trains_VL_CH4", true, true, 19.5, 19.4, [0,0,0],false,true, [], false, [0.7,8.09999,-2.9]], 41 | ["ATS_Trains_VL_CI", false, false, 12, 19.4, [0,0,0],false,true, [], false, [0,0,0]], 42 | // Test Trains Below 43 | ["Land_wagon_flat_dozer", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 44 | ["Land_wagon_flat_container01", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 45 | ["Land_wagon_flat_container02", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 46 | ["Land_wagon_flat_container03", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 47 | ["Land_wagon_flat_excavator", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 48 | ["Land_wagon_flat_lav", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 49 | ["Land_wagon_flat_lumber", false, false, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 50 | ["Land_blue_loco", true, false, 13.5, 19.4, [0,0.05,-0.14],false,false, [], false, [0,0,0]], 51 | ["Land_red_loco", true, false, 13.5, 19.4, [0,0.05,-0.14],false,false, [], false, [0,0,0]], 52 | ["ATS_A2Wagon_Box", false, true, 12, 19.4, [0,-0.43,0.02],false,false, [], false, [0,0,0]], 53 | ["ATS_A2Wagon_Flat", false, true, 17.1, 19.4, [0,-0.02,0.04],false,false, [], false, [0,0,0]], 54 | ["ATS_A2Wagon_Tanker", false, false, 11.5, 19.4, [0,-0.05,0.02],false,false, [], false, [0,0,0]] 55 | ]; 56 | 57 | ATRAIN_Object_Model_To_Type_Map = missionNamespace getVariable ["ATRAIN_Object_Model_To_Type_Map",[]]; 58 | 59 | ATRAIN_Object_Model_To_Type_Map append [ 60 | ["locomotive_01_v1_f.p3d",["Land_Locomotive_01_v1_F",true]], 61 | ["locomotive_01_v2_f.p3d",["Land_Locomotive_01_v2_F",true]], 62 | ["locomotive_01_v3_f.p3d",["Land_Locomotive_01_v3_F",true]], 63 | ["railwaycar_01_passenger_f.p3d",["Land_RailwayCar_01_passenger_F",true]], 64 | ["railwaycar_01_sugarcane_empty_f.p3d",["Land_RailwayCar_01_sugarcane_empty_F",true]], 65 | ["railwaycar_01_sugarcane_f.p3d",["Land_RailwayCar_01_sugarcane_F",true]], 66 | ["railwaycar_01_tank_f.p3d",["Land_RailwayCar_01_tank_F",true]], 67 | ["ats_trains_steam_small.p3d",["ATS_Trains_Steam_Small",true]], 68 | ["ats_trains_steam_large.p3d",["ATS_Trains_Steam_Large",true]], 69 | ["ats_trains_cable_car.p3d",["ATS_Trains_Cable_Car",true]], 70 | ["ats_trains_sd60_engine.p3d",["ATS_Trains_SD60_Engine",true]], 71 | ["ats_trains_sd60_flatbed.p3d",["ATS_Trains_SD60_Flatbed",true]], 72 | ["ats_trains_sd60_oil_tank.p3d",["ATS_Trains_SD60_Oil_Tank",true]], 73 | ["ats_trains_sd60_open_wagon.p3d",["ATS_Trains_SD60_Open_Wagon",true]], 74 | ["ats_trains_sd60_covered_wagon.p3d",["ATS_Trains_SD60_Covered_Wagon",true]], 75 | ["ats_trains_sd60_covered_wagon_black.p3d",["ATS_Trains_SD60_Covered_Wagon_Black",true]], 76 | ["ats_trains_sd60_covered_wagon_blue.p3d",["ATS_Trains_SD60_Covered_Wagon_Blue",true]], 77 | ["ats_trains_sd60_covered_wagon_green.p3d",["ATS_Trains_SD60_Covered_Wagon_Green",true]], 78 | ["ats_trains_sd60_covered_wagon_grey.p3d",["ATS_Trains_SD60_Covered_Wagon_Grey",true]], 79 | ["ats_trains_ae_engine.p3d",["ATS_Trains_AE_Engine",true]], 80 | ["ats_trains_ae_wagon.p3d",["ATS_Trains_AE_Wagon",true]], 81 | // Test Objects Below 82 | ["blue_loco.p3d",["Land_blue_loco",true]], 83 | ["red_loco.p3d",["Land_red_loco",true]], 84 | ["wagon_box.p3d",["ATS_A2Wagon_Box",true]], 85 | ["wagon_flat.p3d",["ATS_A2Wagon_Flat",true]], 86 | ["wagon_tanker.p3d",["ATS_A2Wagon_Tanker",true]] 87 | ]; 88 | 89 | [] call ATRAIN_fnc_rebuildArrayLookupIndexes; 90 | 91 | [] call ATRAIN_fnc_initTrainSound; 92 | 93 | // Start train drawing handler 94 | addMissionEventHandler ["EachFrame", {call ATRAIN_fnc_drawEventHandler}]; 95 | 96 | // Start player action handler 97 | if(hasInterface) then { 98 | [] spawn { 99 | while {true} do { 100 | [] call ATRAIN_fnc_managePlayerTrainActions; 101 | sleep 0.1; 102 | }; 103 | }; 104 | }; 105 | 106 | // Start train particle effects simulation handler 107 | [] spawn { 108 | while {true} do { 109 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 110 | { 111 | [_x] call ATRAIN_fnc_simulateTrainParticleEffects; 112 | } forEach _registeredTrains; 113 | sleep 1; 114 | }; 115 | }; 116 | 117 | // Start train speed simulation handler 118 | [] spawn { 119 | while {true} do { 120 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 121 | { 122 | [_x] call ATRAIN_fnc_simulateTrainVelocity; 123 | [_x] call ATRAIN_fnc_handleVelocityNetworkUpdates; 124 | } forEach _registeredTrains; 125 | sleep 0.1; 126 | }; 127 | }; 128 | 129 | // Start train attachment simulation handler 130 | [] spawn { 131 | while {true} do { 132 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 133 | { 134 | if([_x] call ATRAIN_fnc_isTrainLocal) then { 135 | [_x] call ATRAIN_fnc_simulateTrainAttachment; 136 | }; 137 | } forEach _registeredTrains; 138 | sleep 0.1; 139 | }; 140 | }; 141 | 142 | // Start train position simulation handler 143 | [] spawn { 144 | while {true} do { 145 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 146 | { 147 | if(_x getVariable ["ATRAIN_Calculations_Queued",true]) then { 148 | [_x] call ATRAIN_fnc_simulateTrain; 149 | [_x] call ATRAIN_fnc_handleSimulationNetworkUpdates; 150 | _x setVariable ["ATRAIN_Calculations_Queued",false]; 151 | }; 152 | } forEach _registeredTrains; 153 | sleep 0.1; 154 | }; 155 | }; 156 | 157 | // Start attach player to moving train handler 158 | if(hasInterface) then { 159 | [] spawn { 160 | while {true} do { 161 | private _ridingOnTrain = player getVariable ["ATRAIN_Riding_On_Train", objNull]; 162 | private _currentPassengerCar = player getVariable ["ATRAIN_Current_Train_Passenger_Car",objNull]; 163 | if(isNull _ridingOnTrain && isNull _currentPassengerCar) then { 164 | if((getPosATL player) select 2 > 0.5) then { 165 | private _train = [player] call ATRAIN_fnc_getTrainUnderPlayer; 166 | if(!isNull _train) then { 167 | player setVariable ["ATRAIN_Riding_On_Train", _train]; 168 | [player,_train] spawn ATRAIN_fnc_rideOnTrain; 169 | }; 170 | }; 171 | }; 172 | sleep 0.5; 173 | }; 174 | }; 175 | }; 176 | 177 | // Update player position to follow train 178 | if(hasInterface) then { 179 | [] spawn { 180 | while {true} do { 181 | private _currentCar = player getVariable ["ATRAIN_Current_Train_Car",objNull]; 182 | if(isNull _currentCar) then { 183 | _currentCar = player getVariable ["ATRAIN_Current_Train_Passenger_Car",objNull]; 184 | }; 185 | if(!isNull _currentCar) then { 186 | private _localCar = _currentCar getVariable ["ATRAIN_Local_Copy",_currentCar]; 187 | player setPos (getPos _localCar); 188 | }; 189 | sleep 10; 190 | }; 191 | }; 192 | }; 193 | 194 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/hud/fn_disableHud.sqf: -------------------------------------------------------------------------------- 1 | disableSerialization; 2 | private _hudCtrl = uiNamespace getVariable ["ATRAIN_Hud_Control", nil]; 3 | if(!isNil "_hudCtrl") then { 4 | ctrlDelete _hudCtrl; 5 | uiNamespace setVariable ["ATRAIN_Hud_Control", nil]; 6 | }; 7 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/hud/fn_enableHud.sqf: -------------------------------------------------------------------------------- 1 | disableSerialization; 2 | [] call ATRAIN_fnc_disableHud; 3 | private _hudCtrl = uiNamespace getVariable ["ATRAIN_Hud_Control", nil]; 4 | if(isNil "_hudCtrl") then { 5 | private _h = (getnumber (configfile >> "RscStructuredText" >> "size")) * 5; 6 | private _w = safezoneW - 0.05; 7 | _hudCtrl = (findDisplay 46) ctrlCreate ["RscStructuredText", -1]; 8 | private _pos = [safeZoneX, safeZoneY + safeZoneH - _h, _w, _h]; 9 | _hudCtrl ctrlSetPosition _pos; 10 | _hudCtrl ctrlCommit 0; 11 | uiNamespace setVariable ["ATRAIN_Hud_Control", _hudCtrl]; 12 | private _train = player getVariable ["ATRAIN_Current_Train",objNull]; 13 | while {!isNull _train} do { 14 | private _speed = round ((_train getVariable ["ATRAIN_Local_Velocity",0]) * 3.6); 15 | private _cars = (count (_train getVariable ["ATRAIN_Remote_Cars",[_train]])) - 1; 16 | private _cruiseControlEnabled = _train getVariable ["ATRAIN_Remote_Cruise_Control_Enabled", false]; 17 | private _cruiseControlHud = ""; 18 | if(_cruiseControlEnabled) then { 19 | _cruiseControlHud = " (CC)"; 20 | }; 21 | private _ctrltxt = ("" + str _cars + " cars  
" + str abs _speed + _cruiseControlHud + " km/h
"); 22 | _ctrltxt = parseText _ctrltxt; 23 | _hudCtrl ctrlsetStructuredText _ctrltxt; 24 | sleep 0.5; 25 | _hudCtrl = uiNamespace getVariable ["ATRAIN_Hud_Control", nil]; 26 | _train = player getVariable ["ATRAIN_Current_Train",objNull]; 27 | }; 28 | [] call ATRAIN_fnc_disableHud; 29 | }; 30 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_cleanUpNodePath.sqf: -------------------------------------------------------------------------------- 1 | params ["_train","_distanceFromEngineToRear","_distanceFromEngineToFront"]; 2 | private _nodePath = _train getVariable ["ATRAIN_Local_Node_Path",[]]; 3 | if(count _nodePath <= 2) exitWith {}; 4 | private _trainDistanceFromStart = _train getVariable ["ATRAIN_Local_Distance_From_Front",0]; 5 | private _trainNodePathDistance = _train getVariable ["ATRAIN_Local_Node_Path_Distance",0]; 6 | private _frontStartNodeIndex = _nodePath select 0; 7 | private _frontEndNodeIndex = _nodePath select 1; 8 | private _connection = [_frontStartNodeIndex, _frontEndNodeIndex] call ATRAIN_fnc_getTrackMapConnection; 9 | private _distanceBetweeNodes = _connection select 1; 10 | if(_trainDistanceFromStart - _distanceFromEngineToFront > _distanceBetweeNodes) then { 11 | _nodePath deleteAt 0; 12 | _trainDistanceFromStart = _trainDistanceFromStart - _distanceBetweeNodes; 13 | _trainNodePathDistance = _trainNodePathDistance - _distanceBetweeNodes; 14 | }; 15 | 16 | private _rearStartNodeIndex = _nodePath select ((count _nodePath) - 2); 17 | private _rearEndNodeIndex = _nodePath select ((count _nodePath) - 1); 18 | _connection = [_rearStartNodeIndex, _rearEndNodeIndex] call ATRAIN_fnc_getTrackMapConnection; 19 | _distanceBetweeNodes = _connection select 1; 20 | if(_trainDistanceFromStart + _distanceFromEngineToRear < _trainNodePathDistance - _distanceBetweeNodes) then { 21 | _nodePath deleteAt ((count _nodePath) - 1); 22 | _trainNodePathDistance = _trainNodePathDistance - _distanceBetweeNodes; 23 | }; 24 | _train setVariable ["ATRAIN_Local_Node_Path",_nodePath]; 25 | _train setVariable ["ATRAIN_Local_Node_Path_Distance",_trainNodePathDistance]; 26 | _train setVariable ["ATRAIN_Local_Distance_From_Front",_trainDistanceFromStart]; 27 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_drawEventHandler.sqf: -------------------------------------------------------------------------------- 1 | { 2 | [_x] call ATRAIN_fnc_drawTrain; 3 | } forEach (missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]); 4 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_drawTrain.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainCalculationsQueued = _train getVariable ["ATRAIN_Calculations_Queued",true]; 3 | private _trainCars = _train getVariable ["ATRAIN_Remote_Cars",[_train]]; 4 | private _lastAttachmentTime = _train getVariable ["ATRAIN_Local_Last_Attachment_Time",0]; 5 | private _currentTime = diag_tickTime; 6 | private _lastSeen = _train getVariable ["ATRAIN_New_Alignment_Last_Seen",diag_tickTime]; 7 | private _timeSinceLastSeen = _currentTime - _lastSeen; 8 | private _trainSpeed = _train getVariable ["ATRAIN_Local_Velocity",0]; 9 | 10 | private _maxAnimatedCars = missionNamespace getVariable ["ATRAIN_MAX_CARS_SIMULATED_ENABLED", 3]; 11 | private _carsWithAnimationEnabled = 0; 12 | 13 | { 14 | private _localCopy = _x getVariable ["ATRAIN_Local_Copy", objNull]; 15 | if(isNull _localCopy) then { 16 | _localCopy = [_x, false, false] call ATRAIN_fnc_hideTrainReplaceWithNew; 17 | _localCopy setVariable ["ATRAIN_Is_Local_Copy",true]; 18 | _localCopy setVariable ["ATRAIN_Remote_Copy",_x]; 19 | _localCopy = [_localCopy] call ATRAIN_fnc_initTrainObject; 20 | if(ATRAIN_3rd_Person_Camera_Target == _x) then { 21 | ATRAIN_3rd_Person_Camera_Target = _localCopy; 22 | }; 23 | _x setVariable ["ATRAIN_Local_Copy", _localCopy]; 24 | }; 25 | private _lastDrawPosition = _x getVariable ["ATRAIN_Last_Draw_Position",getPosASLVisual _localCopy]; 26 | private _lastDrawDirection = _x getVariable ["ATRAIN_Last_Draw_Vector_Dir",vectorDir _localCopy]; 27 | private _newDrawDirection = _x getVariable ["ATRAIN_New_Draw_Vector_Dir",_lastDrawDirection]; 28 | private _velocityFromLastToNewPosition = _x getVariable ["ATRAIN_Velocity_From_Last_To_New_Position",0]; 29 | private _directionFromLastToNewPosition = _x getVariable ["ATRAIN_Direction_From_Last_To_New_Position",_lastDrawDirection]; 30 | private _distanceFromLastToNewPosition = _x getVariable ["ATRAIN_Distance_From_Last_To_New_Position", 0]; 31 | private _animateTrain = _x getVariable ["ATRAIN_Remote_Animate_Train",false]; 32 | private _isCableCar = _x getVariable ["ATRAIN_Remote_Is_Cable_Car",false]; 33 | 34 | // Enable in-game simulation for front and rear cars (so that it can collide with objects) 35 | 36 | if(_distanceFromLastToNewPosition > 0.01) then { 37 | if(_carsWithAnimationEnabled < _maxAnimatedCars) then { 38 | _carsWithAnimationEnabled = _carsWithAnimationEnabled + 1; 39 | if(!simulationEnabled _localCopy) then { 40 | _localCopy enableSimulation true; 41 | }; 42 | } else { 43 | if(simulationEnabled _localCopy) then { 44 | _localCopy enableSimulation false; 45 | }; 46 | }; 47 | } else { 48 | if(simulationEnabled _localCopy) then { 49 | _localCopy enableSimulation false; 50 | }; 51 | }; 52 | 53 | if(_distanceFromLastToNewPosition > 0.01) then { 54 | private _distanceMovedFromLastPosition = _timeSinceLastSeen * _velocityFromLastToNewPosition; 55 | private _percentMovedFromLastPosition = 0; 56 | if(_distanceFromLastToNewPosition != 0) then { 57 | _percentMovedFromLastPosition = _distanceMovedFromLastPosition / _distanceFromLastToNewPosition; 58 | }; 59 | _percentMovedFromLastPosition = (_percentMovedFromLastPosition max 0) min 1; 60 | private _currentDrawDirection = vectorNormalized ((_lastDrawDirection vectorMultiply (1-_percentMovedFromLastPosition)) vectorAdd (_newDrawDirection vectorMultiply _percentMovedFromLastPosition)); 61 | private _currentDrawPosition = _lastDrawPosition vectorAdd (_directionFromLastToNewPosition vectorMultiply (_distanceMovedFromLastPosition min _distanceFromLastToNewPosition)); 62 | 63 | if(_isCableCar) then { 64 | _currentDrawDirection set [2,0]; 65 | }; 66 | 67 | _localCopy setVectorDirAndUp [_currentDrawDirection,[0,0,1]]; 68 | _localCopy setPosASL _currentDrawPosition; 69 | 70 | private _attachments = _x getVariable ["ATRAIN_Attachments",[]]; 71 | { 72 | private _object = _x select 0; 73 | private _objectModelPos = _x select 1; 74 | private _objectLocalCopy = _object getVariable ["ATRAIN_Local_Copy", objNull]; 75 | if(isNull _objectLocalCopy) then { 76 | _objectLocalCopy = (typeOf _object) createVehicleLocal [0,0,1000]; 77 | _object setVariable ["ATRAIN_Local_Copy", _objectLocalCopy]; 78 | _object hideObject true; 79 | _objectLocalCopy enableSimulation false; 80 | }; 81 | _objectLocalCopy setVectorDirAndUp [_currentDrawDirection,[0,0,1]]; 82 | _objectLocalCopy setPosASL ((AGLtoASL (_localCopy modelToWorld _objectModelPos)) vectorAdd [0,0,-2.4]); 83 | } forEach _attachments; 84 | 85 | _x setVariable ["ATRAIN_Current_Draw_Position", _currentDrawPosition]; 86 | }; 87 | } forEach _trainCars; 88 | 89 | if(!_trainCalculationsQueued) then { 90 | { 91 | private _newAlignment = _x getVariable ["ATRAIN_Local_Alignment",nil]; 92 | private _localCopy = _x getVariable ["ATRAIN_Local_Copy", objNull]; 93 | if(isNull _localCopy) exitWith {}; 94 | private _currentPosition = _x getVariable ["ATRAIN_Current_Draw_Position", getPosASLVisual _localCopy]; 95 | if(!isNil "_newAlignment") then { 96 | private _frontAlignmentPoint = _newAlignment select 0; 97 | private _frontAlignmentPointPosition = _frontAlignmentPoint select 0; 98 | private _frontAlignmentPointDirection = _frontAlignmentPoint select 1; 99 | private _rearAlignmentPoint = _newAlignment select 1; 100 | private _rearAlignmentPointPosition = _rearAlignmentPoint select 0; 101 | private _rearAlignmentPointDirection = _rearAlignmentPoint select 1; 102 | private _trainVectorDirection = _rearAlignmentPointPosition vectorFromTo _frontAlignmentPointPosition; 103 | private _trainPosition = _frontAlignmentPointPosition vectorAdd ((_rearAlignmentPointPosition vectorDiff _frontAlignmentPointPosition) vectorMultiply 0.5); 104 | private _trainIsBackwards = _x getVariable ["ATRIAN_Remote_Is_Backwards", false]; 105 | private _animateTrain = _x getVariable ["ATRAIN_Remote_Animate_Train",false]; 106 | if(_trainIsBackwards) then { 107 | _trainVectorDirection = _trainVectorDirection vectorMultiply -1; 108 | }; 109 | // Offset position based on train model params 110 | private _positionOffset = _x getVariable ["ATRAIN_Remote_Position_Offset", [0,0,0]]; 111 | _trainPosition = _trainPosition vectorAdd (_trainVectorDirection vectorMultiply (_positionOffset select 0)); 112 | _trainPosition = _trainPosition vectorAdd ((_trainVectorDirection vectorCrossProduct [0,0,1]) vectorMultiply (_positionOffset select 1)); 113 | _trainPosition = _trainPosition vectorAdd [0,0,(_positionOffset select 2)]; 114 | _x setVariable ["ATRAIN_New_Draw_Position",_trainPosition]; 115 | _x setVariable ["ATRAIN_New_Draw_Vector_Dir",_trainVectorDirection]; 116 | _x setVariable ["ATRAIN_Distance_From_Last_To_New_Position",_currentPosition distance _trainPosition]; 117 | private _velocityFromLastToNewPosition = _x getVariable ["ATRAIN_Velocity_From_Last_To_New_Position",0]; 118 | if(_timeSinceLastSeen == 0) then { 119 | _velocityFromLastToNewPosition = ( _velocityFromLastToNewPosition * 0.5); 120 | } else { 121 | private _newVelocityFromLastToNewPosition = ((_currentPosition distance _trainPosition) / _timeSinceLastSeen); 122 | _velocityFromLastToNewPosition = ( _velocityFromLastToNewPosition * 0.5) + ( _newVelocityFromLastToNewPosition * 0.5); 123 | }; 124 | _x setVariable ["ATRAIN_Velocity_From_Last_To_New_Position", _velocityFromLastToNewPosition ]; 125 | _x setVariable ["ATRAIN_Direction_From_Last_To_New_Position",_currentPosition vectorFromTo _trainPosition]; 126 | if(_animateTrain) then { 127 | [_localCopy,_trainSpeed,_trainIsBackwards] call ATRAIN_fnc_setWheelSpeed; 128 | }; 129 | }; 130 | _x setVariable ["ATRAIN_Last_Draw_Position",_currentPosition]; 131 | _x setVariable ["ATRAIN_Last_Draw_Vector_Dir",vectorDir _localCopy]; 132 | } forEach _trainCars; 133 | _train setVariable ["ATRAIN_Calculations_Queued",true]; 134 | _train setVariable ["ATRAIN_New_Alignment_Last_Seen",_currentTime]; 135 | }; 136 | 137 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_handleSimulationNetworkUpdates.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _isTrainLocal = [_train] call ATRAIN_fnc_isTrainLocal; 3 | if(_isTrainLocal) then { 4 | private _currentTime = diag_tickTime; 5 | private _lastUpdateTime = _train getVariable ["ATRAIN_Local_Last_Simulation_Network_Update_Time",0]; 6 | if(_currentTime - _lastUpdateTime > 1) then { 7 | private _distanceFromFront = _train getVariable ["ATRAIN_Local_Distance_From_Front",0]; 8 | private _nodePath = _train getVariable ["ATRAIN_Local_Node_Path",[]]; 9 | private _nodePathDistance = _train getVariable ["ATRAIN_Local_Node_Path_Distance",0]; 10 | private _simulationState = [_distanceFromFront, _nodePath, _nodePathDistance]; 11 | private _remoteSimulationState = _train getVariable ["ATRAIN_Remote_Simulation_State",[]]; 12 | if(str _simulationState != str _remoteSimulationState) then { 13 | //diag_log ("Sending Network Message: " + str _remoteSimulationState); 14 | _train setVariable ["ATRAIN_Remote_Simulation_State",_simulationState,true]; 15 | }; 16 | _train setVariable ["ATRAIN_Local_Last_Simulation_Network_Update_Time",_currentTime]; 17 | }; 18 | } else { 19 | private _remoteSimulationState = _train getVariable ["ATRAIN_Remote_Simulation_State",nil]; 20 | if(!isNil "_remoteSimulationState") then { 21 | //diag_log ("Received Network Message: " + str _remoteSimulationState); 22 | _train setVariable ["ATRAIN_Local_Distance_From_Front",_remoteSimulationState select 0]; 23 | _train setVariable ["ATRAIN_Local_Node_Path",_remoteSimulationState select 1]; 24 | _train setVariable ["ATRAIN_Local_Node_Path_Distance",_remoteSimulationState select 2]; 25 | _train setVariable ["ATRAIN_Remote_Simulation_State",nil]; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_handleVelocityNetworkUpdates.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _isTrainLocal = [_train] call ATRAIN_fnc_isTrainLocal; 3 | if(_isTrainLocal) then { 4 | private _currentTime = diag_tickTime; 5 | private _lastUpdateTime = _train getVariable ["ATRAIN_Local_Last_Velocity_Network_Update_Time",0]; 6 | if(_currentTime - _lastUpdateTime > 1) then { 7 | private _trainVelocity = _train getVariable ["ATRAIN_Local_Velocity",0]; 8 | private _trainRemoteVelocity = _train getVariable ["ATRAIN_Remote_Velocity",0]; 9 | if(_trainVelocity != _trainRemoteVelocity) then { 10 | //diag_log ("Sent Network Message: " + str _trainVelocity); 11 | _train setVariable ["ATRAIN_Remote_Velocity",_trainVelocity,true]; 12 | }; 13 | _train setVariable ["ATRAIN_Local_Last_Velocity_Network_Update_Time",_currentTime]; 14 | }; 15 | } else { 16 | private _trainRemoteVelocity = _train getVariable ["ATRAIN_Remote_Velocity",nil]; 17 | if(!isNil "_trainRemoteVelocity") then { 18 | //diag_log ("Received Network Message: " + str _trainRemoteVelocity); 19 | _train setVariable ["ATRAIN_Local_Velocity",_trainRemoteVelocity]; 20 | _train setVariable ["ATRAIN_Remote_Velocity",nil]; 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_setWheelSpeed.sqf: -------------------------------------------------------------------------------- 1 | params ["_trainCar","_speed","_isBackwards"]; 2 | private _isLocalCopy = _trainCar getVariable ["ATRAIN_Is_Local_Copy",false]; 3 | if(!_isLocalCopy) exitWith {}; 4 | private _currentPhase = _trainCar animationSourcePhase "Wheels_source"; 5 | if(_speed == 0) then { 6 | _trainCar animateSource ["Wheels_source",_currentPhase]; 7 | } else { 8 | private _phaseDirection = 1; 9 | if( _speed < 0 ) then { 10 | _phaseDirection = -1; 11 | }; 12 | if( _isBackwards ) then { 13 | _phaseDirection = _phaseDirection * -1; 14 | }; 15 | private _newPhase = _currentPhase + (10 * _phaseDirection); 16 | private _animationSpeed = (abs _speed) / 6; 17 | _trainCar animateSource ["Wheels_source",_newPhase, _animationSpeed]; 18 | }; 19 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_simulateTrain.sqf: -------------------------------------------------------------------------------- 1 | 2 | params ["_train"]; 3 | 4 | private _driver = _train getVariable ["ATRAIN_Remote_Driver", objNull]; 5 | private _isTrainLocal = [_train] call ATRAIN_fnc_isTrainLocal; 6 | 7 | private _currentSimulationTime = diag_tickTime; 8 | private _lastSimulationTime = _train getVariable ["ATRAIN_Local_Last_Simulation_Time",_currentSimulationTime]; 9 | _train setVariable ["ATRAIN_Local_Last_Simulation_Time",_currentSimulationTime]; 10 | private _deltaSimulationTime = _currentSimulationTime - _lastSimulationTime; 11 | 12 | if(_deltaSimulationTime > 5) then { 13 | _deltaSimulationTime = 0; 14 | }; 15 | 16 | // Calculate train distance from start of path 17 | private _trainDistanceFromFront = _train getVariable ["ATRAIN_Local_Distance_From_Front",0]; 18 | private _trainVelocity = _train getVariable ["ATRAIN_Local_Velocity",0]; 19 | _trainDistanceFromFront = _trainDistanceFromFront - (_trainVelocity * _deltaSimulationTime); 20 | 21 | // Calculate engine alignment 22 | private _engineLength = _train getVariable ["ATRAIN_Remote_Car_Length",6]; 23 | private _engineAlignment = [_train,_train,_trainDistanceFromFront] call ATRAIN_fnc_calculateTrainAlignment; 24 | _train setVariable ["ATRAIN_Local_Alignment", _engineAlignment]; 25 | 26 | // Calculate rear cars alignments 27 | private _trainCarsInRear = _train getVariable ["ATRAIN_Remote_Cars_In_Rear",[]]; 28 | private _rearCarAlignment = _engineAlignment; 29 | private _rearCar = _train; 30 | _carDistanceFrontStart = _trainDistanceFromFront; 31 | _priorCarLength = _engineLength; 32 | { 33 | _rearCar = _x; 34 | private _carLength = _rearCar getVariable ["ATRAIN_Remote_Car_Length", 6]; 35 | _carDistanceFrontStart = _carDistanceFrontStart + ( _priorCarLength / 2 ) + ( _carLength / 2 ); 36 | _rearCarAlignment = [_train,_rearCar,_carDistanceFrontStart] call ATRAIN_fnc_calculateTrainAlignment; 37 | _rearCar setVariable ["ATRAIN_Local_Alignment", _rearCarAlignment]; 38 | _priorCarLength = _carLength; 39 | } forEach _trainCarsInRear; 40 | private _distanceFromEngineToRear = (_carDistanceFrontStart - _trainDistanceFromFront) + ( _priorCarLength / 2 ); 41 | 42 | // Calculate front cars alignments 43 | private _trainCarsInFront = _train getVariable ["ATRAIN_Remote_Cars_In_Front",[]]; 44 | private _frontCarAlignment = _engineAlignment; 45 | private _frontCar = _train; 46 | _carDistanceFrontStart = _trainDistanceFromFront; 47 | _priorCarLength = _engineLength; 48 | { 49 | _frontCar = _x; 50 | private _carLength = _frontCar getVariable ["ATRAIN_Remote_Car_Length", 6]; 51 | _carDistanceFrontStart = _carDistanceFrontStart - ( _priorCarLength / 2 ) - ( _carLength / 2 ); 52 | _frontCarAlignment = [_train,_frontCar,_carDistanceFrontStart] call ATRAIN_fnc_calculateTrainAlignment; 53 | _frontCar setVariable ["ATRAIN_Local_Alignment", _frontCarAlignment]; 54 | _priorCarLength = _carLength; 55 | } forEach _trainCarsInFront; 56 | private _distanceFromEngineToFront = (_trainDistanceFromFront - _carDistanceFrontStart) + ( _priorCarLength / 2 ); 57 | 58 | // Calculate track node updates 59 | private _nodePath = _train getVariable ["ATRAIN_Local_Node_Path",[]]; 60 | private _trainNodePathDistance = _train getVariable ["ATRAIN_Local_Node_Path_Distance",0]; 61 | if((_trainDistanceFromFront - _distanceFromEngineToFront) < 0 || (_trainDistanceFromFront + _distanceFromEngineToRear) > _trainNodePathDistance) then { 62 | private _trainInReverse = _trainVelocity < 0; 63 | private _turnTurnDirection = 0; 64 | if(!isNull _driver) then { 65 | _turnTurnDirection = _driver getVariable ["ATRAIN_Remote_Turn_Direction",0]; 66 | }; 67 | private _trainAlignment = [_train,_frontCar,_trainDistanceFromFront - _distanceFromEngineToFront] call ATRAIN_fnc_calculateTrainAlignment; 68 | private _trainDirection = (_trainAlignment select 0) select 1; 69 | if(_trainInReverse) then { 70 | _trainAlignment = [_train,_rearCar,_trainDistanceFromFront + _distanceFromEngineToRear] call ATRAIN_fnc_calculateTrainAlignment; 71 | _trainDirection = ((_trainAlignment select 1) select 1) vectorMultiply -1; 72 | }; 73 | private _trainDirectionRight = _trainDirection vectorCrossProduct [0,0,1]; 74 | private _finalNodeIndex = _nodePath select 0; 75 | if(_trainInReverse) then { 76 | _finalNodeIndex = _nodePath select ((count _nodePath) - 1); 77 | }; 78 | private _possibleNextNodes = []; 79 | private _mapFinalNode = ATRAIN_Map select _finalNodeIndex; 80 | { 81 | private _connectedNodeIndex = _x select 0; 82 | private _connectedNodeDistance = _x select 1; 83 | private _connectedNodePath = _x select 2; 84 | private _connectedNodePathStartPositionASL = (_connectedNodePath select 0); 85 | private _connectedNodePathSecondPositionASL = (_connectedNodePath select 1); 86 | private _connectedNodeDirection = _connectedNodePathStartPositionASL vectorFromTo _connectedNodePathSecondPositionASL; 87 | if(_trainDirection vectorDotProduct _connectedNodeDirection > 0) then { 88 | _possibleNextNodes pushBack [_connectedNodeIndex, _connectedNodeDirection, _connectedNodeDistance]; 89 | }; 90 | } forEach _mapFinalNode; 91 | private _nextNodeIndex = -1; 92 | private _nextNodeDistance = -1; 93 | private _nextNodeIndexMinValue = 0; 94 | { 95 | private _dirDotProduct = _trainDirectionRight vectorDotProduct (_x select 1); 96 | private _dirDotProductDelta = abs (_turnTurnDirection - _dirDotProduct); 97 | if(_nextNodeIndex == -1 || _dirDotProductDelta < _nextNodeIndexMinValue) then { 98 | _nextNodeIndex = _x select 0; 99 | _nextNodeDistance = _x select 2; 100 | _nextNodeIndexMinValue = _dirDotProductDelta; 101 | }; 102 | } forEach _possibleNextNodes; 103 | if(_nextNodeIndex != -1) then { 104 | if(_trainInReverse) then { 105 | _nodePath = _nodePath + [_nextNodeIndex]; 106 | } else { 107 | _nodePath = [_nextNodeIndex] + _nodePath; 108 | _trainDistanceFromFront = _trainDistanceFromFront + _nextNodeDistance; 109 | }; 110 | _trainNodePathDistance = _trainNodePathDistance + _nextNodeDistance; 111 | _train setVariable ["ATRAIN_Local_Node_Path",_nodePath]; 112 | _train setVariable ["ATRAIN_Local_Node_Path_Distance",_trainNodePathDistance]; 113 | } else { 114 | if(_trainInReverse) then { 115 | _trainDistanceFromFront = _trainNodePathDistance - _distanceFromEngineToRear; 116 | } else { 117 | _trainDistanceFromFront = _distanceFromEngineToFront; 118 | }; 119 | _train setVariable ["ATRAIN_Local_Velocity_Update",0]; 120 | }; 121 | }; 122 | 123 | _train setVariable ["ATRAIN_Local_Distance_From_Front",_trainDistanceFromFront]; 124 | 125 | if(count _nodePath > 2) then { 126 | [_train, _distanceFromEngineToRear, _distanceFromEngineToFront] call ATRAIN_fnc_cleanUpNodePath; 127 | }; 128 | 129 | // Enable lights 130 | private _lightsEnabled = _train getVariable ["ATRAIN_Remote_Lights_Enabled", false]; 131 | private _localCopy = _train getVariable ["ATRAIN_Local_Copy", objNull]; 132 | if(!isNull _localCopy) then { 133 | if(_lightsEnabled && !islighton _localCopy) then { 134 | _localCopy enableSimulation true; 135 | _localCopy setPilotLight true; 136 | }; 137 | if(!_lightsEnabled && islighton _localCopy) then { 138 | _localCopy enableSimulation true; 139 | _localCopy setPilotLight false; 140 | }; 141 | }; 142 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_simulateTrainAttachment.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | 3 | private _trainVelocity = _train getVariable ["ATRAIN_Local_Velocity",0]; 4 | private _trainCars = _train getVariable ["ATRAIN_Remote_Cars",[_train]]; 5 | private _trainCarsInRear = _train getVariable ["ATRAIN_Remote_Cars_In_Rear",[]]; 6 | private _trainCarsInFront = _train getVariable ["ATRAIN_Remote_Cars_In_Front",[]]; 7 | _carLengthMultiplier = 0.53; 8 | 9 | // Check for cars in rear 10 | if(_trainVelocity < 0) then { 11 | private _rearCar = _train; 12 | if(count _trainCarsInRear > 0) then { 13 | _rearCar = _trainCarsInRear select ((count _trainCarsInRear)-1); 14 | }; 15 | private _rearCarLocal = _rearCar getVariable ["ATRAIN_Local_Copy", objNull]; 16 | if(isNull _rearCarLocal) exitWith {}; 17 | private _rearCarPosASL = getPosASLVisual _rearCarLocal; 18 | private _rearCarSearchVectorDir = vectorDir _rearCarLocal; 19 | private _rearCarIsBackwards = _rearCar getVariable ["ATRIAN_Remote_Is_Backwards", false]; 20 | if(!_rearCarIsBackwards) then { 21 | _rearCarSearchVectorDir = _rearCarSearchVectorDir vectorMultiply -1; 22 | }; 23 | private _rearCarLength = _rearCar getVariable ["ATRAIN_Remote_Car_Length",6]; 24 | private _intersectStartASL = _rearCarPosASL vectorAdd (_rearCarSearchVectorDir vectorMultiply (_rearCarLength*_carLengthMultiplier)) vectorAdd [0,0,3]; 25 | private _intersectEndASL = _intersectStartASL vectorAdd [0,0,-3]; 26 | private _newCars = lineIntersectsWith [_intersectStartASL,_intersectEndASL,_rearCarLocal]; 27 | { 28 | private _car = _x; 29 | if(_car getVariable ["ATRAIN_Is_Local_Copy",false]) then { 30 | _car = _car getVariable ["ATRAIN_Remote_Copy",objNull]; 31 | }; 32 | if(!isNull _car) then { 33 | private _trainDef = [_car] call ATRAIN_fnc_getTrainDefinition; 34 | if(count _trainDef > 0 && !(_car in _trainCarsInFront) && !(_car in _trainCarsInRear) && _car != _train && isNull (_car getVariable ["ATRIAN_Current_Train",objNull])) then { 35 | private _carIsBackwards = (_rearCarSearchVectorDir vectorDotProduct (vectorDir _car)) > 0; 36 | _car = [_car] call ATRAIN_fnc_initTrainObject; 37 | _car setVariable ["ATRIAN_Remote_Is_Backwards", _carIsBackwards, true]; 38 | _car setVariable ["ATRIAN_Current_Train", _train, true]; 39 | _trainCarsInRear pushBackUnique _car; 40 | _trainCars pushBackUnique _car; 41 | _train setVariable ["ATRAIN_Remote_Cars_In_Rear",_trainCarsInRear,true]; 42 | _train setVariable ["ATRAIN_Remote_Cars",_trainCars,true]; 43 | _train setVariable ["ATRAIN_Local_Velocity_Update", _trainVelocity / 2]; 44 | _train setVariable ["ATRAIN_Local_Last_Attachment_Time",diag_tickTime]; 45 | }; 46 | }; 47 | } forEach _newCars; 48 | }; 49 | 50 | 51 | // Check for cars in front 52 | if(_trainVelocity > 0) then { 53 | private _frontCar = _train; 54 | if(count _trainCarsInFront > 0) then { 55 | _frontCar = _trainCarsInFront select ((count _trainCarsInFront)-1); 56 | }; 57 | private _frontCarLocal = _frontCar getVariable ["ATRAIN_Local_Copy", objNull]; 58 | if(isNull _frontCarLocal) exitWith {}; 59 | private _frontCarPosASL = getPosASLVisual _frontCarLocal; 60 | private _frontCarSearchVectorDir = vectorDir _frontCarLocal; 61 | private _frontCarIsBackwards = _frontCar getVariable ["ATRIAN_Remote_Is_Backwards", false]; 62 | if(_frontCarIsBackwards) then { 63 | _frontCarSearchVectorDir = _frontCarSearchVectorDir vectorMultiply -1; 64 | }; 65 | private _frontCarLength = _frontCar getVariable ["ATRAIN_Remote_Car_Length",6]; 66 | private _intersectStartASL = _frontCarPosASL vectorAdd (_frontCarSearchVectorDir vectorMultiply (_frontCarLength*_carLengthMultiplier)) vectorAdd [0,0,3]; 67 | private _intersectEndASL = _intersectStartASL vectorAdd [0,0,-3]; 68 | private _newCars = lineIntersectsWith [_intersectStartASL,_intersectEndASL,_frontCarLocal]; 69 | { 70 | private _car = _x; 71 | if(_car getVariable ["ATRAIN_Is_Local_Copy",false]) then { 72 | _car = _car getVariable ["ATRAIN_Remote_Copy",objNull]; 73 | }; 74 | if(!isNull _car) then { 75 | private _trainDef = [_car] call ATRAIN_fnc_getTrainDefinition; 76 | if(count _trainDef > 0 && !(_car in _trainCarsInFront) && !(_car in _trainCarsInRear) && _car != _train && isNull (_car getVariable ["ATRIAN_Current_Train",objNull])) then { 77 | private _carIsBackwards = (_frontCarSearchVectorDir vectorDotProduct (vectorDir _car)) < 0; 78 | _car = [_car] call ATRAIN_fnc_initTrainObject; 79 | _car setVariable ["ATRIAN_Remote_Is_Backwards", _carIsBackwards, true]; 80 | _car setVariable ["ATRIAN_Current_Train", _train, true]; 81 | _trainCarsInFront pushBackUnique _car; 82 | _trainCars pushBackUnique _car; 83 | _train setVariable ["ATRAIN_Remote_Cars_In_Front",_trainCarsInFront,true]; 84 | _train setVariable ["ATRAIN_Remote_Cars",_trainCars,true]; 85 | _train setVariable ["ATRAIN_Local_Velocity_Update",_trainVelocity / 2]; 86 | _train setVariable ["ATRAIN_Local_Last_Attachment_Time",diag_tickTime]; 87 | }; 88 | 89 | }; 90 | } forEach _newCars; 91 | }; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_simulateTrainParticleEffects.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainSpeed = _train getVariable ["ATRAIN_Local_Velocity",0]; 3 | private _trainCars = _train getVariable ["ATRAIN_Remote_Cars",[_train]]; 4 | { 5 | private _trainCar = _x; 6 | private _particleEffects = _trainCar getVariable ["ATRAIN_Remote_Particle_Effects",[]]; 7 | private _particleSourcs = _trainCar getVariable ["ATRAIN_Local_Particle_Sources",[]]; 8 | private _localCopy = _trainCar getVariable ["ATRAIN_Local_Copy", objNull]; 9 | if(!isNull _localCopy) then { 10 | if(_trainSpeed == 0 && count _particleSourcs > 0) then { 11 | { 12 | deleteVehicle _x; 13 | } forEach _particleSourcs; 14 | _trainCar setVariable ["ATRAIN_Local_Particle_Sources",nil]; 15 | }; 16 | if(_trainSpeed != 0 && count _particleSourcs == 0) then { 17 | { 18 | _x params ["_particleType","_modelPosition"]; 19 | if(typeName _modelPosition == "STRING") then { 20 | _modelPosition = _localCopy selectionPosition [_modelPosition, "Memory"]; 21 | }; 22 | 23 | if(_particleType == "steam") then { 24 | private _source = "#particlesource" createVehicleLocal (_localCopy modelToWorld _modelPosition); 25 | 26 | _source setParticleParams 27 | [["\A3\data_f\ParticleEffects\Universal\smoke.p3d",1,0,1,0],"", 28 | "billboard", 29 | 0, 30 | 1, 31 | _modelPosition, 32 | [0, 0, 2], 33 | 3,1.35,1,-0.1, 34 | [0.5, 2], 35 | [[1,1,1,0.25], [1,1,1,0.5], [1,1,1,0]], 36 | [2,2], 37 | 0.1, 38 | 0.08, 39 | "", 40 | "", 41 | _localCopy, 42 | 0, 43 | false, 44 | 0, 45 | [[0,0,0,0]]]; 46 | 47 | _source setParticleRandom 48 | [2, 49 | [0,0,0.1], 50 | [0,0,0.2], 51 | 1, 52 | 0.2, 53 | [0.25,0.25,0.25,1], 54 | 0.01, 55 | 0.03, 56 | 10]; 57 | 58 | _source setDropInterval 0.001; 59 | 60 | _particleSourcs pushBack _source; 61 | }; 62 | } forEach _particleEffects; 63 | _trainCar setVariable ["ATRAIN_Local_Particle_Sources",_particleSourcs]; 64 | }; 65 | }; 66 | } forEach _trainCars; 67 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/simulation/fn_simulateTrainVelocity.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _driver = _train getVariable ["ATRAIN_Remote_Driver", objNull]; 3 | private _movementDirection = 0; 4 | if(!isNull _driver) then { 5 | _movementDirection = _driver getVariable ["ATRAIN_Remote_Movement_Direction",0]; 6 | }; 7 | private _currentCalcTime = diag_tickTime; 8 | private _lastCalcTime = _train getVariable ["ATRAIN_Local_Last_Velocity_Calculation_Time",_currentCalcTime]; 9 | private _deltaCalcTime = (_currentCalcTime - _lastCalcTime); 10 | if(_deltaCalcTime > 2) then { 11 | _deltaCalcTime = 0; 12 | }; 13 | private _carCount = count (_train getVariable ["ATRAIN_Remote_Cars",[_train]]); 14 | 15 | private _trainAccelerationMin = _train getVariable ["ATRAIN_Local_Train_Acceleration_Min", 0.7]; 16 | private _trainAccelerationMax = _train getVariable ["ATRAIN_Local_Train_Acceleration_Max", 1.2]; 17 | private _trainAccelerationRange = _trainAccelerationMax - _trainAccelerationMin; 18 | private _trainAcceleration = _trainAccelerationMin + (_trainAccelerationRange * (1 - (((_carCount / 20) min 1)))); 19 | 20 | private _trainDragMin = _train getVariable ["ATRAIN_Local_Train_Drag_Min", 0.7]; 21 | private _trainDragMax = _train getVariable ["ATRAIN_Local_Train_Drag_Max", 1.2]; 22 | private _trainDragRange = _trainDragMax - _trainDragMin; 23 | private _trainDrag = _trainDragMin + (_trainDragRange * (1 - ((_carCount / 20) min 1))); 24 | 25 | private _cruiseControlEnabled = _train getVariable ["ATRAIN_Remote_Cruise_Control_Enabled", false]; 26 | private _breakEnabled = player getVariable ["ATRAIN_Remote_Break_Enabled", false]; 27 | 28 | if(_cruiseControlEnabled && !_breakEnabled) then { 29 | _trainDrag = 0; 30 | }; 31 | 32 | if(_breakEnabled) then { 33 | _trainAcceleration = 0; 34 | _movementDirection = 0; 35 | _trainDrag = _trainDrag * 2; 36 | }; 37 | 38 | private _trainModelReversed = _train getVariable ["ATRAIN_Remote_Is_Model_Reversed",false]; 39 | if(_trainModelReversed) then { 40 | _movementDirection = _movementDirection * -1; 41 | }; 42 | 43 | private _trainMaxVelocity = _train getVariable ["ATRAIN_Remote_Train_Max_Velocity",12]; 44 | private _trainVelocity = _train getVariable ["ATRAIN_Local_Velocity",0]; 45 | _trainVelocity = (_trainVelocity + (_trainAcceleration * _movementDirection * _deltaCalcTime)) min _trainMaxVelocity max -_trainMaxVelocity; 46 | if(_trainVelocity > 0 && _movementDirection == 0) then { 47 | _trainVelocity = (_trainVelocity - (_trainDrag * _deltaCalcTime)) max 0; 48 | }; 49 | if(_trainVelocity < 0 && _movementDirection == 0) then { 50 | _trainVelocity = (_trainVelocity + (_trainDrag * _deltaCalcTime)) min 0; 51 | }; 52 | private _localVelocityUpdate = _train getVariable ["ATRAIN_Local_Velocity_Update",nil]; 53 | if(!isNil "_localVelocityUpdate") then { 54 | _trainVelocity = _localVelocityUpdate; 55 | _train setVariable ["ATRAIN_Local_Velocity_Update",nil]; 56 | }; 57 | _train setVariable ["ATRAIN_Local_Velocity",_trainVelocity]; 58 | _train setVariable ["ATRAIN_Local_Last_Velocity_Calculation_Time",_currentCalcTime]; 59 | 60 | // Enable the train's engine automatically when the train starts moving 61 | private _enginedEnabled = _train getVariable ["ATRAIN_Remote_Engine_Enabled", false]; 62 | if(_trainVelocity != 0 && !_enginedEnabled) then { 63 | _train setVariable ["ATRAIN_Remote_Engine_Enabled", true, true]; 64 | }; 65 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/sound/fn_addTrainSoundDefinition.sqf: -------------------------------------------------------------------------------- 1 | params ["_trainClass","_soundDefinition"]; 2 | if(isNil "ATRAIN_Train_Sound_Definitions") then { 3 | ATRAIN_Train_Sound_Definitions = []; 4 | ATRAIN_Train_Sound_Definitions_Index = []; 5 | }; 6 | ATRAIN_Train_Sound_Definitions pushBack _this; 7 | ATRAIN_Train_Sound_Definitions_Index pushBack (toLower _trainClass); -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/sound/fn_getTrainSoundDefinition.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | private _trainSoundDef = []; 3 | private _trainType = [_train] call ATRAIN_fnc_getTypeOf; 4 | private _trainSoundDefIndex = ATRAIN_Train_Sound_Definitions_Index find toLower (_trainType select 0); 5 | if(_trainSoundDefIndex >= 0) then { 6 | _trainSoundDef = (ATRAIN_Train_Sound_Definitions select _trainSoundDefIndex) select 1; 7 | }; 8 | _trainSoundDef; 9 | -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/sound/fn_initTrainSound.sqf: -------------------------------------------------------------------------------- 1 | 2 | #define DEFAULT_ENGINE ["ATS_Train_Engine_Sound", 55] 3 | #define DEFAULT_ENGINE_IDLE ["ATS_Train_Engine_Idle_Sound", 55] 4 | #define DEFAULT_TRACK ["ATS_Train_Track_Sound", 26] 5 | #define DEFAULT_BELL ["ATS_Train_Bell_Sound", 56.6] 6 | 7 | { _x call ATRAIN_fnc_addTrainSoundDefinition } forEach [ 8 | ["ATS_Trains_A2Locomotive_Driveable_Blue", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 9 | ["ATS_Trains_A2Locomotive_Driveable_Red", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 10 | ["Land_Locomotive_01_v1_F", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 11 | ["Land_Locomotive_01_v2_F", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 12 | ["Land_Locomotive_01_v3_F", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 13 | ["Land_loco_742_blue", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 14 | ["Land_loco_742_red", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 15 | ["ATS_Trains_Steam_Small", [["ATS_Train_Steam_Engine_Sound", 57], ["ATS_Train_Steam_Engine_Idle_Sound", 35], DEFAULT_TRACK, DEFAULT_BELL]], 16 | ["ATS_Trains_Steam_Large", [["ATS_Train_Steam_Engine_Sound", 57], ["ATS_Train_Steam_Engine_Idle_Sound", 35], DEFAULT_TRACK, DEFAULT_BELL]], 17 | ["ATS_Trains_Cable_Car", []], 18 | ["ATS_Trains_AE_Engine", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 19 | ["ATS_Trains_SD60_Engine", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 20 | ["ATS_Trains_VL_Elgolova", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 21 | ["ATS_Trains_VL_EW", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 22 | ["ATS_Trains_VL_EE", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 23 | ["ATS_Trains_VL_M62", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 24 | ["ATS_Trains_VL_VL10", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 25 | ["ATS_Trains_VL_TVZ", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]], 26 | ["ATS_Trains_VL_CH4", [DEFAULT_ENGINE, DEFAULT_ENGINE_IDLE, DEFAULT_TRACK, DEFAULT_BELL]] 27 | ]; 28 | 29 | // Check if the client has sounds installed 30 | private _config = getArray ( configFile / "CfgSounds" / "ATS_Train_Engine_Sound" / "sound" ); 31 | private _configMission = getArray ( missionConfigFile / "CfgSounds" / "ATS_Train_Engine_Sound" / "sound" ); 32 | private _hasSounds = (count _config > 0 || count _configMission > 0); 33 | 34 | // Start train sound simulation handler 35 | if(hasInterface && _hasSounds) then { 36 | [] spawn { 37 | while {true} do { 38 | private _registeredTrains = missionNamespace getVariable ["ATRAIN_Registered_Trains",[]]; 39 | { 40 | [_x] call ATRAIN_fnc_simulateTrainSounds; 41 | } forEach _registeredTrains; 42 | sleep 0.1; 43 | }; 44 | }; 45 | }; -------------------------------------------------------------------------------- /src/addons/ats/core/functions/train/sound/fn_simulateTrainSounds.sqf: -------------------------------------------------------------------------------- 1 | params ["_train"]; 2 | 3 | #define ENGINE_DISTANCE 50 4 | #define ENGINE_MAX_SPEED 10 5 | #define ENGINE_IDLE_DISTANCE 50 6 | #define ENGINE_IDLE_MAX_SPEED 10 7 | #define TRACK_DISTANCE 75 8 | #define TRACK_MAX_SPEED 10 9 | #define HORN_DISTANCE 600 10 | #define BELL_DISTANCE 100 11 | 12 | private _closestCar = [_train] call ATRAIN_fnc_getNearestTrainCar; 13 | private _closestCarLocal = _closestCar getVariable ["ATRAIN_Local_Copy",_closestCar]; 14 | private _engineCarLocal = _train getVariable ["ATRAIN_Local_Copy",_train]; 15 | 16 | // Don't simulate sounds if train is more than 2k away 17 | if(player distance _closestCarLocal > 1200) exitWith {}; 18 | 19 | // Don't simulate sound if cars aren't local yet 20 | if(_engineCarLocal == _train || _closestCarLocal == _closestCar) exitWith {}; 21 | 22 | private _trainSpeed = abs (_train getVariable ["ATRAIN_Local_Velocity",0]); 23 | 24 | // Get the sound def and cache if not defined yet 25 | private _soundDef = _train getVariable ["ATRAIN_Sound_Def", nil]; 26 | if(isNil "_soundDef") then { 27 | _soundDef = [_train] call ATRAIN_fnc_getTrainSoundDefinition; 28 | _train setVariable ["ATRAIN_Sound_Def", _soundDef]; 29 | }; 30 | 31 | if(count _soundDef == 0) exitWith {}; 32 | 33 | _soundDef params ["_engineSound","_engineIdleSound", "_trackSound", "_bellSound"]; 34 | 35 | // Simulate track sound 36 | private _trackSoundSource = _train getVariable ["TRAIN_Track_Sound_Source", objNull]; 37 | if(isNull _trackSoundSource) then { 38 | _trackSoundSource = [_trackSound select 0,TRACK_DISTANCE,true,_trackSound select 1] call ATRAIN_fnc_createSoundSource; 39 | _train setVariable ["TRAIN_Track_Sound_Source", _trackSoundSource]; 40 | }; 41 | [_trackSoundSource, _closestCarLocal] call ATRAIN_fnc_attachSoundSource; 42 | if(_trainSpeed == 0) then { 43 | [_trackSoundSource, false] call ATRAIN_fnc_enableSoundSource; 44 | } else { 45 | [_trackSoundSource, true] call ATRAIN_fnc_enableSoundSource; 46 | [_trackSoundSource, (_trainSpeed min TRACK_MAX_SPEED)/TRACK_MAX_SPEED ] call ATRAIN_fnc_setSoundSourceVolume; 47 | }; 48 | 49 | // Simulate engine idle sound 50 | private _remoteEngineEnabled = _train getVariable ["ATRAIN_Remote_Engine_Enabled", true]; 51 | private _engineIdleSoundSource = _train getVariable ["TRAIN_Engine_Idle_Sound_Source", objNull]; 52 | if(isNull _engineIdleSoundSource) then { 53 | _engineIdleSoundSource = [_engineIdleSound select 0,ENGINE_IDLE_DISTANCE,true,_engineIdleSound select 1] call ATRAIN_fnc_createSoundSource; 54 | _train setVariable ["TRAIN_Engine_Idle_Sound_Source", _engineIdleSoundSource]; 55 | [_engineIdleSoundSource, true] call ATRAIN_fnc_enableSoundSource; 56 | [_engineIdleSoundSource, _engineCarLocal] call ATRAIN_fnc_attachSoundSource; 57 | }; 58 | if(_remoteEngineEnabled) then { 59 | [_engineIdleSoundSource, true] call ATRAIN_fnc_enableSoundSource; 60 | [_engineIdleSoundSource, (1-((_trainSpeed min ENGINE_IDLE_MAX_SPEED)/ENGINE_IDLE_MAX_SPEED)) max 0.8] call ATRAIN_fnc_setSoundSourceVolume; 61 | } else { 62 | [_engineIdleSoundSource, false] call ATRAIN_fnc_enableSoundSource; 63 | }; 64 | 65 | 66 | // Simulate engine sound 67 | private _engineSoundSource = _train getVariable ["TRAIN_Engine_Sound_Source", objNull]; 68 | if(isNull _engineSoundSource) then { 69 | _engineSoundSource = [_engineSound select 0,ENGINE_DISTANCE,true,_engineSound select 1] call ATRAIN_fnc_createSoundSource; 70 | _train setVariable ["TRAIN_Engine_Sound_Source", _engineSoundSource]; 71 | [_engineSoundSource, _engineCarLocal] call ATRAIN_fnc_attachSoundSource; 72 | }; 73 | if(_trainSpeed == 0) then { 74 | [_engineSoundSource, false] call ATRAIN_fnc_enableSoundSource; 75 | } else { 76 | [_engineSoundSource, true] call ATRAIN_fnc_enableSoundSource; 77 | [_engineSoundSource, (_trainSpeed min ENGINE_MAX_SPEED)/ENGINE_MAX_SPEED] call ATRAIN_fnc_setSoundSourceVolume; 78 | }; 79 | 80 | // Simulate horn sound 81 | private _driver = _train getVariable ["ATRAIN_Remote_Driver", objNull]; 82 | private _remoteHornEnabled = _driver getVariable ["ATRAIN_Remote_Horn_Enabled", false]; 83 | private _localHornEnabled = _train getVariable ["ATRAIN_Local_Horn_Enabled", false]; 84 | if(_remoteHornEnabled && !_localHornEnabled) then { 85 | _train setVariable ["ATRAIN_Local_Horn_Enabled", true]; 86 | [_train, _driver] spawn { 87 | params ["_train","_driver"]; 88 | private _localCopy = _train getVariable ["ATRAIN_Local_Copy", objNull]; 89 | if(!isNull _localCopy) then { 90 | _localCopy say3D ["ATSHornStart", HORN_DISTANCE, 1]; 91 | sleep 0.99; 92 | while { !isNull _driver && alive _driver && _driver getVariable ["ATRAIN_Remote_Horn_Enabled", false]} do { 93 | if((floor random 2) > 0) then { 94 | _localCopy say3D ["ATSHornMiddle1", HORN_DISTANCE, 1]; 95 | } else { 96 | _localCopy say3D ["ATSHornMiddle2", HORN_DISTANCE, 1]; 97 | }; 98 | sleep 0.99; 99 | }; 100 | _localCopy say3D ["ATSHornEnd", HORN_DISTANCE, 1]; 101 | sleep 1; 102 | }; 103 | _train setVariable ["ATRAIN_Local_Horn_Enabled", false]; 104 | }; 105 | }; 106 | 107 | // Simulate bell sound 108 | private _remoteBellEnabled = _driver getVariable ["ATRAIN_Remote_Bell_Enabled", false]; 109 | private _localBellEnabled = _train getVariable ["ATRAIN_Local_Bell_Enabled", false]; 110 | if(_remoteBellEnabled && !_localBellEnabled) then { 111 | private _bellSoundSource = _train getVariable ["TRAIN_Bell_Sound_Source", objNull]; 112 | if(isNull _bellSoundSource) then { 113 | _bellSoundSource = [_bellSound select 0,BELL_DISTANCE,true,_bellSound select 1] call ATRAIN_fnc_createSoundSource; 114 | _train setVariable ["TRAIN_Bell_Sound_Source", _bellSoundSource]; 115 | [_bellSoundSource, _engineCarLocal] call ATRAIN_fnc_attachSoundSource; 116 | }; 117 | [_bellSoundSource, true] call ATRAIN_fnc_enableSoundSource; 118 | [_bellSoundSource, 1] call ATRAIN_fnc_setSoundSourceVolume; 119 | [_bellSoundSource, _driver, _train] spawn { 120 | params ["_bellSoundSource", "_driver", "_train"]; 121 | while { alive _driver && _driver getVariable ["ATRAIN_Remote_Bell_Enabled", false] } do { 122 | sleep 0.5; 123 | }; 124 | // Fade bell sound out 125 | for [{_i=1}, {_i>0}, {_i=_i-0.05}] do 126 | { 127 | [_bellSoundSource, _i] call ATRAIN_fnc_setSoundSourceVolume; 128 | sleep 0.1; 129 | }; 130 | [_bellSoundSource, false] call ATRAIN_fnc_enableSoundSource; 131 | _train setVariable ["ATRAIN_Local_Bell_Enabled", false]; 132 | }; 133 | }; 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/horn_end.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/horn_end.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/horn_middle1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/horn_middle1.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/horn_middle2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/horn_middle2.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/horn_start.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/horn_start.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_bell.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_bell.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_engine.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_engine.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_engine_idle.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_engine_idle.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_horn.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_horn.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_steam_engine.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_steam_engine.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_steam_engine_idle.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_steam_engine_idle.ogg -------------------------------------------------------------------------------- /src/addons/ats/core/sounds/train_track.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/src/addons/ats/core/sounds/train_track.ogg -------------------------------------------------------------------------------- /steamLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/steamLogo.jpg -------------------------------------------------------------------------------- /steamLogo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedTrainSimulator/b8065c75f45d2339e7f6773a35d7a848f7dbe08e/steamLogo.psd --------------------------------------------------------------------------------