diff --git a/.travis.yml b/.travis.yml
index a9f4ddfb441e17f282d9d488239cb5d3fdd5578f..8a137d9d8c8b10e81c98ef39aff58eeddb3f711b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -72,6 +72,21 @@ matrix:
           compiler: gcc-7
           env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3"
           #gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802
+        - os: linux
+          addons:
+            apt:
+              sources:
+              - ubuntu-toolchain-r-test
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-8
+          compiler: gcc-8
+          env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3"
+          #gcc-8 (Ubuntu 7.2.0-1ubuntu1~14.04) 8.1.0
         - os: linux
           compiler: clang
           #clang version 3.5.0 (tags/RELEASE_350/final)
@@ -212,6 +227,7 @@ matrix:
       - compiler: clang-3.9
       - compiler: clang-4.0
       - compiler: clang-5.0
+      - compiler: gcc-8
 
 cache:
   apt: true
diff --git a/bin/Resources/libgme64.dll b/bin/Resources/libgme64.dll
new file mode 100644
index 0000000000000000000000000000000000000000..2ba99450f5c7a9372a5eaa67ccdb1ee20dd5c81c
Binary files /dev/null and b/bin/Resources/libgme64.dll differ
diff --git a/libs/SDL2/COPYING.txt b/libs/SDL2/COPYING.txt
index a1c8bbe5af9caeda179d70c7476e023325d29067..694e58a09f009850b9ea7a1d617560d561a80200 100644
--- a/libs/SDL2/COPYING.txt
+++ b/libs/SDL2/COPYING.txt
@@ -1,6 +1,6 @@
 
 Simple DirectMedia Layer
-Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
   
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/Makefile b/libs/SDL2/Makefile
index a2e6bb9ba08cca81bbcc29d53898d74c2730a737..9edfd003e83e0fc85e28622d61634d5475551dd8 100644
--- a/libs/SDL2/Makefile
+++ b/libs/SDL2/Makefile
@@ -1,12 +1,12 @@
 #
 # Makefile for installing the mingw32 version of the SDL library
 
-CROSS_PATH := /usr/local/cross-tools
+CROSS_PATH := /usr/local
 ARCHITECTURES := i686-w64-mingw32 x86_64-w64-mingw32
 
 all install:
 	@echo "Type \"make native\" to install 32-bit to /usr"
-	@echo "Type \"make cross\" to install 32-bit and 64-bit to CROSS_PATH ($(CROSS_PATH))"
+	@echo "Type \"make cross\" to install 32-bit and 64-bit to $(CROSS_PATH)"
 
 native:
 	make install-package arch=i686-w64-mingw32 prefix=/usr
@@ -22,6 +22,7 @@ install-package:
 	    sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/bin/sdl2-config >$(prefix)/bin/sdl2-config; \
 	    chmod 755 $(prefix)/bin/sdl2-config; \
 	    sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2.la >$(prefix)/lib/libSDL2.la; \
+	    sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2main.la >$(prefix)/lib/libSDL2main.la; \
 	    sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/lib/pkgconfig/sdl2.pc >$(prefix)/lib/pkgconfig/sdl2.pc; \
 	else \
 	    echo "*** ERROR: $(arch) or $(prefix) does not exist!"; \
diff --git a/libs/SDL2/SRB2NOTE.txt b/libs/SDL2/SRB2NOTE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b7da4c9ab31061e8961722cf92af9f0a4e7afe51
--- /dev/null
+++ b/libs/SDL2/SRB2NOTE.txt
@@ -0,0 +1,15 @@
+# SDL Development Libaries
+
+Download both the VC and MinGW packages and extract them here.
+
+https://www.libsdl.org/download-2.0.php
+
+## VC Package
+
+* include
+* lib
+
+## MinGW Package
+
+* i686-w64-mingw32
+* x86_64-w64-mingw32
diff --git a/libs/SDL2/WhatsNew.txt b/libs/SDL2/WhatsNew.txt
index 9c8d538403e8b89000e0e27f7a8bc3b3d1fca26f..9074b12ba7056cc4f81881a1e1ddf0274eab60d3 100644
--- a/libs/SDL2/WhatsNew.txt
+++ b/libs/SDL2/WhatsNew.txt
@@ -1,6 +1,91 @@
 
 This is a list of major changes in SDL's version history.
 
+---------------------------------------------------------------------------
+2.0.9:
+---------------------------------------------------------------------------
+
+General:
+* Added a new sensor API, initialized by passing SDL_INIT_SENSOR to SDL_Init(), and defined in SDL_sensor.h
+* Added an event SDL_SENSORUPDATE which is sent when a sensor is updated
+* Added SDL_GetDisplayOrientation() to return the current display orientation
+* Added an event SDL_DISPLAYEVENT which is sent when the display orientation changes
+* Added HIDAPI joystick drivers for more consistent support for Xbox, PS4 and Nintendo Switch Pro controller support across platforms. (Thanks to Valve for contributing the PS4 and Nintendo Switch Pro controller support)
+* Added support for many other popular game controllers
+* Added SDL_JoystickGetDevicePlayerIndex(), SDL_JoystickGetPlayerIndex(), and SDL_GameControllerGetPlayerIndex() to get the player index for a controller. For XInput controllers this returns the XInput index for the controller.
+* Added SDL_GameControllerRumble() and SDL_JoystickRumble() which allow simple rumble without using the haptics API
+* Added SDL_GameControllerMappingForDeviceIndex() to get the mapping for a controller before it's opened
+* Added the hint SDL_HINT_MOUSE_DOUBLE_CLICK_TIME to control the mouse double-click time
+* Added the hint SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS to control the mouse double-click radius, in pixels
+* Added SDL_HasColorKey() to return whether a surface has a colorkey active
+* Added SDL_HasAVX512F() to return whether the CPU has AVX-512F features
+* Added SDL_IsTablet() to return whether the application is running on a tablet
+* Added SDL_THREAD_PRIORITY_TIME_CRITICAL for threads that must run at the highest priority
+
+Mac OS X:
+* Fixed black screen at start on Mac OS X Mojave
+
+Linux:
+* Added SDL_LinuxSetThreadPriority() to allow adjusting the thread priority of native threads using RealtimeKit if available.
+
+iOS:
+* Fixed Asian IME input
+
+Android:
+* Updated required Android SDK to API 26, to match Google's new App Store requirements
+* Added support for wired USB Xbox, PS4, and Nintendo Switch Pro controllers
+* Added support for relative mouse mode on Android 7.0 and newer (except where it's broken, on Chromebooks and when in DeX mode with Samsung Experience 9.0)
+* Added support for custom mouse cursors on Android 7.0 and newer
+* Added the hint SDL_HINT_ANDROID_TRAP_BACK_BUTTON to control whether the back button will back out of the app (the default) or be passed to the application as SDL_SCANCODE_AC_BACK
+* Added SDL_AndroidBackButton() to trigger the Android system back button behavior when handling the back button in the application
+* Added SDL_IsChromebook() to return whether the app is running in the Chromebook Android runtime
+* Added SDL_IsDeXMode() to return whether the app is running while docked in the Samsung DeX
+
+
+---------------------------------------------------------------------------
+2.0.8:
+---------------------------------------------------------------------------
+
+General:
+* Added SDL_fmod() and SDL_log10()
+* Each of the SDL math functions now has the corresponding float version
+* Added SDL_SetYUVConversionMode() and SDL_GetYUVConversionMode() to control the formula used when converting to and from YUV colorspace. The options are JPEG, BT.601, and BT.709
+
+Windows:
+* Implemented WASAPI support on Windows UWP and removed the deprecated XAudio2 implementation
+* Added resampling support on WASAPI on Windows 7 and above
+
+Windows UWP:
+* Added SDL_WinRTGetDeviceFamily() to find out what type of device your application is running on
+
+Mac OS X:
+* Added support for the Vulkan SDK for Mac:
+  https://www.lunarg.com/lunarg-releases-vulkan-sdk-1-0-69-0-for-mac/
+* Added support for OpenGL ES using ANGLE when it's available
+
+Mac OS X / iOS / tvOS:
+* Added a Metal 2D render implementation
+* Added SDL_RenderGetMetalLayer() and SDL_RenderGetMetalCommandEncoder() to insert your own drawing into SDL rendering when using the Metal implementation
+
+iOS:
+* Added the hint SDL_HINT_IOS_HIDE_HOME_INDICATOR to control whether the home indicator bar on iPhone X should be hidden. This defaults to dimming the indicator for fullscreen applications and showing the indicator for windowed applications.
+
+iOS / Android:
+* Added the hint SDL_HINT_RETURN_KEY_HIDES_IME to control whether the return key on the software keyboard should hide the keyboard or send a key event (the default)
+
+Android:
+* SDL now supports building with Android Studio and Gradle by default, and the old Ant project is available in android-project-ant
+* SDL now requires the API 19 SDK to build, but can still target devices down to API 14 (Android 4.0.1)
+* Added SDL_IsAndroidTV() to tell whether the application is running on Android TV
+
+Android / tvOS:
+* Added the hint SDL_HINT_TV_REMOTE_AS_JOYSTICK to control whether TV remotes should be listed as joystick devices (the default) or send keyboard events.
+
+Linux:
+* Added the hint SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR to control whether the X server should skip the compositor for the SDL application. This defaults to "1"
+* Added the hint SDL_HINT_VIDEO_DOUBLE_BUFFER to control whether the Raspberry Pi and KMSDRM video drivers should use double or triple buffering (the default)
+
+
 ---------------------------------------------------------------------------
 2.0.7:
 ---------------------------------------------------------------------------
diff --git a/libs/SDL2/docs/README-android.md b/libs/SDL2/docs/README-android.md
index 62874f4355ae2c46c6aec864f370d9a258e26eb8..7f3263dc3afe769c96f3503150281c5cb3b7bd60 100644
--- a/libs/SDL2/docs/README-android.md
+++ b/libs/SDL2/docs/README-android.md
@@ -4,20 +4,24 @@ Android
 Matt Styles wrote a tutorial on building SDL for Android with Visual Studio:
 http://trederia.blogspot.de/2017/03/building-sdl2-for-android-with-visual.html
 
-The rest of this README covers the old style build process.
+The rest of this README covers the Android gradle style build process.
+
+If you are using the older ant build process, it is no longer officially
+supported, but you can use the "android-project-ant" directory as a template.
+
 
 ================================================================================
  Requirements
 ================================================================================
 
-Android SDK (version 16 or later)
+Android SDK (version 26 or later)
 https://developer.android.com/sdk/index.html
 
-Android NDK r7 or later
+Android NDK r15c or later
 https://developer.android.com/tools/sdk/ndk/index.html
 
-Minimum API level supported by SDL: 10 (Android 2.3.3)
-Joystick support is available for API level >= 12 devices.
+Minimum API level supported by SDL: 14 (Android 4.0.1)
+
 
 ================================================================================
  How the port works
@@ -31,15 +35,12 @@ Joystick support is available for API level >= 12 devices.
 - This eventually produces a standard Android .apk package
 
 The Android Java code implements an "Activity" and can be found in:
-android-project/src/org/libsdl/app/SDLActivity.java
+android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
 
 The Java code loads your game code, the SDL shared library, and
 dispatches to native functions implemented in the SDL library:
 src/core/android/SDL_android.c
 
-Your project must include some glue code that starts your main() routine:
-src/main/android/SDL_android_main.c
-
 
 ================================================================================
  Building an app
@@ -74,71 +75,30 @@ For more complex projects, follow these instructions:
     
 1. Copy the android-project directory wherever you want to keep your projects
    and rename it to the name of your project.
-2. Move or symlink this SDL directory into the "<project>/jni" directory
-3. Edit "<project>/jni/src/Android.mk" to include your source files
-4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source
-
-If you want to use the Eclipse IDE, skip to the Eclipse section below.
+2. Move or symlink this SDL directory into the "<project>/app/jni" directory
+3. Edit "<project>/app/jni/src/Android.mk" to include your source files
 
-5. Create "<project>/local.properties" and use that to point to the Android SDK directory, by writing a line with the following form:
+4a. If you want to use Android Studio, simply open your <project> directory and start building.
 
-       sdk.dir=PATH_TO_ANDROID_SDK
-
-6. Run 'ant debug' in android/project. This compiles the .java and eventually 
-   creates a .apk with the native code embedded
-7. 'ant debug install' will push the apk to the device or emulator (if connected)
+4b. If you want to build manually, run './gradlew installDebug' in the project directory. This compiles the .java, creates an .apk with the native code embedded, and installs it on any connected Android device
 
 Here's an explanation of the files in the Android project, so you can customize them:
 
-    android-project/
-        AndroidManifest.xml	- package manifest. Among others, it contains the class name
-        			  of the main Activity and the package name of the application.
-        build.properties	- empty
-        build.xml		- build description file, used by ant. The actual application name
-        			  is specified here.
-        default.properties	- holds the target ABI for the application, android-10 and up
-        project.properties	- holds the target ABI for the application, android-10 and up
-        local.properties	- holds the SDK path, you should change this to the path to your SDK
+    android-project/app
+        build.gradle            - build info including the application version and SDK
+        src/main/AndroidManifest.xml	- package manifest. Among others, it contains the class name of the main Activity and the package name of the application.
         jni/			- directory holding native code
-        jni/Android.mk		- Android makefile that can call recursively the Android.mk files
-        			  in all subdirectories
+        jni/Application.mk	- Application JNI settings, including target platform and STL library
+        jni/Android.mk		- Android makefile that can call recursively the Android.mk files in all subdirectories
         jni/SDL/		- (symlink to) directory holding the SDL library files
         jni/SDL/Android.mk	- Android makefile for creating the SDL shared library
         jni/src/		- directory holding your C/C++ source
-        jni/src/Android.mk	- Android makefile that you should customize to include your 
-                                  source code and any library references
-        res/			- directory holding resources for your application
-        res/drawable-*		- directories holding icons for different phone hardware. Could be
-        			  one dir called "drawable".
-        res/layout/main.xml	- Usually contains a file main.xml, which declares the screen layout.
-        			  We don't need it because we use the SDL video output.
-        res/values/strings.xml	- strings used in your application, including the application name
-        			  shown on the phone.
-        src/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding
-        			  to SDL.  Be very careful changing this, as the SDL library relies
-        			  on this implementation.
-
-
-================================================================================
- Build an app with static linking of libSDL
-================================================================================
-
-This build uses the Android NDK module system.
-
-Instructions:
-1. Copy the android-project directory wherever you want to keep your projects
-   and rename it to the name of your project.
-2. Rename "<project>/jni/src/Android_static.mk" to "<project>/jni/src/Android.mk"
-   (overwrite the existing one)
-3. Edit "<project>/jni/src/Android.mk" to include your source files
-4. create and export an environment variable named NDK_MODULE_PATH that points
-   to the parent directory of this SDL directory. e.g.:
-
-       export NDK_MODULE_PATH="$PWD"/..
-
-5. Edit "<project>/src/org/libsdl/app/SDLActivity.java" and remove the call to
-   System.loadLibrary("SDL2").
-6. Run 'ndk-build' (a script provided by the NDK). This compiles the C source
+        jni/src/Android.mk	- Android makefile that you should customize to include your source code and any library references
+        src/main/assets/	- directory holding asset files for your application
+        src/main/res/		- directory holding resources for your application
+        src/main/res/mipmap-*	- directories holding icons for different phone hardware
+        src/main/res/values/strings.xml	- strings used in your application, including the application name
+        src/main/java/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding to SDL. Be very careful changing this, as the SDL library relies on this implementation. You should instead subclass this for your application.
 
 
 ================================================================================
@@ -171,25 +131,23 @@ Here's an example of a minimal class file:
 Then replace "SDLActivity" in AndroidManifest.xml with the name of your
 class, .e.g. "MyGame"
 
+
 ================================================================================
  Customizing your application icon
 ================================================================================
 
 Conceptually changing your icon is just replacing the "ic_launcher.png" files in
-the drawable directories under the res directory. There are four directories for
-different screen sizes. These can be replaced with one dir called "drawable",
-containing an icon file "ic_launcher.png" with dimensions 48x48 or 72x72.
+the drawable directories under the res directory. There are several directories
+for different screen sizes.
 
-You may need to change the name of your icon in AndroidManifest.xml to match
-this icon filename.
 
 ================================================================================
  Loading assets
 ================================================================================
 
-Any files you put in the "assets" directory of your android-project directory
-will get bundled into the application package and you can load them using the
-standard functions in SDL_rwops.h.
+Any files you put in the "app/src/main/assets" directory of your project
+directory will get bundled into the application package and you can load
+them using the standard functions in SDL_rwops.h.
 
 There are also a few Android specific functions that allow you to get other
 useful paths for saving and loading data:
@@ -211,6 +169,7 @@ disable this behaviour, see for example:
     
 http://ponystyle.com/blog/2010/03/26/dealing-with-asset-compression-in-android-apps/
 
+
 ================================================================================
  Pause / Resume behaviour
 ================================================================================
@@ -231,6 +190,7 @@ a specific message, (which is not yet implemented!) and restore your textures
 manually or quit the app (which is actually the kind of behaviour you'll see
 under iOS, if the OS can not restore your GL context it will just kill your app)
 
+
 ================================================================================
  Threads and the Java VM
 ================================================================================
@@ -246,6 +206,7 @@ Android_JNI_SetupThread() before doing anything else otherwise SDL will attach
 your thread automatically anyway (when you make an SDL call), but it'll never
 detach it.
 
+
 ================================================================================
  Using STL
 ================================================================================
@@ -253,34 +214,10 @@ detach it.
 You can use STL in your project by creating an Application.mk file in the jni
 folder and adding the following line:
 
-    APP_STL := stlport_static
+    APP_STL := c++_shared
 
-For more information check out CPLUSPLUS-SUPPORT.html in the NDK documentation.
-
-================================================================================
- Additional documentation
-================================================================================
-
-The documentation in the NDK docs directory is very helpful in understanding the
-build process and how to work with native code on the Android platform.
-
-The best place to start is with docs/OVERVIEW.TXT
-
-
-================================================================================
- Using Eclipse
-================================================================================
-
-First make sure that you've installed Eclipse and the Android extensions as described here:
-	https://developer.android.com/tools/sdk/eclipse-adt.html
-
-Once you've copied the SDL android project and customized it, you can create an Eclipse project from it:
- * File -> New -> Other
- * Select the Android -> Android Project wizard and click Next
- * Enter the name you'd like your project to have
- * Select "Create project from existing source" and browse for your project directory
- * Make sure the Build Target is set to Android 3.1 (API 12)
- * Click Finish
+For more information go here:
+	https://developer.android.com/ndk/guides/cpp-support
 
 
 ================================================================================
@@ -295,13 +232,11 @@ Especially useful is the info on setting up OpenGL ES 2.0 emulation.
 Notice that this software emulator is incredibly slow and needs a lot of disk space.
 Using a real device works better.
 
+
 ================================================================================
  Troubleshooting
 ================================================================================
 
-You can create and run an emulator from the Eclipse IDE:
- * Window -> Android SDK and AVD Manager
-
 You can see if adb can see any devices with the following command:
 
     adb devices
@@ -338,7 +273,10 @@ You can see the complete command line that ndk-build is using by passing V=1 on
 
     ndk-build V=1
 
-If your application crashes in native code, you can use addr2line to convert the
+If your application crashes in native code, you can use ndk-stack to get a symbolic stack trace:
+	https://developer.android.com/ndk/guides/ndk-stack
+
+If you want to go through the process manually, you can use addr2line to convert the
 addresses in the stack trace to lines in your code.
 
 For example, if your crash looks like this:
@@ -426,36 +364,30 @@ When you're done instrumenting with valgrind, you can disable the wrapper:
 
     adb shell setprop wrap.org.libsdl.app ""
 
+
 ================================================================================
  Graphics debugging
 ================================================================================
 
 If you are developing on a compatible Tegra-based tablet, NVidia provides
-Tegra Graphics Debugger at their website.  Because SDL2 dynamically loads EGL
+Tegra Graphics Debugger at their website. Because SDL2 dynamically loads EGL
 and GLES libraries, you must follow their instructions for installing the
-interposer library on a rooted device.  The non-rooted instructions are not
+interposer library on a rooted device. The non-rooted instructions are not
 compatible with applications that use SDL2 for video.
 
 The Tegra Graphics Debugger is available from NVidia here:
 https://developer.nvidia.com/tegra-graphics-debugger
 
+
 ================================================================================
- Why is API level 10 the minimum required?
+ Why is API level 14 the minimum required?
 ================================================================================
 
-API level 10 is the minimum required level at runtime (that is, on the device) 
-because SDL requires some functionality for running not
-available on older devices. Since the incorporation of joystick support into SDL,
-the minimum SDK required to *build* SDL is version 12. Devices running API levels
-10-11 are still supported, only with the joystick functionality disabled.
-
-Support for native OpenGL ES and ES2 applications was introduced in the NDK for
-API level 4 and 8. EGL was made a stable API in the NDK for API level 9, which
-has since then been obsoleted, with the recommendation to developers to bump the
-required API level to 10.
+The latest NDK toolchain doesn't support targeting earlier than API level 14.
 As of this writing, according to https://developer.android.com/about/dashboards/index.html
-about 90% of the Android devices accessing Google Play support API level 10 or
-higher (March 2013).
+about 99% of the Android devices accessing Google Play support API level 14 or
+higher (October 2017).
+
 
 ================================================================================
  A note regarding the use of the "dirty rectangles" rendering technique
@@ -475,6 +407,7 @@ screen each frame.
 
 Reference: http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html
 
+
 ================================================================================
  Known issues
 ================================================================================
diff --git a/libs/SDL2/docs/README-dynapi.md b/libs/SDL2/docs/README-dynapi.md
index bfaecb34496e5c1f142a2fadabd3b585dd4f84b3..b9a58bce1dd12db13076b927be9ee0d31861e588 100644
--- a/libs/SDL2/docs/README-dynapi.md
+++ b/libs/SDL2/docs/README-dynapi.md
@@ -64,7 +64,7 @@ level of indirection, we can do things like this:
     export SDL_DYNAMIC_API=/my/actual/libSDL-2.0.so.0
     ./MyGameThatIsStaticallyLinkedToSDL2
 
-And now, this game that is staticallly linked to SDL, can still be overridden 
+And now, this game that is statically linked to SDL, can still be overridden 
 with a newer, or better, SDL. The statically linked one will only be used as 
 far as calling into the jump table in this case. But in cases where no override
 is desired, the statically linked version will provide its own jump table, 
diff --git a/libs/SDL2/docs/README-raspberrypi.md b/libs/SDL2/docs/README-raspberrypi.md
index d64e7cb36ccf44d9dff4d940f6f667bb0d0c73f4..2c95e0649f78b4be2739271f8f45a5f16ad7fadd 100644
--- a/libs/SDL2/docs/README-raspberrypi.md
+++ b/libs/SDL2/docs/README-raspberrypi.md
@@ -27,6 +27,16 @@ OpenGL ES 2.x, it usually comes pre-installed, but in any case:
     
 sudo apt-get install libraspberrypi0 libraspberrypi-bin libraspberrypi-dev
 
+
+================================================================================
+ NEON
+================================================================================
+
+If your Pi has NEON support, make sure you add -mfpu=neon to your CFLAGS so
+that SDL will select some otherwise-disabled highly-optimized code. The
+original Pi units don't have NEON, the Pi2 probably does, and the Pi3
+definitely does.
+
 ================================================================================
  Cross compiling from x86 Linux
 ================================================================================
diff --git a/libs/SDL2/docs/README-winrt.md b/libs/SDL2/docs/README-winrt.md
index 8e993b57ad8f3b34b615ba4f5d8c7e5791eca1f5..35b7e6d872e079568c4f6b3d810517a28a68a7f7 100644
--- a/libs/SDL2/docs/README-winrt.md
+++ b/libs/SDL2/docs/README-winrt.md
@@ -23,7 +23,7 @@ Requirements
     typically do not include support for creating WinRT apps, to note.
     (The "Community" editions of Visual C++ do, however, support both
     desktop/Win32 and WinRT development).
-  - Visual Studio 2017 can be used, however it is recommented that you install
+  - Visual Studio 2017 can be used, however it is recommended that you install
     the Visual C++ 2015 build tools.  These build tools can be installed
     using VS 2017's installer.  Be sure to also install the workload for
     "Universal Windows Platform development", its optional component, the
@@ -33,7 +33,7 @@ Requirements
     earlier versions of Windows, such as Windows 7, is not always supported
     by Visual Studio, and you may get error(s) when attempting to do so.
   - Visual C++ 2012 can only build apps that target versions 8.0 of Windows,
-    or  Windows Phone.  8.0-targetted apps will run on devices running 8.1
+    or  Windows Phone.  8.0-targeted apps will run on devices running 8.1
     editions of Windows, however they will not be able to take advantage of
     8.1-specific features.
   - Visual C++ 2013 cannot create app projects that target Windows 8.0.
@@ -54,7 +54,7 @@ Requirements
 Status
 ------
 
-Here is a rough list of what works, and what doens't:
+Here is a rough list of what works, and what doesn't:
 
 * What works:
   * compilation via Visual C++ 2012 through 2015
@@ -70,7 +70,10 @@ Here is a rough list of what works, and what doens't:
     SDL_GetPerformanceFrequency(), etc.)
   * file I/O via SDL_RWops
   * mouse input  (unsupported on Windows Phone)
-  * audio, via a modified version of SDL's XAudio2 backend
+  * audio, via SDL's WASAPI backend (if you want to record, your app must 
+    have "Microphone" capabilities enabled in its manifest, and the user must 
+    not have blocked access. Otherwise, capture devices will fail to work,
+    presenting as a device disconnect shortly after opening it.)
   * .DLL file loading.  Libraries *MUST* be packaged inside applications.  Loading
     anything outside of the app is not supported.
   * system path retrieval via SDL's filesystem APIs
diff --git a/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll b/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll
index c21f747c2f45540809ff1fd901e2bb607ead0fff..70177904476cc7ab959c84e08a92df76cd0d748c 100755
Binary files a/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll and b/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll differ
diff --git a/libs/SDL2/i686-w64-mingw32/bin/sdl2-config b/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
index 7fdb82515a58a2d3a0764ab51adcc072bb91d4e5..e1060b3f2d78da06616e639fb5a5316502e25694 100755
--- a/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
+++ b/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-prefix=/usr/local/i686-w64-mingw32
+prefix=/opt/local/i686-w64-mingw32
 exec_prefix=${prefix}
 exec_prefix_set=no
 libdir=${exec_prefix}/lib
@@ -39,17 +39,17 @@ while test $# -gt 0; do
       echo $exec_prefix
       ;;
     --version)
-      echo 2.0.7
+      echo 2.0.9
       ;;
     --cflags)
       echo -I${prefix}/include/SDL2  -Dmain=SDL_main
       ;;
     --libs)
-      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2  -mwindows
+      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2 -mwindows
       ;;
     --static-libs)
 #    --libs|--static-libs)
-      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2  -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc
+      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2 -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -static-libgcc
       ;;
     *)
       echo "${usage}" 1>&2
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
index 366d50fa39095f0185247d490b31753351ef887c..fc35a419efd9076076aca339303a2937d5e6ada7 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,6 +51,7 @@
 #include "SDL_power.h"
 #include "SDL_render.h"
 #include "SDL_rwops.h"
+#include "SDL_sensor.h"
 #include "SDL_shape.h"
 #include "SDL_system.h"
 #include "SDL_thread.h"
@@ -80,10 +81,11 @@ extern "C" {
 #define SDL_INIT_HAPTIC         0x00001000u
 #define SDL_INIT_GAMECONTROLLER 0x00002000u  /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
 #define SDL_INIT_EVENTS         0x00004000u
+#define SDL_INIT_SENSOR         0x00008000u
 #define SDL_INIT_NOPARACHUTE    0x00100000u  /**< compatibility; this flag is ignored. */
 #define SDL_INIT_EVERYTHING ( \
                 SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
-                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
+                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \
             )
 /* @} */
 
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
index 90abbe39b6f1e5bd7e0bfa3d54b00954efe06e9a..b38f928ae14bb68e916bae1048a4c8648a1a20d8 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
index 36e37f3b786840231bf87fddf563c695037c7fc5..b2287748c8f87973ef2aef5093812c0065b89725 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -158,6 +158,9 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
 #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("lwsync" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("lwsync" : : : "memory")
+#elif defined(__GNUC__) && defined(__aarch64__)
+#define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
+#define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #elif defined(__GNUC__) && defined(__arm__)
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
index f119c2b2678fc531efe1d3ecc8b1f1751169de53..d3e1bface4d406c3d6c1c3f141a36a3fce8e926b 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -140,7 +140,8 @@ typedef Uint16 SDL_AudioFormat;
 #define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE    0x00000001
 #define SDL_AUDIO_ALLOW_FORMAT_CHANGE       0x00000002
 #define SDL_AUDIO_ALLOW_CHANNELS_CHANGE     0x00000004
-#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
+#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE      0x00000008
+#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
 /* @} */
 
 /* @} *//* Audio flags */
@@ -527,7 +528,7 @@ extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioForm
  *
  *  \param stream The stream the audio data is being added to
  *  \param buf A pointer to the audio data to add
- *  \param int The number of bytes to write to the stream
+ *  \param len The number of bytes to write to the stream
  *  \return 0 on success, or -1 on error.
  *
  *  \sa SDL_NewAudioStream
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
index bc28572902181c1edf67998fe3800c0269b4c451..eb8322f0d0a181b364871c28df42010ead3f17b1 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
index 9abd0bd4cf11c6d4d9931a20f21db32e2af0cdc6..36a5ea76f0c52c4364cb5f156cdf7252c0441ecc 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
index 341f4ba42b17e2025a5a27ecaa3925e3f618c1ad..f28751ebb8ffe5c67f17ccab94f2a55165fea4c8 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
index 1bbb83848142162b87676b35e03d964d5bec56dd..c58be8e72ee0dbb9e73f94be9d8c2c595aa630e5 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -82,6 +82,9 @@ typedef unsigned int uintptr_t;
 #define HAVE_DSOUND_H 1
 #define HAVE_DXGI_H 1
 #define HAVE_XINPUT_H 1
+#define HAVE_MMDEVICEAPI_H 1
+#define HAVE_AUDIOCLIENT_H 1
+#define HAVE_ENDPOINTVOLUME_H 1
 
 /* This is disabled by default to avoid C runtime dependencies and manifest requirements */
 #ifdef HAVE_LIBC
@@ -109,13 +112,15 @@ typedef unsigned int uintptr_t;
 #define HAVE_MEMCMP 1
 #define HAVE_STRLEN 1
 #define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-#define HAVE__STRLWR 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__STRUPR */
+/* #undef HAVE__STRLWR */
 #define HAVE_STRCHR 1
 #define HAVE_STRRCHR 1
 #define HAVE_STRSTR 1
-#define HAVE__LTOA 1
-#define HAVE__ULTOA 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__LTOA */
+/* #undef HAVE__ULTOA */
 #define HAVE_STRTOL 1
 #define HAVE_STRTOUL 1
 #define HAVE_STRTOD 1
@@ -125,30 +130,45 @@ typedef unsigned int uintptr_t;
 #define HAVE_STRNCMP 1
 #define HAVE__STRICMP 1
 #define HAVE__STRNICMP 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE__COPYSIGN 1
+#define HAVE_ACOS   1
+#define HAVE_ACOSF  1
+#define HAVE_ASIN   1
+#define HAVE_ASINF  1
+#define HAVE_ATAN   1
+#define HAVE_ATANF  1
+#define HAVE_ATAN2  1
+#define HAVE_ATAN2F 1
+#define HAVE_CEILF  1
+#define HAVE__COPYSIGN  1
+#define HAVE_COS    1
+#define HAVE_COSF   1
+#define HAVE_EXP    1
+#define HAVE_EXPF   1
+#define HAVE_FABS   1
+#define HAVE_FABSF  1
+#define HAVE_FLOOR  1
+#define HAVE_FLOORF 1
+#define HAVE_FMOD   1
+#define HAVE_FMODF  1
+#define HAVE_LOG    1
+#define HAVE_LOGF   1
+#define HAVE_LOG10  1
+#define HAVE_LOG10F 1
+#define HAVE_POW    1
+#define HAVE_POWF   1
+#define HAVE_SIN    1
+#define HAVE_SINF   1
+#define HAVE_SQRT   1
+#define HAVE_SQRTF  1
+#define HAVE_TAN    1
+#define HAVE_TANF   1
 #if defined(_MSC_VER)
 /* These functions were added with the VC++ 2013 C runtime library */
 #if _MSC_VER >= 1800
 #define HAVE_STRTOLL 1
 #define HAVE_VSSCANF 1
 #define HAVE_SCALBN 1
+#define HAVE_SCALBNF    1
 #endif
 /* This function is available with at least the VC++ 2008 C runtime library */
 #if _MSC_VER >= 1400
@@ -166,7 +186,6 @@ typedef unsigned int uintptr_t;
 /* Enable various audio drivers */
 #define SDL_AUDIO_DRIVER_WASAPI 1
 #define SDL_AUDIO_DRIVER_DSOUND 1
-#define SDL_AUDIO_DRIVER_XAUDIO2    0
 #define SDL_AUDIO_DRIVER_WINMM  1
 #define SDL_AUDIO_DRIVER_DISK   1
 #define SDL_AUDIO_DRIVER_DUMMY  1
@@ -174,9 +193,13 @@ typedef unsigned int uintptr_t;
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
 #define SDL_JOYSTICK_XINPUT 1
+#define SDL_JOYSTICK_HIDAPI 1
 #define SDL_HAPTIC_DINPUT   1
 #define SDL_HAPTIC_XINPUT   1
 
+/* Enable the dummy sensor driver */
+#define SDL_SENSOR_DUMMY  1
+
 /* Enable various shared object loading systems */
 #define SDL_LOADSO_WINDOWS  1
 
@@ -194,7 +217,7 @@ typedef unsigned int uintptr_t;
 #define SDL_VIDEO_RENDER_D3D    1
 #endif
 #ifndef SDL_VIDEO_RENDER_D3D11
-#define SDL_VIDEO_RENDER_D3D11	0
+#define SDL_VIDEO_RENDER_D3D11  0
 #endif
 
 /* Enable OpenGL support */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
index 94b64b03bc5dd394af7f2ccfc5968fb1c0e9dfc5..ee3a47e841242fdae7e697f6b5de18a2a47c1ecf 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,27 +51,35 @@
 #include <intrin.h>
 #else
 #ifdef __ALTIVEC__
-#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__)
+#if defined(HAVE_ALTIVEC_H) && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H)
 #include <altivec.h>
 #undef pixel
+#undef bool
 #endif
 #endif
-#ifdef __MMX__
-#include <mmintrin.h>
+#if defined(__ARM_NEON__) && !defined(SDL_DISABLE_ARM_NEON_H)
+#include <arm_neon.h>
 #endif
-#ifdef __3dNOW__
+#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
 #include <mm3dnow.h>
 #endif
-#ifdef __SSE__
+#if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
+#include <immintrin.h>
+#else
+#if defined(__MMX__) && !defined(SDL_DISABLE_MMINTRIN_H)
+#include <mmintrin.h>
+#endif
+#if defined(__SSE__) && !defined(SDL_DISABLE_XMMINTRIN_H)
 #include <xmmintrin.h>
 #endif
-#ifdef __SSE2__
+#if defined(__SSE2__) && !defined(SDL_DISABLE_EMMINTRIN_H)
 #include <emmintrin.h>
 #endif
-#ifdef __SSE3__
+#if defined(__SSE3__) && !defined(SDL_DISABLE_PMMINTRIN_H)
 #include <pmmintrin.h>
 #endif
-#endif
+#endif /* HAVE_IMMINTRIN_H */
+#endif /* compiler version */
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -154,6 +162,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
 
+/**
+ *  This function returns true if the CPU has AVX-512F (foundation) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
+
 /**
  *  This function returns true if the CPU has NEON (ARM SIMD) features.
  */
@@ -164,7 +177,6 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
  */
 extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
 
-
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
index e47fbe8624700058a55aff35c8cd39081a19695f..d65ed437c33fe307657aca04f192de87e0ff55e9 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -24,7 +24,7 @@
  *
  *  This is a simple file to encapsulate the EGL API headers.
  */
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
index 3eda7f2871144111f5cdfb24e0d57dd988c440c4..ed0bf5ba8f94888115422d06601ff4200119a9e6 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
index 49be9827e182ae56227e8dde300b7e8c03f8cfb8..c0e46298e8ffdbc6cf6abc4381a7ba9e2dcf1a33 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
index 0fc09bc37d795c8b5a4c34bebf9c78134a4c499f..af22eb6466661378e252d090b1504471f74833a8 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -85,6 +85,9 @@ typedef enum
                                      Called on Android in onResume()
                                 */
 
+    /* Display events */
+    SDL_DISPLAYEVENT   = 0x150,  /**< Display state change */
+
     /* Window events */
     SDL_WINDOWEVENT    = 0x200, /**< Window state change */
     SDL_SYSWMEVENT,             /**< System specific event */
@@ -144,6 +147,9 @@ typedef enum
     SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
     SDL_AUDIODEVICEREMOVED,        /**< An audio device has been removed. */
 
+    /* Sensor events */
+    SDL_SENSORUPDATE = 0x1200,     /**< A sensor was updated */
+
     /* Render events */
     SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
     SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
@@ -168,6 +174,21 @@ typedef struct SDL_CommonEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_CommonEvent;
 
+/**
+ *  \brief Display state change event data (event.display.*)
+ */
+typedef struct SDL_DisplayEvent
+{
+    Uint32 type;        /**< ::SDL_DISPLAYEVENT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint32 display;     /**< The associated display index */
+    Uint8 event;        /**< ::SDL_DisplayEventID */
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
+    Sint32 data1;       /**< event dependent data */
+} SDL_DisplayEvent;
+
 /**
  *  \brief Window state change event data (event.window.*)
  */
@@ -471,6 +492,17 @@ typedef struct SDL_DropEvent
 } SDL_DropEvent;
 
 
+/**
+ *  \brief Sensor event structure (event.sensor.*)
+ */
+typedef struct SDL_SensorEvent
+{
+    Uint32 type;        /**< ::SDL_SENSORUPDATE */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Sint32 which;       /**< The instance ID of the sensor */
+    float data[6];      /**< Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData() */
+} SDL_SensorEvent;
+
 /**
  *  \brief The "quit requested" event
  */
@@ -526,6 +558,7 @@ typedef union SDL_Event
 {
     Uint32 type;                    /**< Event type, shared with all events */
     SDL_CommonEvent common;         /**< Common event data */
+    SDL_DisplayEvent display;       /**< Window event data */
     SDL_WindowEvent window;         /**< Window event data */
     SDL_KeyboardEvent key;          /**< Keyboard event data */
     SDL_TextEditingEvent edit;      /**< Text editing event data */
@@ -542,6 +575,7 @@ typedef union SDL_Event
     SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
     SDL_AudioDeviceEvent adevice;   /**< Audio device event data */
+    SDL_SensorEvent sensor;         /**< Sensor event data */
     SDL_QuitEvent quit;             /**< Quit request event data */
     SDL_UserEvent user;             /**< Custom event data */
     SDL_SysWMEvent syswm;           /**< System dependent window event data */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
index a1c846ad0f07b71a61a60c147c709c2dc6e2c15f..fa6a1fa6e7b2ad4b9e341f6cf71c4e7fca925586 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
index c9215132ef50a7f214b7b4bf248d6fc73c3ff3f4..6ae9c95428907172257a93dfd6074865891f6571 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -175,6 +175,14 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index);
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
 
+/**
+ *  Get the mapping of a game controller.
+ *  This can be called before any controllers are opened.
+ *
+ *  \return the mapping string.  Must be freed with SDL_free().  Returns NULL if no mapping is available
+ */
+extern DECLSPEC char *SDLCALL SDL_GameControllerMappingForDeviceIndex(int joystick_index);
+
 /**
  *  Open a game controller for use.
  *  The index passed as an argument refers to the N'th game controller on the system.
@@ -196,6 +204,13 @@ extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
 
+/**
+ *  Get the player index of an opened game controller, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
+
 /**
  *  Get the USB vendor ID of an opened controller, if available.
  *  If the vendor ID isn't available this function returns 0.
@@ -345,6 +360,19 @@ SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
 extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
                                                           SDL_GameControllerButton button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param gamecontroller The controller to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a controller previously opened with SDL_GameControllerOpen().
  */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
index 2bba6a7294fa93240d5f6eefbd8d16c5773761ea..b223d80d44c3debd2de55420aaf1e907d1a08919 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
index 60daefaa709bbbc0a1796bd9af6f9be073cacedd..2ea1bfc1602ee571b0ac3238b183117fcb20f25d 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -117,6 +117,17 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* FIXME: For SDL 2.1, adjust all the magnitude variables to be Uint16 (0xFFFF).
+ *
+ * At the moment the magnitude variables are mixed between signed/unsigned, and
+ * it is also not made clear that ALL of those variables expect a max of 0x7FFF.
+ *
+ * Some platforms may have higher precision than that (Linux FF, Windows XInput)
+ * so we should fix the inconsistency in favor of higher possible precision,
+ * adjusting for platforms that use different scales.
+ * -flibit
+ */
+
 /**
  *  \typedef SDL_Haptic
  *
@@ -656,8 +667,8 @@ typedef struct SDL_HapticRamp
  * This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
  *
  * The Left/Right effect is used to explicitly control the large and small
- * motors, commonly found in modern game controllers. One motor is high
- * frequency, the other is low frequency.
+ * motors, commonly found in modern game controllers. The small (right) motor
+ * is high frequency, and the large (left) motor is low frequency.
  *
  * \sa SDL_HAPTIC_LEFTRIGHT
  * \sa SDL_HapticEffect
@@ -668,7 +679,7 @@ typedef struct SDL_HapticLeftRight
     Uint16 type;            /**< ::SDL_HAPTIC_LEFTRIGHT */
 
     /* Replay */
-    Uint32 length;          /**< Duration of the effect. */
+    Uint32 length;          /**< Duration of the effect in milliseconds. */
 
     /* Rumble */
     Uint16 large_magnitude; /**< Control of the large controller motor. */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
index 007a4bee05c0dc4ef90b1d24e88eb1137cedc945..4ee72e97d66db40a703620a9d0a162a952de1498 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,7 @@ extern "C" {
  *    "opengl"
  *    "opengles2"
  *    "opengles"
+ *    "metal"
  *    "software"
  *
  *  The default varies by platform, but it's the first one in the list that
@@ -210,6 +211,18 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_X11_NET_WM_PING      "SDL_VIDEO_X11_NET_WM_PING"
 
+/**
+ * \brief A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint should be used.
+ * 
+ * This variable can be set to the following values:
+ * "0" - Disable _NET_WM_BYPASS_COMPOSITOR
+ * "1" - Enable _NET_WM_BYPASS_COMPOSITOR
+ * 
+ * By default SDL will use _NET_WM_BYPASS_COMPOSITOR
+ * 
+ */
+#define SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"
+
 /**
  *  \brief  A variable controlling whether the window frame and title bar are interactive when the cursor is hidden 
  *
@@ -249,6 +262,16 @@ extern "C" {
  */
 #define SDL_HINT_GRAB_KEYBOARD              "SDL_GRAB_KEYBOARD"
 
+/**
+ *  \brief  A variable setting the double click time, in milliseconds.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME    "SDL_MOUSE_DOUBLE_CLICK_TIME"
+
+/**
+ *  \brief  A variable setting the double click radius, in pixels.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS    "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
+
 /**
  *  \brief  A variable setting the speed scale for mouse motion, in floating point, when the mouse is not in relative mode
  */
@@ -316,7 +339,7 @@ extern "C" {
 #define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
 
 /**
- *  \brief  A variable controlling which orientations are allowed on iOS.
+ *  \brief  A variable controlling which orientations are allowed on iOS/Android.
  *
  *  In some circumstances it is necessary to be able to explicitly control
  *  which UI orientations are allowed.
@@ -354,17 +377,37 @@ extern "C" {
  */
 #define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION"
 
+/**
+ * \brief  A variable controlling whether the home indicator bar on iPhone X
+ *         should be hidden.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - The indicator bar is not hidden (default for windowed applications)
+ *    "1"       - The indicator bar is hidden and is shown when the screen is touched (useful for movie playback applications)
+ *    "2"       - The indicator bar is dim and the first swipe makes it visible and the second swipe performs the "home" action (default for fullscreen applications)
+ */
+#define SDL_HINT_IOS_HIDE_HOME_INDICATOR "SDL_IOS_HIDE_HOME_INDICATOR"
+
 /**
  *  \brief  A variable controlling whether the Android / iOS built-in
- *  accelerometer should be listed as a joystick device, rather than listing
- *  actual joysticks only.
+ *  accelerometer should be listed as a joystick device.
  *
  *  This variable can be set to the following values:
- *    "0"       - List only real joysticks and accept input from them
- *    "1"       - List real joysticks along with the accelerometer as if it were a 3 axis joystick (the default).
+ *    "0"       - The accelerometer is not listed as a joystick
+ *    "1"       - The accelerometer is available as a 3 axis joystick (the default).
  */
 #define SDL_HINT_ACCELEROMETER_AS_JOYSTICK "SDL_ACCELEROMETER_AS_JOYSTICK"
 
+/**
+ *  \brief  A variable controlling whether the Android / tvOS remotes
+ *  should be listed as joystick devices, instead of sending keyboard events.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Remotes send enter/escape/arrow key events
+ *    "1"       - Remotes are available as 2 axis, 2 button joysticks (the default).
+ */
+#define SDL_HINT_TV_REMOTE_AS_JOYSTICK "SDL_TV_REMOTE_AS_JOYSTICK"
+
 /**
  *  \brief  A variable that lets you disable the detection and use of Xinput gamepad devices
  *
@@ -432,6 +475,88 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
+/**
+ *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI drivers are not used
+ *    "1"       - HIDAPI drivers are used (the default)
+ *
+ *  This variable is the default for all drivers, but can be overridden by the hints for specific drivers below.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI "SDL_JOYSTICK_HIDAPI"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4 "SDL_JOYSTICK_HIDAPI_PS4"
+
+/**
+ *  \brief  A variable controlling whether extended input reports should be used for PS4 controllers when using the HIDAPI driver.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - extended reports are not enabled (the default)
+ *    "1"       - extended reports
+ *
+ *  Extended input reports allow rumble on Bluetooth PS4 controllers, but
+ *  break DirectInput handling for applications that don't use SDL.
+ *
+ *  Once extended reports are enabled, they can not be disabled without
+ *  power cycling the controller.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
+
+/**
+ *  \brief  A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
+ *
+ *  The variable can be set to the following values:
+ *    "0"       - Do not scan for Steam Controllers
+ *    "1"       - Scan for Steam Controllers (the default)
+ *
+ *  The default value is "1".  This hint must be set before initializing the joystick subsystem.
+ */
+#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
+
+
 /**
  *  \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
  *      This is a debugging aid for developers and not expected to be used by end users. The default is "1"
@@ -494,6 +619,10 @@ extern "C" {
 *  This is specially useful if you build SDL against a non glibc libc library (such as musl) which
 *  provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
 *  Support for this hint is currently available only in the pthread, Windows, and PSP backend.
+*
+*  Instead of this hint, in 2.0.9 and later, you can use
+*  SDL_CreateThreadWithStackSize(). This hint only works with the classic
+*  SDL_CreateThread().
 */
 #define SDL_HINT_THREAD_STACK_SIZE              "SDL_THREAD_STACK_SIZE"
 
@@ -719,6 +848,35 @@ extern "C" {
  */
 #define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
 
+ /**
+ * \brief A variable to control whether we trap the Android back button to handle it manually.
+ *        This is necessary for the right mouse button to work on some Android devices, or
+ *        to be able to trap the back button for use in your code reliably.  If set to true,
+ *        the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of 
+ *        SDL_SCANCODE_AC_BACK.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - Back button will be handled as usual for system. (default)
+ *   "1"       - Back button will be trapped, allowing you to handle the key press
+ *               manually.  (This will also let right mouse click work on systems 
+ *               where the right mouse button functions as back.)
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON"
+
+ /**
+ * \brief A variable to control whether the return key on the soft keyboard
+ *        should hide the soft keyboard on Android and iOS.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - The return key will be handled as a key event. This is the behaviour of SDL <= 2.0.3. (default)
+ *   "1"       - The return key will hide the keyboard.
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_RETURN_KEY_HIDES_IME "SDL_RETURN_KEY_HIDES_IME"
+
 /**
  *  \brief override the binding element for keyboard inputs for Emscripten builds
  *
@@ -752,7 +910,7 @@ extern "C" {
  *   "0"       - SDL will generate a window-close event when it sees Alt+F4.
  *   "1"       - SDL will only do normal key handling for Alt+F4.
  */
-#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4	"SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
+#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
 
 /**
  *  \brief Prevent SDL from using version 4 of the bitmap header when saving BMPs.
@@ -797,6 +955,24 @@ extern "C" {
  */
 #define SDL_HINT_RPI_VIDEO_LAYER           "SDL_RPI_VIDEO_LAYER"
 
+/**
+ * \brief Tell the video driver that we only want a double buffer.
+ *
+ * By default, most lowlevel 2D APIs will use a triple buffer scheme that 
+ * wastes no CPU time on waiting for vsync after issuing a flip, but
+ * introduces a frame of latency. On the other hand, using a double buffer
+ * scheme instead is recommended for cases where low latency is an important
+ * factor because we save a whole frame of latency.
+ * We do so by waiting for vsync immediately after issuing a flip, usually just
+ * after eglSwapBuffers call in the backend's *_SwapWindow function.
+ *
+ * Since it's driver-specific, it's only supported where possible and
+ * implemented. Currently supported the following drivers:
+ * - KMSDRM (kmsdrm)
+ * - Raspberry Pi (raspberrypi)
+ */
+#define SDL_HINT_VIDEO_DOUBLE_BUFFER      "SDL_VIDEO_DOUBLE_BUFFER"
+
 /**
  *  \brief  A variable controlling what driver to use for OpenGL ES contexts.
  *
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
index f598dc828dafa2751d3aba2286059a8298d79aa3..6e05a9c2056cf7134c22459066d253e80e9a4315 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,10 +97,10 @@ typedef enum
 typedef enum
 {
     SDL_JOYSTICK_POWER_UNKNOWN = -1,
-    SDL_JOYSTICK_POWER_EMPTY,
-    SDL_JOYSTICK_POWER_LOW,
-    SDL_JOYSTICK_POWER_MEDIUM,
-    SDL_JOYSTICK_POWER_FULL,
+    SDL_JOYSTICK_POWER_EMPTY,   /* <= 5% */
+    SDL_JOYSTICK_POWER_LOW,     /* <= 20% */
+    SDL_JOYSTICK_POWER_MEDIUM,  /* <= 70% */
+    SDL_JOYSTICK_POWER_FULL,    /* <= 100% */
     SDL_JOYSTICK_POWER_WIRED,
     SDL_JOYSTICK_POWER_MAX
 } SDL_JoystickPowerLevel;
@@ -132,6 +132,12 @@ extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
 
+/**
+ *  Get the player index of a joystick, or -1 if it's not available
+ *  This can be called before any joysticks are opened.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetDevicePlayerIndex(int device_index);
+
 /**
  *  Return the GUID for the joystick at this index
  *  This can be called before any joysticks are opened.
@@ -194,6 +200,13 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
 
+/**
+ *  Get the player index of an opened joystick, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
+
 /**
  *  Return the GUID for this opened joystick
  */
@@ -361,6 +374,19 @@ extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
 extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
                                                     int button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param joystick The joystick to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a joystick previously opened with SDL_JoystickOpen().
  */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
index e78ca469082c793a8190331c01766a3e3374a5ba..87482317161a6e05324bf5ab769743b1a385b436 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
index c41e45ff61b6959937f7f4e912cef24064b72e1f..d7d5b1dbcdefce3777ee48eddcc46853eba2e584 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
index 6ea256c6ae5813dc7b00c269101b4e866fbb5fcc..da56fb452779ee015da429caa8da746c985b0ee0 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
index 356d0e1cf7492f54d82e5829a6030587400869d1..e12b6588601712bd217578226f143941ff019cbb 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
index 2af32360f7be842213bca1253268d5198c768377..98558217fc23ea63118899e44a710b7ba934c720 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -63,10 +63,13 @@
 /* On Android SDL provides a Java class in SDLActivity.java that is the
    main activity entry point.
 
-   See README-android.md for more details on extending that class.
+   See docs/README-android.md for more details on extending that class.
  */
 #define SDL_MAIN_NEEDED
 
+/* We need to export SDL_main so it can be launched from Java */
+#define SDLMAIN_DECLSPEC    DECLSPEC
+
 #elif defined(__NACL__)
 /* On NACL we use ppapi_simple to set up the application helper code,
    then wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before 
@@ -85,6 +88,10 @@
 #define C_LINKAGE
 #endif /* __cplusplus */
 
+#ifndef SDLMAIN_DECLSPEC
+#define SDLMAIN_DECLSPEC
+#endif
+
 /**
  *  \file SDL_main.h
  *
@@ -107,7 +114,7 @@
 /**
  *  The prototype for the application's main() function
  */
-extern C_LINKAGE DECLSPEC int SDL_main(int argc, char *argv[]);
+extern C_LINKAGE SDLMAIN_DECLSPEC int SDL_main(int argc, char *argv[]);
 
 
 #include "begin_code.h"
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
index c326d8f01098b147e1bff015fb8e355e37f00744..b7be59d88f50ad7686b794ca13cd66f29e7ef557 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
index 6001bd46c1e80270d85d18dd72025b0c17f2722a..d3c9f6156cba36ecff91929d7a7eda0784b4af69 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
index 0272379e55e16bb25a913f9b4e4ca11809af7b56..ba4247ced8176dd98396d552536bc4646faa7841 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
index 8095ed3ffd4df27fb77a15eebcd532536c3efc09..ecd863f4ca873b55249601228efc5fc578aa4fb1 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
index 314dd57eda395c3b9e7bcbaf2d3749b9aa01864d..253d9c93a96f875aa53a51a5a615d4d732d9926d 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
index 800c593070a9ea28a1f01c1d2b84e0f15ad2b33c..18dd984b3ed21bf5fd3bbfcf1a8a34fe58dfca6f 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
index 102f2f3fa7075c34639c03109939460ab2e7c2cc..6ccecf216572b4c9514bded0fd0a1c54690e57d8 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
index 04246689f5957e5170ad6be433e089e2483ea85a..0b4364b185231109d61663b4acb50e60e1d8fa16 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -287,7 +287,9 @@ enum
     SDL_PIXELFORMAT_NV12 =      /**< Planar mode: Y + U/V interleaved  (2 planes) */
         SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
     SDL_PIXELFORMAT_NV21 =      /**< Planar mode: Y + V/U interleaved  (2 planes) */
-        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
+        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'),
+    SDL_PIXELFORMAT_EXTERNAL_OES =      /**< Android video texture format */
+        SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ')
 };
 
 typedef struct SDL_Color
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
index 9dde385fa67364dbcfcf22598e33961970c4348e..7dea4ce940fe02f1b233d15ec6a75c9452a0422c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -121,7 +121,12 @@
 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
 /* Try to find out if we're compiling for WinRT or non-WinRT */
 #if defined(_MSC_VER) && defined(__has_include)
-#define HAVE_WINAPIFAMILY_H __has_include(<winapifamily.h>)
+#if __has_include(<winapifamily.h>)
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
 /* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
 #elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
 #define HAVE_WINAPIFAMILY_H 1
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
index d48e8a3795dfd0d9f8a1cd9ad07ba1c54b1b0d7c..a4fe8a9359c247678ad56a47f8b8106fa465f4a9 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
index 9283c381050a4013097e533a1723c64bb6392938..fea56a8d88b6a0ac9e12807d693628f80991bc3e 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
index c4f6d74b339ddc7b71372221758dc229043362fd..543bb618694ea9d4b5383e71a7c35b666b9e754c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
index ea6ef9ff645cef9e643162828ccb6b5173d1b732..d336192974f4cedab0497ad6ac60aaba19f3f389 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -898,6 +898,27 @@ extern DECLSPEC int SDLCALL SDL_GL_BindTexture(SDL_Texture *texture, float *texw
  */
 extern DECLSPEC int SDLCALL SDL_GL_UnbindTexture(SDL_Texture *texture);
 
+/**
+ *  \brief Get the CAMetalLayer associated with the given Metal renderer
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return CAMetalLayer* on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalCommandEncoder()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
+
+/**
+ *  \brief Get the Metal command encoder for the current frame
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return id<MTLRenderCommandEncoder> on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalLayer()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
index 9376093ee76bd46fbb70196e87673cda9d53ccd6..92fbe67b132156d911795af5e14b335d15645c66 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
@@ -1,2 +1,2 @@
-#define SDL_REVISION "hg-11645:2088cd828335"
-#define SDL_REVISION_NUMBER 11645
+#define SDL_REVISION "hg-12373:8feb5da6f2fb"
+#define SDL_REVISION_NUMBER 12373
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
index 7f0cbdfd55d5fabdd8ff80fc5ec605a7dd70bc0c..0960699d4857bb302e9024e7263c89a725a9a276 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
index 1d55212048560455d110797913a3dde07416768c..63871aa3b10beed824756b430687a3e16d7ebe44 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac163a8cd1be73201742fe56293ddc840653f706
--- /dev/null
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h
@@ -0,0 +1,251 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_sensor.h
+ *
+ *  Include file for SDL sensor event handling
+ *
+ */
+
+#ifndef _SDL_sensor_h
+#define _SDL_sensor_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ *  \brief SDL_sensor.h
+ *
+ *  In order to use these functions, SDL_Init() must have been called
+ *  with the ::SDL_INIT_SENSOR flag.  This causes SDL to scan the system
+ *  for sensors, and load appropriate drivers.
+ */
+
+struct _SDL_Sensor;
+typedef struct _SDL_Sensor SDL_Sensor;
+
+/**
+ * This is a unique ID for a sensor for the time it is connected to the system,
+ * and is never reused for the lifetime of the application.
+ *
+ * The ID value starts at 0 and increments from there. The value -1 is an invalid ID.
+ */
+typedef Sint32 SDL_SensorID;
+
+/* The different sensors defined by SDL
+ *
+ * Additional sensors may be available, using platform dependent semantics.
+ *
+ * Hare are the additional Android sensors:
+ * https://developer.android.com/reference/android/hardware/SensorEvent.html#values
+ */
+typedef enum
+{
+    SDL_SENSOR_INVALID = -1,    /**< Returned for an invalid sensor */
+    SDL_SENSOR_UNKNOWN,         /**< Unknown sensor type */
+    SDL_SENSOR_ACCEL,           /**< Accelerometer */
+    SDL_SENSOR_GYRO             /**< Gyroscope */
+} SDL_SensorType;
+
+/**
+ * Accelerometer sensor
+ *
+ * The accelerometer returns the current acceleration in SI meters per
+ * second squared. This includes gravity, so a device at rest will have
+ * an acceleration of SDL_STANDARD_GRAVITY straight down.
+ *
+ * values[0]: Acceleration on the x axis
+ * values[1]: Acceleration on the y axis
+ * values[2]: Acceleration on the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+#define SDL_STANDARD_GRAVITY    9.80665f
+
+/**
+ * Gyroscope sensor
+ *
+ * The gyroscope returns the current rate of rotation in radians per second.
+ * The rotation is positive in the counter-clockwise direction. That is,
+ * an observer looking from a positive location on one of the axes would
+ * see positive rotation on that axis when it appeared to be rotating
+ * counter-clockwise.
+ *
+ * values[0]: Angular speed around the x axis
+ * values[1]: Angular speed around the y axis
+ * values[2]: Angular speed around the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+
+/* Function prototypes */
+
+/**
+ *  \brief Count the number of sensors attached to the system right now
+ */
+extern DECLSPEC int SDLCALL SDL_NumSensors(void);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ * 
+ *  \return The sensor name, or NULL if device_index is out of range.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetDeviceName(int device_index);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetDeviceType(int device_index);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if device_index is out of range.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetDeviceNonPortableType(int device_index);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetDeviceInstanceID(int device_index);
+
+/**
+ *  \brief Open a sensor for use.
+ *
+ *  The index passed as an argument refers to the N'th sensor on the system.
+ *
+ *  \return A sensor identifier, or NULL if an error occurred.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorOpen(int device_index);
+
+/**
+ * Return the SDL_Sensor associated with an instance id.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorFromInstanceID(SDL_SensorID instance_id);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  \return The sensor name, or NULL if the sensor is NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetName(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetNonPortableType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetInstanceID(SDL_Sensor *sensor);
+
+/**
+ *  Get the current state of an opened sensor.
+ *
+ *  The number of values and interpretation of the data is sensor dependent.
+ *
+ *  \param sensor The sensor to query
+ *  \param data A pointer filled with the current sensor state
+ *  \param num_values The number of values to write to data
+ *
+ *  \return 0 or -1 if an error occurred.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values);
+
+/**
+ *  Close a sensor previously opened with SDL_SensorOpen()
+ */
+extern DECLSPEC void SDLCALL SDL_SensorClose(SDL_Sensor * sensor);
+
+/**
+ *  Update the current state of the open sensors.
+ *
+ *  This is called automatically by the event loop if sensor events are enabled.
+ *
+ *  This needs to be called from the thread that initialized the sensor subsystem.
+ */
+extern DECLSPEC void SDLCALL SDL_SensorUpdate(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_sensor_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
index 9e492d93a4d1f6e42bcb2bbfec31fd71520cbaaa..40a6baaaec3d4d7e46c1da1fed54949123421035 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
index 72402299f2da1892dd2224bc436b1822007f9b51..e373bc380f68867e5638b8f6ea26521a66a906ee 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -86,6 +86,28 @@
 #ifdef HAVE_FLOAT_H
 # include <float.h>
 #endif
+#if defined(HAVE_ALLOCA) && !defined(alloca)
+# if defined(HAVE_ALLOCA_H)
+#  include <alloca.h>
+# elif defined(__GNUC__)
+#  define alloca __builtin_alloca
+# elif defined(_MSC_VER)
+#  include <malloc.h>
+#  define alloca _alloca
+# elif defined(__WATCOMC__)
+#  include <malloc.h>
+# elif defined(__BORLANDC__)
+#  include <malloc.h>
+# elif defined(__DMC__)
+#  include <stdlib.h>
+# elif defined(__AIX__)
+#pragma alloca
+# elif defined(__MRC__)
+void *alloca(unsigned);
+# else
+char *alloca();
+# endif
+#endif
 
 /**
  *  The number of elements in an array.
@@ -328,28 +350,6 @@ SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
 extern "C" {
 #endif
 
-#if defined(HAVE_ALLOCA) && !defined(alloca)
-# if defined(HAVE_ALLOCA_H)
-#  include <alloca.h>
-# elif defined(__GNUC__)
-#  define alloca __builtin_alloca
-# elif defined(_MSC_VER)
-#  include <malloc.h>
-#  define alloca _alloca
-# elif defined(__WATCOMC__)
-#  include <malloc.h>
-# elif defined(__BORLANDC__)
-#  include <malloc.h>
-# elif defined(__DMC__)
-#  include <stdlib.h>
-# elif defined(__AIX__)
-#pragma alloca
-# elif defined(__MRC__)
-void *alloca(unsigned);
-# else
-char *alloca();
-# endif
-#endif
 #ifdef HAVE_ALLOCA
 #define SDL_stack_alloc(type, count)    (type*)alloca(sizeof(type)*(count))
 #define SDL_stack_free(data)
@@ -445,12 +445,12 @@ SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 #endif
 }
 
-
 extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 
 extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
 
+extern DECLSPEC wchar_t *SDLCALL SDL_wcsdup(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
 extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
@@ -501,18 +501,35 @@ extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size
 #endif
 
 extern DECLSPEC double SDLCALL SDL_acos(double x);
+extern DECLSPEC float SDLCALL SDL_acosf(float x);
 extern DECLSPEC double SDLCALL SDL_asin(double x);
+extern DECLSPEC float SDLCALL SDL_asinf(float x);
 extern DECLSPEC double SDLCALL SDL_atan(double x);
+extern DECLSPEC float SDLCALL SDL_atanf(float x);
 extern DECLSPEC double SDLCALL SDL_atan2(double x, double y);
+extern DECLSPEC float SDLCALL SDL_atan2f(float x, float y);
 extern DECLSPEC double SDLCALL SDL_ceil(double x);
+extern DECLSPEC float SDLCALL SDL_ceilf(float x);
 extern DECLSPEC double SDLCALL SDL_copysign(double x, double y);
+extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_cos(double x);
 extern DECLSPEC float SDLCALL SDL_cosf(float x);
+extern DECLSPEC double SDLCALL SDL_exp(double x);
+extern DECLSPEC float SDLCALL SDL_expf(float x);
 extern DECLSPEC double SDLCALL SDL_fabs(double x);
+extern DECLSPEC float SDLCALL SDL_fabsf(float x);
 extern DECLSPEC double SDLCALL SDL_floor(double x);
+extern DECLSPEC float SDLCALL SDL_floorf(float x);
+extern DECLSPEC double SDLCALL SDL_fmod(double x, double y);
+extern DECLSPEC float SDLCALL SDL_fmodf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_log(double x);
+extern DECLSPEC float SDLCALL SDL_logf(float x);
+extern DECLSPEC double SDLCALL SDL_log10(double x);
+extern DECLSPEC float SDLCALL SDL_log10f(float x);
 extern DECLSPEC double SDLCALL SDL_pow(double x, double y);
+extern DECLSPEC float SDLCALL SDL_powf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_scalbn(double x, int n);
+extern DECLSPEC float SDLCALL SDL_scalbnf(float x, int n);
 extern DECLSPEC double SDLCALL SDL_sin(double x);
 extern DECLSPEC float SDLCALL SDL_sinf(float x);
 extern DECLSPEC double SDLCALL SDL_sqrt(double x);
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
index 510690c9cffe37fa3153d547d87c9ed0089584c2..730d49fc805ec54d5725c7369db4578d194aa56a 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,6 +97,17 @@ typedef struct SDL_Surface
 typedef int (SDLCALL *SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
                                  struct SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ * \brief The formula used for converting between YUV and RGB
+ */
+typedef enum
+{
+    SDL_YUV_CONVERSION_JPEG,        /**< Full range JPEG */
+    SDL_YUV_CONVERSION_BT601,       /**< BT.601 (the default) */
+    SDL_YUV_CONVERSION_BT709,       /**< BT.709 */
+    SDL_YUV_CONVERSION_AUTOMATIC    /**< BT.601 for SD content, BT.709 for HD content */
+} SDL_YUV_CONVERSION_MODE;
+
 /**
  *  Allocate and free an RGB surface.
  *
@@ -237,6 +248,13 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface * surface,
 extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
                                             int flag, Uint32 key);
 
+/**
+ *  \brief Returns whether the surface has a color key
+ *
+ *  \return SDL_TRUE if the surface has a color key, or SDL_FALSE if the surface is NULL or has no color key
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasColorKey(SDL_Surface * surface);
+
 /**
  *  \brief Gets the color key (transparent pixel) in a blittable surface.
  *
@@ -509,6 +527,20 @@ extern DECLSPEC int SDLCALL SDL_LowerBlitScaled
     (SDL_Surface * src, SDL_Rect * srcrect,
     SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ *  \brief Set the YUV conversion mode
+ */
+extern DECLSPEC void SDLCALL SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
+
+/**
+ *  \brief Get the YUV conversion mode
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionMode(void);
+
+/**
+ *  \brief Get the YUV conversion mode, returning the correct mode for the resolution when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionModeForResolution(int width, int height);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
index eb069b33d8127f026de8b57b1869ccf3297f75e6..4dc372d6b14bb7fd49f64f716d1f9f29e3a15fbc 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a
 #endif /* __WIN32__ */
 
 
+/* Platform specific functions for Linux */
+#ifdef __LINUX__
+
+/**
+   \brief Sets the UNIX nice value for a thread, using setpriority() if possible, and RealtimeKit if available.
+
+   \return 0 on success, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
+ 
+#endif /* __LINUX__ */
+	
 /* Platform specific functions for iOS */
 #if defined(__IPHONEOS__) && __IPHONEOS__
 
@@ -108,6 +120,26 @@ extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(void);
  */
 extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(void);
 
+/**
+   \brief Return true if the application is running on Android TV
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
+
+/**
+   \brief Return true if the application is running on a Chromebook
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void);
+
+/**
+  \brief Return true is the application is running on a Samsung DeX docking station
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void);
+
+/**
+ \brief Trigger the Android system back button behavior.
+ */
+extern DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
+
 /**
    See the official Android developer guide for more information:
    http://developer.android.com/guide/topics/data/data-storage.html
@@ -169,6 +201,25 @@ typedef enum
 } SDL_WinRT_Path;
 
 
+/**
+ *  \brief WinRT Device Family
+ */
+typedef enum
+{
+    /** \brief Unknown family  */
+    SDL_WINRT_DEVICEFAMILY_UNKNOWN,
+
+    /** \brief Desktop family*/
+    SDL_WINRT_DEVICEFAMILY_DESKTOP,
+
+    /** \brief Mobile family (for example smartphone) */
+    SDL_WINRT_DEVICEFAMILY_MOBILE,
+
+    /** \brief XBox family */
+    SDL_WINRT_DEVICEFAMILY_XBOX,
+} SDL_WinRT_DeviceFamily;
+
+
 /**
  *  \brief Retrieves a WinRT defined path on the local file system
  *
@@ -203,8 +254,20 @@ extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path
  */
 extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
 
+/**
+ *  \brief Detects the device family of WinRT plattform on runtime
+ *
+ *  \return Device family
+ */
+extern DECLSPEC SDL_WinRT_DeviceFamily SDLCALL SDL_WinRTGetDeviceFamily();
+
 #endif /* __WINRT__ */
 
+/**
+ \brief Return true if the current device is a tablet.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsTablet(void);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
index 2d18afb6cf90173ca289b53f74dad013a3440909..f1c4021cc8b37be22124d28a99733d1e696e71e6 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -33,12 +33,6 @@
 #include "SDL_video.h"
 #include "SDL_version.h"
 
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  *  \file SDL_syswm.h
  *
@@ -110,6 +104,12 @@ typedef void *EGLSurface;
 #include "SDL_egl.h"
 #endif
 
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  *  These are the various supported windowing subsystems
  */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
index f55afcb02273929055de6bf3a8848c2025e3bda3..6cc373bf809ca34195c28d7ef465fffac49c0e89 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
index 11d8363942948261e7a2403c3556d7e45860ef8a..1788d7a206916e92ccc607c24d93805ec368c838 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
index 24eeb32af1b8731d95e28084a051b219480810be..be2e6b2aab48af89d8aab4986bd15bd0fc13bd68 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
index 9f4c4587ade92d8afe8d8102bd216db4458930e3..c22e447d8aee297971e6c51e4c1dd2fdb3a5cd52 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
index add480c349fd91512e3a3229f44858407529a106..3d235d07400f10b10297e533f7d74c2cf02bc394 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
index 58c9f9d5e5f3334e23df3bbcba45cc6483635f67..59cbdcad6bcb101764c689f915d8395866b6ea6a 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
index 6cf05747ad91914fe7155322876cd3ff6e2a28d6..8fcb9ebbfa1ba58da745c08e0eb0a322e00319c6 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
index 68c4bcb7c44ff1fb09722fa81be6fb5013917eef..8641e0a7e3ad9945ed5ec93813920017bcc06447 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
index 683d2f8a689e8d49b1c750493a6c04112a19b8e3..9c4dd5b82954fc21c15ff9027372ca3419c6252e 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
index 9f993fbbc880ded0f9c4c2dd81d838fb60753ed2..ebd44fb5021c3f4fc64dcab127780ab7da89ebd2 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
index 67ca7d1defbb70c02e83d43eef7f11ee6cbc81e5..0e4105768fdb6bd059ad867cb90d74637e28660c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
index 43b67f521be347be755fa725dfd2bdd6b96f6c01..4827ae6f2c372db861a635ae9faa32637f152a18 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
index 2b01922c3ed5b82aace74bce3c661ce7c8b62782..0eb414ff2e4db2488ac5671f9d1a91048d0f3b34 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
index d0f6575cd5ac7562cb5dba1ca84b5e94b4a3f029..554dd0b61d02481d6f665dbde0799361b1967632 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -54,12 +54,13 @@ typedef unsigned int SDL_TLSID;
 /**
  *  The SDL thread priority.
  *
- *  \note On many systems you require special privileges to set high priority.
+ *  \note On many systems you require special privileges to set high or time critical priority.
  */
 typedef enum {
     SDL_THREAD_PRIORITY_LOW,
     SDL_THREAD_PRIORITY_NORMAL,
-    SDL_THREAD_PRIORITY_HIGH
+    SDL_THREAD_PRIORITY_HIGH,
+    SDL_THREAD_PRIORITY_TIME_CRITICAL
 } SDL_ThreadPriority;
 
 /**
@@ -105,14 +106,24 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
 
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
+                 const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
+
+
 /**
  *  Create a thread.
  */
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #endif
 
 #elif defined(__OS2__)
@@ -132,15 +143,31 @@ extern DECLSPEC SDL_Thread *SDLCALL
 SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #endif
 
 #else
 
+/**
+ *  Create a thread with a default stack size.
+ *
+ *  This is equivalent to calling:
+ *  SDL_CreateThreadWithStackSize(fn, name, 0, data);
+ */
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+
 /**
  *  Create a thread.
  *
@@ -158,9 +185,17 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
  *   If a system imposes requirements, SDL will try to munge the string for
  *    it (truncate, etc), but the original string contents will be available
  *    from SDL_GetThreadName().
+ *
+ *   The size (in bytes) of the new stack can be specified. Zero means "use
+ *    the system default" which might be wildly different between platforms
+ *    (x86 Linux generally defaults to eight megabytes, an embedded device
+ *    might be a few kilobytes instead).
+ *
+ *   In SDL 2.1, stacksize will be folded into the original SDL_CreateThread
+ *    function.
  */
 extern DECLSPEC SDL_Thread *SDLCALL
-SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data);
 
 #endif
 
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
index 282625d3f0dc8dfe2b94fa48032d037cace0de3c..5600618ff4f8fbaacb2edf547ef8da1c182a0257 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
index db9e25ebdccad221a3c38bbce06b02bec65c3c2c..f4075e79a5b5dd486579aa374474e3927101abe1 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
index 06ee80cb358963b2fca3d8218a81595345e52671..4ac248c8c577f5150c8de8ad1b36df3bd4aea854 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
index 5b4c402486d6adb4e8ebaec3cfa4bee301e48e8b..31443e149adc071cba7431bc0cd47b007f1a0e22 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      7
+#define SDL_PATCHLEVEL      9
 
 /**
  *  \brief Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
index 6f6cda8b182b22160d97c0d9d5e684290419d0b9..461f13805101c9214ef4bd9b6df3143c3f093692 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -110,7 +110,9 @@ typedef enum
     SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
-    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
+    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported.
+                                                     On macOS NSHighResolutionCapable must be set true in the
+                                                     application's Info.plist for this to have any effect. */
     SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,      /**< window has mouse captured (unrelated to INPUT_GRABBED) */
     SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,      /**< window should always be above others */
     SDL_WINDOW_SKIP_TASKBAR  = 0x00010000,      /**< window should not be added to the taskbar */
@@ -167,6 +169,24 @@ typedef enum
     SDL_WINDOWEVENT_HIT_TEST        /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */
 } SDL_WindowEventID;
 
+/**
+ *  \brief Event subtype for display events
+ */
+typedef enum
+{
+    SDL_DISPLAYEVENT_NONE,          /**< Never used */
+    SDL_DISPLAYEVENT_ORIENTATION    /**< Display orientation has changed to data1 */
+} SDL_DisplayEventID;
+
+typedef enum
+{
+    SDL_ORIENTATION_UNKNOWN,            /**< The display orientation can't be determined */
+    SDL_ORIENTATION_LANDSCAPE,          /**< The display is in landscape mode, with the right side up, relative to portrait mode */
+    SDL_ORIENTATION_LANDSCAPE_FLIPPED,  /**< The display is in landscape mode, with the left side up, relative to portrait mode */
+    SDL_ORIENTATION_PORTRAIT,           /**< The display is in portrait mode */
+    SDL_ORIENTATION_PORTRAIT_FLIPPED    /**< The display is in portrait mode, upside down */
+} SDL_DisplayOrientation;
+
 /**
  *  \brief An opaque handle to an OpenGL context.
  */
@@ -314,18 +334,6 @@ extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex);
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
 
-/**
- *  \brief Get the dots/pixels-per-inch for a display
- *
- *  \note Diagonal, horizontal and vertical DPI can all be optionally
- *        returned if the parameter is non-NULL.
- *
- *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
- *
- *  \sa SDL_GetNumVideoDisplays()
- */
-extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
-
 /**
  *  \brief Get the usable desktop area represented by a display, with the
  *         primary display located at 0,0
@@ -345,6 +353,27 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, fl
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
 
+/**
+ *  \brief Get the dots/pixels-per-inch for a display
+ *
+ *  \note Diagonal, horizontal and vertical DPI can all be optionally
+ *        returned if the parameter is non-NULL.
+ *
+ *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
+
+/**
+ *  \brief Get the orientation of a display
+ *
+ *  \return The orientation of the display, or SDL_ORIENTATION_UNKNOWN if it isn't available.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC SDL_DisplayOrientation SDLCALL SDL_GetDisplayOrientation(int displayIndex);
+
 /**
  *  \brief Returns the number of available display modes.
  *
@@ -470,7 +499,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window);
  *  If the window is created with any of the SDL_WINDOW_OPENGL or
  *  SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function
  *  (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the
- *  corrensponding UnloadLibrary function is called by SDL_DestroyWindow().
+ *  corresponding UnloadLibrary function is called by SDL_DestroyWindow().
  *
  *  If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver,
  *  SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail.
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_vulkan.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_vulkan.h
index 803b5feef3489ba257ae3664cc93afc9f8fbcf1d..972cca4d7c2658f735d96d549ccd2a5819592b16 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_vulkan.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_vulkan.h
@@ -69,30 +69,43 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
  *  \brief Dynamically load a Vulkan loader library.
  *
  *  \param [in] path The platform dependent Vulkan loader library name, or
- *              \c NULL to open the default Vulkan loader library.
+ *              \c NULL.
  *
  *  \return \c 0 on success, or \c -1 if the library couldn't be loaded.
  *
- *  This should be done after initializing the video driver, but before
+ *  If \a path is NULL SDL will use the value of the environment variable
+ *  \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
+ *  loader library.
+ *
+ *  This should be called after initializing the video driver, but before
  *  creating any Vulkan windows. If no Vulkan loader library is loaded, the
  *  default library will be loaded upon creation of the first Vulkan window.
  *
- *  \note If you specify a non-NULL \a path, you should retrieve all of the
- *        Vulkan functions used in your program from the dynamic library using
+ *  \note It is fairly common for Vulkan applications to link with \a libvulkan
+ *        instead of explicitly loading it at run time. This will work with
+ *        SDL provided the application links to a dynamic library and both it
+ *        and SDL use the same search path.
+ *
+ *  \note If you specify a non-NULL \c path, an application should retrieve all
+ *        of the Vulkan functions it uses from the dynamic library using
  *        \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee
- *        \a path points to the same vulkan loader library that you linked to.
+ *        \c path points to the same vulkan loader library the application
+ *        linked to.
  *
  *  \note On Apple devices, if \a path is NULL, SDL will attempt to find
  *        the vkGetInstanceProcAddr address within all the mach-o images of
- *        the current process. This is because the currently (v0.17.0)
- *        recommended MoltenVK (Vulkan on Metal) usage is as a static library.
- *        If it is not found then SDL will attempt to load \c libMoltenVK.dylib.
- *        Applications using the dylib alternative therefore do not need to do
- *        anything special when calling SDL.
- *
- *  \note On non-Apple devices, SDL requires you to either not link to the
- *        Vulkan loader or link to a dynamic library version. This limitation
- *        may be removed in a future version of SDL.
+ *        the current process. This is because it is fairly common for Vulkan
+ *        applications to link with libvulkan (and historically MoltenVK was
+ *        provided as a static library). If it is not found then, on macOS, SDL
+ *        will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
+ *        \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
+ *        On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
+ *        using a dynamic framework or .dylib must ensure it is included in its
+ *        application bundle.
+ *
+ *  \note On non-Apple devices, application linking with a static libvulkan is
+ *        not supported. Either do not link to the Vulkan loader or link to a
+ *        dynamic library version.
  *
  *  \note This function will fail if there are no working Vulkan drivers
  *        installed.
@@ -122,11 +135,11 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \brief Get the names of the Vulkan instance extensions needed to create
  *         a surface with \c SDL_Vulkan_CreateSurface().
  *
- *  \param [in]     window Window for which the required Vulkan instance
+ *  \param [in]     \c NULL or window Window for which the required Vulkan instance
  *                  extensions should be retrieved
- *  \param [in,out] count pointer to an \c unsigned related to the number of
+ *  \param [in,out] pCount pointer to an \c unsigned related to the number of
  *                  required Vulkan instance extensions
- *  \param [out]    names \c NULL or a pointer to an array to be filled with the
+ *  \param [out]    pNames \c NULL or a pointer to an array to be filled with the
  *                  required Vulkan instance extensions
  *
  *  \return \c SDL_TRUE on success, \c SDL_FALSE on error.
@@ -140,6 +153,10 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  is smaller than the number of required extensions, \c SDL_FALSE will be
  *  returned instead of \c SDL_TRUE, to indicate that not all the required
  *  extensions were returned.
+ * 
+ *  \note If \c window is not NULL, it will be checked against its creation
+ *        flags to ensure that the Vulkan flag is present. This parameter
+ *        will be removed in a future major release.
  *
  *  \note The returned list of extensions will contain \c VK_KHR_surface
  *        and zero or more platform specific extensions
@@ -147,12 +164,13 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \note The extension names queried here must be enabled when calling
  *        VkCreateInstance, otherwise surface creation will fail.
  *
- *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag.
+ *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag
+ *        or be \c NULL
  *
  *  \code
  *  unsigned int count;
  *  // get count of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, NULL))
  *      handle_error();
  *
  *  static const char *const additionalExtensions[] =
@@ -166,7 +184,7 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *      handle_error();
  *
  *  // get names of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, names))
  *      handle_error();
  *
  *  // copy additional extensions after required extensions
@@ -240,6 +258,9 @@ extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_CreateSurface(
  * platform with high-DPI support (Apple calls this "Retina"), and not disabled
  * by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
  *
+ *  \note On macOS high-DPI support must be enabled for an application by
+ *        setting NSHighResolutionCapable to true in its Info.plist.
+ *
  *  \sa SDL_GetWindowSize()
  *  \sa SDL_CreateWindow()
  */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
index 5372d6f04df418acb02bf51cd545c2170bb73849..6c2106246f2583ba711451bc7e39fc2af7e9eec7 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
index 2a352dbb9ec7502c62b561f30bd7433b18e581d1..b3b70a4c833d80305bbffd306c8ac099babdf419 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake b/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
index 208b7c637f7d711afa4a076e04374cacc7abd1af..ee347fcb9bbafc54f19abc1bd9dac7bfcfbb57e1 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
+++ b/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
@@ -1,11 +1,11 @@
 # sdl2 cmake project-config input for ./configure scripts
 
-set(prefix "/usr/local/i686-w64-mingw32") 
+set(prefix "/opt/local/i686-w64-mingw32") 
 set(exec_prefix "${prefix}")
 set(libdir "${exec_prefix}/lib")
-set(SDL2_PREFIX "/usr/local/i686-w64-mingw32")
-set(SDL2_EXEC_PREFIX "/usr/local/i686-w64-mingw32")
+set(SDL2_PREFIX "/opt/local/i686-w64-mingw32")
+set(SDL2_EXEC_PREFIX "/opt/local/i686-w64-mingw32")
 set(SDL2_LIBDIR "${exec_prefix}/lib")
 set(SDL2_INCLUDE_DIRS "${prefix}/include/SDL2")
-set(SDL2_LIBRARIES "-L${SDL2_LIBDIR}  -lmingw32 -lSDL2main -lSDL2  -mwindows")
+set(SDL2_LIBRARIES "-L${SDL2_LIBDIR}  -lmingw32 -lSDL2main -lSDL2 -mwindows")
 string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a
index 771ee00bdb5b07b4e3d44b3b281f439f784abd23..05489a95a2b41c45ee9036080891ae5bfbf43f8b 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a
index 59d480738003a4f95de26aa1dbb45185d9a2ee42..b20371a131abe0dbb63bbebe22e48e7c57d8b611 100755
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la
new file mode 100644
index 0000000000000000000000000000000000000000..3848c7db9b285b53d6b47f26d37e916b71ff2145
--- /dev/null
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la
@@ -0,0 +1,41 @@
+# libSDL2.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='../bin/SDL2.dll'
+
+# Names of this library.
+library_names='libSDL2.dll.a'
+
+# The name of the static archive.
+old_library='libSDL2.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=' -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2.
+current=9
+age=9
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a
index 5f2cfa28f6442bb2d17a57febb97b13e027189a7..190f9e0728d3d281de92cbd305313f5c62fb3388 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la
new file mode 100644
index 0000000000000000000000000000000000000000..5f96235bdbe06f364f89aa9146c3b399cb6b330b
--- /dev/null
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la
@@ -0,0 +1,41 @@
+# libSDL2_test.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libSDL2_test.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=''
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2_test.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a
index 9dddabbfcb8d76cac50bded6b9bdf2e6c5bff0fe..df7c95b95ea3a7595d4ccc18eeaabe16dce0f4e7 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la
new file mode 100644
index 0000000000000000000000000000000000000000..d01b8a1724d3a32f2791b44c0cfa39ee7238928b
--- /dev/null
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la
@@ -0,0 +1,41 @@
+# libSDL2main.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libSDL2main.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=''
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2main.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc b/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
index 407c95c48f15c6e7579544527cfdfe4a8af25e20..25fc5928ed6be962f6ba000aee947d6aa8e97c74 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
+++ b/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
@@ -1,15 +1,15 @@
 # sdl pkg-config source file
 
-prefix=/usr/local/i686-w64-mingw32
+prefix=/opt/local/i686-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: sdl2
 Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
-Version: 2.0.7
+Version: 2.0.9
 Requires:
 Conflicts:
-Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2  -mwindows
-Libs.private: -lmingw32 -lSDL2main -lSDL2  -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc
+Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2 -mwindows
+Libs.private: -lmingw32 -lSDL2main -lSDL2 -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -static-libgcc
 Cflags: -I${includedir}/SDL2  -Dmain=SDL_main
diff --git a/libs/SDL2/include/SDL.h b/libs/SDL2/include/SDL.h
old mode 100755
new mode 100644
index 366d50fa39095f0185247d490b31753351ef887c..fc35a419efd9076076aca339303a2937d5e6ada7
--- a/libs/SDL2/include/SDL.h
+++ b/libs/SDL2/include/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,6 +51,7 @@
 #include "SDL_power.h"
 #include "SDL_render.h"
 #include "SDL_rwops.h"
+#include "SDL_sensor.h"
 #include "SDL_shape.h"
 #include "SDL_system.h"
 #include "SDL_thread.h"
@@ -80,10 +81,11 @@ extern "C" {
 #define SDL_INIT_HAPTIC         0x00001000u
 #define SDL_INIT_GAMECONTROLLER 0x00002000u  /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
 #define SDL_INIT_EVENTS         0x00004000u
+#define SDL_INIT_SENSOR         0x00008000u
 #define SDL_INIT_NOPARACHUTE    0x00100000u  /**< compatibility; this flag is ignored. */
 #define SDL_INIT_EVERYTHING ( \
                 SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
-                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
+                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \
             )
 /* @} */
 
diff --git a/libs/SDL2/include/SDL_assert.h b/libs/SDL2/include/SDL_assert.h
old mode 100755
new mode 100644
index 90abbe39b6f1e5bd7e0bfa3d54b00954efe06e9a..b38f928ae14bb68e916bae1048a4c8648a1a20d8
--- a/libs/SDL2/include/SDL_assert.h
+++ b/libs/SDL2/include/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_atomic.h b/libs/SDL2/include/SDL_atomic.h
old mode 100755
new mode 100644
index 36e37f3b786840231bf87fddf563c695037c7fc5..b2287748c8f87973ef2aef5093812c0065b89725
--- a/libs/SDL2/include/SDL_atomic.h
+++ b/libs/SDL2/include/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -158,6 +158,9 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
 #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("lwsync" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("lwsync" : : : "memory")
+#elif defined(__GNUC__) && defined(__aarch64__)
+#define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
+#define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #elif defined(__GNUC__) && defined(__arm__)
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
diff --git a/libs/SDL2/include/SDL_audio.h b/libs/SDL2/include/SDL_audio.h
old mode 100755
new mode 100644
index f119c2b2678fc531efe1d3ecc8b1f1751169de53..d3e1bface4d406c3d6c1c3f141a36a3fce8e926b
--- a/libs/SDL2/include/SDL_audio.h
+++ b/libs/SDL2/include/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -140,7 +140,8 @@ typedef Uint16 SDL_AudioFormat;
 #define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE    0x00000001
 #define SDL_AUDIO_ALLOW_FORMAT_CHANGE       0x00000002
 #define SDL_AUDIO_ALLOW_CHANNELS_CHANGE     0x00000004
-#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
+#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE      0x00000008
+#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
 /* @} */
 
 /* @} *//* Audio flags */
@@ -527,7 +528,7 @@ extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioForm
  *
  *  \param stream The stream the audio data is being added to
  *  \param buf A pointer to the audio data to add
- *  \param int The number of bytes to write to the stream
+ *  \param len The number of bytes to write to the stream
  *  \return 0 on success, or -1 on error.
  *
  *  \sa SDL_NewAudioStream
diff --git a/libs/SDL2/include/SDL_bits.h b/libs/SDL2/include/SDL_bits.h
old mode 100755
new mode 100644
index bc28572902181c1edf67998fe3800c0269b4c451..eb8322f0d0a181b364871c28df42010ead3f17b1
--- a/libs/SDL2/include/SDL_bits.h
+++ b/libs/SDL2/include/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_blendmode.h b/libs/SDL2/include/SDL_blendmode.h
old mode 100755
new mode 100644
index 9abd0bd4cf11c6d4d9931a20f21db32e2af0cdc6..36a5ea76f0c52c4364cb5f156cdf7252c0441ecc
--- a/libs/SDL2/include/SDL_blendmode.h
+++ b/libs/SDL2/include/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_clipboard.h b/libs/SDL2/include/SDL_clipboard.h
old mode 100755
new mode 100644
index 341f4ba42b17e2025a5a27ecaa3925e3f618c1ad..f28751ebb8ffe5c67f17ccab94f2a55165fea4c8
--- a/libs/SDL2/include/SDL_clipboard.h
+++ b/libs/SDL2/include/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_config.h b/libs/SDL2/include/SDL_config.h
old mode 100755
new mode 100644
index 1bbb83848142162b87676b35e03d964d5bec56dd..c58be8e72ee0dbb9e73f94be9d8c2c595aa630e5
--- a/libs/SDL2/include/SDL_config.h
+++ b/libs/SDL2/include/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -82,6 +82,9 @@ typedef unsigned int uintptr_t;
 #define HAVE_DSOUND_H 1
 #define HAVE_DXGI_H 1
 #define HAVE_XINPUT_H 1
+#define HAVE_MMDEVICEAPI_H 1
+#define HAVE_AUDIOCLIENT_H 1
+#define HAVE_ENDPOINTVOLUME_H 1
 
 /* This is disabled by default to avoid C runtime dependencies and manifest requirements */
 #ifdef HAVE_LIBC
@@ -109,13 +112,15 @@ typedef unsigned int uintptr_t;
 #define HAVE_MEMCMP 1
 #define HAVE_STRLEN 1
 #define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-#define HAVE__STRLWR 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__STRUPR */
+/* #undef HAVE__STRLWR */
 #define HAVE_STRCHR 1
 #define HAVE_STRRCHR 1
 #define HAVE_STRSTR 1
-#define HAVE__LTOA 1
-#define HAVE__ULTOA 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__LTOA */
+/* #undef HAVE__ULTOA */
 #define HAVE_STRTOL 1
 #define HAVE_STRTOUL 1
 #define HAVE_STRTOD 1
@@ -125,30 +130,45 @@ typedef unsigned int uintptr_t;
 #define HAVE_STRNCMP 1
 #define HAVE__STRICMP 1
 #define HAVE__STRNICMP 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE__COPYSIGN 1
+#define HAVE_ACOS   1
+#define HAVE_ACOSF  1
+#define HAVE_ASIN   1
+#define HAVE_ASINF  1
+#define HAVE_ATAN   1
+#define HAVE_ATANF  1
+#define HAVE_ATAN2  1
+#define HAVE_ATAN2F 1
+#define HAVE_CEILF  1
+#define HAVE__COPYSIGN  1
+#define HAVE_COS    1
+#define HAVE_COSF   1
+#define HAVE_EXP    1
+#define HAVE_EXPF   1
+#define HAVE_FABS   1
+#define HAVE_FABSF  1
+#define HAVE_FLOOR  1
+#define HAVE_FLOORF 1
+#define HAVE_FMOD   1
+#define HAVE_FMODF  1
+#define HAVE_LOG    1
+#define HAVE_LOGF   1
+#define HAVE_LOG10  1
+#define HAVE_LOG10F 1
+#define HAVE_POW    1
+#define HAVE_POWF   1
+#define HAVE_SIN    1
+#define HAVE_SINF   1
+#define HAVE_SQRT   1
+#define HAVE_SQRTF  1
+#define HAVE_TAN    1
+#define HAVE_TANF   1
 #if defined(_MSC_VER)
 /* These functions were added with the VC++ 2013 C runtime library */
 #if _MSC_VER >= 1800
 #define HAVE_STRTOLL 1
 #define HAVE_VSSCANF 1
 #define HAVE_SCALBN 1
+#define HAVE_SCALBNF    1
 #endif
 /* This function is available with at least the VC++ 2008 C runtime library */
 #if _MSC_VER >= 1400
@@ -166,7 +186,6 @@ typedef unsigned int uintptr_t;
 /* Enable various audio drivers */
 #define SDL_AUDIO_DRIVER_WASAPI 1
 #define SDL_AUDIO_DRIVER_DSOUND 1
-#define SDL_AUDIO_DRIVER_XAUDIO2    0
 #define SDL_AUDIO_DRIVER_WINMM  1
 #define SDL_AUDIO_DRIVER_DISK   1
 #define SDL_AUDIO_DRIVER_DUMMY  1
@@ -174,9 +193,13 @@ typedef unsigned int uintptr_t;
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
 #define SDL_JOYSTICK_XINPUT 1
+#define SDL_JOYSTICK_HIDAPI 1
 #define SDL_HAPTIC_DINPUT   1
 #define SDL_HAPTIC_XINPUT   1
 
+/* Enable the dummy sensor driver */
+#define SDL_SENSOR_DUMMY  1
+
 /* Enable various shared object loading systems */
 #define SDL_LOADSO_WINDOWS  1
 
@@ -194,7 +217,7 @@ typedef unsigned int uintptr_t;
 #define SDL_VIDEO_RENDER_D3D    1
 #endif
 #ifndef SDL_VIDEO_RENDER_D3D11
-#define SDL_VIDEO_RENDER_D3D11	0
+#define SDL_VIDEO_RENDER_D3D11  0
 #endif
 
 /* Enable OpenGL support */
diff --git a/libs/SDL2/include/SDL_config.h.cmake b/libs/SDL2/include/SDL_config.h.cmake
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config.h.in b/libs/SDL2/include/SDL_config.h.in
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_android.h b/libs/SDL2/include/SDL_config_android.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_iphoneos.h b/libs/SDL2/include/SDL_config_iphoneos.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_macosx.h b/libs/SDL2/include/SDL_config_macosx.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_macosx.h.orig b/libs/SDL2/include/SDL_config_macosx.h.orig
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_minimal.h b/libs/SDL2/include/SDL_config_minimal.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_pandora.h b/libs/SDL2/include/SDL_config_pandora.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_psp.h b/libs/SDL2/include/SDL_config_psp.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_windows.h b/libs/SDL2/include/SDL_config_windows.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_winrt.h b/libs/SDL2/include/SDL_config_winrt.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_config_wiz.h b/libs/SDL2/include/SDL_config_wiz.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_copying.h b/libs/SDL2/include/SDL_copying.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_cpuinfo.h b/libs/SDL2/include/SDL_cpuinfo.h
old mode 100755
new mode 100644
index 94b64b03bc5dd394af7f2ccfc5968fb1c0e9dfc5..ee3a47e841242fdae7e697f6b5de18a2a47c1ecf
--- a/libs/SDL2/include/SDL_cpuinfo.h
+++ b/libs/SDL2/include/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,27 +51,35 @@
 #include <intrin.h>
 #else
 #ifdef __ALTIVEC__
-#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__)
+#if defined(HAVE_ALTIVEC_H) && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H)
 #include <altivec.h>
 #undef pixel
+#undef bool
 #endif
 #endif
-#ifdef __MMX__
-#include <mmintrin.h>
+#if defined(__ARM_NEON__) && !defined(SDL_DISABLE_ARM_NEON_H)
+#include <arm_neon.h>
 #endif
-#ifdef __3dNOW__
+#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
 #include <mm3dnow.h>
 #endif
-#ifdef __SSE__
+#if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
+#include <immintrin.h>
+#else
+#if defined(__MMX__) && !defined(SDL_DISABLE_MMINTRIN_H)
+#include <mmintrin.h>
+#endif
+#if defined(__SSE__) && !defined(SDL_DISABLE_XMMINTRIN_H)
 #include <xmmintrin.h>
 #endif
-#ifdef __SSE2__
+#if defined(__SSE2__) && !defined(SDL_DISABLE_EMMINTRIN_H)
 #include <emmintrin.h>
 #endif
-#ifdef __SSE3__
+#if defined(__SSE3__) && !defined(SDL_DISABLE_PMMINTRIN_H)
 #include <pmmintrin.h>
 #endif
-#endif
+#endif /* HAVE_IMMINTRIN_H */
+#endif /* compiler version */
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -154,6 +162,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
 
+/**
+ *  This function returns true if the CPU has AVX-512F (foundation) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
+
 /**
  *  This function returns true if the CPU has NEON (ARM SIMD) features.
  */
@@ -164,7 +177,6 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
  */
 extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
 
-
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/include/SDL_egl.h b/libs/SDL2/include/SDL_egl.h
old mode 100755
new mode 100644
index e47fbe8624700058a55aff35c8cd39081a19695f..d65ed437c33fe307657aca04f192de87e0ff55e9
--- a/libs/SDL2/include/SDL_egl.h
+++ b/libs/SDL2/include/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -24,7 +24,7 @@
  *
  *  This is a simple file to encapsulate the EGL API headers.
  */
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
diff --git a/libs/SDL2/include/SDL_endian.h b/libs/SDL2/include/SDL_endian.h
old mode 100755
new mode 100644
index 3eda7f2871144111f5cdfb24e0d57dd988c440c4..ed0bf5ba8f94888115422d06601ff4200119a9e6
--- a/libs/SDL2/include/SDL_endian.h
+++ b/libs/SDL2/include/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_error.h b/libs/SDL2/include/SDL_error.h
old mode 100755
new mode 100644
index 49be9827e182ae56227e8dde300b7e8c03f8cfb8..c0e46298e8ffdbc6cf6abc4381a7ba9e2dcf1a33
--- a/libs/SDL2/include/SDL_error.h
+++ b/libs/SDL2/include/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_events.h b/libs/SDL2/include/SDL_events.h
old mode 100755
new mode 100644
index 0fc09bc37d795c8b5a4c34bebf9c78134a4c499f..af22eb6466661378e252d090b1504471f74833a8
--- a/libs/SDL2/include/SDL_events.h
+++ b/libs/SDL2/include/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -85,6 +85,9 @@ typedef enum
                                      Called on Android in onResume()
                                 */
 
+    /* Display events */
+    SDL_DISPLAYEVENT   = 0x150,  /**< Display state change */
+
     /* Window events */
     SDL_WINDOWEVENT    = 0x200, /**< Window state change */
     SDL_SYSWMEVENT,             /**< System specific event */
@@ -144,6 +147,9 @@ typedef enum
     SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
     SDL_AUDIODEVICEREMOVED,        /**< An audio device has been removed. */
 
+    /* Sensor events */
+    SDL_SENSORUPDATE = 0x1200,     /**< A sensor was updated */
+
     /* Render events */
     SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
     SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
@@ -168,6 +174,21 @@ typedef struct SDL_CommonEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_CommonEvent;
 
+/**
+ *  \brief Display state change event data (event.display.*)
+ */
+typedef struct SDL_DisplayEvent
+{
+    Uint32 type;        /**< ::SDL_DISPLAYEVENT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint32 display;     /**< The associated display index */
+    Uint8 event;        /**< ::SDL_DisplayEventID */
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
+    Sint32 data1;       /**< event dependent data */
+} SDL_DisplayEvent;
+
 /**
  *  \brief Window state change event data (event.window.*)
  */
@@ -471,6 +492,17 @@ typedef struct SDL_DropEvent
 } SDL_DropEvent;
 
 
+/**
+ *  \brief Sensor event structure (event.sensor.*)
+ */
+typedef struct SDL_SensorEvent
+{
+    Uint32 type;        /**< ::SDL_SENSORUPDATE */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Sint32 which;       /**< The instance ID of the sensor */
+    float data[6];      /**< Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData() */
+} SDL_SensorEvent;
+
 /**
  *  \brief The "quit requested" event
  */
@@ -526,6 +558,7 @@ typedef union SDL_Event
 {
     Uint32 type;                    /**< Event type, shared with all events */
     SDL_CommonEvent common;         /**< Common event data */
+    SDL_DisplayEvent display;       /**< Window event data */
     SDL_WindowEvent window;         /**< Window event data */
     SDL_KeyboardEvent key;          /**< Keyboard event data */
     SDL_TextEditingEvent edit;      /**< Text editing event data */
@@ -542,6 +575,7 @@ typedef union SDL_Event
     SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
     SDL_AudioDeviceEvent adevice;   /**< Audio device event data */
+    SDL_SensorEvent sensor;         /**< Sensor event data */
     SDL_QuitEvent quit;             /**< Quit request event data */
     SDL_UserEvent user;             /**< Custom event data */
     SDL_SysWMEvent syswm;           /**< System dependent window event data */
diff --git a/libs/SDL2/include/SDL_filesystem.h b/libs/SDL2/include/SDL_filesystem.h
old mode 100755
new mode 100644
index a1c846ad0f07b71a61a60c147c709c2dc6e2c15f..fa6a1fa6e7b2ad4b9e341f6cf71c4e7fca925586
--- a/libs/SDL2/include/SDL_filesystem.h
+++ b/libs/SDL2/include/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_gamecontroller.h b/libs/SDL2/include/SDL_gamecontroller.h
old mode 100755
new mode 100644
index c9215132ef50a7f214b7b4bf248d6fc73c3ff3f4..6ae9c95428907172257a93dfd6074865891f6571
--- a/libs/SDL2/include/SDL_gamecontroller.h
+++ b/libs/SDL2/include/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -175,6 +175,14 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index);
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
 
+/**
+ *  Get the mapping of a game controller.
+ *  This can be called before any controllers are opened.
+ *
+ *  \return the mapping string.  Must be freed with SDL_free().  Returns NULL if no mapping is available
+ */
+extern DECLSPEC char *SDLCALL SDL_GameControllerMappingForDeviceIndex(int joystick_index);
+
 /**
  *  Open a game controller for use.
  *  The index passed as an argument refers to the N'th game controller on the system.
@@ -196,6 +204,13 @@ extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
 
+/**
+ *  Get the player index of an opened game controller, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
+
 /**
  *  Get the USB vendor ID of an opened controller, if available.
  *  If the vendor ID isn't available this function returns 0.
@@ -345,6 +360,19 @@ SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
 extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
                                                           SDL_GameControllerButton button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param gamecontroller The controller to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a controller previously opened with SDL_GameControllerOpen().
  */
diff --git a/libs/SDL2/include/SDL_gesture.h b/libs/SDL2/include/SDL_gesture.h
old mode 100755
new mode 100644
index 2bba6a7294fa93240d5f6eefbd8d16c5773761ea..b223d80d44c3debd2de55420aaf1e907d1a08919
--- a/libs/SDL2/include/SDL_gesture.h
+++ b/libs/SDL2/include/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_haptic.h b/libs/SDL2/include/SDL_haptic.h
old mode 100755
new mode 100644
index 60daefaa709bbbc0a1796bd9af6f9be073cacedd..2ea1bfc1602ee571b0ac3238b183117fcb20f25d
--- a/libs/SDL2/include/SDL_haptic.h
+++ b/libs/SDL2/include/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -117,6 +117,17 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* FIXME: For SDL 2.1, adjust all the magnitude variables to be Uint16 (0xFFFF).
+ *
+ * At the moment the magnitude variables are mixed between signed/unsigned, and
+ * it is also not made clear that ALL of those variables expect a max of 0x7FFF.
+ *
+ * Some platforms may have higher precision than that (Linux FF, Windows XInput)
+ * so we should fix the inconsistency in favor of higher possible precision,
+ * adjusting for platforms that use different scales.
+ * -flibit
+ */
+
 /**
  *  \typedef SDL_Haptic
  *
@@ -656,8 +667,8 @@ typedef struct SDL_HapticRamp
  * This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
  *
  * The Left/Right effect is used to explicitly control the large and small
- * motors, commonly found in modern game controllers. One motor is high
- * frequency, the other is low frequency.
+ * motors, commonly found in modern game controllers. The small (right) motor
+ * is high frequency, and the large (left) motor is low frequency.
  *
  * \sa SDL_HAPTIC_LEFTRIGHT
  * \sa SDL_HapticEffect
@@ -668,7 +679,7 @@ typedef struct SDL_HapticLeftRight
     Uint16 type;            /**< ::SDL_HAPTIC_LEFTRIGHT */
 
     /* Replay */
-    Uint32 length;          /**< Duration of the effect. */
+    Uint32 length;          /**< Duration of the effect in milliseconds. */
 
     /* Rumble */
     Uint16 large_magnitude; /**< Control of the large controller motor. */
diff --git a/libs/SDL2/include/SDL_hints.h b/libs/SDL2/include/SDL_hints.h
old mode 100755
new mode 100644
index 007a4bee05c0dc4ef90b1d24e88eb1137cedc945..4ee72e97d66db40a703620a9d0a162a952de1498
--- a/libs/SDL2/include/SDL_hints.h
+++ b/libs/SDL2/include/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,7 @@ extern "C" {
  *    "opengl"
  *    "opengles2"
  *    "opengles"
+ *    "metal"
  *    "software"
  *
  *  The default varies by platform, but it's the first one in the list that
@@ -210,6 +211,18 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_X11_NET_WM_PING      "SDL_VIDEO_X11_NET_WM_PING"
 
+/**
+ * \brief A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint should be used.
+ * 
+ * This variable can be set to the following values:
+ * "0" - Disable _NET_WM_BYPASS_COMPOSITOR
+ * "1" - Enable _NET_WM_BYPASS_COMPOSITOR
+ * 
+ * By default SDL will use _NET_WM_BYPASS_COMPOSITOR
+ * 
+ */
+#define SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"
+
 /**
  *  \brief  A variable controlling whether the window frame and title bar are interactive when the cursor is hidden 
  *
@@ -249,6 +262,16 @@ extern "C" {
  */
 #define SDL_HINT_GRAB_KEYBOARD              "SDL_GRAB_KEYBOARD"
 
+/**
+ *  \brief  A variable setting the double click time, in milliseconds.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME    "SDL_MOUSE_DOUBLE_CLICK_TIME"
+
+/**
+ *  \brief  A variable setting the double click radius, in pixels.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS    "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
+
 /**
  *  \brief  A variable setting the speed scale for mouse motion, in floating point, when the mouse is not in relative mode
  */
@@ -316,7 +339,7 @@ extern "C" {
 #define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
 
 /**
- *  \brief  A variable controlling which orientations are allowed on iOS.
+ *  \brief  A variable controlling which orientations are allowed on iOS/Android.
  *
  *  In some circumstances it is necessary to be able to explicitly control
  *  which UI orientations are allowed.
@@ -354,17 +377,37 @@ extern "C" {
  */
 #define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION"
 
+/**
+ * \brief  A variable controlling whether the home indicator bar on iPhone X
+ *         should be hidden.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - The indicator bar is not hidden (default for windowed applications)
+ *    "1"       - The indicator bar is hidden and is shown when the screen is touched (useful for movie playback applications)
+ *    "2"       - The indicator bar is dim and the first swipe makes it visible and the second swipe performs the "home" action (default for fullscreen applications)
+ */
+#define SDL_HINT_IOS_HIDE_HOME_INDICATOR "SDL_IOS_HIDE_HOME_INDICATOR"
+
 /**
  *  \brief  A variable controlling whether the Android / iOS built-in
- *  accelerometer should be listed as a joystick device, rather than listing
- *  actual joysticks only.
+ *  accelerometer should be listed as a joystick device.
  *
  *  This variable can be set to the following values:
- *    "0"       - List only real joysticks and accept input from them
- *    "1"       - List real joysticks along with the accelerometer as if it were a 3 axis joystick (the default).
+ *    "0"       - The accelerometer is not listed as a joystick
+ *    "1"       - The accelerometer is available as a 3 axis joystick (the default).
  */
 #define SDL_HINT_ACCELEROMETER_AS_JOYSTICK "SDL_ACCELEROMETER_AS_JOYSTICK"
 
+/**
+ *  \brief  A variable controlling whether the Android / tvOS remotes
+ *  should be listed as joystick devices, instead of sending keyboard events.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Remotes send enter/escape/arrow key events
+ *    "1"       - Remotes are available as 2 axis, 2 button joysticks (the default).
+ */
+#define SDL_HINT_TV_REMOTE_AS_JOYSTICK "SDL_TV_REMOTE_AS_JOYSTICK"
+
 /**
  *  \brief  A variable that lets you disable the detection and use of Xinput gamepad devices
  *
@@ -432,6 +475,88 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
+/**
+ *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI drivers are not used
+ *    "1"       - HIDAPI drivers are used (the default)
+ *
+ *  This variable is the default for all drivers, but can be overridden by the hints for specific drivers below.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI "SDL_JOYSTICK_HIDAPI"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4 "SDL_JOYSTICK_HIDAPI_PS4"
+
+/**
+ *  \brief  A variable controlling whether extended input reports should be used for PS4 controllers when using the HIDAPI driver.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - extended reports are not enabled (the default)
+ *    "1"       - extended reports
+ *
+ *  Extended input reports allow rumble on Bluetooth PS4 controllers, but
+ *  break DirectInput handling for applications that don't use SDL.
+ *
+ *  Once extended reports are enabled, they can not be disabled without
+ *  power cycling the controller.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
+
+/**
+ *  \brief  A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
+ *
+ *  The variable can be set to the following values:
+ *    "0"       - Do not scan for Steam Controllers
+ *    "1"       - Scan for Steam Controllers (the default)
+ *
+ *  The default value is "1".  This hint must be set before initializing the joystick subsystem.
+ */
+#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
+
+
 /**
  *  \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
  *      This is a debugging aid for developers and not expected to be used by end users. The default is "1"
@@ -494,6 +619,10 @@ extern "C" {
 *  This is specially useful if you build SDL against a non glibc libc library (such as musl) which
 *  provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
 *  Support for this hint is currently available only in the pthread, Windows, and PSP backend.
+*
+*  Instead of this hint, in 2.0.9 and later, you can use
+*  SDL_CreateThreadWithStackSize(). This hint only works with the classic
+*  SDL_CreateThread().
 */
 #define SDL_HINT_THREAD_STACK_SIZE              "SDL_THREAD_STACK_SIZE"
 
@@ -719,6 +848,35 @@ extern "C" {
  */
 #define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
 
+ /**
+ * \brief A variable to control whether we trap the Android back button to handle it manually.
+ *        This is necessary for the right mouse button to work on some Android devices, or
+ *        to be able to trap the back button for use in your code reliably.  If set to true,
+ *        the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of 
+ *        SDL_SCANCODE_AC_BACK.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - Back button will be handled as usual for system. (default)
+ *   "1"       - Back button will be trapped, allowing you to handle the key press
+ *               manually.  (This will also let right mouse click work on systems 
+ *               where the right mouse button functions as back.)
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON"
+
+ /**
+ * \brief A variable to control whether the return key on the soft keyboard
+ *        should hide the soft keyboard on Android and iOS.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - The return key will be handled as a key event. This is the behaviour of SDL <= 2.0.3. (default)
+ *   "1"       - The return key will hide the keyboard.
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_RETURN_KEY_HIDES_IME "SDL_RETURN_KEY_HIDES_IME"
+
 /**
  *  \brief override the binding element for keyboard inputs for Emscripten builds
  *
@@ -752,7 +910,7 @@ extern "C" {
  *   "0"       - SDL will generate a window-close event when it sees Alt+F4.
  *   "1"       - SDL will only do normal key handling for Alt+F4.
  */
-#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4	"SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
+#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
 
 /**
  *  \brief Prevent SDL from using version 4 of the bitmap header when saving BMPs.
@@ -797,6 +955,24 @@ extern "C" {
  */
 #define SDL_HINT_RPI_VIDEO_LAYER           "SDL_RPI_VIDEO_LAYER"
 
+/**
+ * \brief Tell the video driver that we only want a double buffer.
+ *
+ * By default, most lowlevel 2D APIs will use a triple buffer scheme that 
+ * wastes no CPU time on waiting for vsync after issuing a flip, but
+ * introduces a frame of latency. On the other hand, using a double buffer
+ * scheme instead is recommended for cases where low latency is an important
+ * factor because we save a whole frame of latency.
+ * We do so by waiting for vsync immediately after issuing a flip, usually just
+ * after eglSwapBuffers call in the backend's *_SwapWindow function.
+ *
+ * Since it's driver-specific, it's only supported where possible and
+ * implemented. Currently supported the following drivers:
+ * - KMSDRM (kmsdrm)
+ * - Raspberry Pi (raspberrypi)
+ */
+#define SDL_HINT_VIDEO_DOUBLE_BUFFER      "SDL_VIDEO_DOUBLE_BUFFER"
+
 /**
  *  \brief  A variable controlling what driver to use for OpenGL ES contexts.
  *
diff --git a/libs/SDL2/include/SDL_joystick.h b/libs/SDL2/include/SDL_joystick.h
old mode 100755
new mode 100644
index f598dc828dafa2751d3aba2286059a8298d79aa3..6e05a9c2056cf7134c22459066d253e80e9a4315
--- a/libs/SDL2/include/SDL_joystick.h
+++ b/libs/SDL2/include/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,10 +97,10 @@ typedef enum
 typedef enum
 {
     SDL_JOYSTICK_POWER_UNKNOWN = -1,
-    SDL_JOYSTICK_POWER_EMPTY,
-    SDL_JOYSTICK_POWER_LOW,
-    SDL_JOYSTICK_POWER_MEDIUM,
-    SDL_JOYSTICK_POWER_FULL,
+    SDL_JOYSTICK_POWER_EMPTY,   /* <= 5% */
+    SDL_JOYSTICK_POWER_LOW,     /* <= 20% */
+    SDL_JOYSTICK_POWER_MEDIUM,  /* <= 70% */
+    SDL_JOYSTICK_POWER_FULL,    /* <= 100% */
     SDL_JOYSTICK_POWER_WIRED,
     SDL_JOYSTICK_POWER_MAX
 } SDL_JoystickPowerLevel;
@@ -132,6 +132,12 @@ extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
 
+/**
+ *  Get the player index of a joystick, or -1 if it's not available
+ *  This can be called before any joysticks are opened.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetDevicePlayerIndex(int device_index);
+
 /**
  *  Return the GUID for the joystick at this index
  *  This can be called before any joysticks are opened.
@@ -194,6 +200,13 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
 
+/**
+ *  Get the player index of an opened joystick, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
+
 /**
  *  Return the GUID for this opened joystick
  */
@@ -361,6 +374,19 @@ extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
 extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
                                                     int button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param joystick The joystick to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a joystick previously opened with SDL_JoystickOpen().
  */
diff --git a/libs/SDL2/include/SDL_keyboard.h b/libs/SDL2/include/SDL_keyboard.h
old mode 100755
new mode 100644
index e78ca469082c793a8190331c01766a3e3374a5ba..87482317161a6e05324bf5ab769743b1a385b436
--- a/libs/SDL2/include/SDL_keyboard.h
+++ b/libs/SDL2/include/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_keycode.h b/libs/SDL2/include/SDL_keycode.h
old mode 100755
new mode 100644
index c41e45ff61b6959937f7f4e912cef24064b72e1f..d7d5b1dbcdefce3777ee48eddcc46853eba2e584
--- a/libs/SDL2/include/SDL_keycode.h
+++ b/libs/SDL2/include/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_loadso.h b/libs/SDL2/include/SDL_loadso.h
old mode 100755
new mode 100644
index 6ea256c6ae5813dc7b00c269101b4e866fbb5fcc..da56fb452779ee015da429caa8da746c985b0ee0
--- a/libs/SDL2/include/SDL_loadso.h
+++ b/libs/SDL2/include/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_log.h b/libs/SDL2/include/SDL_log.h
old mode 100755
new mode 100644
index 356d0e1cf7492f54d82e5829a6030587400869d1..e12b6588601712bd217578226f143941ff019cbb
--- a/libs/SDL2/include/SDL_log.h
+++ b/libs/SDL2/include/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_main.h b/libs/SDL2/include/SDL_main.h
old mode 100755
new mode 100644
index 2af32360f7be842213bca1253268d5198c768377..98558217fc23ea63118899e44a710b7ba934c720
--- a/libs/SDL2/include/SDL_main.h
+++ b/libs/SDL2/include/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -63,10 +63,13 @@
 /* On Android SDL provides a Java class in SDLActivity.java that is the
    main activity entry point.
 
-   See README-android.md for more details on extending that class.
+   See docs/README-android.md for more details on extending that class.
  */
 #define SDL_MAIN_NEEDED
 
+/* We need to export SDL_main so it can be launched from Java */
+#define SDLMAIN_DECLSPEC    DECLSPEC
+
 #elif defined(__NACL__)
 /* On NACL we use ppapi_simple to set up the application helper code,
    then wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before 
@@ -85,6 +88,10 @@
 #define C_LINKAGE
 #endif /* __cplusplus */
 
+#ifndef SDLMAIN_DECLSPEC
+#define SDLMAIN_DECLSPEC
+#endif
+
 /**
  *  \file SDL_main.h
  *
@@ -107,7 +114,7 @@
 /**
  *  The prototype for the application's main() function
  */
-extern C_LINKAGE DECLSPEC int SDL_main(int argc, char *argv[]);
+extern C_LINKAGE SDLMAIN_DECLSPEC int SDL_main(int argc, char *argv[]);
 
 
 #include "begin_code.h"
diff --git a/libs/SDL2/include/SDL_messagebox.h b/libs/SDL2/include/SDL_messagebox.h
old mode 100755
new mode 100644
index c326d8f01098b147e1bff015fb8e355e37f00744..b7be59d88f50ad7686b794ca13cd66f29e7ef557
--- a/libs/SDL2/include/SDL_messagebox.h
+++ b/libs/SDL2/include/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_mouse.h b/libs/SDL2/include/SDL_mouse.h
old mode 100755
new mode 100644
index 6001bd46c1e80270d85d18dd72025b0c17f2722a..d3c9f6156cba36ecff91929d7a7eda0784b4af69
--- a/libs/SDL2/include/SDL_mouse.h
+++ b/libs/SDL2/include/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_mutex.h b/libs/SDL2/include/SDL_mutex.h
old mode 100755
new mode 100644
index 0272379e55e16bb25a913f9b4e4ca11809af7b56..ba4247ced8176dd98396d552536bc4646faa7841
--- a/libs/SDL2/include/SDL_mutex.h
+++ b/libs/SDL2/include/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_name.h b/libs/SDL2/include/SDL_name.h
old mode 100755
new mode 100644
index 8095ed3ffd4df27fb77a15eebcd532536c3efc09..ecd863f4ca873b55249601228efc5fc578aa4fb1
--- a/libs/SDL2/include/SDL_name.h
+++ b/libs/SDL2/include/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengl.h b/libs/SDL2/include/SDL_opengl.h
old mode 100755
new mode 100644
index 314dd57eda395c3b9e7bcbaf2d3749b9aa01864d..253d9c93a96f875aa53a51a5a615d4d732d9926d
--- a/libs/SDL2/include/SDL_opengl.h
+++ b/libs/SDL2/include/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengl_glext.h b/libs/SDL2/include/SDL_opengl_glext.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_opengles.h b/libs/SDL2/include/SDL_opengles.h
old mode 100755
new mode 100644
index 800c593070a9ea28a1f01c1d2b84e0f15ad2b33c..18dd984b3ed21bf5fd3bbfcf1a8a34fe58dfca6f
--- a/libs/SDL2/include/SDL_opengles.h
+++ b/libs/SDL2/include/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengles2.h b/libs/SDL2/include/SDL_opengles2.h
old mode 100755
new mode 100644
index 102f2f3fa7075c34639c03109939460ab2e7c2cc..6ccecf216572b4c9514bded0fd0a1c54690e57d8
--- a/libs/SDL2/include/SDL_opengles2.h
+++ b/libs/SDL2/include/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengles2_gl2.h b/libs/SDL2/include/SDL_opengles2_gl2.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_opengles2_gl2ext.h b/libs/SDL2/include/SDL_opengles2_gl2ext.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_opengles2_gl2platform.h b/libs/SDL2/include/SDL_opengles2_gl2platform.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_opengles2_khrplatform.h b/libs/SDL2/include/SDL_opengles2_khrplatform.h
old mode 100755
new mode 100644
diff --git a/libs/SDL2/include/SDL_pixels.h b/libs/SDL2/include/SDL_pixels.h
old mode 100755
new mode 100644
index 04246689f5957e5170ad6be433e089e2483ea85a..0b4364b185231109d61663b4acb50e60e1d8fa16
--- a/libs/SDL2/include/SDL_pixels.h
+++ b/libs/SDL2/include/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -287,7 +287,9 @@ enum
     SDL_PIXELFORMAT_NV12 =      /**< Planar mode: Y + U/V interleaved  (2 planes) */
         SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
     SDL_PIXELFORMAT_NV21 =      /**< Planar mode: Y + V/U interleaved  (2 planes) */
-        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
+        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'),
+    SDL_PIXELFORMAT_EXTERNAL_OES =      /**< Android video texture format */
+        SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ')
 };
 
 typedef struct SDL_Color
diff --git a/libs/SDL2/include/SDL_platform.h b/libs/SDL2/include/SDL_platform.h
old mode 100755
new mode 100644
index 9dde385fa67364dbcfcf22598e33961970c4348e..7dea4ce940fe02f1b233d15ec6a75c9452a0422c
--- a/libs/SDL2/include/SDL_platform.h
+++ b/libs/SDL2/include/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -121,7 +121,12 @@
 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
 /* Try to find out if we're compiling for WinRT or non-WinRT */
 #if defined(_MSC_VER) && defined(__has_include)
-#define HAVE_WINAPIFAMILY_H __has_include(<winapifamily.h>)
+#if __has_include(<winapifamily.h>)
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
 /* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
 #elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
 #define HAVE_WINAPIFAMILY_H 1
diff --git a/libs/SDL2/include/SDL_power.h b/libs/SDL2/include/SDL_power.h
old mode 100755
new mode 100644
index d48e8a3795dfd0d9f8a1cd9ad07ba1c54b1b0d7c..a4fe8a9359c247678ad56a47f8b8106fa465f4a9
--- a/libs/SDL2/include/SDL_power.h
+++ b/libs/SDL2/include/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_quit.h b/libs/SDL2/include/SDL_quit.h
old mode 100755
new mode 100644
index 9283c381050a4013097e533a1723c64bb6392938..fea56a8d88b6a0ac9e12807d693628f80991bc3e
--- a/libs/SDL2/include/SDL_quit.h
+++ b/libs/SDL2/include/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_rect.h b/libs/SDL2/include/SDL_rect.h
old mode 100755
new mode 100644
index c4f6d74b339ddc7b71372221758dc229043362fd..543bb618694ea9d4b5383e71a7c35b666b9e754c
--- a/libs/SDL2/include/SDL_rect.h
+++ b/libs/SDL2/include/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_render.h b/libs/SDL2/include/SDL_render.h
old mode 100755
new mode 100644
index ea6ef9ff645cef9e643162828ccb6b5173d1b732..d336192974f4cedab0497ad6ac60aaba19f3f389
--- a/libs/SDL2/include/SDL_render.h
+++ b/libs/SDL2/include/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -898,6 +898,27 @@ extern DECLSPEC int SDLCALL SDL_GL_BindTexture(SDL_Texture *texture, float *texw
  */
 extern DECLSPEC int SDLCALL SDL_GL_UnbindTexture(SDL_Texture *texture);
 
+/**
+ *  \brief Get the CAMetalLayer associated with the given Metal renderer
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return CAMetalLayer* on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalCommandEncoder()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
+
+/**
+ *  \brief Get the Metal command encoder for the current frame
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return id<MTLRenderCommandEncoder> on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalLayer()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/include/SDL_revision.h b/libs/SDL2/include/SDL_revision.h
old mode 100755
new mode 100644
index 9376093ee76bd46fbb70196e87673cda9d53ccd6..92fbe67b132156d911795af5e14b335d15645c66
--- a/libs/SDL2/include/SDL_revision.h
+++ b/libs/SDL2/include/SDL_revision.h
@@ -1,2 +1,2 @@
-#define SDL_REVISION "hg-11645:2088cd828335"
-#define SDL_REVISION_NUMBER 11645
+#define SDL_REVISION "hg-12373:8feb5da6f2fb"
+#define SDL_REVISION_NUMBER 12373
diff --git a/libs/SDL2/include/SDL_rwops.h b/libs/SDL2/include/SDL_rwops.h
old mode 100755
new mode 100644
index 7f0cbdfd55d5fabdd8ff80fc5ec605a7dd70bc0c..0960699d4857bb302e9024e7263c89a725a9a276
--- a/libs/SDL2/include/SDL_rwops.h
+++ b/libs/SDL2/include/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_scancode.h b/libs/SDL2/include/SDL_scancode.h
old mode 100755
new mode 100644
index 1d55212048560455d110797913a3dde07416768c..63871aa3b10beed824756b430687a3e16d7ebe44
--- a/libs/SDL2/include/SDL_scancode.h
+++ b/libs/SDL2/include/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_sensor.h b/libs/SDL2/include/SDL_sensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac163a8cd1be73201742fe56293ddc840653f706
--- /dev/null
+++ b/libs/SDL2/include/SDL_sensor.h
@@ -0,0 +1,251 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_sensor.h
+ *
+ *  Include file for SDL sensor event handling
+ *
+ */
+
+#ifndef _SDL_sensor_h
+#define _SDL_sensor_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ *  \brief SDL_sensor.h
+ *
+ *  In order to use these functions, SDL_Init() must have been called
+ *  with the ::SDL_INIT_SENSOR flag.  This causes SDL to scan the system
+ *  for sensors, and load appropriate drivers.
+ */
+
+struct _SDL_Sensor;
+typedef struct _SDL_Sensor SDL_Sensor;
+
+/**
+ * This is a unique ID for a sensor for the time it is connected to the system,
+ * and is never reused for the lifetime of the application.
+ *
+ * The ID value starts at 0 and increments from there. The value -1 is an invalid ID.
+ */
+typedef Sint32 SDL_SensorID;
+
+/* The different sensors defined by SDL
+ *
+ * Additional sensors may be available, using platform dependent semantics.
+ *
+ * Hare are the additional Android sensors:
+ * https://developer.android.com/reference/android/hardware/SensorEvent.html#values
+ */
+typedef enum
+{
+    SDL_SENSOR_INVALID = -1,    /**< Returned for an invalid sensor */
+    SDL_SENSOR_UNKNOWN,         /**< Unknown sensor type */
+    SDL_SENSOR_ACCEL,           /**< Accelerometer */
+    SDL_SENSOR_GYRO             /**< Gyroscope */
+} SDL_SensorType;
+
+/**
+ * Accelerometer sensor
+ *
+ * The accelerometer returns the current acceleration in SI meters per
+ * second squared. This includes gravity, so a device at rest will have
+ * an acceleration of SDL_STANDARD_GRAVITY straight down.
+ *
+ * values[0]: Acceleration on the x axis
+ * values[1]: Acceleration on the y axis
+ * values[2]: Acceleration on the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+#define SDL_STANDARD_GRAVITY    9.80665f
+
+/**
+ * Gyroscope sensor
+ *
+ * The gyroscope returns the current rate of rotation in radians per second.
+ * The rotation is positive in the counter-clockwise direction. That is,
+ * an observer looking from a positive location on one of the axes would
+ * see positive rotation on that axis when it appeared to be rotating
+ * counter-clockwise.
+ *
+ * values[0]: Angular speed around the x axis
+ * values[1]: Angular speed around the y axis
+ * values[2]: Angular speed around the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+
+/* Function prototypes */
+
+/**
+ *  \brief Count the number of sensors attached to the system right now
+ */
+extern DECLSPEC int SDLCALL SDL_NumSensors(void);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ * 
+ *  \return The sensor name, or NULL if device_index is out of range.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetDeviceName(int device_index);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetDeviceType(int device_index);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if device_index is out of range.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetDeviceNonPortableType(int device_index);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetDeviceInstanceID(int device_index);
+
+/**
+ *  \brief Open a sensor for use.
+ *
+ *  The index passed as an argument refers to the N'th sensor on the system.
+ *
+ *  \return A sensor identifier, or NULL if an error occurred.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorOpen(int device_index);
+
+/**
+ * Return the SDL_Sensor associated with an instance id.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorFromInstanceID(SDL_SensorID instance_id);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  \return The sensor name, or NULL if the sensor is NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetName(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetNonPortableType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetInstanceID(SDL_Sensor *sensor);
+
+/**
+ *  Get the current state of an opened sensor.
+ *
+ *  The number of values and interpretation of the data is sensor dependent.
+ *
+ *  \param sensor The sensor to query
+ *  \param data A pointer filled with the current sensor state
+ *  \param num_values The number of values to write to data
+ *
+ *  \return 0 or -1 if an error occurred.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values);
+
+/**
+ *  Close a sensor previously opened with SDL_SensorOpen()
+ */
+extern DECLSPEC void SDLCALL SDL_SensorClose(SDL_Sensor * sensor);
+
+/**
+ *  Update the current state of the open sensors.
+ *
+ *  This is called automatically by the event loop if sensor events are enabled.
+ *
+ *  This needs to be called from the thread that initialized the sensor subsystem.
+ */
+extern DECLSPEC void SDLCALL SDL_SensorUpdate(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_sensor_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/include/SDL_shape.h b/libs/SDL2/include/SDL_shape.h
old mode 100755
new mode 100644
index 9e492d93a4d1f6e42bcb2bbfec31fd71520cbaaa..40a6baaaec3d4d7e46c1da1fed54949123421035
--- a/libs/SDL2/include/SDL_shape.h
+++ b/libs/SDL2/include/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_stdinc.h b/libs/SDL2/include/SDL_stdinc.h
old mode 100755
new mode 100644
index 72402299f2da1892dd2224bc436b1822007f9b51..e373bc380f68867e5638b8f6ea26521a66a906ee
--- a/libs/SDL2/include/SDL_stdinc.h
+++ b/libs/SDL2/include/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -86,6 +86,28 @@
 #ifdef HAVE_FLOAT_H
 # include <float.h>
 #endif
+#if defined(HAVE_ALLOCA) && !defined(alloca)
+# if defined(HAVE_ALLOCA_H)
+#  include <alloca.h>
+# elif defined(__GNUC__)
+#  define alloca __builtin_alloca
+# elif defined(_MSC_VER)
+#  include <malloc.h>
+#  define alloca _alloca
+# elif defined(__WATCOMC__)
+#  include <malloc.h>
+# elif defined(__BORLANDC__)
+#  include <malloc.h>
+# elif defined(__DMC__)
+#  include <stdlib.h>
+# elif defined(__AIX__)
+#pragma alloca
+# elif defined(__MRC__)
+void *alloca(unsigned);
+# else
+char *alloca();
+# endif
+#endif
 
 /**
  *  The number of elements in an array.
@@ -328,28 +350,6 @@ SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
 extern "C" {
 #endif
 
-#if defined(HAVE_ALLOCA) && !defined(alloca)
-# if defined(HAVE_ALLOCA_H)
-#  include <alloca.h>
-# elif defined(__GNUC__)
-#  define alloca __builtin_alloca
-# elif defined(_MSC_VER)
-#  include <malloc.h>
-#  define alloca _alloca
-# elif defined(__WATCOMC__)
-#  include <malloc.h>
-# elif defined(__BORLANDC__)
-#  include <malloc.h>
-# elif defined(__DMC__)
-#  include <stdlib.h>
-# elif defined(__AIX__)
-#pragma alloca
-# elif defined(__MRC__)
-void *alloca(unsigned);
-# else
-char *alloca();
-# endif
-#endif
 #ifdef HAVE_ALLOCA
 #define SDL_stack_alloc(type, count)    (type*)alloca(sizeof(type)*(count))
 #define SDL_stack_free(data)
@@ -445,12 +445,12 @@ SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 #endif
 }
 
-
 extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 
 extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
 
+extern DECLSPEC wchar_t *SDLCALL SDL_wcsdup(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
 extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
@@ -501,18 +501,35 @@ extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size
 #endif
 
 extern DECLSPEC double SDLCALL SDL_acos(double x);
+extern DECLSPEC float SDLCALL SDL_acosf(float x);
 extern DECLSPEC double SDLCALL SDL_asin(double x);
+extern DECLSPEC float SDLCALL SDL_asinf(float x);
 extern DECLSPEC double SDLCALL SDL_atan(double x);
+extern DECLSPEC float SDLCALL SDL_atanf(float x);
 extern DECLSPEC double SDLCALL SDL_atan2(double x, double y);
+extern DECLSPEC float SDLCALL SDL_atan2f(float x, float y);
 extern DECLSPEC double SDLCALL SDL_ceil(double x);
+extern DECLSPEC float SDLCALL SDL_ceilf(float x);
 extern DECLSPEC double SDLCALL SDL_copysign(double x, double y);
+extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_cos(double x);
 extern DECLSPEC float SDLCALL SDL_cosf(float x);
+extern DECLSPEC double SDLCALL SDL_exp(double x);
+extern DECLSPEC float SDLCALL SDL_expf(float x);
 extern DECLSPEC double SDLCALL SDL_fabs(double x);
+extern DECLSPEC float SDLCALL SDL_fabsf(float x);
 extern DECLSPEC double SDLCALL SDL_floor(double x);
+extern DECLSPEC float SDLCALL SDL_floorf(float x);
+extern DECLSPEC double SDLCALL SDL_fmod(double x, double y);
+extern DECLSPEC float SDLCALL SDL_fmodf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_log(double x);
+extern DECLSPEC float SDLCALL SDL_logf(float x);
+extern DECLSPEC double SDLCALL SDL_log10(double x);
+extern DECLSPEC float SDLCALL SDL_log10f(float x);
 extern DECLSPEC double SDLCALL SDL_pow(double x, double y);
+extern DECLSPEC float SDLCALL SDL_powf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_scalbn(double x, int n);
+extern DECLSPEC float SDLCALL SDL_scalbnf(float x, int n);
 extern DECLSPEC double SDLCALL SDL_sin(double x);
 extern DECLSPEC float SDLCALL SDL_sinf(float x);
 extern DECLSPEC double SDLCALL SDL_sqrt(double x);
diff --git a/libs/SDL2/include/SDL_surface.h b/libs/SDL2/include/SDL_surface.h
old mode 100755
new mode 100644
index 510690c9cffe37fa3153d547d87c9ed0089584c2..730d49fc805ec54d5725c7369db4578d194aa56a
--- a/libs/SDL2/include/SDL_surface.h
+++ b/libs/SDL2/include/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,6 +97,17 @@ typedef struct SDL_Surface
 typedef int (SDLCALL *SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
                                  struct SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ * \brief The formula used for converting between YUV and RGB
+ */
+typedef enum
+{
+    SDL_YUV_CONVERSION_JPEG,        /**< Full range JPEG */
+    SDL_YUV_CONVERSION_BT601,       /**< BT.601 (the default) */
+    SDL_YUV_CONVERSION_BT709,       /**< BT.709 */
+    SDL_YUV_CONVERSION_AUTOMATIC    /**< BT.601 for SD content, BT.709 for HD content */
+} SDL_YUV_CONVERSION_MODE;
+
 /**
  *  Allocate and free an RGB surface.
  *
@@ -237,6 +248,13 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface * surface,
 extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
                                             int flag, Uint32 key);
 
+/**
+ *  \brief Returns whether the surface has a color key
+ *
+ *  \return SDL_TRUE if the surface has a color key, or SDL_FALSE if the surface is NULL or has no color key
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasColorKey(SDL_Surface * surface);
+
 /**
  *  \brief Gets the color key (transparent pixel) in a blittable surface.
  *
@@ -509,6 +527,20 @@ extern DECLSPEC int SDLCALL SDL_LowerBlitScaled
     (SDL_Surface * src, SDL_Rect * srcrect,
     SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ *  \brief Set the YUV conversion mode
+ */
+extern DECLSPEC void SDLCALL SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
+
+/**
+ *  \brief Get the YUV conversion mode
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionMode(void);
+
+/**
+ *  \brief Get the YUV conversion mode, returning the correct mode for the resolution when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionModeForResolution(int width, int height);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/include/SDL_system.h b/libs/SDL2/include/SDL_system.h
old mode 100755
new mode 100644
index eb069b33d8127f026de8b57b1869ccf3297f75e6..4dc372d6b14bb7fd49f64f716d1f9f29e3a15fbc
--- a/libs/SDL2/include/SDL_system.h
+++ b/libs/SDL2/include/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a
 #endif /* __WIN32__ */
 
 
+/* Platform specific functions for Linux */
+#ifdef __LINUX__
+
+/**
+   \brief Sets the UNIX nice value for a thread, using setpriority() if possible, and RealtimeKit if available.
+
+   \return 0 on success, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
+ 
+#endif /* __LINUX__ */
+	
 /* Platform specific functions for iOS */
 #if defined(__IPHONEOS__) && __IPHONEOS__
 
@@ -108,6 +120,26 @@ extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(void);
  */
 extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(void);
 
+/**
+   \brief Return true if the application is running on Android TV
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
+
+/**
+   \brief Return true if the application is running on a Chromebook
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void);
+
+/**
+  \brief Return true is the application is running on a Samsung DeX docking station
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void);
+
+/**
+ \brief Trigger the Android system back button behavior.
+ */
+extern DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
+
 /**
    See the official Android developer guide for more information:
    http://developer.android.com/guide/topics/data/data-storage.html
@@ -169,6 +201,25 @@ typedef enum
 } SDL_WinRT_Path;
 
 
+/**
+ *  \brief WinRT Device Family
+ */
+typedef enum
+{
+    /** \brief Unknown family  */
+    SDL_WINRT_DEVICEFAMILY_UNKNOWN,
+
+    /** \brief Desktop family*/
+    SDL_WINRT_DEVICEFAMILY_DESKTOP,
+
+    /** \brief Mobile family (for example smartphone) */
+    SDL_WINRT_DEVICEFAMILY_MOBILE,
+
+    /** \brief XBox family */
+    SDL_WINRT_DEVICEFAMILY_XBOX,
+} SDL_WinRT_DeviceFamily;
+
+
 /**
  *  \brief Retrieves a WinRT defined path on the local file system
  *
@@ -203,8 +254,20 @@ extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path
  */
 extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
 
+/**
+ *  \brief Detects the device family of WinRT plattform on runtime
+ *
+ *  \return Device family
+ */
+extern DECLSPEC SDL_WinRT_DeviceFamily SDLCALL SDL_WinRTGetDeviceFamily();
+
 #endif /* __WINRT__ */
 
+/**
+ \brief Return true if the current device is a tablet.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsTablet(void);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/include/SDL_syswm.h b/libs/SDL2/include/SDL_syswm.h
old mode 100755
new mode 100644
index 2d18afb6cf90173ca289b53f74dad013a3440909..f1c4021cc8b37be22124d28a99733d1e696e71e6
--- a/libs/SDL2/include/SDL_syswm.h
+++ b/libs/SDL2/include/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -33,12 +33,6 @@
 #include "SDL_video.h"
 #include "SDL_version.h"
 
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  *  \file SDL_syswm.h
  *
@@ -110,6 +104,12 @@ typedef void *EGLSurface;
 #include "SDL_egl.h"
 #endif
 
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  *  These are the various supported windowing subsystems
  */
diff --git a/libs/SDL2/include/SDL_test.h b/libs/SDL2/include/SDL_test.h
old mode 100755
new mode 100644
index f55afcb02273929055de6bf3a8848c2025e3bda3..6cc373bf809ca34195c28d7ef465fffac49c0e89
--- a/libs/SDL2/include/SDL_test.h
+++ b/libs/SDL2/include/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_assert.h b/libs/SDL2/include/SDL_test_assert.h
old mode 100755
new mode 100644
index 11d8363942948261e7a2403c3556d7e45860ef8a..1788d7a206916e92ccc607c24d93805ec368c838
--- a/libs/SDL2/include/SDL_test_assert.h
+++ b/libs/SDL2/include/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_common.h b/libs/SDL2/include/SDL_test_common.h
old mode 100755
new mode 100644
index 24eeb32af1b8731d95e28084a051b219480810be..be2e6b2aab48af89d8aab4986bd15bd0fc13bd68
--- a/libs/SDL2/include/SDL_test_common.h
+++ b/libs/SDL2/include/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_compare.h b/libs/SDL2/include/SDL_test_compare.h
old mode 100755
new mode 100644
index 9f4c4587ade92d8afe8d8102bd216db4458930e3..c22e447d8aee297971e6c51e4c1dd2fdb3a5cd52
--- a/libs/SDL2/include/SDL_test_compare.h
+++ b/libs/SDL2/include/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_crc32.h b/libs/SDL2/include/SDL_test_crc32.h
old mode 100755
new mode 100644
index add480c349fd91512e3a3229f44858407529a106..3d235d07400f10b10297e533f7d74c2cf02bc394
--- a/libs/SDL2/include/SDL_test_crc32.h
+++ b/libs/SDL2/include/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_font.h b/libs/SDL2/include/SDL_test_font.h
old mode 100755
new mode 100644
index 58c9f9d5e5f3334e23df3bbcba45cc6483635f67..59cbdcad6bcb101764c689f915d8395866b6ea6a
--- a/libs/SDL2/include/SDL_test_font.h
+++ b/libs/SDL2/include/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_fuzzer.h b/libs/SDL2/include/SDL_test_fuzzer.h
old mode 100755
new mode 100644
index 6cf05747ad91914fe7155322876cd3ff6e2a28d6..8fcb9ebbfa1ba58da745c08e0eb0a322e00319c6
--- a/libs/SDL2/include/SDL_test_fuzzer.h
+++ b/libs/SDL2/include/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_harness.h b/libs/SDL2/include/SDL_test_harness.h
old mode 100755
new mode 100644
index 68c4bcb7c44ff1fb09722fa81be6fb5013917eef..8641e0a7e3ad9945ed5ec93813920017bcc06447
--- a/libs/SDL2/include/SDL_test_harness.h
+++ b/libs/SDL2/include/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_images.h b/libs/SDL2/include/SDL_test_images.h
old mode 100755
new mode 100644
index 683d2f8a689e8d49b1c750493a6c04112a19b8e3..9c4dd5b82954fc21c15ff9027372ca3419c6252e
--- a/libs/SDL2/include/SDL_test_images.h
+++ b/libs/SDL2/include/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_log.h b/libs/SDL2/include/SDL_test_log.h
old mode 100755
new mode 100644
index 9f993fbbc880ded0f9c4c2dd81d838fb60753ed2..ebd44fb5021c3f4fc64dcab127780ab7da89ebd2
--- a/libs/SDL2/include/SDL_test_log.h
+++ b/libs/SDL2/include/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_md5.h b/libs/SDL2/include/SDL_test_md5.h
old mode 100755
new mode 100644
index 67ca7d1defbb70c02e83d43eef7f11ee6cbc81e5..0e4105768fdb6bd059ad867cb90d74637e28660c
--- a/libs/SDL2/include/SDL_test_md5.h
+++ b/libs/SDL2/include/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_memory.h b/libs/SDL2/include/SDL_test_memory.h
old mode 100755
new mode 100644
index 43b67f521be347be755fa725dfd2bdd6b96f6c01..4827ae6f2c372db861a635ae9faa32637f152a18
--- a/libs/SDL2/include/SDL_test_memory.h
+++ b/libs/SDL2/include/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_random.h b/libs/SDL2/include/SDL_test_random.h
old mode 100755
new mode 100644
index 2b01922c3ed5b82aace74bce3c661ce7c8b62782..0eb414ff2e4db2488ac5671f9d1a91048d0f3b34
--- a/libs/SDL2/include/SDL_test_random.h
+++ b/libs/SDL2/include/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_thread.h b/libs/SDL2/include/SDL_thread.h
old mode 100755
new mode 100644
index d0f6575cd5ac7562cb5dba1ca84b5e94b4a3f029..554dd0b61d02481d6f665dbde0799361b1967632
--- a/libs/SDL2/include/SDL_thread.h
+++ b/libs/SDL2/include/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -54,12 +54,13 @@ typedef unsigned int SDL_TLSID;
 /**
  *  The SDL thread priority.
  *
- *  \note On many systems you require special privileges to set high priority.
+ *  \note On many systems you require special privileges to set high or time critical priority.
  */
 typedef enum {
     SDL_THREAD_PRIORITY_LOW,
     SDL_THREAD_PRIORITY_NORMAL,
-    SDL_THREAD_PRIORITY_HIGH
+    SDL_THREAD_PRIORITY_HIGH,
+    SDL_THREAD_PRIORITY_TIME_CRITICAL
 } SDL_ThreadPriority;
 
 /**
@@ -105,14 +106,24 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
 
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
+                 const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
+
+
 /**
  *  Create a thread.
  */
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #endif
 
 #elif defined(__OS2__)
@@ -132,15 +143,31 @@ extern DECLSPEC SDL_Thread *SDLCALL
 SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #endif
 
 #else
 
+/**
+ *  Create a thread with a default stack size.
+ *
+ *  This is equivalent to calling:
+ *  SDL_CreateThreadWithStackSize(fn, name, 0, data);
+ */
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+
 /**
  *  Create a thread.
  *
@@ -158,9 +185,17 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
  *   If a system imposes requirements, SDL will try to munge the string for
  *    it (truncate, etc), but the original string contents will be available
  *    from SDL_GetThreadName().
+ *
+ *   The size (in bytes) of the new stack can be specified. Zero means "use
+ *    the system default" which might be wildly different between platforms
+ *    (x86 Linux generally defaults to eight megabytes, an embedded device
+ *    might be a few kilobytes instead).
+ *
+ *   In SDL 2.1, stacksize will be folded into the original SDL_CreateThread
+ *    function.
  */
 extern DECLSPEC SDL_Thread *SDLCALL
-SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data);
 
 #endif
 
diff --git a/libs/SDL2/include/SDL_timer.h b/libs/SDL2/include/SDL_timer.h
old mode 100755
new mode 100644
index 282625d3f0dc8dfe2b94fa48032d037cace0de3c..5600618ff4f8fbaacb2edf547ef8da1c182a0257
--- a/libs/SDL2/include/SDL_timer.h
+++ b/libs/SDL2/include/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_touch.h b/libs/SDL2/include/SDL_touch.h
old mode 100755
new mode 100644
index db9e25ebdccad221a3c38bbce06b02bec65c3c2c..f4075e79a5b5dd486579aa374474e3927101abe1
--- a/libs/SDL2/include/SDL_touch.h
+++ b/libs/SDL2/include/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_types.h b/libs/SDL2/include/SDL_types.h
old mode 100755
new mode 100644
index 06ee80cb358963b2fca3d8218a81595345e52671..4ac248c8c577f5150c8de8ad1b36df3bd4aea854
--- a/libs/SDL2/include/SDL_types.h
+++ b/libs/SDL2/include/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_version.h b/libs/SDL2/include/SDL_version.h
old mode 100755
new mode 100644
index 5b4c402486d6adb4e8ebaec3cfa4bee301e48e8b..31443e149adc071cba7431bc0cd47b007f1a0e22
--- a/libs/SDL2/include/SDL_version.h
+++ b/libs/SDL2/include/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      7
+#define SDL_PATCHLEVEL      9
 
 /**
  *  \brief Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/include/SDL_video.h b/libs/SDL2/include/SDL_video.h
old mode 100755
new mode 100644
index 6f6cda8b182b22160d97c0d9d5e684290419d0b9..461f13805101c9214ef4bd9b6df3143c3f093692
--- a/libs/SDL2/include/SDL_video.h
+++ b/libs/SDL2/include/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -110,7 +110,9 @@ typedef enum
     SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
-    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
+    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported.
+                                                     On macOS NSHighResolutionCapable must be set true in the
+                                                     application's Info.plist for this to have any effect. */
     SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,      /**< window has mouse captured (unrelated to INPUT_GRABBED) */
     SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,      /**< window should always be above others */
     SDL_WINDOW_SKIP_TASKBAR  = 0x00010000,      /**< window should not be added to the taskbar */
@@ -167,6 +169,24 @@ typedef enum
     SDL_WINDOWEVENT_HIT_TEST        /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */
 } SDL_WindowEventID;
 
+/**
+ *  \brief Event subtype for display events
+ */
+typedef enum
+{
+    SDL_DISPLAYEVENT_NONE,          /**< Never used */
+    SDL_DISPLAYEVENT_ORIENTATION    /**< Display orientation has changed to data1 */
+} SDL_DisplayEventID;
+
+typedef enum
+{
+    SDL_ORIENTATION_UNKNOWN,            /**< The display orientation can't be determined */
+    SDL_ORIENTATION_LANDSCAPE,          /**< The display is in landscape mode, with the right side up, relative to portrait mode */
+    SDL_ORIENTATION_LANDSCAPE_FLIPPED,  /**< The display is in landscape mode, with the left side up, relative to portrait mode */
+    SDL_ORIENTATION_PORTRAIT,           /**< The display is in portrait mode */
+    SDL_ORIENTATION_PORTRAIT_FLIPPED    /**< The display is in portrait mode, upside down */
+} SDL_DisplayOrientation;
+
 /**
  *  \brief An opaque handle to an OpenGL context.
  */
@@ -314,18 +334,6 @@ extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex);
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
 
-/**
- *  \brief Get the dots/pixels-per-inch for a display
- *
- *  \note Diagonal, horizontal and vertical DPI can all be optionally
- *        returned if the parameter is non-NULL.
- *
- *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
- *
- *  \sa SDL_GetNumVideoDisplays()
- */
-extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
-
 /**
  *  \brief Get the usable desktop area represented by a display, with the
  *         primary display located at 0,0
@@ -345,6 +353,27 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, fl
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
 
+/**
+ *  \brief Get the dots/pixels-per-inch for a display
+ *
+ *  \note Diagonal, horizontal and vertical DPI can all be optionally
+ *        returned if the parameter is non-NULL.
+ *
+ *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
+
+/**
+ *  \brief Get the orientation of a display
+ *
+ *  \return The orientation of the display, or SDL_ORIENTATION_UNKNOWN if it isn't available.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC SDL_DisplayOrientation SDLCALL SDL_GetDisplayOrientation(int displayIndex);
+
 /**
  *  \brief Returns the number of available display modes.
  *
@@ -470,7 +499,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window);
  *  If the window is created with any of the SDL_WINDOW_OPENGL or
  *  SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function
  *  (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the
- *  corrensponding UnloadLibrary function is called by SDL_DestroyWindow().
+ *  corresponding UnloadLibrary function is called by SDL_DestroyWindow().
  *
  *  If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver,
  *  SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail.
diff --git a/libs/SDL2/include/SDL_vulkan.h b/libs/SDL2/include/SDL_vulkan.h
old mode 100755
new mode 100644
index 803b5feef3489ba257ae3664cc93afc9f8fbcf1d..972cca4d7c2658f735d96d549ccd2a5819592b16
--- a/libs/SDL2/include/SDL_vulkan.h
+++ b/libs/SDL2/include/SDL_vulkan.h
@@ -69,30 +69,43 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
  *  \brief Dynamically load a Vulkan loader library.
  *
  *  \param [in] path The platform dependent Vulkan loader library name, or
- *              \c NULL to open the default Vulkan loader library.
+ *              \c NULL.
  *
  *  \return \c 0 on success, or \c -1 if the library couldn't be loaded.
  *
- *  This should be done after initializing the video driver, but before
+ *  If \a path is NULL SDL will use the value of the environment variable
+ *  \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
+ *  loader library.
+ *
+ *  This should be called after initializing the video driver, but before
  *  creating any Vulkan windows. If no Vulkan loader library is loaded, the
  *  default library will be loaded upon creation of the first Vulkan window.
  *
- *  \note If you specify a non-NULL \a path, you should retrieve all of the
- *        Vulkan functions used in your program from the dynamic library using
+ *  \note It is fairly common for Vulkan applications to link with \a libvulkan
+ *        instead of explicitly loading it at run time. This will work with
+ *        SDL provided the application links to a dynamic library and both it
+ *        and SDL use the same search path.
+ *
+ *  \note If you specify a non-NULL \c path, an application should retrieve all
+ *        of the Vulkan functions it uses from the dynamic library using
  *        \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee
- *        \a path points to the same vulkan loader library that you linked to.
+ *        \c path points to the same vulkan loader library the application
+ *        linked to.
  *
  *  \note On Apple devices, if \a path is NULL, SDL will attempt to find
  *        the vkGetInstanceProcAddr address within all the mach-o images of
- *        the current process. This is because the currently (v0.17.0)
- *        recommended MoltenVK (Vulkan on Metal) usage is as a static library.
- *        If it is not found then SDL will attempt to load \c libMoltenVK.dylib.
- *        Applications using the dylib alternative therefore do not need to do
- *        anything special when calling SDL.
- *
- *  \note On non-Apple devices, SDL requires you to either not link to the
- *        Vulkan loader or link to a dynamic library version. This limitation
- *        may be removed in a future version of SDL.
+ *        the current process. This is because it is fairly common for Vulkan
+ *        applications to link with libvulkan (and historically MoltenVK was
+ *        provided as a static library). If it is not found then, on macOS, SDL
+ *        will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
+ *        \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
+ *        On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
+ *        using a dynamic framework or .dylib must ensure it is included in its
+ *        application bundle.
+ *
+ *  \note On non-Apple devices, application linking with a static libvulkan is
+ *        not supported. Either do not link to the Vulkan loader or link to a
+ *        dynamic library version.
  *
  *  \note This function will fail if there are no working Vulkan drivers
  *        installed.
@@ -122,11 +135,11 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \brief Get the names of the Vulkan instance extensions needed to create
  *         a surface with \c SDL_Vulkan_CreateSurface().
  *
- *  \param [in]     window Window for which the required Vulkan instance
+ *  \param [in]     \c NULL or window Window for which the required Vulkan instance
  *                  extensions should be retrieved
- *  \param [in,out] count pointer to an \c unsigned related to the number of
+ *  \param [in,out] pCount pointer to an \c unsigned related to the number of
  *                  required Vulkan instance extensions
- *  \param [out]    names \c NULL or a pointer to an array to be filled with the
+ *  \param [out]    pNames \c NULL or a pointer to an array to be filled with the
  *                  required Vulkan instance extensions
  *
  *  \return \c SDL_TRUE on success, \c SDL_FALSE on error.
@@ -140,6 +153,10 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  is smaller than the number of required extensions, \c SDL_FALSE will be
  *  returned instead of \c SDL_TRUE, to indicate that not all the required
  *  extensions were returned.
+ * 
+ *  \note If \c window is not NULL, it will be checked against its creation
+ *        flags to ensure that the Vulkan flag is present. This parameter
+ *        will be removed in a future major release.
  *
  *  \note The returned list of extensions will contain \c VK_KHR_surface
  *        and zero or more platform specific extensions
@@ -147,12 +164,13 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \note The extension names queried here must be enabled when calling
  *        VkCreateInstance, otherwise surface creation will fail.
  *
- *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag.
+ *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag
+ *        or be \c NULL
  *
  *  \code
  *  unsigned int count;
  *  // get count of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, NULL))
  *      handle_error();
  *
  *  static const char *const additionalExtensions[] =
@@ -166,7 +184,7 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *      handle_error();
  *
  *  // get names of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, names))
  *      handle_error();
  *
  *  // copy additional extensions after required extensions
@@ -240,6 +258,9 @@ extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_CreateSurface(
  * platform with high-DPI support (Apple calls this "Retina"), and not disabled
  * by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
  *
+ *  \note On macOS high-DPI support must be enabled for an application by
+ *        setting NSHighResolutionCapable to true in its Info.plist.
+ *
  *  \sa SDL_GetWindowSize()
  *  \sa SDL_CreateWindow()
  */
diff --git a/libs/SDL2/include/begin_code.h b/libs/SDL2/include/begin_code.h
old mode 100755
new mode 100644
index 5372d6f04df418acb02bf51cd545c2170bb73849..6c2106246f2583ba711451bc7e39fc2af7e9eec7
--- a/libs/SDL2/include/begin_code.h
+++ b/libs/SDL2/include/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/close_code.h b/libs/SDL2/include/close_code.h
old mode 100755
new mode 100644
index 2a352dbb9ec7502c62b561f30bd7433b18e581d1..b3b70a4c833d80305bbffd306c8ac099babdf419
--- a/libs/SDL2/include/close_code.h
+++ b/libs/SDL2/include/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/lib/x64/SDL2.dll b/libs/SDL2/lib/x64/SDL2.dll
old mode 100755
new mode 100644
index 6776cdd891ea4479c662519a1667ddc08ca5a8ef..934f8091c7d59b5d479026cfab1ec45d9077fff1
Binary files a/libs/SDL2/lib/x64/SDL2.dll and b/libs/SDL2/lib/x64/SDL2.dll differ
diff --git a/libs/SDL2/lib/x64/SDL2.lib b/libs/SDL2/lib/x64/SDL2.lib
old mode 100755
new mode 100644
index 42e5ee7d0d205716ff111f3142617a81a0e8979b..f4941ae0e34edcfb71f31cdf289afeae0b3c2305
Binary files a/libs/SDL2/lib/x64/SDL2.lib and b/libs/SDL2/lib/x64/SDL2.lib differ
diff --git a/libs/SDL2/lib/x64/SDL2main.lib b/libs/SDL2/lib/x64/SDL2main.lib
old mode 100755
new mode 100644
index 1f409a2499d5306887d22041f9520cbb6c3a28f7..6129946574aa807aad3da264518444cc115f51f4
Binary files a/libs/SDL2/lib/x64/SDL2main.lib and b/libs/SDL2/lib/x64/SDL2main.lib differ
diff --git a/libs/SDL2/lib/x64/SDL2test.lib b/libs/SDL2/lib/x64/SDL2test.lib
old mode 100755
new mode 100644
index b54347ddc4cfbcdacf2110d9391ed9f60a47decf..5b0328280a7dffe20df128d6685f235b10d77459
Binary files a/libs/SDL2/lib/x64/SDL2test.lib and b/libs/SDL2/lib/x64/SDL2test.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2.dll b/libs/SDL2/lib/x86/SDL2.dll
old mode 100755
new mode 100644
index c21f747c2f45540809ff1fd901e2bb607ead0fff..70177904476cc7ab959c84e08a92df76cd0d748c
Binary files a/libs/SDL2/lib/x86/SDL2.dll and b/libs/SDL2/lib/x86/SDL2.dll differ
diff --git a/libs/SDL2/lib/x86/SDL2.lib b/libs/SDL2/lib/x86/SDL2.lib
old mode 100755
new mode 100644
index a36fab5a3bed78ec4a6ad5903ab40c58054318b0..cef79017ce2858e313eac2c6fccda4e7014bd77e
Binary files a/libs/SDL2/lib/x86/SDL2.lib and b/libs/SDL2/lib/x86/SDL2.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2main.lib b/libs/SDL2/lib/x86/SDL2main.lib
old mode 100755
new mode 100644
index 2080d5db5f3bec958f02a2c35c17ec69fad0dd6f..55c40c7a0757d13e7b178f76267b507c958b6626
Binary files a/libs/SDL2/lib/x86/SDL2main.lib and b/libs/SDL2/lib/x86/SDL2main.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2test.lib b/libs/SDL2/lib/x86/SDL2test.lib
old mode 100755
new mode 100644
index c26c50f612086cf4ed28fe3288f6974567893f2a..d7a395ff1dd03a19bb4624e023c0856454e789e6
Binary files a/libs/SDL2/lib/x86/SDL2test.lib and b/libs/SDL2/lib/x86/SDL2test.lib differ
diff --git a/libs/SDL2/test/CMakeLists.txt b/libs/SDL2/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3c25c5c7c98790944cc22c408cec58152544b0e6
--- /dev/null
+++ b/libs/SDL2/test/CMakeLists.txt
@@ -0,0 +1,122 @@
+cmake_minimum_required(VERSION 2.8.11)
+project(SDL2 C)
+
+# Global settings for all of the test targets
+# FIXME: is this wrong?
+remove_definitions(-DUSING_GENERATED_CONFIG_H)
+link_libraries(SDL2_test SDL2-static)
+
+# FIXME: Parent directory CMakeLists.txt only sets these for mingw/cygwin,
+# but we need them for VS as well.
+if(WINDOWS)
+    link_libraries(SDL2main)
+    add_definitions(-Dmain=SDL_main)
+endif()
+
+add_executable(checkkeys checkkeys.c)
+add_executable(loopwave loopwave.c)
+add_executable(loopwavequeue loopwavequeue.c)
+add_executable(testresample testresample.c)
+add_executable(testaudioinfo testaudioinfo.c)
+
+file(GLOB TESTAUTOMATION_SOURCE_FILES testautomation*.c)
+add_executable(testautomation ${TESTAUTOMATION_SOURCE_FILES})
+
+add_executable(testmultiaudio testmultiaudio.c)
+add_executable(testaudiohotplug testaudiohotplug.c)
+add_executable(testaudiocapture testaudiocapture.c)
+add_executable(testatomic testatomic.c)
+add_executable(testintersections testintersections.c)
+add_executable(testrelative testrelative.c)
+add_executable(testhittesting testhittesting.c)
+add_executable(testdraw2 testdraw2.c)
+add_executable(testdrawchessboard testdrawchessboard.c)
+add_executable(testdropfile testdropfile.c)
+add_executable(testerror testerror.c)
+add_executable(testfile testfile.c)
+add_executable(testgamecontroller testgamecontroller.c)
+add_executable(testgesture testgesture.c)
+add_executable(testgl2 testgl2.c)
+add_executable(testgles testgles.c)
+add_executable(testgles2 testgles2.c)
+add_executable(testhaptic testhaptic.c)
+add_executable(testhotplug testhotplug.c)
+add_executable(testrumble testrumble.c)
+add_executable(testthread testthread.c)
+add_executable(testiconv testiconv.c)
+add_executable(testime testime.c)
+add_executable(testjoystick testjoystick.c)
+add_executable(testkeys testkeys.c)
+add_executable(testloadso testloadso.c)
+add_executable(testlock testlock.c)
+
+if(APPLE)
+    add_executable(testnative testnative.c
+                              testnativecocoa.m
+                              testnativex11.c)
+elseif(WINDOWS)
+    add_executable(testnative testnative.c testnativew32.c)
+elseif(UNIX)
+    add_executable(testnative testnative.c testnativex11.c)
+endif()
+
+add_executable(testoverlay2 testoverlay2.c testyuv_cvt.c)
+add_executable(testplatform testplatform.c)
+add_executable(testpower testpower.c)
+add_executable(testfilesystem testfilesystem.c)
+add_executable(testrendertarget testrendertarget.c)
+add_executable(testscale testscale.c)
+add_executable(testsem testsem.c)
+add_executable(testshader testshader.c)
+add_executable(testshape testshape.c)
+add_executable(testsprite2 testsprite2.c)
+add_executable(testspriteminimal testspriteminimal.c)
+add_executable(teststreaming teststreaming.c)
+add_executable(testtimer testtimer.c)
+add_executable(testver testver.c)
+add_executable(testviewport testviewport.c)
+add_executable(testwm2 testwm2.c)
+add_executable(testyuv testyuv.c testyuv_cvt.c)
+add_executable(torturethread torturethread.c)
+add_executable(testrendercopyex testrendercopyex.c)
+add_executable(testmessage testmessage.c)
+add_executable(testdisplayinfo testdisplayinfo.c)
+add_executable(testqsort testqsort.c)
+add_executable(testbounds testbounds.c)
+add_executable(testcustomcursor testcustomcursor.c)
+add_executable(controllermap controllermap.c)
+add_executable(testvulkan testvulkan.c)
+
+# HACK: Dummy target to cause the resource files to be copied to the build directory.
+# Need to make it an executable so we can use the TARGET_FILE_DIR generator expression.
+# This is needed so they get copied to the correct Debug/Release subdirectory in Xcode.
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/resources_dummy.c "int main(int argc, const char **argv){ return 1; }\n")
+add_executable(SDL2_test_resoureces ${CMAKE_CURRENT_BINARY_DIR}/resources_dummy.c)
+
+file(GLOB RESOURCE_FILES *.bmp *.wav)
+foreach(RESOURCE_FILE ${RESOURCE_FILES})
+    add_custom_command(TARGET SDL2_test_resoureces POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${RESOURCE_FILE} $<TARGET_FILE_DIR:SDL2_test_resoureces>)
+endforeach(RESOURCE_FILE)
+
+file(COPY ${RESOURCE_FILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+# TODO: Might be easier to make all targets depend on the resources...?
+add_dependencies(testscale SDL2_test_resoureces)
+add_dependencies(testrendercopyex SDL2_test_resoureces)
+add_dependencies(controllermap SDL2_test_resoureces)
+add_dependencies(testyuv SDL2_test_resoureces)
+add_dependencies(testgamecontroller SDL2_test_resoureces)
+add_dependencies(testshape SDL2_test_resoureces)
+add_dependencies(testshader SDL2_test_resoureces)
+add_dependencies(testnative SDL2_test_resoureces)
+add_dependencies(testspriteminimal SDL2_test_resoureces)
+add_dependencies(testautomation SDL2_test_resoureces)
+add_dependencies(testcustomcursor SDL2_test_resoureces)
+add_dependencies(testrendertarget SDL2_test_resoureces)
+add_dependencies(testsprite2 SDL2_test_resoureces)
+
+add_dependencies(loopwave SDL2_test_resoureces)
+add_dependencies(loopwavequeue SDL2_test_resoureces)
+add_dependencies(testresample SDL2_test_resoureces)
+add_dependencies(testaudiohotplug SDL2_test_resoureces)
+add_dependencies(testmultiaudio SDL2_test_resoureces)
diff --git a/libs/SDL2/test/Makefile.in b/libs/SDL2/test/Makefile.in
index 0ac70e923be6800d88b1ff7a226546a13d3a6baa..9ddd6ffe7785e606f2c6ba4bcbfda8aca65f37f8 100644
--- a/libs/SDL2/test/Makefile.in
+++ b/libs/SDL2/test/Makefile.in
@@ -9,19 +9,23 @@ LIBS	= @LIBS@
 
 TARGETS = \
 	checkkeys$(EXE) \
+	controllermap$(EXE) \
 	loopwave$(EXE) \
 	loopwavequeue$(EXE) \
 	testatomic$(EXE) \
-	testaudioinfo$(EXE) \
 	testaudiocapture$(EXE) \
+	testaudiohotplug$(EXE) \
+	testaudioinfo$(EXE) \
 	testautomation$(EXE) \
 	testbounds$(EXE) \
 	testcustomcursor$(EXE) \
+	testdisplayinfo$(EXE) \
 	testdraw2$(EXE) \
 	testdrawchessboard$(EXE) \
 	testdropfile$(EXE) \
 	testerror$(EXE) \
 	testfile$(EXE) \
+	testfilesystem$(EXE) \
 	testgamecontroller$(EXE) \
 	testgesture$(EXE) \
 	testgl2$(EXE) \
@@ -29,44 +33,42 @@ TARGETS = \
 	testgles2$(EXE) \
 	testhaptic$(EXE) \
 	testhittesting$(EXE) \
-	testrumble$(EXE) \
 	testhotplug$(EXE) \
-	testthread$(EXE) \
 	testiconv$(EXE) \
 	testime$(EXE) \
 	testintersections$(EXE) \
-	testrelative$(EXE) \
 	testjoystick$(EXE) \
 	testkeys$(EXE) \
 	testloadso$(EXE) \
 	testlock$(EXE) \
+	testmessage$(EXE) \
 	testmultiaudio$(EXE) \
-	testaudiohotplug$(EXE) \
 	testnative$(EXE) \
 	testoverlay2$(EXE) \
 	testplatform$(EXE) \
 	testpower$(EXE) \
-	testfilesystem$(EXE) \
+	testqsort$(EXE) \
+	testrelative$(EXE) \
+	testrendercopyex$(EXE) \
 	testrendertarget$(EXE) \
 	testresample$(EXE) \
+	testrumble$(EXE) \
 	testscale$(EXE) \
 	testsem$(EXE) \
+	testsensor$(EXE) \
 	testshader$(EXE) \
 	testshape$(EXE) \
 	testsprite2$(EXE) \
 	testspriteminimal$(EXE) \
 	teststreaming$(EXE) \
+	testthread$(EXE) \
 	testtimer$(EXE) \
 	testver$(EXE) \
 	testviewport$(EXE) \
+	testvulkan$(EXE) \
 	testwm2$(EXE) \
+	testyuv$(EXE) \
 	torturethread$(EXE) \
-	testrendercopyex$(EXE) \
-	testmessage$(EXE) \
-	testdisplayinfo$(EXE) \
-	testqsort$(EXE) \
-	controllermap$(EXE) \
-	testvulkan$(EXE) \
 	
 all: Makefile $(TARGETS) copydatafiles
 
@@ -218,7 +220,7 @@ endif
 endif
 endif
 
-testoverlay2$(EXE): $(srcdir)/testoverlay2.c
+testoverlay2$(EXE): $(srcdir)/testoverlay2.c $(srcdir)/testyuv_cvt.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
 testplatform$(EXE): $(srcdir)/testplatform.c
@@ -239,6 +241,9 @@ testscale$(EXE): $(srcdir)/testscale.c
 testsem$(EXE): $(srcdir)/testsem.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
+testsensor$(EXE): $(srcdir)/testsensor.c
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
 testshader$(EXE): $(srcdir)/testshader.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @GLLIB@ @MATHLIB@
 
@@ -266,6 +271,9 @@ testviewport$(EXE): $(srcdir)/testviewport.c
 testwm2$(EXE): $(srcdir)/testwm2.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
+testyuv$(EXE): $(srcdir)/testyuv.c $(srcdir)/testyuv_cvt.c
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
 torturethread$(EXE): $(srcdir)/torturethread.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
@@ -309,7 +317,10 @@ distclean: clean
 %.wav: $(srcdir)/%.wav
 	cp $< $@
 
-copydatafiles: copybmpfiles copywavfiles
+%.dat: $(srcdir)/%.dat
+	cp $< $@
+
+copydatafiles: copybmpfiles copywavfiles copydatfiles
 .PHONY : copydatafiles
 
 copybmpfiles: $(foreach bmp,$(wildcard $(srcdir)/*.bmp),$(notdir $(bmp)))
@@ -318,3 +329,6 @@ copybmpfiles: $(foreach bmp,$(wildcard $(srcdir)/*.bmp),$(notdir $(bmp)))
 copywavfiles: $(foreach wav,$(wildcard $(srcdir)/*.wav),$(notdir $(wav)))
 .PHONY : copywavfiles
 
+copydatfiles: $(foreach dat,$(wildcard $(srcdir)/*.dat),$(notdir $(dat)))
+.PHONY : copydatfiles
+
diff --git a/libs/SDL2/test/checkkeys.c b/libs/SDL2/test/checkkeys.c
index 066c786d4392db048109551a6ab9b96ce63be8eb..4452acaba5220484a12a4a74382161490f58dc98 100644
--- a/libs/SDL2/test/checkkeys.c
+++ b/libs/SDL2/test/checkkeys.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/controllermap.c b/libs/SDL2/test/controllermap.c
index c4fe5929c3ade4870cee18a5d9c18c6b9b9b53b0..2ca53518a7e6d3b9b16e15c1377d6f929437cdc3 100644
--- a/libs/SDL2/test/controllermap.c
+++ b/libs/SDL2/test/controllermap.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/loopwave.c b/libs/SDL2/test/loopwave.c
index 63e19961105559b647f339147e33a30184b4c66a..88d8fc87181e493f6ad61f07d28c203497d2cb61 100644
--- a/libs/SDL2/test/loopwave.c
+++ b/libs/SDL2/test/loopwave.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/loopwavequeue.c b/libs/SDL2/test/loopwavequeue.c
index 3dc7792f6d6ecf1559c95da5a09e231e19b64488..3f0a69e1594fabb7e301879f6837ce2cf714eabe 100644
--- a/libs/SDL2/test/loopwavequeue.c
+++ b/libs/SDL2/test/loopwavequeue.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testatomic.c b/libs/SDL2/test/testatomic.c
index f8dca91785ca6f108851b6a6ace0e1e007dc2c48..6af9d4bf62830033495e5dd781c25a96a42da040 100644
--- a/libs/SDL2/test/testatomic.c
+++ b/libs/SDL2/test/testatomic.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testaudiocapture.c b/libs/SDL2/test/testaudiocapture.c
index 3b7ea0b790b90f5a00eacbbed68d4285bea82cd2..a418d123c4bf35f1e27cc5b0df13d92dcb206b78 100644
--- a/libs/SDL2/test/testaudiocapture.c
+++ b/libs/SDL2/test/testaudiocapture.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testaudiohotplug.c b/libs/SDL2/test/testaudiohotplug.c
index a72f91745e49d8996a79f3930c87917e01773dc4..374cbb27b74a3ae8bce6dcf3a41df30cc10f2435 100644
--- a/libs/SDL2/test/testaudiohotplug.c
+++ b/libs/SDL2/test/testaudiohotplug.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testaudioinfo.c b/libs/SDL2/test/testaudioinfo.c
index c70b86b5e07e326bb57fb9a5993b98a9b55251e3..adecce9b7249608c68077d34c34cd5b14f48b859 100644
--- a/libs/SDL2/test/testaudioinfo.c
+++ b/libs/SDL2/test/testaudioinfo.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testautomation.c b/libs/SDL2/test/testautomation.c
index 9fd22be072409110c87d52966e111366ac8d6e8e..bb799ea43b60e34143132a6292b6b8b7592c9281 100644
--- a/libs/SDL2/test/testautomation.c
+++ b/libs/SDL2/test/testautomation.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testbounds.c b/libs/SDL2/test/testbounds.c
index bc46cb823fee8528ced0bfeea6686daeb3aa8cc3..764809446a29e3620ba3d41d8744b9d4fc76f651 100644
--- a/libs/SDL2/test/testbounds.c
+++ b/libs/SDL2/test/testbounds.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testcustomcursor.c b/libs/SDL2/test/testcustomcursor.c
index 59c6409db01f58dfa61b964690c1fe77a8660934..469449818559b285a185ef460b83e0bda4c8ec63 100644
--- a/libs/SDL2/test/testcustomcursor.c
+++ b/libs/SDL2/test/testcustomcursor.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -73,6 +73,24 @@ init_color_cursor(const char *file)
     SDL_Cursor *cursor = NULL;
     SDL_Surface *surface = SDL_LoadBMP(file);
     if (surface) {
+        if (surface->format->palette) {
+            SDL_SetColorKey(surface, 1, *(Uint8 *) surface->pixels);
+        } else {
+            switch (surface->format->BitsPerPixel) {
+            case 15:
+                SDL_SetColorKey(surface, 1, (*(Uint16 *)surface->pixels) & 0x00007FFF);
+                break;
+            case 16:
+                SDL_SetColorKey(surface, 1, *(Uint16 *)surface->pixels);
+                break;
+            case 24:
+                SDL_SetColorKey(surface, 1, (*(Uint32 *)surface->pixels) & 0x00FFFFFF);
+                break;
+            case 32:
+                SDL_SetColorKey(surface, 1, *(Uint32 *)surface->pixels);
+                break;
+            }
+        }
         cursor = SDL_CreateColorCursor(surface, 0, 0);
         SDL_FreeSurface(surface);
     }
@@ -116,7 +134,9 @@ init_system_cursor(const char *image[])
 
 static SDLTest_CommonState *state;
 int done;
-SDL_Cursor *cursor = NULL;
+static SDL_Cursor *cursors[1+SDL_NUM_SYSTEM_CURSORS];
+static int current_cursor;
+static int show_cursor;
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
 static void
@@ -134,6 +154,18 @@ loop()
     /* Check for events */
     while (SDL_PollEvent(&event)) {
         SDLTest_CommonEvent(state, &event, &done);
+        if (event.type == SDL_MOUSEBUTTONDOWN) {
+            if (event.button.button == SDL_BUTTON_LEFT) {
+                ++current_cursor;
+                if (current_cursor == SDL_arraysize(cursors)) {
+                    current_cursor = 0;
+                }
+                SDL_SetCursor(cursors[current_cursor]);
+            } else {
+                show_cursor = !show_cursor;
+                SDL_ShowCursor(show_cursor);
+            }
+        }
     }
     
     for (i = 0; i < state->num_windows; ++i) {
@@ -188,15 +220,22 @@ main(int argc, char *argv[])
     }
 
     if (color_cursor) {
-        cursor = init_color_cursor(color_cursor);
+        cursors[0] = init_color_cursor(color_cursor);
     } else {
-        cursor = init_system_cursor(arrow);
+        cursors[0] = init_system_cursor(arrow);
     }
-    if (!cursor) {
+    if (!cursors[0]) {
         SDL_Log("Error, couldn't create cursor\n");
         quit(2);
     }
-    SDL_SetCursor(cursor);
+    for (i = 0; i < SDL_NUM_SYSTEM_CURSORS; ++i) {
+        cursors[1+i] = SDL_CreateSystemCursor((SDL_SystemCursor)i);
+        if (!cursors[1+i]) {
+            SDL_Log("Error, couldn't create system cursor %d\n", i);
+            quit(2);
+        }
+    }
+    SDL_SetCursor(cursors[0]);
 
     /* Main render loop */
     done = 0;
@@ -208,9 +247,13 @@ main(int argc, char *argv[])
     }
 #endif
 
-    SDL_FreeCursor(cursor);
+    for (i = 0; i < SDL_arraysize(cursors); ++i) {
+        SDL_FreeCursor(cursors[i]);
+    }
     quit(0);
 
     /* keep the compiler happy ... */
     return(0);
 }
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/test/testdisplayinfo.c b/libs/SDL2/test/testdisplayinfo.c
index 51c19b010be3044b8a66308a7aaa2a70fa936a78..0cc5fbdd74bdc8aed1b008c22d5862419c6c7d5c 100644
--- a/libs/SDL2/test/testdisplayinfo.c
+++ b/libs/SDL2/test/testdisplayinfo.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testdraw2.c b/libs/SDL2/test/testdraw2.c
index 1472a3863e16ed5f426ce39fd25d5eaa68f0c014..91ee7eea2c765c98555ca1632f3eba4499951e9e 100644
--- a/libs/SDL2/test/testdraw2.c
+++ b/libs/SDL2/test/testdraw2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testdrawchessboard.c b/libs/SDL2/test/testdrawchessboard.c
index cef8621fca8e7eb9b5dc64ea02e346d73426d59c..3dd78e1ac662302174e5dfacf7de6e07d22e6d2c 100644
--- a/libs/SDL2/test/testdrawchessboard.c
+++ b/libs/SDL2/test/testdrawchessboard.c
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testdropfile.c b/libs/SDL2/test/testdropfile.c
index b3cb17d9bff69f9bfeb0d86803cb366ab2bc7c75..1c2a3f0e64197330515b5e370f9c297e7aaac401 100644
--- a/libs/SDL2/test/testdropfile.c
+++ b/libs/SDL2/test/testdropfile.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testerror.c b/libs/SDL2/test/testerror.c
index 468f8a7fb8ae789a7417b564a2733513669a3bec..87fcab21b3e5e98b05404d1f7748a93f80e3f9d1 100644
--- a/libs/SDL2/test/testerror.c
+++ b/libs/SDL2/test/testerror.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testfile.c b/libs/SDL2/test/testfile.c
index 23215ea277a258bee07f75ac4fad4ff779b593c1..e563d77bee96cd27a34a985b94e8716c42035dfc 100644
--- a/libs/SDL2/test/testfile.c
+++ b/libs/SDL2/test/testfile.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testfilesystem.c b/libs/SDL2/test/testfilesystem.c
index e8a3b3c36d29b9038b0bd0ee7911b2dd45e93902..ada4e864ced90d9d5c14a9d6bccf44c6476438d4 100644
--- a/libs/SDL2/test/testfilesystem.c
+++ b/libs/SDL2/test/testfilesystem.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testgamecontroller.c b/libs/SDL2/test/testgamecontroller.c
index f586bfe220e90efdc6f50c5b732a82f9d2a373bb..c8616d7cd21abae4ce857e31426eb5ef9f5c65bd 100644
--- a/libs/SDL2/test/testgamecontroller.c
+++ b/libs/SDL2/test/testgamecontroller.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -114,6 +114,11 @@ loop(void *arg)
         case SDL_CONTROLLERBUTTONDOWN:
         case SDL_CONTROLLERBUTTONUP:
             SDL_Log("Controller button %s %s\n", SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button), event.cbutton.state ? "pressed" : "released");
+            /* First button triggers a 0.5 second full strength rumble */
+            if (event.type == SDL_CONTROLLERBUTTONDOWN &&
+                event.cbutton.button == SDL_CONTROLLER_BUTTON_A) {
+                SDL_GameControllerRumble(gamecontroller, 0xFFFF, 0xFFFF, 500);
+            }
             break;
         case SDL_KEYDOWN:
             if (event.key.keysym.sym != SDLK_ESCAPE) {
diff --git a/libs/SDL2/test/testgesture.c b/libs/SDL2/test/testgesture.c
index f7db94fbeb36108d0e6847c8ab94033dc28af135..f4b254a65b7b777782047a44e063533c6bcfd4c4 100644
--- a/libs/SDL2/test/testgesture.c
+++ b/libs/SDL2/test/testgesture.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testgl2.c b/libs/SDL2/test/testgl2.c
index 114c14105ebecea81e9f27db9951021d5940340c..dd01d0e291ae34cef950068fb5416d21b8fa6181 100644
--- a/libs/SDL2/test/testgl2.c
+++ b/libs/SDL2/test/testgl2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testgles.c b/libs/SDL2/test/testgles.c
index cb1da1407e30df9ff77861e94293984b7b2bafeb..96895da0f7992d48fc6af3886846efee73233b2e 100644
--- a/libs/SDL2/test/testgles.c
+++ b/libs/SDL2/test/testgles.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testgles2.c b/libs/SDL2/test/testgles2.c
index 282e0b611e70e4e70afbacf79f4a18e1a148d2d1..c4578a5cc7987b558b3b4a713fbfa704b6bf76d3 100644
--- a/libs/SDL2/test/testgles2.c
+++ b/libs/SDL2/test/testgles2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testhotplug.c b/libs/SDL2/test/testhotplug.c
index 765ce2639499a6d1fda317f38844f7c8343cd0c2..72c90e8d97dbfdc1ac60afa32e1ca4398b171b30 100644
--- a/libs/SDL2/test/testhotplug.c
+++ b/libs/SDL2/test/testhotplug.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testiconv.c b/libs/SDL2/test/testiconv.c
index ff3b28c93c7eadfe401cf216c387532dba3fea87..47e8c377acb5b33229cf8c1f270ab88c95662744 100644
--- a/libs/SDL2/test/testiconv.c
+++ b/libs/SDL2/test/testiconv.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testime.c b/libs/SDL2/test/testime.c
index 32f80cd6bd63cc75efd800197de707b439d1d7e4..77bb86962869ea03970e2ee881c372dc6b530207 100644
--- a/libs/SDL2/test/testime.c
+++ b/libs/SDL2/test/testime.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testintersections.c b/libs/SDL2/test/testintersections.c
index dcf1bc172f5578262092599cbc73652b4400a15d..619df0640e1599ed200887872bc71ae0f5322df5 100644
--- a/libs/SDL2/test/testintersections.c
+++ b/libs/SDL2/test/testintersections.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testjoystick.c b/libs/SDL2/test/testjoystick.c
index 50e5cc96ef17618fbabe1a9312cb7fffed111226..bca74924401048fba60712304d7db4fbe7da3756 100644
--- a/libs/SDL2/test/testjoystick.c
+++ b/libs/SDL2/test/testjoystick.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -90,6 +90,10 @@ loop(void *arg)
             case SDL_JOYBUTTONDOWN:
                 SDL_Log("Joystick %d button %d down\n",
                        event.jbutton.which, event.jbutton.button);
+                /* First button triggers a 0.5 second full strength rumble */
+                if (event.jbutton.button == 0) {
+                    SDL_JoystickRumble(joystick, 0xFFFF, 0xFFFF, 500);
+                }
                 break;
             case SDL_JOYBUTTONUP:
                 SDL_Log("Joystick %d button %d up\n",
diff --git a/libs/SDL2/test/testkeys.c b/libs/SDL2/test/testkeys.c
index 33649d22928d3d2648619e330437f8d81d752a56..73f880e13acefbc6c2475cb950b250ed930dc744 100644
--- a/libs/SDL2/test/testkeys.c
+++ b/libs/SDL2/test/testkeys.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testloadso.c b/libs/SDL2/test/testloadso.c
index 2dce11d6a52f79e0b93a4a56361eaade8f648bba..c6fa33106ff6cda7d172aa6fd57d8abb66f86892 100644
--- a/libs/SDL2/test/testloadso.c
+++ b/libs/SDL2/test/testloadso.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testlock.c b/libs/SDL2/test/testlock.c
index e79fcda966cfd50dc54c8dda2427b5c35f221420..8299a9a675decc8ef63715526ec42491b65d6ad0 100644
--- a/libs/SDL2/test/testlock.c
+++ b/libs/SDL2/test/testlock.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testmessage.c b/libs/SDL2/test/testmessage.c
index 07d0b0309794b0a6e68fea24a9e041f8f5c6d831..8488d8eda61ac4c2ad7d8275d2d819e8b9e33276 100644
--- a/libs/SDL2/test/testmessage.c
+++ b/libs/SDL2/test/testmessage.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testmultiaudio.c b/libs/SDL2/test/testmultiaudio.c
index 4bae3859cb0e1efe7fa21ad6ccdd9102947ecac5..52a4cac7d96150c41e0d8b532e5675b7fe982adc 100644
--- a/libs/SDL2/test/testmultiaudio.c
+++ b/libs/SDL2/test/testmultiaudio.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnative.c b/libs/SDL2/test/testnative.c
index 83bc495dfeccdbdb072048092e469bc80c8ebff6..674d9d3b4d8520a5a86424b230d9e845d1d00f55 100644
--- a/libs/SDL2/test/testnative.c
+++ b/libs/SDL2/test/testnative.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnative.h b/libs/SDL2/test/testnative.h
index b2ee5fa44b43605a25159a74aedcca2a0b5a9981..29d85fb325b923d97de0c0cd1e1b28f7d8b7ccc5 100644
--- a/libs/SDL2/test/testnative.h
+++ b/libs/SDL2/test/testnative.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnativew32.c b/libs/SDL2/test/testnativew32.c
index 7a27b127ae63fca311ce28f7bf2f96c9deaf7fbd..7e96bc697a2b6d8429c6b596df72e5b0c41d91e6 100644
--- a/libs/SDL2/test/testnativew32.c
+++ b/libs/SDL2/test/testnativew32.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnativex11.c b/libs/SDL2/test/testnativex11.c
index 8908d22ffd2039b0b8f8e7437d89c739a45e319a..386c25e9ec423a119a388aa71529ab9d0a55a027 100644
--- a/libs/SDL2/test/testnativex11.c
+++ b/libs/SDL2/test/testnativex11.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testoverlay2.c b/libs/SDL2/test/testoverlay2.c
index 2145c4d36b045d4b106c3d9ac88d2b6d8ace1b0b..daf07d3e941fc723f06e0c00a8e116d989c17baa 100644
--- a/libs/SDL2/test/testoverlay2.c
+++ b/libs/SDL2/test/testoverlay2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -16,16 +16,14 @@
  *                                                                              *
  ********************************************************************************/
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
 #ifdef __EMSCRIPTEN__
 #include <emscripten/emscripten.h>
 #endif
 
 #include "SDL.h"
 
+#include "testyuv_cvt.h"
+
 #define MOOSEPIC_W 64
 #define MOOSEPIC_H 88
 
@@ -149,7 +147,6 @@ SDL_Renderer *renderer;
 int paused = 0;
 int i;
 SDL_bool done = SDL_FALSE;
-Uint32 pixel_format = SDL_PIXELFORMAT_YV12;
 static int fpsdelay;
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
@@ -160,91 +157,6 @@ quit(int rc)
     exit(rc);
 }
 
-/* All RGB2YUV conversion code and some other parts of code has been taken from testoverlay.c */
-
-/* NOTE: These RGB conversion functions are not intended for speed,
-         only as examples.
-*/
-
-void
-RGBtoYUV(Uint8 * rgb, int *yuv, int monochrome, int luminance)
-{
-    if (monochrome) {
-#if 1                           /* these are the two formulas that I found on the FourCC site... */
-        yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
-        yuv[1] = 128;
-        yuv[2] = 128;
-#else
-        yuv[0] = (int)(0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16;
-        yuv[1] = 128;
-        yuv[2] = 128;
-#endif
-    } else {
-#if 1                           /* these are the two formulas that I found on the FourCC site... */
-        yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
-        yuv[1] = (int)((rgb[2] - yuv[0]) * 0.565 + 128);
-        yuv[2] = (int)((rgb[0] - yuv[0]) * 0.713 + 128);
-#else
-        yuv[0] = (0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16;
-        yuv[1] = 128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]);
-        yuv[2] = 128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]);
-#endif
-    }
-
-    if (luminance != 100) {
-        yuv[0] = yuv[0] * luminance / 100;
-        if (yuv[0] > 255)
-            yuv[0] = 255;
-    }
-}
-
-void
-ConvertRGBtoYV12(Uint8 *rgb, Uint8 *out, int w, int h,
-                 int monochrome, int luminance)
-{
-    int x, y;
-    int yuv[3];
-    Uint8 *op[3];
-
-    op[0] = out;
-    op[1] = op[0] + w*h;
-    op[2] = op[1] + w*h/4;
-    for (y = 0; y < h; ++y) {
-        for (x = 0; x < w; ++x) {
-            RGBtoYUV(rgb, yuv, monochrome, luminance);
-            *(op[0]++) = yuv[0];
-            if (x % 2 == 0 && y % 2 == 0) {
-                *(op[1]++) = yuv[2];
-                *(op[2]++) = yuv[1];
-            }
-            rgb += 3;
-        }
-    }
-}
-
-void
-ConvertRGBtoNV12(Uint8 *rgb, Uint8 *out, int w, int h,
-                 int monochrome, int luminance)
-{
-    int x, y;
-    int yuv[3];
-    Uint8 *op[2];
-
-    op[0] = out;
-    op[1] = op[0] + w*h;
-    for (y = 0; y < h; ++y) {
-        for (x = 0; x < w; ++x) {
-            RGBtoYUV(rgb, yuv, monochrome, luminance);
-            *(op[0]++) = yuv[0];
-            if (x % 2 == 0 && y % 2 == 0) {
-                *(op[1]++) = yuv[1];
-                *(op[1]++) = yuv[2];
-            }
-            rgb += 3;
-        }
-    }
-}
-
 static void
 PrintUsage(char *argv0)
 {
@@ -307,7 +219,7 @@ loop()
     if (!paused) {
         i = (i + 1) % MOOSEFRAMES_COUNT;
 
-        SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*SDL_BYTESPERPIXEL(pixel_format));
+        SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W);
     }
     SDL_RenderClear(renderer);
     SDL_RenderCopy(renderer, MooseTexture, NULL, &displayrect);
@@ -329,11 +241,6 @@ main(int argc, char **argv)
     int j;
     int fps = 12;
     int nodelay = 0;
-#ifdef TEST_NV12
-    Uint32 pixel_format = SDL_PIXELFORMAT_NV12;
-#else
-    Uint32 pixel_format = SDL_PIXELFORMAT_YV12;
-#endif
     int scale = 5;
 
     /* Enable standard application logging */
@@ -347,7 +254,7 @@ main(int argc, char **argv)
     while (argc > 1) {
         if (strcmp(argv[1], "-fps") == 0) {
             if (argv[2]) {
-                fps = atoi(argv[2]);
+                fps = SDL_atoi(argv[2]);
                 if (fps == 0) {
                     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                             "The -fps option requires an argument [from 1 to 1000], default is 12.\n");
@@ -371,7 +278,7 @@ main(int argc, char **argv)
             argc -= 1;
         } else if (strcmp(argv[1], "-scale") == 0) {
             if (argv[2]) {
-                scale = atoi(argv[2]);
+                scale = SDL_atoi(argv[2]);
                 if (scale == 0) {
                     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                             "The -scale option requires an argument [from 1 to 50], default is 5.\n");
@@ -439,7 +346,7 @@ main(int argc, char **argv)
         quit(4);
     }
 
-    MooseTexture = SDL_CreateTexture(renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H);
+    MooseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H);
     if (!MooseTexture) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
         free(RawMooseData);
@@ -461,17 +368,9 @@ main(int argc, char **argv)
             rgb[2] = MooseColors[frame[j]].b;
             rgb += 3;
         }
-        switch (pixel_format) {
-        case SDL_PIXELFORMAT_YV12:
-            ConvertRGBtoYV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
-            break;
-        case SDL_PIXELFORMAT_NV12:
-            ConvertRGBtoNV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
-            break;
-        default:
-            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported pixel format\n");
-            break;
-        }
+        ConvertRGBtoYUV(SDL_PIXELFORMAT_YV12, MooseFrameRGB, MOOSEPIC_W*3, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H,
+            SDL_GetYUVConversionModeForResolution(MOOSEPIC_W, MOOSEPIC_H),
+            0, 100);
     }
 
     free(RawMooseData);
diff --git a/libs/SDL2/test/testplatform.c b/libs/SDL2/test/testplatform.c
index 0cba8fe76c31a50082c173cf810312555389f9e1..1c1d2dcd83b3078d8c067facd0ca45edede0938d 100644
--- a/libs/SDL2/test/testplatform.c
+++ b/libs/SDL2/test/testplatform.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -380,6 +380,7 @@ TestCPUInfo(SDL_bool verbose)
         SDL_Log("SSE4.2 %s\n", SDL_HasSSE42()? "detected" : "not detected");
         SDL_Log("AVX %s\n", SDL_HasAVX()? "detected" : "not detected");
         SDL_Log("AVX2 %s\n", SDL_HasAVX2()? "detected" : "not detected");
+        SDL_Log("AVX-512F %s\n", SDL_HasAVX512F()? "detected" : "not detected");
         SDL_Log("NEON %s\n", SDL_HasNEON()? "detected" : "not detected");
         SDL_Log("System RAM %d MB\n", SDL_GetSystemRAM());
     }
diff --git a/libs/SDL2/test/testpower.c b/libs/SDL2/test/testpower.c
index 48d64f094eab10f0183f9f0090d552463369c77b..adb58832accf6ba1dd0166b597c07670c6299d88 100644
--- a/libs/SDL2/test/testpower.c
+++ b/libs/SDL2/test/testpower.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testqsort.c b/libs/SDL2/test/testqsort.c
index 8867539364df747395c7050d3bf547586f90841a..e83b0731e5896effbc5ce68cdac16fd24e8382c6 100644
--- a/libs/SDL2/test/testqsort.c
+++ b/libs/SDL2/test/testqsort.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testrelative.c b/libs/SDL2/test/testrelative.c
index 5d2ab5d93f344e3887b6bc9ad09bd2ecf649874b..816329ff567b98be5d4a1c6b66e4e8d69c2bd1b5 100644
--- a/libs/SDL2/test/testrelative.c
+++ b/libs/SDL2/test/testrelative.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testrendercopyex.c b/libs/SDL2/test/testrendercopyex.c
index 72a54e649ae60babfbf492131b332a738c042858..209a351576458de0190e1fe14ee8c80eefca4a8b 100644
--- a/libs/SDL2/test/testrendercopyex.c
+++ b/libs/SDL2/test/testrendercopyex.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testrendertarget.c b/libs/SDL2/test/testrendertarget.c
index ec21f2e4301f1fcb8996fae54e8188a6a024519f..7d24d8aeaebc3f21ad74b3987e6b0ace82bbd80e 100644
--- a/libs/SDL2/test/testrendertarget.c
+++ b/libs/SDL2/test/testrendertarget.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testresample.c b/libs/SDL2/test/testresample.c
index a54a47dcb02b342d8d48ebbbba57b7e0e2b8ffeb..4234d9e4549359dcbe23e5206728d7dea9d76ea9 100644
--- a/libs/SDL2/test/testresample.c
+++ b/libs/SDL2/test/testresample.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -93,7 +93,7 @@ main(int argc, char **argv)
     SDL_WriteLE32(io, 0x45564157);      /* WAVE */
     SDL_WriteLE32(io, 0x20746D66);      /* fmt */
     SDL_WriteLE32(io, 16);      /* chunk size */
-    SDL_WriteLE16(io, 1);       /* uncompressed */
+    SDL_WriteLE16(io, SDL_AUDIO_ISFLOAT(spec.format) ? 3 : 1);       /* uncompressed */
     SDL_WriteLE16(io, cvtchans);   /* channels */
     SDL_WriteLE32(io, cvtfreq); /* sample rate */
     SDL_WriteLE32(io, avgbytes);        /* average bytes per second */
diff --git a/libs/SDL2/test/testrumble.c b/libs/SDL2/test/testrumble.c
index a22c52ec2a24ab7dec4c55839be202d792173966..908a6aafb4dc71ddfb4a6a3c8b45dd47bc88c5a2 100644
--- a/libs/SDL2/test/testrumble.c
+++ b/libs/SDL2/test/testrumble.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testscale.c b/libs/SDL2/test/testscale.c
index 34451d6fc482e423ec0554fa81ebf954aa290e7d..e1b46fcc8ded92377ec91e4aacd7927352b9c66d 100644
--- a/libs/SDL2/test/testscale.c
+++ b/libs/SDL2/test/testscale.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testsem.c b/libs/SDL2/test/testsem.c
index 13438b1b6ca9036ab494262b74bed04626165137..884763e6a3adeeebf7ce6dedee4c56a14161c66f 100644
--- a/libs/SDL2/test/testsem.c
+++ b/libs/SDL2/test/testsem.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testsensor.c b/libs/SDL2/test/testsensor.c
new file mode 100644
index 0000000000000000000000000000000000000000..00bfd137deaa2a2a155f63ccae1d20caa919e6f4
--- /dev/null
+++ b/libs/SDL2/test/testsensor.c
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+
+/* Simple test of the SDL sensor code */
+
+#include "SDL.h"
+
+static const char *GetSensorTypeString(SDL_SensorType type)
+{
+    static char unknown_type[64];
+
+    switch (type)
+    {
+    case SDL_SENSOR_INVALID:
+        return "SDL_SENSOR_INVALID";
+    case SDL_SENSOR_UNKNOWN:
+        return "SDL_SENSOR_UNKNOWN";
+    case SDL_SENSOR_ACCEL:
+        return "SDL_SENSOR_ACCEL";
+    case SDL_SENSOR_GYRO:
+        return "SDL_SENSOR_GYRO";
+    default:
+        SDL_snprintf(unknown_type, sizeof(unknown_type), "UNKNOWN (%d)", type);
+        return unknown_type;
+    }
+}
+
+static void HandleSensorEvent(SDL_SensorEvent *event)
+{
+    SDL_Sensor *sensor = SDL_SensorFromInstanceID(event->which);
+    if (!sensor) {
+        SDL_Log("Couldn't get sensor for sensor event\n");
+        return;
+    }
+
+    switch (SDL_SensorGetType(sensor)) {
+    case SDL_SENSOR_ACCEL:
+        SDL_Log("Accelerometer update: %.2f, %.2f, %.2f\n", event->data[0], event->data[1], event->data[2]);
+        break;
+    case SDL_SENSOR_GYRO:
+        SDL_Log("Gyro update: %.2f, %.2f, %.2f\n", event->data[0], event->data[1], event->data[2]);
+        break;
+    default:
+        SDL_Log("Sensor update for sensor type %s\n", GetSensorTypeString(SDL_SensorGetType(sensor)));
+        break;
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    int i;
+    int num_sensors, num_opened;
+
+    /* Load the SDL library */
+    if (SDL_Init(SDL_INIT_SENSOR) < 0) {
+        SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError());
+        return (1);
+    }
+
+    num_sensors = SDL_NumSensors();
+    num_opened = 0;
+
+    SDL_Log("There are %d sensors available\n", num_sensors);
+    for (i = 0; i < num_sensors; ++i) {
+        SDL_Log("Sensor %d: %s, type %s, platform type %d\n",
+            SDL_SensorGetDeviceInstanceID(i),
+            SDL_SensorGetDeviceName(i),
+            GetSensorTypeString(SDL_SensorGetDeviceType(i)),
+            SDL_SensorGetDeviceNonPortableType(i));
+
+        if (SDL_SensorGetDeviceType(i) != SDL_SENSOR_UNKNOWN) {
+            SDL_Sensor *sensor = SDL_SensorOpen(i);
+            if (sensor == NULL) {
+                SDL_Log("Couldn't open sensor %d: %s\n", SDL_SensorGetDeviceInstanceID(i), SDL_GetError());
+            } else {
+                ++num_opened;
+            }
+        }
+    }
+    SDL_Log("Opened %d sensors\n", num_opened);
+
+    if (num_opened > 0) {
+        SDL_bool done = SDL_FALSE;
+        SDL_Event event;
+
+        SDL_CreateWindow("Sensor Test", 0, 0, 0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP);
+        while (!done) {
+            while (SDL_PollEvent(&event) > 0) {
+                switch (event.type) {
+                case SDL_SENSORUPDATE:
+                    HandleSensorEvent(&event.sensor);
+                    break;
+                case SDL_MOUSEBUTTONUP:
+                case SDL_KEYUP:
+                case SDL_QUIT:
+                    done = SDL_TRUE;
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+    }
+
+    SDL_Quit();
+    return (0);
+}
diff --git a/libs/SDL2/test/testshader.c b/libs/SDL2/test/testshader.c
index 1700da1ccc1d6c9ee83eda6b92a476c4357f09c9..ee0ccdad200a3c5a13ea036ecccee853407e8e58 100644
--- a/libs/SDL2/test/testshader.c
+++ b/libs/SDL2/test/testshader.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testshape.c b/libs/SDL2/test/testshape.c
index d54cc2265a1527a91975c0c5d12ee17a7111637d..7e451e667b232dbdbeb5e41d204aa9172dafebb0 100644
--- a/libs/SDL2/test/testshape.c
+++ b/libs/SDL2/test/testshape.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testsprite2.c b/libs/SDL2/test/testsprite2.c
index 14258f74cd2efdc05f891dc30cb0991086f864ef..b0348f85d7c3927e597f9440d41d2b3d191adcad 100644
--- a/libs/SDL2/test/testsprite2.c
+++ b/libs/SDL2/test/testsprite2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testspriteminimal.c b/libs/SDL2/test/testspriteminimal.c
index 478c5849677173ae8c8bd6ccf96bd4426ec6dc93..92560002ac441d29dad1d6b01bd68f568127ab87 100644
--- a/libs/SDL2/test/testspriteminimal.c
+++ b/libs/SDL2/test/testspriteminimal.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/teststreaming.c b/libs/SDL2/test/teststreaming.c
index 76a9fed18888fc576631c4566d38398198f519ed..7ec6891062676d6eb3de8fb18dd93a112db5612a 100644
--- a/libs/SDL2/test/teststreaming.c
+++ b/libs/SDL2/test/teststreaming.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testthread.c b/libs/SDL2/test/testthread.c
index 6557b2fc742289143d776fb84c95f942fe72d0fe..4555a1e9457477ddf0c39123d4c3618cafa8ca1a 100644
--- a/libs/SDL2/test/testthread.c
+++ b/libs/SDL2/test/testthread.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -20,6 +20,7 @@
 
 static SDL_TLSID tls;
 static int alive = 0;
+static int testprio = 0;
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
 static void
@@ -29,14 +30,37 @@ quit(int rc)
     exit(rc);
 }
 
+static const char *
+getprioritystr(SDL_ThreadPriority priority)
+{
+    switch(priority)
+    {
+    case SDL_THREAD_PRIORITY_LOW: return "SDL_THREAD_PRIORITY_LOW";
+    case SDL_THREAD_PRIORITY_NORMAL: return "SDL_THREAD_PRIORITY_NORMAL";
+    case SDL_THREAD_PRIORITY_HIGH: return "SDL_THREAD_PRIORITY_HIGH";
+    case SDL_THREAD_PRIORITY_TIME_CRITICAL: return "SDL_THREAD_PRIORITY_TIME_CRITICAL";
+    }
+
+    return "???";
+}
+
 int SDLCALL
 ThreadFunc(void *data)
 {
+    SDL_ThreadPriority prio = SDL_THREAD_PRIORITY_NORMAL;
+
     SDL_TLSSet(tls, "baby thread", NULL);
     SDL_Log("Started thread %s: My thread id is %lu, thread data = %s\n",
            (char *) data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls));
     while (alive) {
         SDL_Log("Thread '%s' is alive!\n", (char *) data);
+
+        if (testprio) {
+            SDL_Log("SDL_SetThreadPriority(%s):%d\n", getprioritystr(prio), SDL_SetThreadPriority(prio));
+            if (++prio > SDL_THREAD_PRIORITY_TIME_CRITICAL)
+                prio = SDL_THREAD_PRIORITY_LOW;
+        }
+
         SDL_Delay(1 * 1000);
     }
     SDL_Log("Thread '%s' exiting!\n", (char *) data);
@@ -55,6 +79,7 @@ killed(int sig)
 int
 main(int argc, char *argv[])
 {
+    int arg = 1;
     SDL_Thread *thread;
 
     /* Enable standard application logging */
@@ -66,6 +91,13 @@ main(int argc, char *argv[])
         return (1);
     }
 
+    while (argv[arg] && *argv[arg] == '-') {
+        if (SDL_strcmp(argv[arg], "--prio") == 0) {
+            testprio = 1;
+        }
+        ++arg;
+    }
+
     tls = SDL_TLSCreate();
     SDL_assert(tls);
     SDL_TLSSet(tls, "main thread", NULL);
diff --git a/libs/SDL2/test/testtimer.c b/libs/SDL2/test/testtimer.c
index 261497be74da6e54b874b759f6a4112fcb29cfba..34764c1c96b6e30dc2dd13ec4d2ce73c51929984 100644
--- a/libs/SDL2/test/testtimer.c
+++ b/libs/SDL2/test/testtimer.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testver.c b/libs/SDL2/test/testver.c
index 04a7a9010e5197d7e4b549e4792528a9520ae7fa..1ae0083457bbc9b9083c8dfdb4ab424914d49c00 100644
--- a/libs/SDL2/test/testver.c
+++ b/libs/SDL2/test/testver.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testviewport.c b/libs/SDL2/test/testviewport.c
index f9d0bd5aa60f708102a5ecc71aeda3fed24c0144..4b8d20e76d77dc12f73def864b1102515005a62a 100644
--- a/libs/SDL2/test/testviewport.c
+++ b/libs/SDL2/test/testviewport.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testvulkan.c b/libs/SDL2/test/testvulkan.c
index 95cbec8039ecf658853eabde379f5a428ea65bba..cd682af1f6019a804a59adad2f91c0e50195b983 100644
--- a/libs/SDL2/test/testvulkan.c
+++ b/libs/SDL2/test/testvulkan.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -255,7 +255,7 @@ static void createInstance(void)
     appInfo.apiVersion = VK_API_VERSION_1_0;
     instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
     instanceCreateInfo.pApplicationInfo = &appInfo;
-    if(!SDL_Vulkan_GetInstanceExtensions(state->windows[0], &extensionCount, NULL))
+    if(!SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, NULL))
     {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                      "SDL_Vulkan_GetInstanceExtensions(): %s\n",
@@ -268,7 +268,7 @@ static void createInstance(void)
         SDL_OutOfMemory();
         quit(2);
     }
-    if(!SDL_Vulkan_GetInstanceExtensions(state->windows[0], &extensionCount, extensions))
+    if(!SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, extensions))
     {
         SDL_free((void*)extensions);
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
diff --git a/libs/SDL2/test/testwm2.c b/libs/SDL2/test/testwm2.c
index ab3eea2f5bb2a2b90dfed4120fc91ea07f396cb5..5da38730947cfef3f973a90d1eab219d97dd5d75 100644
--- a/libs/SDL2/test/testwm2.c
+++ b/libs/SDL2/test/testwm2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -146,6 +146,9 @@ main(int argc, char *argv[])
         quit(2);
     }
 
+    SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
+    SDL_EventState(SDL_DROPTEXT, SDL_ENABLE);
+
     for (i = 0; i < state->num_windows; ++i) {
         SDL_Renderer *renderer = state->renderers[i];
         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
diff --git a/libs/SDL2/test/testyuv.bmp b/libs/SDL2/test/testyuv.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..af32034b6b5b858be470f9ef3bb023bc199bf96e
Binary files /dev/null and b/libs/SDL2/test/testyuv.bmp differ
diff --git a/libs/SDL2/test/testyuv.c b/libs/SDL2/test/testyuv.c
new file mode 100644
index 0000000000000000000000000000000000000000..f52ab9f72ec81e70e671dcdbf87aba773ae9e10e
--- /dev/null
+++ b/libs/SDL2/test/testyuv.c
@@ -0,0 +1,455 @@
+/*
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_test_font.h"
+#include "testyuv_cvt.h"
+
+
+/* 422 (YUY2, etc) formats are the largest */
+#define MAX_YUV_SURFACE_SIZE(W, H, P)  (H*4*(W+P+1)/2)
+
+
+/* Return true if the YUV format is packed pixels */
+static SDL_bool is_packed_yuv_format(Uint32 format)
+{
+    return (format == SDL_PIXELFORMAT_YUY2 ||
+            format == SDL_PIXELFORMAT_UYVY ||
+            format == SDL_PIXELFORMAT_YVYU);
+}
+
+/* Create a surface with a good pattern for verifying YUV conversion */
+static SDL_Surface *generate_test_pattern(int pattern_size)
+{
+    SDL_Surface *pattern = SDL_CreateRGBSurfaceWithFormat(0, pattern_size, pattern_size, 0, SDL_PIXELFORMAT_RGB24);
+
+    if (pattern) {
+        int i, x, y;
+        Uint8 *p, c;
+        const int thickness = 2;    /* Important so 2x2 blocks of color are the same, to avoid Cr/Cb interpolation over pixels */
+
+        /* R, G, B in alternating horizontal bands */
+        for (y = 0; y < pattern->h; y += thickness) {
+            for (i = 0; i < thickness; ++i) {
+                p = (Uint8 *)pattern->pixels + (y + i) * pattern->pitch + ((y/thickness) % 3);
+                for (x = 0; x < pattern->w; ++x) {
+                    *p = 0xFF;
+                    p += 3;
+                }
+            }
+        }
+
+        /* Black and white in alternating vertical bands */
+        c = 0xFF;
+        for (x = 1*thickness; x < pattern->w; x += 2*thickness) {
+            for (i = 0; i < thickness; ++i) {
+                p = (Uint8 *)pattern->pixels + (x + i)*3;
+                for (y = 0; y < pattern->h; ++y) {
+                    SDL_memset(p, c, 3);
+                    p += pattern->pitch;
+                }
+            }
+            if (c) {
+                c = 0x00;
+            } else {
+                c = 0xFF;
+            }
+        }
+    }
+    return pattern;
+}
+
+static SDL_bool verify_yuv_data(Uint32 format, const Uint8 *yuv, int yuv_pitch, SDL_Surface *surface)
+{
+    const int tolerance = 20;
+    const int size = (surface->h * surface->pitch);
+    Uint8 *rgb;
+    SDL_bool result = SDL_FALSE;
+
+    rgb = (Uint8 *)SDL_malloc(size);
+    if (!rgb) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory");
+        return SDL_FALSE;
+    }
+
+    if (SDL_ConvertPixels(surface->w, surface->h, format, yuv, yuv_pitch, surface->format->format, rgb, surface->pitch) == 0) {
+        int x, y;
+        result = SDL_TRUE;
+        for (y = 0; y < surface->h; ++y) {
+            const Uint8 *actual = rgb + y * surface->pitch;
+            const Uint8 *expected = (const Uint8 *)surface->pixels + y * surface->pitch;
+            for (x = 0; x < surface->w; ++x) {
+                int deltaR = (int)actual[0] - expected[0];
+                int deltaG = (int)actual[1] - expected[1];
+                int deltaB = (int)actual[2] - expected[2];
+                int distance = (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
+                if (distance > tolerance) {
+                    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Pixel at %d,%d was 0x%.2x,0x%.2x,0x%.2x, expected 0x%.2x,0x%.2x,0x%.2x, distance = %d\n", x, y, actual[0], actual[1], actual[2], expected[0], expected[1], expected[2], distance);
+                    result = SDL_FALSE;
+                }
+                actual += 3;
+                expected += 3;
+            }
+        }
+    } else {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(format), SDL_GetPixelFormatName(surface->format->format), SDL_GetError());
+    }
+    SDL_free(rgb);
+
+    return result;
+}
+
+static int run_automated_tests(int pattern_size, int extra_pitch)
+{
+    const Uint32 formats[] = {
+        SDL_PIXELFORMAT_YV12,
+        SDL_PIXELFORMAT_IYUV,
+        SDL_PIXELFORMAT_NV12,
+        SDL_PIXELFORMAT_NV21,
+        SDL_PIXELFORMAT_YUY2,
+        SDL_PIXELFORMAT_UYVY,
+        SDL_PIXELFORMAT_YVYU
+    };
+    int i, j;
+    SDL_Surface *pattern = generate_test_pattern(pattern_size);
+    const int yuv_len = MAX_YUV_SURFACE_SIZE(pattern->w, pattern->h, extra_pitch);
+    Uint8 *yuv1 = (Uint8 *)SDL_malloc(yuv_len);
+    Uint8 *yuv2 = (Uint8 *)SDL_malloc(yuv_len);
+    int yuv1_pitch, yuv2_pitch;
+    int result = -1;
+    
+    if (!pattern || !yuv1 || !yuv2) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate test surfaces");
+        goto done;
+    }
+
+    /* Verify conversion from YUV formats */
+    for (i = 0; i < SDL_arraysize(formats); ++i) {
+        if (!ConvertRGBtoYUV(formats[i], pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, SDL_GetYUVConversionModeForResolution(pattern->w, pattern->h), 0, 100)) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s\n", SDL_GetPixelFormatName(formats[i]));
+            goto done;
+        }
+        yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w);
+        if (!verify_yuv_data(formats[i], yuv1, yuv1_pitch, pattern)) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB\n", SDL_GetPixelFormatName(formats[i]));
+            goto done;
+        }
+    }
+
+    /* Verify conversion to YUV formats */
+    for (i = 0; i < SDL_arraysize(formats); ++i) {
+        yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
+        if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
+            goto done;
+        }
+        if (!verify_yuv_data(formats[i], yuv1, yuv1_pitch, pattern)) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s\n", SDL_GetPixelFormatName(formats[i]));
+            goto done;
+        }
+    }
+
+    /* Verify conversion between YUV formats */
+    for (i = 0; i < SDL_arraysize(formats); ++i) {
+        for (j = 0; j < SDL_arraysize(formats); ++j) {
+            yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
+            yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
+            if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
+                goto done;
+            }
+            if (SDL_ConvertPixels(pattern->w, pattern->h, formats[i], yuv1, yuv1_pitch, formats[j], yuv2, yuv2_pitch) < 0) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
+                goto done;
+            }
+            if (!verify_yuv_data(formats[j], yuv2, yuv2_pitch, pattern)) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
+                goto done;
+            }
+        }
+    }
+
+    /* Verify conversion between YUV formats in-place */
+    for (i = 0; i < SDL_arraysize(formats); ++i) {
+        for (j = 0; j < SDL_arraysize(formats); ++j) {
+            if (is_packed_yuv_format(formats[i]) != is_packed_yuv_format(formats[j])) {
+                /* Can't change plane vs packed pixel layout in-place */
+                continue;
+            }
+
+            yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
+            yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
+            if (SDL_ConvertPixels(pattern->w, pattern->h, pattern->format->format, pattern->pixels, pattern->pitch, formats[i], yuv1, yuv1_pitch) < 0) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(pattern->format->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
+                goto done;
+            }
+            if (SDL_ConvertPixels(pattern->w, pattern->h, formats[i], yuv1, yuv1_pitch, formats[j], yuv1, yuv2_pitch) < 0) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
+                goto done;
+            }
+            if (!verify_yuv_data(formats[j], yuv1, yuv2_pitch, pattern)) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s\n", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
+                goto done;
+            }
+        }
+    }
+
+
+    result = 0;
+
+done:
+    SDL_free(yuv1);
+    SDL_free(yuv2);
+    SDL_FreeSurface(pattern);
+    return result;
+}
+
+int
+main(int argc, char **argv)
+{
+    struct {
+        SDL_bool enable_intrinsics;
+        int pattern_size;
+        int extra_pitch;
+    } automated_test_params[] = {
+        /* Test: even width and height */
+        { SDL_FALSE, 2, 0 },
+        { SDL_FALSE, 4, 0 },
+        /* Test: odd width and height */
+        { SDL_FALSE, 1, 0 },
+        { SDL_FALSE, 3, 0 },
+        /* Test: even width and height, extra pitch */
+        { SDL_FALSE, 2, 3 },
+        { SDL_FALSE, 4, 3 },
+        /* Test: odd width and height, extra pitch */
+        { SDL_FALSE, 1, 3 },
+        { SDL_FALSE, 3, 3 },
+        /* Test: even width and height with intrinsics */
+        { SDL_TRUE, 32, 0 },
+        /* Test: odd width and height with intrinsics */
+        { SDL_TRUE, 33, 0 },
+        { SDL_TRUE, 37, 0 },
+        /* Test: even width and height with intrinsics, extra pitch */
+        { SDL_TRUE, 32, 3 },
+        /* Test: odd width and height with intrinsics, extra pitch */
+        { SDL_TRUE, 33, 3 },
+        { SDL_TRUE, 37, 3 },
+    };
+    int arg = 1;
+    const char *filename;
+    SDL_Surface *original;
+    SDL_Surface *converted;
+    SDL_Window *window;
+    SDL_Renderer *renderer;
+    SDL_Texture *output[3];
+    const char *titles[3] = { "ORIGINAL", "SOFTWARE", "HARDWARE" };
+    char title[128];
+    const char *yuv_name;
+    const char *yuv_mode;
+    Uint32 rgb_format = SDL_PIXELFORMAT_RGBX8888;
+    Uint32 yuv_format = SDL_PIXELFORMAT_YV12;
+    int current = 0;
+    int pitch;
+    Uint8 *raw_yuv;
+    Uint32 then, now, i, iterations = 100;
+    SDL_bool should_run_automated_tests = SDL_FALSE;
+
+    while (argv[arg] && *argv[arg] == '-') {
+        if (SDL_strcmp(argv[arg], "--jpeg") == 0) {
+            SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_JPEG);
+        } else if (SDL_strcmp(argv[arg], "--bt601") == 0) {
+            SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_BT601);
+        } else if (SDL_strcmp(argv[arg], "--bt709") == 0) {
+            SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_BT709);
+        } else if (SDL_strcmp(argv[arg], "--auto") == 0) {
+            SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_AUTOMATIC);
+        } else if (SDL_strcmp(argv[arg], "--yv12") == 0) {
+            yuv_format = SDL_PIXELFORMAT_YV12;
+        } else if (SDL_strcmp(argv[arg], "--iyuv") == 0) {
+            yuv_format = SDL_PIXELFORMAT_IYUV;
+        } else if (SDL_strcmp(argv[arg], "--yuy2") == 0) {
+            yuv_format = SDL_PIXELFORMAT_YUY2;
+        } else if (SDL_strcmp(argv[arg], "--uyvy") == 0) {
+            yuv_format = SDL_PIXELFORMAT_UYVY;
+        } else if (SDL_strcmp(argv[arg], "--yvyu") == 0) {
+            yuv_format = SDL_PIXELFORMAT_YVYU;
+        } else if (SDL_strcmp(argv[arg], "--nv12") == 0) {
+            yuv_format = SDL_PIXELFORMAT_NV12;
+        } else if (SDL_strcmp(argv[arg], "--nv21") == 0) {
+            yuv_format = SDL_PIXELFORMAT_NV21;
+        } else if (SDL_strcmp(argv[arg], "--rgb555") == 0) {
+            rgb_format = SDL_PIXELFORMAT_RGB555;
+        } else if (SDL_strcmp(argv[arg], "--rgb565") == 0) {
+            rgb_format = SDL_PIXELFORMAT_RGB565;
+        } else if (SDL_strcmp(argv[arg], "--rgb24") == 0) {
+            rgb_format = SDL_PIXELFORMAT_RGB24;
+        } else if (SDL_strcmp(argv[arg], "--argb") == 0) {
+            rgb_format = SDL_PIXELFORMAT_ARGB8888;
+        } else if (SDL_strcmp(argv[arg], "--abgr") == 0) {
+            rgb_format = SDL_PIXELFORMAT_ABGR8888;
+        } else if (SDL_strcmp(argv[arg], "--rgba") == 0) {
+            rgb_format = SDL_PIXELFORMAT_RGBA8888;
+        } else if (SDL_strcmp(argv[arg], "--bgra") == 0) {
+            rgb_format = SDL_PIXELFORMAT_BGRA8888;
+        } else if (SDL_strcmp(argv[arg], "--automated") == 0) {
+            should_run_automated_tests = SDL_TRUE;
+        } else {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: %s [--jpeg|--bt601|-bt709|--auto] [--yv12|--iyuv|--yuy2|--uyvy|--yvyu|--nv12|--nv21] [--rgb555|--rgb565|--rgb24|--argb|--abgr|--rgba|--bgra] [image_filename]\n", argv[0]);
+            return 1;
+        }
+        ++arg;
+    }
+
+    /* Run automated tests */
+    if (should_run_automated_tests) {
+        for (i = 0; i < SDL_arraysize(automated_test_params); ++i) {
+            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Running automated test, pattern size %d, extra pitch %d, intrinsics %s\n", 
+                automated_test_params[i].pattern_size,
+                automated_test_params[i].extra_pitch,
+                automated_test_params[i].enable_intrinsics ? "enabled" : "disabled");
+            if (run_automated_tests(automated_test_params[i].pattern_size, automated_test_params[i].extra_pitch) < 0) {
+                return 2;
+            }
+        }
+        return 0;
+    }
+
+    if (argv[arg]) {
+        filename = argv[arg];
+    } else {
+        filename = "testyuv.bmp";
+    }
+    original = SDL_ConvertSurfaceFormat(SDL_LoadBMP(filename), SDL_PIXELFORMAT_RGB24, 0);
+    if (!original) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
+        return 3;
+    }
+
+    raw_yuv = SDL_calloc(1, MAX_YUV_SURFACE_SIZE(original->w, original->h, 0));
+    ConvertRGBtoYUV(yuv_format, original->pixels, original->pitch, raw_yuv, original->w, original->h,
+        SDL_GetYUVConversionModeForResolution(original->w, original->h),
+        0, 100);
+    pitch = CalculateYUVPitch(yuv_format, original->w);
+
+    converted = SDL_CreateRGBSurfaceWithFormat(0, original->w, original->h, 0, rgb_format);
+    if (!converted) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create converted surface: %s\n", SDL_GetError());
+        return 3;
+    }
+
+    then = SDL_GetTicks();
+    for ( i = 0; i < iterations; ++i ) {
+        SDL_ConvertPixels(original->w, original->h, yuv_format, raw_yuv, pitch, rgb_format, converted->pixels, converted->pitch);
+    }
+    now = SDL_GetTicks();
+    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%d iterations in %d ms, %.2fms each\n", iterations, (now - then), (float)(now - then)/iterations);
+
+    window = SDL_CreateWindow("YUV test",
+                              SDL_WINDOWPOS_UNDEFINED,
+                              SDL_WINDOWPOS_UNDEFINED,
+                              original->w, original->h,
+                              0);
+    if (!window) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
+        return 4;
+    }
+
+    renderer = SDL_CreateRenderer(window, -1, 0);
+    if (!renderer) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
+        return 4;
+    }
+
+    output[0] = SDL_CreateTextureFromSurface(renderer, original);
+    output[1] = SDL_CreateTextureFromSurface(renderer, converted);
+    output[2] = SDL_CreateTexture(renderer, yuv_format, SDL_TEXTUREACCESS_STREAMING, original->w, original->h);
+    if (!output[0] || !output[1] || !output[2]) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
+        return 5;
+    }
+    SDL_UpdateTexture(output[2], NULL, raw_yuv, pitch);
+    
+    yuv_name = SDL_GetPixelFormatName(yuv_format);
+    if (SDL_strncmp(yuv_name, "SDL_PIXELFORMAT_", 16) == 0) {
+        yuv_name += 16;
+    }
+
+    switch (SDL_GetYUVConversionModeForResolution(original->w, original->h)) {
+    case SDL_YUV_CONVERSION_JPEG:
+        yuv_mode = "JPEG";
+        break;
+    case SDL_YUV_CONVERSION_BT601:
+        yuv_mode = "BT.601";
+        break;
+    case SDL_YUV_CONVERSION_BT709:
+        yuv_mode = "BT.709";
+        break;
+    default:
+        yuv_mode = "UNKNOWN";
+        break;
+    }
+
+    { int done = 0;
+        while ( !done )
+        {
+            SDL_Event event;
+            while (SDL_PollEvent(&event) > 0) {
+                if (event.type == SDL_QUIT) {
+                    done = 1;
+                }
+                if (event.type == SDL_KEYDOWN) {
+                    if (event.key.keysym.sym == SDLK_ESCAPE) {
+                        done = 1;
+                    } else if (event.key.keysym.sym == SDLK_LEFT) {
+                        --current;
+                    } else if (event.key.keysym.sym == SDLK_RIGHT) {
+                        ++current;
+                    }
+                }
+                if (event.type == SDL_MOUSEBUTTONDOWN) {
+                    if (event.button.x < (original->w/2)) {
+                        --current;
+                    } else {
+                        ++current;
+                    }
+                }
+            }
+
+            /* Handle wrapping */
+            if (current < 0) {
+                current += SDL_arraysize(output);
+            }
+            if (current >= SDL_arraysize(output)) {
+                current -= SDL_arraysize(output);
+            }
+
+            SDL_RenderClear(renderer);
+            SDL_RenderCopy(renderer, output[current], NULL, NULL);
+            SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
+            if (current == 0) {
+                SDLTest_DrawString(renderer, 4, 4, titles[current]);
+            } else {
+                SDL_snprintf(title, sizeof(title), "%s %s %s", titles[current], yuv_name, yuv_mode);
+                SDLTest_DrawString(renderer, 4, 4, title);
+            }
+            SDL_RenderPresent(renderer);
+            SDL_Delay(10);
+        }
+    }
+    SDL_Quit();
+    return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/test/testyuv_cvt.c b/libs/SDL2/test/testyuv_cvt.c
new file mode 100644
index 0000000000000000000000000000000000000000..553a3fa185de6647db5f9386a4fbe3a8695c63b9
--- /dev/null
+++ b/libs/SDL2/test/testyuv_cvt.c
@@ -0,0 +1,300 @@
+/*
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+
+#include "SDL.h"
+
+#include "testyuv_cvt.h"
+
+
+static float clip3(float x, float y, float z)
+{
+    return ((z < x) ? x : ((z > y) ? y : z));
+}
+
+static void RGBtoYUV(Uint8 * rgb, int *yuv, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
+{
+    if (mode == SDL_YUV_CONVERSION_JPEG) {
+        /* Full range YUV */
+        yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
+        yuv[1] = (int)((rgb[2] - yuv[0]) * 0.565 + 128);
+        yuv[2] = (int)((rgb[0] - yuv[0]) * 0.713 + 128);
+    } else {
+        // This formula is from Microsoft's documentation:
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx
+        // L = Kr * R + Kb * B + (1 - Kr - Kb) * G
+        // Y =                   floor(2^(M-8) * (219*(L-Z)/S + 16) + 0.5);
+        // U = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(B-L) / ((1-Kb)*S) + 128) + 0.5));
+        // V = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(R-L) / ((1-Kr)*S) + 128) + 0.5));
+        float S, Z, R, G, B, L, Kr, Kb, Y, U, V;
+
+        if (mode == SDL_YUV_CONVERSION_BT709) {
+            /* BT.709 */
+            Kr = 0.2126f;
+            Kb = 0.0722f;
+        } else {
+            /* BT.601 */
+            Kr = 0.299f;
+            Kb = 0.114f;
+        }
+
+        S = 255.0f;
+        Z = 0.0f;
+        R = rgb[0];
+        G = rgb[1];
+        B = rgb[2];
+        L = Kr * R + Kb * B + (1 - Kr - Kb) * G;
+        Y = (Uint8)SDL_floorf((219*(L-Z)/S + 16) + 0.5f);
+        U = (Uint8)clip3(0, 255, SDL_floorf((112.0f*(B-L) / ((1.0f-Kb)*S) + 128) + 0.5f));
+        V = (Uint8)clip3(0, 255, SDL_floorf((112.0f*(R-L) / ((1.0f-Kr)*S) + 128) + 0.5f));
+
+        yuv[0] = (Uint8)Y;
+        yuv[1] = (Uint8)U;
+        yuv[2] = (Uint8)V;
+    }
+
+    if (monochrome) {
+        yuv[1] = 128;
+        yuv[2] = 128;
+    }
+
+    if (luminance != 100) {
+        yuv[0] = yuv[0] * luminance / 100;
+        if (yuv[0] > 255)
+            yuv[0] = 255;
+    }
+}
+
+static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
+{
+    int x, y;
+    int yuv[4][3];
+    Uint8 *Y1, *Y2, *U, *V;
+    Uint8 *rgb1, *rgb2;
+    int rgb_row_advance = (pitch - w*3) + pitch;
+    int UV_advance;
+
+    rgb1 = src;
+    rgb2 = src + pitch;
+
+    Y1 = out;
+    Y2 = Y1 + w;
+    switch (format) {
+    case SDL_PIXELFORMAT_YV12:
+        V = (Y1 + h * w);
+        U = V + ((h + 1)/2)*((w + 1)/2);
+        UV_advance = 1;
+        break;
+    case SDL_PIXELFORMAT_IYUV:
+        U = (Y1 + h * w);
+        V = U + ((h + 1)/2)*((w + 1)/2);
+        UV_advance = 1;
+        break;
+    case SDL_PIXELFORMAT_NV12:
+        U = (Y1 + h * w);
+        V = U + 1;
+        UV_advance = 2;
+        break;
+    case SDL_PIXELFORMAT_NV21:
+        V = (Y1 + h * w);
+        U = V + 1;
+        UV_advance = 2;
+        break;
+    default:
+        SDL_assert(!"Unsupported planar YUV format");
+        return;
+    }
+
+    for (y = 0; y < (h - 1); y += 2) {
+        for (x = 0; x < (w - 1); x += 2) {
+            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
+            rgb1 += 3;
+            *Y1++ = (Uint8)yuv[0][0];
+
+            RGBtoYUV(rgb1, yuv[1], mode, monochrome, luminance);
+            rgb1 += 3;
+            *Y1++ = (Uint8)yuv[1][0];
+
+            RGBtoYUV(rgb2, yuv[2], mode, monochrome, luminance);
+            rgb2 += 3;
+            *Y2++ = (Uint8)yuv[2][0];
+
+            RGBtoYUV(rgb2, yuv[3], mode, monochrome, luminance);
+            rgb2 += 3;
+            *Y2++ = (Uint8)yuv[3][0];
+
+            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1])/4.0f + 0.5f);
+            U += UV_advance;
+
+            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2])/4.0f + 0.5f);
+            V += UV_advance;
+        }
+        /* Last column */
+        if (x == (w - 1)) {
+            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
+            rgb1 += 3;
+            *Y1++ = (Uint8)yuv[0][0];
+
+            RGBtoYUV(rgb2, yuv[2], mode, monochrome, luminance);
+            rgb2 += 3;
+            *Y2++ = (Uint8)yuv[2][0];
+
+            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[2][1])/2.0f + 0.5f);
+            U += UV_advance;
+
+            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[2][2])/2.0f + 0.5f);
+            V += UV_advance;
+        }
+        Y1 += w;
+        Y2 += w;
+        rgb1 += rgb_row_advance;
+        rgb2 += rgb_row_advance;
+    }
+    /* Last row */
+    if (y == (h - 1)) {
+        for (x = 0; x < (w - 1); x += 2) {
+            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
+            rgb1 += 3;
+            *Y1++ = (Uint8)yuv[0][0];
+
+            RGBtoYUV(rgb1, yuv[1], mode, monochrome, luminance);
+            rgb1 += 3;
+            *Y1++ = (Uint8)yuv[1][0];
+
+            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1])/2.0f + 0.5f);
+            U += UV_advance;
+
+            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2])/2.0f + 0.5f);
+            V += UV_advance;
+        }
+        /* Last column */
+        if (x == (w - 1)) {
+            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
+            *Y1++ = (Uint8)yuv[0][0];
+
+            *U = (Uint8)yuv[0][1];
+            U += UV_advance;
+
+            *V = (Uint8)yuv[0][2];
+            V += UV_advance;
+        }
+    }
+}
+
+static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
+{
+    int x, y;
+    int yuv[2][3];
+    Uint8 *Y1, *Y2, *U, *V;
+    Uint8 *rgb;
+    int rgb_row_advance = (pitch - w*3);
+
+    rgb = src;
+
+    switch (format) {
+    case SDL_PIXELFORMAT_YUY2:
+        Y1 = out;
+        U = out+1;
+        Y2 = out+2;
+        V = out+3;
+        break;
+    case SDL_PIXELFORMAT_UYVY:
+        U = out;
+        Y1 = out+1;
+        V = out+2;
+        Y2 = out+3;
+        break;
+    case SDL_PIXELFORMAT_YVYU:
+        Y1 = out;
+        V = out+1;
+        Y2 = out+2;
+        U = out+3;
+        break;
+    default:
+        SDL_assert(!"Unsupported packed YUV format");
+        return;
+    }
+
+    for (y = 0; y < h; ++y) {
+        for (x = 0; x < (w - 1); x += 2) {
+            RGBtoYUV(rgb, yuv[0], mode, monochrome, luminance);
+            rgb += 3;
+            *Y1 = (Uint8)yuv[0][0];
+            Y1 += 4;
+
+            RGBtoYUV(rgb, yuv[1], mode, monochrome, luminance);
+            rgb += 3;
+            *Y2 = (Uint8)yuv[1][0];
+            Y2 += 4;
+
+            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1])/2.0f + 0.5f);
+            U += 4;
+
+            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2])/2.0f + 0.5f);
+            V += 4;
+        }
+        /* Last column */
+        if (x == (w - 1)) {
+            RGBtoYUV(rgb, yuv[0], mode, monochrome, luminance);
+            rgb += 3;
+            *Y2 = *Y1 = (Uint8)yuv[0][0];
+            Y1 += 4;
+            Y2 += 4;
+
+            *U = (Uint8)yuv[0][1];
+            U += 4;
+
+            *V = (Uint8)yuv[0][2];
+            V += 4;
+        }
+        rgb += rgb_row_advance;
+    }
+}
+
+SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
+{
+    switch (format)
+    {
+    case SDL_PIXELFORMAT_YV12:
+    case SDL_PIXELFORMAT_IYUV:
+    case SDL_PIXELFORMAT_NV12:
+    case SDL_PIXELFORMAT_NV21:
+        ConvertRGBtoPlanar2x2(format, src, pitch, out, w, h, mode, monochrome, luminance);
+        return SDL_TRUE;
+    case SDL_PIXELFORMAT_YUY2:
+    case SDL_PIXELFORMAT_UYVY:
+    case SDL_PIXELFORMAT_YVYU:
+        ConvertRGBtoPacked4(format, src, pitch, out, w, h, mode, monochrome, luminance);
+        return SDL_TRUE;
+    default:
+        return SDL_FALSE;
+    }
+}
+
+int CalculateYUVPitch(Uint32 format, int width)
+{
+    switch (format)
+    {
+    case SDL_PIXELFORMAT_YV12:
+    case SDL_PIXELFORMAT_IYUV:
+    case SDL_PIXELFORMAT_NV12:
+    case SDL_PIXELFORMAT_NV21:
+        return width;
+    case SDL_PIXELFORMAT_YUY2:
+    case SDL_PIXELFORMAT_UYVY:
+    case SDL_PIXELFORMAT_YVYU:
+        return 4*((width + 1)/2);
+    default:
+        return 0;
+    }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/test/testyuv_cvt.h b/libs/SDL2/test/testyuv_cvt.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd845878f4607518d2a32746c61e28e2555d82b8
--- /dev/null
+++ b/libs/SDL2/test/testyuv_cvt.h
@@ -0,0 +1,16 @@
+/*
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+
+/* These functions are designed for testing correctness, not for speed */
+
+extern SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance);
+extern int CalculateYUVPitch(Uint32 format, int width);
diff --git a/libs/SDL2/test/torturethread.c b/libs/SDL2/test/torturethread.c
index 4c2679b8ebd749f729918965cacea63754e5a328..9b1a407eea2dfe167ef5e662079f1bce9f624468 100644
--- a/libs/SDL2/test/torturethread.c
+++ b/libs/SDL2/test/torturethread.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll b/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll
index 6776cdd891ea4479c662519a1667ddc08ca5a8ef..934f8091c7d59b5d479026cfab1ec45d9077fff1 100755
Binary files a/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll and b/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config b/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
index 34d3cb87742057ac1bbc25d362470cc998ff7ee7..9809f6002224622f26ee76a054673fc9cadd7249 100755
--- a/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
+++ b/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-prefix=/usr/local/x86_64-w64-mingw32
+prefix=/opt/local/x86_64-w64-mingw32
 exec_prefix=${prefix}
 exec_prefix_set=no
 libdir=${exec_prefix}/lib
@@ -39,17 +39,17 @@ while test $# -gt 0; do
       echo $exec_prefix
       ;;
     --version)
-      echo 2.0.7
+      echo 2.0.9
       ;;
     --cflags)
       echo -I${prefix}/include/SDL2  -Dmain=SDL_main
       ;;
     --libs)
-      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2  -mwindows
+      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2 -mwindows
       ;;
     --static-libs)
 #    --libs|--static-libs)
-      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2  -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc
+      echo -L${exec_prefix}/lib  -lmingw32 -lSDL2main -lSDL2 -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -static-libgcc
       ;;
     *)
       echo "${usage}" 1>&2
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
index 366d50fa39095f0185247d490b31753351ef887c..fc35a419efd9076076aca339303a2937d5e6ada7 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,6 +51,7 @@
 #include "SDL_power.h"
 #include "SDL_render.h"
 #include "SDL_rwops.h"
+#include "SDL_sensor.h"
 #include "SDL_shape.h"
 #include "SDL_system.h"
 #include "SDL_thread.h"
@@ -80,10 +81,11 @@ extern "C" {
 #define SDL_INIT_HAPTIC         0x00001000u
 #define SDL_INIT_GAMECONTROLLER 0x00002000u  /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
 #define SDL_INIT_EVENTS         0x00004000u
+#define SDL_INIT_SENSOR         0x00008000u
 #define SDL_INIT_NOPARACHUTE    0x00100000u  /**< compatibility; this flag is ignored. */
 #define SDL_INIT_EVERYTHING ( \
                 SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
-                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
+                SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \
             )
 /* @} */
 
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
index 90abbe39b6f1e5bd7e0bfa3d54b00954efe06e9a..b38f928ae14bb68e916bae1048a4c8648a1a20d8 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
index 36e37f3b786840231bf87fddf563c695037c7fc5..b2287748c8f87973ef2aef5093812c0065b89725 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -158,6 +158,9 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
 #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("lwsync" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("lwsync" : : : "memory")
+#elif defined(__GNUC__) && defined(__aarch64__)
+#define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
+#define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #elif defined(__GNUC__) && defined(__arm__)
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
index f119c2b2678fc531efe1d3ecc8b1f1751169de53..d3e1bface4d406c3d6c1c3f141a36a3fce8e926b 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -140,7 +140,8 @@ typedef Uint16 SDL_AudioFormat;
 #define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE    0x00000001
 #define SDL_AUDIO_ALLOW_FORMAT_CHANGE       0x00000002
 #define SDL_AUDIO_ALLOW_CHANNELS_CHANGE     0x00000004
-#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
+#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE      0x00000008
+#define SDL_AUDIO_ALLOW_ANY_CHANGE          (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
 /* @} */
 
 /* @} *//* Audio flags */
@@ -527,7 +528,7 @@ extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioForm
  *
  *  \param stream The stream the audio data is being added to
  *  \param buf A pointer to the audio data to add
- *  \param int The number of bytes to write to the stream
+ *  \param len The number of bytes to write to the stream
  *  \return 0 on success, or -1 on error.
  *
  *  \sa SDL_NewAudioStream
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
index bc28572902181c1edf67998fe3800c0269b4c451..eb8322f0d0a181b364871c28df42010ead3f17b1 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
index 9abd0bd4cf11c6d4d9931a20f21db32e2af0cdc6..36a5ea76f0c52c4364cb5f156cdf7252c0441ecc 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
index 341f4ba42b17e2025a5a27ecaa3925e3f618c1ad..f28751ebb8ffe5c67f17ccab94f2a55165fea4c8 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
index 1bbb83848142162b87676b35e03d964d5bec56dd..c58be8e72ee0dbb9e73f94be9d8c2c595aa630e5 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -82,6 +82,9 @@ typedef unsigned int uintptr_t;
 #define HAVE_DSOUND_H 1
 #define HAVE_DXGI_H 1
 #define HAVE_XINPUT_H 1
+#define HAVE_MMDEVICEAPI_H 1
+#define HAVE_AUDIOCLIENT_H 1
+#define HAVE_ENDPOINTVOLUME_H 1
 
 /* This is disabled by default to avoid C runtime dependencies and manifest requirements */
 #ifdef HAVE_LIBC
@@ -109,13 +112,15 @@ typedef unsigned int uintptr_t;
 #define HAVE_MEMCMP 1
 #define HAVE_STRLEN 1
 #define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-#define HAVE__STRLWR 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__STRUPR */
+/* #undef HAVE__STRLWR */
 #define HAVE_STRCHR 1
 #define HAVE_STRRCHR 1
 #define HAVE_STRSTR 1
-#define HAVE__LTOA 1
-#define HAVE__ULTOA 1
+/* These functions have security warnings, so we won't use them */
+/* #undef HAVE__LTOA */
+/* #undef HAVE__ULTOA */
 #define HAVE_STRTOL 1
 #define HAVE_STRTOUL 1
 #define HAVE_STRTOD 1
@@ -125,30 +130,45 @@ typedef unsigned int uintptr_t;
 #define HAVE_STRNCMP 1
 #define HAVE__STRICMP 1
 #define HAVE__STRNICMP 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE__COPYSIGN 1
+#define HAVE_ACOS   1
+#define HAVE_ACOSF  1
+#define HAVE_ASIN   1
+#define HAVE_ASINF  1
+#define HAVE_ATAN   1
+#define HAVE_ATANF  1
+#define HAVE_ATAN2  1
+#define HAVE_ATAN2F 1
+#define HAVE_CEILF  1
+#define HAVE__COPYSIGN  1
+#define HAVE_COS    1
+#define HAVE_COSF   1
+#define HAVE_EXP    1
+#define HAVE_EXPF   1
+#define HAVE_FABS   1
+#define HAVE_FABSF  1
+#define HAVE_FLOOR  1
+#define HAVE_FLOORF 1
+#define HAVE_FMOD   1
+#define HAVE_FMODF  1
+#define HAVE_LOG    1
+#define HAVE_LOGF   1
+#define HAVE_LOG10  1
+#define HAVE_LOG10F 1
+#define HAVE_POW    1
+#define HAVE_POWF   1
+#define HAVE_SIN    1
+#define HAVE_SINF   1
+#define HAVE_SQRT   1
+#define HAVE_SQRTF  1
+#define HAVE_TAN    1
+#define HAVE_TANF   1
 #if defined(_MSC_VER)
 /* These functions were added with the VC++ 2013 C runtime library */
 #if _MSC_VER >= 1800
 #define HAVE_STRTOLL 1
 #define HAVE_VSSCANF 1
 #define HAVE_SCALBN 1
+#define HAVE_SCALBNF    1
 #endif
 /* This function is available with at least the VC++ 2008 C runtime library */
 #if _MSC_VER >= 1400
@@ -166,7 +186,6 @@ typedef unsigned int uintptr_t;
 /* Enable various audio drivers */
 #define SDL_AUDIO_DRIVER_WASAPI 1
 #define SDL_AUDIO_DRIVER_DSOUND 1
-#define SDL_AUDIO_DRIVER_XAUDIO2    0
 #define SDL_AUDIO_DRIVER_WINMM  1
 #define SDL_AUDIO_DRIVER_DISK   1
 #define SDL_AUDIO_DRIVER_DUMMY  1
@@ -174,9 +193,13 @@ typedef unsigned int uintptr_t;
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
 #define SDL_JOYSTICK_XINPUT 1
+#define SDL_JOYSTICK_HIDAPI 1
 #define SDL_HAPTIC_DINPUT   1
 #define SDL_HAPTIC_XINPUT   1
 
+/* Enable the dummy sensor driver */
+#define SDL_SENSOR_DUMMY  1
+
 /* Enable various shared object loading systems */
 #define SDL_LOADSO_WINDOWS  1
 
@@ -194,7 +217,7 @@ typedef unsigned int uintptr_t;
 #define SDL_VIDEO_RENDER_D3D    1
 #endif
 #ifndef SDL_VIDEO_RENDER_D3D11
-#define SDL_VIDEO_RENDER_D3D11	0
+#define SDL_VIDEO_RENDER_D3D11  0
 #endif
 
 /* Enable OpenGL support */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
index 94b64b03bc5dd394af7f2ccfc5968fb1c0e9dfc5..ee3a47e841242fdae7e697f6b5de18a2a47c1ecf 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -51,27 +51,35 @@
 #include <intrin.h>
 #else
 #ifdef __ALTIVEC__
-#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__)
+#if defined(HAVE_ALTIVEC_H) && !defined(__APPLE_ALTIVEC__) && !defined(SDL_DISABLE_ALTIVEC_H)
 #include <altivec.h>
 #undef pixel
+#undef bool
 #endif
 #endif
-#ifdef __MMX__
-#include <mmintrin.h>
+#if defined(__ARM_NEON__) && !defined(SDL_DISABLE_ARM_NEON_H)
+#include <arm_neon.h>
 #endif
-#ifdef __3dNOW__
+#if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
 #include <mm3dnow.h>
 #endif
-#ifdef __SSE__
+#if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
+#include <immintrin.h>
+#else
+#if defined(__MMX__) && !defined(SDL_DISABLE_MMINTRIN_H)
+#include <mmintrin.h>
+#endif
+#if defined(__SSE__) && !defined(SDL_DISABLE_XMMINTRIN_H)
 #include <xmmintrin.h>
 #endif
-#ifdef __SSE2__
+#if defined(__SSE2__) && !defined(SDL_DISABLE_EMMINTRIN_H)
 #include <emmintrin.h>
 #endif
-#ifdef __SSE3__
+#if defined(__SSE3__) && !defined(SDL_DISABLE_PMMINTRIN_H)
 #include <pmmintrin.h>
 #endif
-#endif
+#endif /* HAVE_IMMINTRIN_H */
+#endif /* compiler version */
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -154,6 +162,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
 
+/**
+ *  This function returns true if the CPU has AVX-512F (foundation) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
+
 /**
  *  This function returns true if the CPU has NEON (ARM SIMD) features.
  */
@@ -164,7 +177,6 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
  */
 extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
 
-
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
index e47fbe8624700058a55aff35c8cd39081a19695f..d65ed437c33fe307657aca04f192de87e0ff55e9 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -24,7 +24,7 @@
  *
  *  This is a simple file to encapsulate the EGL API headers.
  */
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
index 3eda7f2871144111f5cdfb24e0d57dd988c440c4..ed0bf5ba8f94888115422d06601ff4200119a9e6 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
index 49be9827e182ae56227e8dde300b7e8c03f8cfb8..c0e46298e8ffdbc6cf6abc4381a7ba9e2dcf1a33 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
index 0fc09bc37d795c8b5a4c34bebf9c78134a4c499f..af22eb6466661378e252d090b1504471f74833a8 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -85,6 +85,9 @@ typedef enum
                                      Called on Android in onResume()
                                 */
 
+    /* Display events */
+    SDL_DISPLAYEVENT   = 0x150,  /**< Display state change */
+
     /* Window events */
     SDL_WINDOWEVENT    = 0x200, /**< Window state change */
     SDL_SYSWMEVENT,             /**< System specific event */
@@ -144,6 +147,9 @@ typedef enum
     SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */
     SDL_AUDIODEVICEREMOVED,        /**< An audio device has been removed. */
 
+    /* Sensor events */
+    SDL_SENSORUPDATE = 0x1200,     /**< A sensor was updated */
+
     /* Render events */
     SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
     SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
@@ -168,6 +174,21 @@ typedef struct SDL_CommonEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_CommonEvent;
 
+/**
+ *  \brief Display state change event data (event.display.*)
+ */
+typedef struct SDL_DisplayEvent
+{
+    Uint32 type;        /**< ::SDL_DISPLAYEVENT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint32 display;     /**< The associated display index */
+    Uint8 event;        /**< ::SDL_DisplayEventID */
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
+    Sint32 data1;       /**< event dependent data */
+} SDL_DisplayEvent;
+
 /**
  *  \brief Window state change event data (event.window.*)
  */
@@ -471,6 +492,17 @@ typedef struct SDL_DropEvent
 } SDL_DropEvent;
 
 
+/**
+ *  \brief Sensor event structure (event.sensor.*)
+ */
+typedef struct SDL_SensorEvent
+{
+    Uint32 type;        /**< ::SDL_SENSORUPDATE */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Sint32 which;       /**< The instance ID of the sensor */
+    float data[6];      /**< Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData() */
+} SDL_SensorEvent;
+
 /**
  *  \brief The "quit requested" event
  */
@@ -526,6 +558,7 @@ typedef union SDL_Event
 {
     Uint32 type;                    /**< Event type, shared with all events */
     SDL_CommonEvent common;         /**< Common event data */
+    SDL_DisplayEvent display;       /**< Window event data */
     SDL_WindowEvent window;         /**< Window event data */
     SDL_KeyboardEvent key;          /**< Keyboard event data */
     SDL_TextEditingEvent edit;      /**< Text editing event data */
@@ -542,6 +575,7 @@ typedef union SDL_Event
     SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
     SDL_AudioDeviceEvent adevice;   /**< Audio device event data */
+    SDL_SensorEvent sensor;         /**< Sensor event data */
     SDL_QuitEvent quit;             /**< Quit request event data */
     SDL_UserEvent user;             /**< Custom event data */
     SDL_SysWMEvent syswm;           /**< System dependent window event data */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
index a1c846ad0f07b71a61a60c147c709c2dc6e2c15f..fa6a1fa6e7b2ad4b9e341f6cf71c4e7fca925586 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
index c9215132ef50a7f214b7b4bf248d6fc73c3ff3f4..6ae9c95428907172257a93dfd6074865891f6571 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -175,6 +175,14 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index);
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
 
+/**
+ *  Get the mapping of a game controller.
+ *  This can be called before any controllers are opened.
+ *
+ *  \return the mapping string.  Must be freed with SDL_free().  Returns NULL if no mapping is available
+ */
+extern DECLSPEC char *SDLCALL SDL_GameControllerMappingForDeviceIndex(int joystick_index);
+
 /**
  *  Open a game controller for use.
  *  The index passed as an argument refers to the N'th game controller on the system.
@@ -196,6 +204,13 @@ extern DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerFromInstanceID(SDL
  */
 extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
 
+/**
+ *  Get the player index of an opened game controller, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
+
 /**
  *  Get the USB vendor ID of an opened controller, if available.
  *  If the vendor ID isn't available this function returns 0.
@@ -345,6 +360,19 @@ SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
 extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
                                                           SDL_GameControllerButton button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param gamecontroller The controller to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a controller previously opened with SDL_GameControllerOpen().
  */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
index 2bba6a7294fa93240d5f6eefbd8d16c5773761ea..b223d80d44c3debd2de55420aaf1e907d1a08919 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
index 60daefaa709bbbc0a1796bd9af6f9be073cacedd..2ea1bfc1602ee571b0ac3238b183117fcb20f25d 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -117,6 +117,17 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* FIXME: For SDL 2.1, adjust all the magnitude variables to be Uint16 (0xFFFF).
+ *
+ * At the moment the magnitude variables are mixed between signed/unsigned, and
+ * it is also not made clear that ALL of those variables expect a max of 0x7FFF.
+ *
+ * Some platforms may have higher precision than that (Linux FF, Windows XInput)
+ * so we should fix the inconsistency in favor of higher possible precision,
+ * adjusting for platforms that use different scales.
+ * -flibit
+ */
+
 /**
  *  \typedef SDL_Haptic
  *
@@ -656,8 +667,8 @@ typedef struct SDL_HapticRamp
  * This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
  *
  * The Left/Right effect is used to explicitly control the large and small
- * motors, commonly found in modern game controllers. One motor is high
- * frequency, the other is low frequency.
+ * motors, commonly found in modern game controllers. The small (right) motor
+ * is high frequency, and the large (left) motor is low frequency.
  *
  * \sa SDL_HAPTIC_LEFTRIGHT
  * \sa SDL_HapticEffect
@@ -668,7 +679,7 @@ typedef struct SDL_HapticLeftRight
     Uint16 type;            /**< ::SDL_HAPTIC_LEFTRIGHT */
 
     /* Replay */
-    Uint32 length;          /**< Duration of the effect. */
+    Uint32 length;          /**< Duration of the effect in milliseconds. */
 
     /* Rumble */
     Uint16 large_magnitude; /**< Control of the large controller motor. */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
index 007a4bee05c0dc4ef90b1d24e88eb1137cedc945..4ee72e97d66db40a703620a9d0a162a952de1498 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,7 @@ extern "C" {
  *    "opengl"
  *    "opengles2"
  *    "opengles"
+ *    "metal"
  *    "software"
  *
  *  The default varies by platform, but it's the first one in the list that
@@ -210,6 +211,18 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_X11_NET_WM_PING      "SDL_VIDEO_X11_NET_WM_PING"
 
+/**
+ * \brief A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint should be used.
+ * 
+ * This variable can be set to the following values:
+ * "0" - Disable _NET_WM_BYPASS_COMPOSITOR
+ * "1" - Enable _NET_WM_BYPASS_COMPOSITOR
+ * 
+ * By default SDL will use _NET_WM_BYPASS_COMPOSITOR
+ * 
+ */
+#define SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"
+
 /**
  *  \brief  A variable controlling whether the window frame and title bar are interactive when the cursor is hidden 
  *
@@ -249,6 +262,16 @@ extern "C" {
  */
 #define SDL_HINT_GRAB_KEYBOARD              "SDL_GRAB_KEYBOARD"
 
+/**
+ *  \brief  A variable setting the double click time, in milliseconds.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME    "SDL_MOUSE_DOUBLE_CLICK_TIME"
+
+/**
+ *  \brief  A variable setting the double click radius, in pixels.
+ */
+#define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS    "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
+
 /**
  *  \brief  A variable setting the speed scale for mouse motion, in floating point, when the mouse is not in relative mode
  */
@@ -316,7 +339,7 @@ extern "C" {
 #define SDL_HINT_IDLE_TIMER_DISABLED "SDL_IOS_IDLE_TIMER_DISABLED"
 
 /**
- *  \brief  A variable controlling which orientations are allowed on iOS.
+ *  \brief  A variable controlling which orientations are allowed on iOS/Android.
  *
  *  In some circumstances it is necessary to be able to explicitly control
  *  which UI orientations are allowed.
@@ -354,17 +377,37 @@ extern "C" {
  */
 #define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION"
 
+/**
+ * \brief  A variable controlling whether the home indicator bar on iPhone X
+ *         should be hidden.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - The indicator bar is not hidden (default for windowed applications)
+ *    "1"       - The indicator bar is hidden and is shown when the screen is touched (useful for movie playback applications)
+ *    "2"       - The indicator bar is dim and the first swipe makes it visible and the second swipe performs the "home" action (default for fullscreen applications)
+ */
+#define SDL_HINT_IOS_HIDE_HOME_INDICATOR "SDL_IOS_HIDE_HOME_INDICATOR"
+
 /**
  *  \brief  A variable controlling whether the Android / iOS built-in
- *  accelerometer should be listed as a joystick device, rather than listing
- *  actual joysticks only.
+ *  accelerometer should be listed as a joystick device.
  *
  *  This variable can be set to the following values:
- *    "0"       - List only real joysticks and accept input from them
- *    "1"       - List real joysticks along with the accelerometer as if it were a 3 axis joystick (the default).
+ *    "0"       - The accelerometer is not listed as a joystick
+ *    "1"       - The accelerometer is available as a 3 axis joystick (the default).
  */
 #define SDL_HINT_ACCELEROMETER_AS_JOYSTICK "SDL_ACCELEROMETER_AS_JOYSTICK"
 
+/**
+ *  \brief  A variable controlling whether the Android / tvOS remotes
+ *  should be listed as joystick devices, instead of sending keyboard events.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Remotes send enter/escape/arrow key events
+ *    "1"       - Remotes are available as 2 axis, 2 button joysticks (the default).
+ */
+#define SDL_HINT_TV_REMOTE_AS_JOYSTICK "SDL_TV_REMOTE_AS_JOYSTICK"
+
 /**
  *  \brief  A variable that lets you disable the detection and use of Xinput gamepad devices
  *
@@ -432,6 +475,88 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
+/**
+ *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI drivers are not used
+ *    "1"       - HIDAPI drivers are used (the default)
+ *
+ *  This variable is the default for all drivers, but can be overridden by the hints for specific drivers below.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI "SDL_JOYSTICK_HIDAPI"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4 "SDL_JOYSTICK_HIDAPI_PS4"
+
+/**
+ *  \brief  A variable controlling whether extended input reports should be used for PS4 controllers when using the HIDAPI driver.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - extended reports are not enabled (the default)
+ *    "1"       - extended reports
+ *
+ *  Extended input reports allow rumble on Bluetooth PS4 controllers, but
+ *  break DirectInput handling for applications that don't use SDL.
+ *
+ *  Once extended reports are enabled, they can not be disabled without
+ *  power cycling the controller.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
+
+/**
+ *  \brief  A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
+ *
+ *  The variable can be set to the following values:
+ *    "0"       - Do not scan for Steam Controllers
+ *    "1"       - Scan for Steam Controllers (the default)
+ *
+ *  The default value is "1".  This hint must be set before initializing the joystick subsystem.
+ */
+#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
+
+
 /**
  *  \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
  *      This is a debugging aid for developers and not expected to be used by end users. The default is "1"
@@ -494,6 +619,10 @@ extern "C" {
 *  This is specially useful if you build SDL against a non glibc libc library (such as musl) which
 *  provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses).
 *  Support for this hint is currently available only in the pthread, Windows, and PSP backend.
+*
+*  Instead of this hint, in 2.0.9 and later, you can use
+*  SDL_CreateThreadWithStackSize(). This hint only works with the classic
+*  SDL_CreateThread().
 */
 #define SDL_HINT_THREAD_STACK_SIZE              "SDL_THREAD_STACK_SIZE"
 
@@ -719,6 +848,35 @@ extern "C" {
  */
 #define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
 
+ /**
+ * \brief A variable to control whether we trap the Android back button to handle it manually.
+ *        This is necessary for the right mouse button to work on some Android devices, or
+ *        to be able to trap the back button for use in your code reliably.  If set to true,
+ *        the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of 
+ *        SDL_SCANCODE_AC_BACK.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - Back button will be handled as usual for system. (default)
+ *   "1"       - Back button will be trapped, allowing you to handle the key press
+ *               manually.  (This will also let right mouse click work on systems 
+ *               where the right mouse button functions as back.)
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON"
+
+ /**
+ * \brief A variable to control whether the return key on the soft keyboard
+ *        should hide the soft keyboard on Android and iOS.
+ *
+ * The variable can be set to the following values:
+ *   "0"       - The return key will be handled as a key event. This is the behaviour of SDL <= 2.0.3. (default)
+ *   "1"       - The return key will hide the keyboard.
+ *
+ * The value of this hint is used at runtime, so it can be changed at any time.
+ */
+#define SDL_HINT_RETURN_KEY_HIDES_IME "SDL_RETURN_KEY_HIDES_IME"
+
 /**
  *  \brief override the binding element for keyboard inputs for Emscripten builds
  *
@@ -752,7 +910,7 @@ extern "C" {
  *   "0"       - SDL will generate a window-close event when it sees Alt+F4.
  *   "1"       - SDL will only do normal key handling for Alt+F4.
  */
-#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4	"SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
+#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
 
 /**
  *  \brief Prevent SDL from using version 4 of the bitmap header when saving BMPs.
@@ -797,6 +955,24 @@ extern "C" {
  */
 #define SDL_HINT_RPI_VIDEO_LAYER           "SDL_RPI_VIDEO_LAYER"
 
+/**
+ * \brief Tell the video driver that we only want a double buffer.
+ *
+ * By default, most lowlevel 2D APIs will use a triple buffer scheme that 
+ * wastes no CPU time on waiting for vsync after issuing a flip, but
+ * introduces a frame of latency. On the other hand, using a double buffer
+ * scheme instead is recommended for cases where low latency is an important
+ * factor because we save a whole frame of latency.
+ * We do so by waiting for vsync immediately after issuing a flip, usually just
+ * after eglSwapBuffers call in the backend's *_SwapWindow function.
+ *
+ * Since it's driver-specific, it's only supported where possible and
+ * implemented. Currently supported the following drivers:
+ * - KMSDRM (kmsdrm)
+ * - Raspberry Pi (raspberrypi)
+ */
+#define SDL_HINT_VIDEO_DOUBLE_BUFFER      "SDL_VIDEO_DOUBLE_BUFFER"
+
 /**
  *  \brief  A variable controlling what driver to use for OpenGL ES contexts.
  *
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
index f598dc828dafa2751d3aba2286059a8298d79aa3..6e05a9c2056cf7134c22459066d253e80e9a4315 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,10 +97,10 @@ typedef enum
 typedef enum
 {
     SDL_JOYSTICK_POWER_UNKNOWN = -1,
-    SDL_JOYSTICK_POWER_EMPTY,
-    SDL_JOYSTICK_POWER_LOW,
-    SDL_JOYSTICK_POWER_MEDIUM,
-    SDL_JOYSTICK_POWER_FULL,
+    SDL_JOYSTICK_POWER_EMPTY,   /* <= 5% */
+    SDL_JOYSTICK_POWER_LOW,     /* <= 20% */
+    SDL_JOYSTICK_POWER_MEDIUM,  /* <= 70% */
+    SDL_JOYSTICK_POWER_FULL,    /* <= 100% */
     SDL_JOYSTICK_POWER_WIRED,
     SDL_JOYSTICK_POWER_MAX
 } SDL_JoystickPowerLevel;
@@ -132,6 +132,12 @@ extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
 
+/**
+ *  Get the player index of a joystick, or -1 if it's not available
+ *  This can be called before any joysticks are opened.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetDevicePlayerIndex(int device_index);
+
 /**
  *  Return the GUID for the joystick at this index
  *  This can be called before any joysticks are opened.
@@ -194,6 +200,13 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID
  */
 extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick * joystick);
 
+/**
+ *  Get the player index of an opened joystick, or -1 if it's not available
+ *
+ *  For XInput controllers this returns the XInput user index.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
+
 /**
  *  Return the GUID for this opened joystick
  */
@@ -361,6 +374,19 @@ extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
 extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
                                                     int button);
 
+/**
+ *  Trigger a rumble effect
+ *  Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ *  \param joystick The joystick to vibrate
+ *  \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
+ *  \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
+ *  \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ *  \return 0, or -1 if rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
 /**
  *  Close a joystick previously opened with SDL_JoystickOpen().
  */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
index e78ca469082c793a8190331c01766a3e3374a5ba..87482317161a6e05324bf5ab769743b1a385b436 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
index c41e45ff61b6959937f7f4e912cef24064b72e1f..d7d5b1dbcdefce3777ee48eddcc46853eba2e584 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
index 6ea256c6ae5813dc7b00c269101b4e866fbb5fcc..da56fb452779ee015da429caa8da746c985b0ee0 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
index 356d0e1cf7492f54d82e5829a6030587400869d1..e12b6588601712bd217578226f143941ff019cbb 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
index 2af32360f7be842213bca1253268d5198c768377..98558217fc23ea63118899e44a710b7ba934c720 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -63,10 +63,13 @@
 /* On Android SDL provides a Java class in SDLActivity.java that is the
    main activity entry point.
 
-   See README-android.md for more details on extending that class.
+   See docs/README-android.md for more details on extending that class.
  */
 #define SDL_MAIN_NEEDED
 
+/* We need to export SDL_main so it can be launched from Java */
+#define SDLMAIN_DECLSPEC    DECLSPEC
+
 #elif defined(__NACL__)
 /* On NACL we use ppapi_simple to set up the application helper code,
    then wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before 
@@ -85,6 +88,10 @@
 #define C_LINKAGE
 #endif /* __cplusplus */
 
+#ifndef SDLMAIN_DECLSPEC
+#define SDLMAIN_DECLSPEC
+#endif
+
 /**
  *  \file SDL_main.h
  *
@@ -107,7 +114,7 @@
 /**
  *  The prototype for the application's main() function
  */
-extern C_LINKAGE DECLSPEC int SDL_main(int argc, char *argv[]);
+extern C_LINKAGE SDLMAIN_DECLSPEC int SDL_main(int argc, char *argv[]);
 
 
 #include "begin_code.h"
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
index c326d8f01098b147e1bff015fb8e355e37f00744..b7be59d88f50ad7686b794ca13cd66f29e7ef557 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
index 6001bd46c1e80270d85d18dd72025b0c17f2722a..d3c9f6156cba36ecff91929d7a7eda0784b4af69 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
index 0272379e55e16bb25a913f9b4e4ca11809af7b56..ba4247ced8176dd98396d552536bc4646faa7841 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
index 8095ed3ffd4df27fb77a15eebcd532536c3efc09..ecd863f4ca873b55249601228efc5fc578aa4fb1 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
index 314dd57eda395c3b9e7bcbaf2d3749b9aa01864d..253d9c93a96f875aa53a51a5a615d4d732d9926d 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
index 800c593070a9ea28a1f01c1d2b84e0f15ad2b33c..18dd984b3ed21bf5fd3bbfcf1a8a34fe58dfca6f 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
index 102f2f3fa7075c34639c03109939460ab2e7c2cc..6ccecf216572b4c9514bded0fd0a1c54690e57d8 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
index 04246689f5957e5170ad6be433e089e2483ea85a..0b4364b185231109d61663b4acb50e60e1d8fa16 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -287,7 +287,9 @@ enum
     SDL_PIXELFORMAT_NV12 =      /**< Planar mode: Y + U/V interleaved  (2 planes) */
         SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
     SDL_PIXELFORMAT_NV21 =      /**< Planar mode: Y + V/U interleaved  (2 planes) */
-        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
+        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'),
+    SDL_PIXELFORMAT_EXTERNAL_OES =      /**< Android video texture format */
+        SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ')
 };
 
 typedef struct SDL_Color
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
index 9dde385fa67364dbcfcf22598e33961970c4348e..7dea4ce940fe02f1b233d15ec6a75c9452a0422c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -121,7 +121,12 @@
 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
 /* Try to find out if we're compiling for WinRT or non-WinRT */
 #if defined(_MSC_VER) && defined(__has_include)
-#define HAVE_WINAPIFAMILY_H __has_include(<winapifamily.h>)
+#if __has_include(<winapifamily.h>)
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
 /* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
 #elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
 #define HAVE_WINAPIFAMILY_H 1
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
index d48e8a3795dfd0d9f8a1cd9ad07ba1c54b1b0d7c..a4fe8a9359c247678ad56a47f8b8106fa465f4a9 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
index 9283c381050a4013097e533a1723c64bb6392938..fea56a8d88b6a0ac9e12807d693628f80991bc3e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
index c4f6d74b339ddc7b71372221758dc229043362fd..543bb618694ea9d4b5383e71a7c35b666b9e754c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
index ea6ef9ff645cef9e643162828ccb6b5173d1b732..d336192974f4cedab0497ad6ac60aaba19f3f389 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -898,6 +898,27 @@ extern DECLSPEC int SDLCALL SDL_GL_BindTexture(SDL_Texture *texture, float *texw
  */
 extern DECLSPEC int SDLCALL SDL_GL_UnbindTexture(SDL_Texture *texture);
 
+/**
+ *  \brief Get the CAMetalLayer associated with the given Metal renderer
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return CAMetalLayer* on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalCommandEncoder()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
+
+/**
+ *  \brief Get the Metal command encoder for the current frame
+ *
+ *  \param renderer The renderer to query
+ *
+ *  \return id<MTLRenderCommandEncoder> on success, or NULL if the renderer isn't a Metal renderer
+ *
+ *  \sa SDL_RenderGetMetalLayer()
+ */
+extern DECLSPEC void *SDLCALL SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
index 9376093ee76bd46fbb70196e87673cda9d53ccd6..92fbe67b132156d911795af5e14b335d15645c66 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
@@ -1,2 +1,2 @@
-#define SDL_REVISION "hg-11645:2088cd828335"
-#define SDL_REVISION_NUMBER 11645
+#define SDL_REVISION "hg-12373:8feb5da6f2fb"
+#define SDL_REVISION_NUMBER 12373
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
index 7f0cbdfd55d5fabdd8ff80fc5ec605a7dd70bc0c..0960699d4857bb302e9024e7263c89a725a9a276 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
index 1d55212048560455d110797913a3dde07416768c..63871aa3b10beed824756b430687a3e16d7ebe44 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac163a8cd1be73201742fe56293ddc840653f706
--- /dev/null
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h
@@ -0,0 +1,251 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_sensor.h
+ *
+ *  Include file for SDL sensor event handling
+ *
+ */
+
+#ifndef _SDL_sensor_h
+#define _SDL_sensor_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ *  \brief SDL_sensor.h
+ *
+ *  In order to use these functions, SDL_Init() must have been called
+ *  with the ::SDL_INIT_SENSOR flag.  This causes SDL to scan the system
+ *  for sensors, and load appropriate drivers.
+ */
+
+struct _SDL_Sensor;
+typedef struct _SDL_Sensor SDL_Sensor;
+
+/**
+ * This is a unique ID for a sensor for the time it is connected to the system,
+ * and is never reused for the lifetime of the application.
+ *
+ * The ID value starts at 0 and increments from there. The value -1 is an invalid ID.
+ */
+typedef Sint32 SDL_SensorID;
+
+/* The different sensors defined by SDL
+ *
+ * Additional sensors may be available, using platform dependent semantics.
+ *
+ * Hare are the additional Android sensors:
+ * https://developer.android.com/reference/android/hardware/SensorEvent.html#values
+ */
+typedef enum
+{
+    SDL_SENSOR_INVALID = -1,    /**< Returned for an invalid sensor */
+    SDL_SENSOR_UNKNOWN,         /**< Unknown sensor type */
+    SDL_SENSOR_ACCEL,           /**< Accelerometer */
+    SDL_SENSOR_GYRO             /**< Gyroscope */
+} SDL_SensorType;
+
+/**
+ * Accelerometer sensor
+ *
+ * The accelerometer returns the current acceleration in SI meters per
+ * second squared. This includes gravity, so a device at rest will have
+ * an acceleration of SDL_STANDARD_GRAVITY straight down.
+ *
+ * values[0]: Acceleration on the x axis
+ * values[1]: Acceleration on the y axis
+ * values[2]: Acceleration on the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+#define SDL_STANDARD_GRAVITY    9.80665f
+
+/**
+ * Gyroscope sensor
+ *
+ * The gyroscope returns the current rate of rotation in radians per second.
+ * The rotation is positive in the counter-clockwise direction. That is,
+ * an observer looking from a positive location on one of the axes would
+ * see positive rotation on that axis when it appeared to be rotating
+ * counter-clockwise.
+ *
+ * values[0]: Angular speed around the x axis
+ * values[1]: Angular speed around the y axis
+ * values[2]: Angular speed around the z axis
+ *
+ * For phones held in portrait mode, the axes are defined as follows:
+ * -X ... +X : left ... right
+ * -Y ... +Y : bottom ... top
+ * -Z ... +Z : farther ... closer
+ * 
+ * The axis data is not changed when the phone is rotated.
+ *
+ * \sa SDL_GetDisplayOrientation()
+ */
+
+/* Function prototypes */
+
+/**
+ *  \brief Count the number of sensors attached to the system right now
+ */
+extern DECLSPEC int SDLCALL SDL_NumSensors(void);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ * 
+ *  \return The sensor name, or NULL if device_index is out of range.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetDeviceName(int device_index);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetDeviceType(int device_index);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if device_index is out of range.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetDeviceNonPortableType(int device_index);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if device_index is out of range.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetDeviceInstanceID(int device_index);
+
+/**
+ *  \brief Open a sensor for use.
+ *
+ *  The index passed as an argument refers to the N'th sensor on the system.
+ *
+ *  \return A sensor identifier, or NULL if an error occurred.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorOpen(int device_index);
+
+/**
+ * Return the SDL_Sensor associated with an instance id.
+ */
+extern DECLSPEC SDL_Sensor *SDLCALL SDL_SensorFromInstanceID(SDL_SensorID instance_id);
+
+/**
+ *  \brief Get the implementation dependent name of a sensor.
+ *
+ *  \return The sensor name, or NULL if the sensor is NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_SensorGetName(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor type, or SDL_SENSOR_INVALID if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorType SDLCALL SDL_SensorGetType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the platform dependent type of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor platform dependent type, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetNonPortableType(SDL_Sensor *sensor);
+
+/**
+ *  \brief Get the instance ID of a sensor.
+ *
+ *  This can be called before any sensors are opened.
+ *
+ *  \return The sensor instance ID, or -1 if the sensor is NULL.
+ */
+extern DECLSPEC SDL_SensorID SDLCALL SDL_SensorGetInstanceID(SDL_Sensor *sensor);
+
+/**
+ *  Get the current state of an opened sensor.
+ *
+ *  The number of values and interpretation of the data is sensor dependent.
+ *
+ *  \param sensor The sensor to query
+ *  \param data A pointer filled with the current sensor state
+ *  \param num_values The number of values to write to data
+ *
+ *  \return 0 or -1 if an error occurred.
+ */
+extern DECLSPEC int SDLCALL SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values);
+
+/**
+ *  Close a sensor previously opened with SDL_SensorOpen()
+ */
+extern DECLSPEC void SDLCALL SDL_SensorClose(SDL_Sensor * sensor);
+
+/**
+ *  Update the current state of the open sensors.
+ *
+ *  This is called automatically by the event loop if sensor events are enabled.
+ *
+ *  This needs to be called from the thread that initialized the sensor subsystem.
+ */
+extern DECLSPEC void SDLCALL SDL_SensorUpdate(void);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_sensor_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
index 9e492d93a4d1f6e42bcb2bbfec31fd71520cbaaa..40a6baaaec3d4d7e46c1da1fed54949123421035 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
index 72402299f2da1892dd2224bc436b1822007f9b51..e373bc380f68867e5638b8f6ea26521a66a906ee 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -86,6 +86,28 @@
 #ifdef HAVE_FLOAT_H
 # include <float.h>
 #endif
+#if defined(HAVE_ALLOCA) && !defined(alloca)
+# if defined(HAVE_ALLOCA_H)
+#  include <alloca.h>
+# elif defined(__GNUC__)
+#  define alloca __builtin_alloca
+# elif defined(_MSC_VER)
+#  include <malloc.h>
+#  define alloca _alloca
+# elif defined(__WATCOMC__)
+#  include <malloc.h>
+# elif defined(__BORLANDC__)
+#  include <malloc.h>
+# elif defined(__DMC__)
+#  include <stdlib.h>
+# elif defined(__AIX__)
+#pragma alloca
+# elif defined(__MRC__)
+void *alloca(unsigned);
+# else
+char *alloca();
+# endif
+#endif
 
 /**
  *  The number of elements in an array.
@@ -328,28 +350,6 @@ SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
 extern "C" {
 #endif
 
-#if defined(HAVE_ALLOCA) && !defined(alloca)
-# if defined(HAVE_ALLOCA_H)
-#  include <alloca.h>
-# elif defined(__GNUC__)
-#  define alloca __builtin_alloca
-# elif defined(_MSC_VER)
-#  include <malloc.h>
-#  define alloca _alloca
-# elif defined(__WATCOMC__)
-#  include <malloc.h>
-# elif defined(__BORLANDC__)
-#  include <malloc.h>
-# elif defined(__DMC__)
-#  include <stdlib.h>
-# elif defined(__AIX__)
-#pragma alloca
-# elif defined(__MRC__)
-void *alloca(unsigned);
-# else
-char *alloca();
-# endif
-#endif
 #ifdef HAVE_ALLOCA
 #define SDL_stack_alloc(type, count)    (type*)alloca(sizeof(type)*(count))
 #define SDL_stack_free(data)
@@ -445,12 +445,12 @@ SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 #endif
 }
 
-
 extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 
 extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
 extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
 
+extern DECLSPEC wchar_t *SDLCALL SDL_wcsdup(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
 extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
 extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
@@ -501,18 +501,35 @@ extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size
 #endif
 
 extern DECLSPEC double SDLCALL SDL_acos(double x);
+extern DECLSPEC float SDLCALL SDL_acosf(float x);
 extern DECLSPEC double SDLCALL SDL_asin(double x);
+extern DECLSPEC float SDLCALL SDL_asinf(float x);
 extern DECLSPEC double SDLCALL SDL_atan(double x);
+extern DECLSPEC float SDLCALL SDL_atanf(float x);
 extern DECLSPEC double SDLCALL SDL_atan2(double x, double y);
+extern DECLSPEC float SDLCALL SDL_atan2f(float x, float y);
 extern DECLSPEC double SDLCALL SDL_ceil(double x);
+extern DECLSPEC float SDLCALL SDL_ceilf(float x);
 extern DECLSPEC double SDLCALL SDL_copysign(double x, double y);
+extern DECLSPEC float SDLCALL SDL_copysignf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_cos(double x);
 extern DECLSPEC float SDLCALL SDL_cosf(float x);
+extern DECLSPEC double SDLCALL SDL_exp(double x);
+extern DECLSPEC float SDLCALL SDL_expf(float x);
 extern DECLSPEC double SDLCALL SDL_fabs(double x);
+extern DECLSPEC float SDLCALL SDL_fabsf(float x);
 extern DECLSPEC double SDLCALL SDL_floor(double x);
+extern DECLSPEC float SDLCALL SDL_floorf(float x);
+extern DECLSPEC double SDLCALL SDL_fmod(double x, double y);
+extern DECLSPEC float SDLCALL SDL_fmodf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_log(double x);
+extern DECLSPEC float SDLCALL SDL_logf(float x);
+extern DECLSPEC double SDLCALL SDL_log10(double x);
+extern DECLSPEC float SDLCALL SDL_log10f(float x);
 extern DECLSPEC double SDLCALL SDL_pow(double x, double y);
+extern DECLSPEC float SDLCALL SDL_powf(float x, float y);
 extern DECLSPEC double SDLCALL SDL_scalbn(double x, int n);
+extern DECLSPEC float SDLCALL SDL_scalbnf(float x, int n);
 extern DECLSPEC double SDLCALL SDL_sin(double x);
 extern DECLSPEC float SDLCALL SDL_sinf(float x);
 extern DECLSPEC double SDLCALL SDL_sqrt(double x);
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
index 510690c9cffe37fa3153d547d87c9ed0089584c2..730d49fc805ec54d5725c7369db4578d194aa56a 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -97,6 +97,17 @@ typedef struct SDL_Surface
 typedef int (SDLCALL *SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
                                  struct SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ * \brief The formula used for converting between YUV and RGB
+ */
+typedef enum
+{
+    SDL_YUV_CONVERSION_JPEG,        /**< Full range JPEG */
+    SDL_YUV_CONVERSION_BT601,       /**< BT.601 (the default) */
+    SDL_YUV_CONVERSION_BT709,       /**< BT.709 */
+    SDL_YUV_CONVERSION_AUTOMATIC    /**< BT.601 for SD content, BT.709 for HD content */
+} SDL_YUV_CONVERSION_MODE;
+
 /**
  *  Allocate and free an RGB surface.
  *
@@ -237,6 +248,13 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface * surface,
 extern DECLSPEC int SDLCALL SDL_SetColorKey(SDL_Surface * surface,
                                             int flag, Uint32 key);
 
+/**
+ *  \brief Returns whether the surface has a color key
+ *
+ *  \return SDL_TRUE if the surface has a color key, or SDL_FALSE if the surface is NULL or has no color key
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasColorKey(SDL_Surface * surface);
+
 /**
  *  \brief Gets the color key (transparent pixel) in a blittable surface.
  *
@@ -509,6 +527,20 @@ extern DECLSPEC int SDLCALL SDL_LowerBlitScaled
     (SDL_Surface * src, SDL_Rect * srcrect,
     SDL_Surface * dst, SDL_Rect * dstrect);
 
+/**
+ *  \brief Set the YUV conversion mode
+ */
+extern DECLSPEC void SDLCALL SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
+
+/**
+ *  \brief Get the YUV conversion mode
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionMode(void);
+
+/**
+ *  \brief Get the YUV conversion mode, returning the correct mode for the resolution when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC
+ */
+extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionModeForResolution(int width, int height);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
index eb069b33d8127f026de8b57b1869ccf3297f75e6..4dc372d6b14bb7fd49f64f716d1f9f29e3a15fbc 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -76,6 +76,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a
 #endif /* __WIN32__ */
 
 
+/* Platform specific functions for Linux */
+#ifdef __LINUX__
+
+/**
+   \brief Sets the UNIX nice value for a thread, using setpriority() if possible, and RealtimeKit if available.
+
+   \return 0 on success, or -1 on error.
+ */
+extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
+ 
+#endif /* __LINUX__ */
+	
 /* Platform specific functions for iOS */
 #if defined(__IPHONEOS__) && __IPHONEOS__
 
@@ -108,6 +120,26 @@ extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(void);
  */
 extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(void);
 
+/**
+   \brief Return true if the application is running on Android TV
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
+
+/**
+   \brief Return true if the application is running on a Chromebook
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void);
+
+/**
+  \brief Return true is the application is running on a Samsung DeX docking station
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void);
+
+/**
+ \brief Trigger the Android system back button behavior.
+ */
+extern DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
+
 /**
    See the official Android developer guide for more information:
    http://developer.android.com/guide/topics/data/data-storage.html
@@ -169,6 +201,25 @@ typedef enum
 } SDL_WinRT_Path;
 
 
+/**
+ *  \brief WinRT Device Family
+ */
+typedef enum
+{
+    /** \brief Unknown family  */
+    SDL_WINRT_DEVICEFAMILY_UNKNOWN,
+
+    /** \brief Desktop family*/
+    SDL_WINRT_DEVICEFAMILY_DESKTOP,
+
+    /** \brief Mobile family (for example smartphone) */
+    SDL_WINRT_DEVICEFAMILY_MOBILE,
+
+    /** \brief XBox family */
+    SDL_WINRT_DEVICEFAMILY_XBOX,
+} SDL_WinRT_DeviceFamily;
+
+
 /**
  *  \brief Retrieves a WinRT defined path on the local file system
  *
@@ -203,8 +254,20 @@ extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path
  */
 extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
 
+/**
+ *  \brief Detects the device family of WinRT plattform on runtime
+ *
+ *  \return Device family
+ */
+extern DECLSPEC SDL_WinRT_DeviceFamily SDLCALL SDL_WinRTGetDeviceFamily();
+
 #endif /* __WINRT__ */
 
+/**
+ \brief Return true if the current device is a tablet.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_IsTablet(void);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
index 2d18afb6cf90173ca289b53f74dad013a3440909..f1c4021cc8b37be22124d28a99733d1e696e71e6 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -33,12 +33,6 @@
 #include "SDL_video.h"
 #include "SDL_version.h"
 
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  *  \file SDL_syswm.h
  *
@@ -110,6 +104,12 @@ typedef void *EGLSurface;
 #include "SDL_egl.h"
 #endif
 
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  *  These are the various supported windowing subsystems
  */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
index f55afcb02273929055de6bf3a8848c2025e3bda3..6cc373bf809ca34195c28d7ef465fffac49c0e89 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
index 11d8363942948261e7a2403c3556d7e45860ef8a..1788d7a206916e92ccc607c24d93805ec368c838 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
index 24eeb32af1b8731d95e28084a051b219480810be..be2e6b2aab48af89d8aab4986bd15bd0fc13bd68 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
index 9f4c4587ade92d8afe8d8102bd216db4458930e3..c22e447d8aee297971e6c51e4c1dd2fdb3a5cd52 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
index add480c349fd91512e3a3229f44858407529a106..3d235d07400f10b10297e533f7d74c2cf02bc394 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
index 58c9f9d5e5f3334e23df3bbcba45cc6483635f67..59cbdcad6bcb101764c689f915d8395866b6ea6a 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
index 6cf05747ad91914fe7155322876cd3ff6e2a28d6..8fcb9ebbfa1ba58da745c08e0eb0a322e00319c6 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
index 68c4bcb7c44ff1fb09722fa81be6fb5013917eef..8641e0a7e3ad9945ed5ec93813920017bcc06447 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
index 683d2f8a689e8d49b1c750493a6c04112a19b8e3..9c4dd5b82954fc21c15ff9027372ca3419c6252e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
index 9f993fbbc880ded0f9c4c2dd81d838fb60753ed2..ebd44fb5021c3f4fc64dcab127780ab7da89ebd2 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
index 67ca7d1defbb70c02e83d43eef7f11ee6cbc81e5..0e4105768fdb6bd059ad867cb90d74637e28660c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
index 43b67f521be347be755fa725dfd2bdd6b96f6c01..4827ae6f2c372db861a635ae9faa32637f152a18 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
index 2b01922c3ed5b82aace74bce3c661ce7c8b62782..0eb414ff2e4db2488ac5671f9d1a91048d0f3b34 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
index d0f6575cd5ac7562cb5dba1ca84b5e94b4a3f029..554dd0b61d02481d6f665dbde0799361b1967632 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -54,12 +54,13 @@ typedef unsigned int SDL_TLSID;
 /**
  *  The SDL thread priority.
  *
- *  \note On many systems you require special privileges to set high priority.
+ *  \note On many systems you require special privileges to set high or time critical priority.
  */
 typedef enum {
     SDL_THREAD_PRIORITY_LOW,
     SDL_THREAD_PRIORITY_NORMAL,
-    SDL_THREAD_PRIORITY_HIGH
+    SDL_THREAD_PRIORITY_HIGH,
+    SDL_THREAD_PRIORITY_TIME_CRITICAL
 } SDL_ThreadPriority;
 
 /**
@@ -105,14 +106,24 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
 
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
+                 const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
+
+
 /**
  *  Create a thread.
  */
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthreadex, (pfnSDL_CurrentEndThread)_endthreadex)
 #endif
 
 #elif defined(__OS2__)
@@ -132,15 +143,31 @@ extern DECLSPEC SDL_Thread *SDLCALL
 SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data,
+                 pfnSDL_CurrentBeginThread pfnBeginThread,
+                 pfnSDL_CurrentEndThread pfnEndThread);
 #if defined(SDL_CreateThread) && SDL_DYNAMIC_API
 #undef SDL_CreateThread
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#undef SDL_CreateThreadWithStackSize
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #else
 #define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
+#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)_beginthread, (pfnSDL_CurrentEndThread)_endthread)
 #endif
 
 #else
 
+/**
+ *  Create a thread with a default stack size.
+ *
+ *  This is equivalent to calling:
+ *  SDL_CreateThreadWithStackSize(fn, name, 0, data);
+ */
+extern DECLSPEC SDL_Thread *SDLCALL
+SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+
 /**
  *  Create a thread.
  *
@@ -158,9 +185,17 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
  *   If a system imposes requirements, SDL will try to munge the string for
  *    it (truncate, etc), but the original string contents will be available
  *    from SDL_GetThreadName().
+ *
+ *   The size (in bytes) of the new stack can be specified. Zero means "use
+ *    the system default" which might be wildly different between platforms
+ *    (x86 Linux generally defaults to eight megabytes, an embedded device
+ *    might be a few kilobytes instead).
+ *
+ *   In SDL 2.1, stacksize will be folded into the original SDL_CreateThread
+ *    function.
  */
 extern DECLSPEC SDL_Thread *SDLCALL
-SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data);
 
 #endif
 
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
index 282625d3f0dc8dfe2b94fa48032d037cace0de3c..5600618ff4f8fbaacb2edf547ef8da1c182a0257 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
index db9e25ebdccad221a3c38bbce06b02bec65c3c2c..f4075e79a5b5dd486579aa374474e3927101abe1 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
index 06ee80cb358963b2fca3d8218a81595345e52671..4ac248c8c577f5150c8de8ad1b36df3bd4aea854 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
index 5b4c402486d6adb4e8ebaec3cfa4bee301e48e8b..31443e149adc071cba7431bc0cd47b007f1a0e22 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      7
+#define SDL_PATCHLEVEL      9
 
 /**
  *  \brief Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
index 6f6cda8b182b22160d97c0d9d5e684290419d0b9..461f13805101c9214ef4bd9b6df3143c3f093692 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -110,7 +110,9 @@ typedef enum
     SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
-    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
+    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported.
+                                                     On macOS NSHighResolutionCapable must be set true in the
+                                                     application's Info.plist for this to have any effect. */
     SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,      /**< window has mouse captured (unrelated to INPUT_GRABBED) */
     SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,      /**< window should always be above others */
     SDL_WINDOW_SKIP_TASKBAR  = 0x00010000,      /**< window should not be added to the taskbar */
@@ -167,6 +169,24 @@ typedef enum
     SDL_WINDOWEVENT_HIT_TEST        /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */
 } SDL_WindowEventID;
 
+/**
+ *  \brief Event subtype for display events
+ */
+typedef enum
+{
+    SDL_DISPLAYEVENT_NONE,          /**< Never used */
+    SDL_DISPLAYEVENT_ORIENTATION    /**< Display orientation has changed to data1 */
+} SDL_DisplayEventID;
+
+typedef enum
+{
+    SDL_ORIENTATION_UNKNOWN,            /**< The display orientation can't be determined */
+    SDL_ORIENTATION_LANDSCAPE,          /**< The display is in landscape mode, with the right side up, relative to portrait mode */
+    SDL_ORIENTATION_LANDSCAPE_FLIPPED,  /**< The display is in landscape mode, with the left side up, relative to portrait mode */
+    SDL_ORIENTATION_PORTRAIT,           /**< The display is in portrait mode */
+    SDL_ORIENTATION_PORTRAIT_FLIPPED    /**< The display is in portrait mode, upside down */
+} SDL_DisplayOrientation;
+
 /**
  *  \brief An opaque handle to an OpenGL context.
  */
@@ -314,18 +334,6 @@ extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex);
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
 
-/**
- *  \brief Get the dots/pixels-per-inch for a display
- *
- *  \note Diagonal, horizontal and vertical DPI can all be optionally
- *        returned if the parameter is non-NULL.
- *
- *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
- *
- *  \sa SDL_GetNumVideoDisplays()
- */
-extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
-
 /**
  *  \brief Get the usable desktop area represented by a display, with the
  *         primary display located at 0,0
@@ -345,6 +353,27 @@ extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, fl
  */
 extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
 
+/**
+ *  \brief Get the dots/pixels-per-inch for a display
+ *
+ *  \note Diagonal, horizontal and vertical DPI can all be optionally
+ *        returned if the parameter is non-NULL.
+ *
+ *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
+
+/**
+ *  \brief Get the orientation of a display
+ *
+ *  \return The orientation of the display, or SDL_ORIENTATION_UNKNOWN if it isn't available.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC SDL_DisplayOrientation SDLCALL SDL_GetDisplayOrientation(int displayIndex);
+
 /**
  *  \brief Returns the number of available display modes.
  *
@@ -470,7 +499,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window);
  *  If the window is created with any of the SDL_WINDOW_OPENGL or
  *  SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function
  *  (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the
- *  corrensponding UnloadLibrary function is called by SDL_DestroyWindow().
+ *  corresponding UnloadLibrary function is called by SDL_DestroyWindow().
  *
  *  If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver,
  *  SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail.
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_vulkan.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_vulkan.h
index 803b5feef3489ba257ae3664cc93afc9f8fbcf1d..972cca4d7c2658f735d96d549ccd2a5819592b16 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_vulkan.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_vulkan.h
@@ -69,30 +69,43 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
  *  \brief Dynamically load a Vulkan loader library.
  *
  *  \param [in] path The platform dependent Vulkan loader library name, or
- *              \c NULL to open the default Vulkan loader library.
+ *              \c NULL.
  *
  *  \return \c 0 on success, or \c -1 if the library couldn't be loaded.
  *
- *  This should be done after initializing the video driver, but before
+ *  If \a path is NULL SDL will use the value of the environment variable
+ *  \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
+ *  loader library.
+ *
+ *  This should be called after initializing the video driver, but before
  *  creating any Vulkan windows. If no Vulkan loader library is loaded, the
  *  default library will be loaded upon creation of the first Vulkan window.
  *
- *  \note If you specify a non-NULL \a path, you should retrieve all of the
- *        Vulkan functions used in your program from the dynamic library using
+ *  \note It is fairly common for Vulkan applications to link with \a libvulkan
+ *        instead of explicitly loading it at run time. This will work with
+ *        SDL provided the application links to a dynamic library and both it
+ *        and SDL use the same search path.
+ *
+ *  \note If you specify a non-NULL \c path, an application should retrieve all
+ *        of the Vulkan functions it uses from the dynamic library using
  *        \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee
- *        \a path points to the same vulkan loader library that you linked to.
+ *        \c path points to the same vulkan loader library the application
+ *        linked to.
  *
  *  \note On Apple devices, if \a path is NULL, SDL will attempt to find
  *        the vkGetInstanceProcAddr address within all the mach-o images of
- *        the current process. This is because the currently (v0.17.0)
- *        recommended MoltenVK (Vulkan on Metal) usage is as a static library.
- *        If it is not found then SDL will attempt to load \c libMoltenVK.dylib.
- *        Applications using the dylib alternative therefore do not need to do
- *        anything special when calling SDL.
- *
- *  \note On non-Apple devices, SDL requires you to either not link to the
- *        Vulkan loader or link to a dynamic library version. This limitation
- *        may be removed in a future version of SDL.
+ *        the current process. This is because it is fairly common for Vulkan
+ *        applications to link with libvulkan (and historically MoltenVK was
+ *        provided as a static library). If it is not found then, on macOS, SDL
+ *        will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
+ *        \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
+ *        On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
+ *        using a dynamic framework or .dylib must ensure it is included in its
+ *        application bundle.
+ *
+ *  \note On non-Apple devices, application linking with a static libvulkan is
+ *        not supported. Either do not link to the Vulkan loader or link to a
+ *        dynamic library version.
  *
  *  \note This function will fail if there are no working Vulkan drivers
  *        installed.
@@ -122,11 +135,11 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \brief Get the names of the Vulkan instance extensions needed to create
  *         a surface with \c SDL_Vulkan_CreateSurface().
  *
- *  \param [in]     window Window for which the required Vulkan instance
+ *  \param [in]     \c NULL or window Window for which the required Vulkan instance
  *                  extensions should be retrieved
- *  \param [in,out] count pointer to an \c unsigned related to the number of
+ *  \param [in,out] pCount pointer to an \c unsigned related to the number of
  *                  required Vulkan instance extensions
- *  \param [out]    names \c NULL or a pointer to an array to be filled with the
+ *  \param [out]    pNames \c NULL or a pointer to an array to be filled with the
  *                  required Vulkan instance extensions
  *
  *  \return \c SDL_TRUE on success, \c SDL_FALSE on error.
@@ -140,6 +153,10 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  is smaller than the number of required extensions, \c SDL_FALSE will be
  *  returned instead of \c SDL_TRUE, to indicate that not all the required
  *  extensions were returned.
+ * 
+ *  \note If \c window is not NULL, it will be checked against its creation
+ *        flags to ensure that the Vulkan flag is present. This parameter
+ *        will be removed in a future major release.
  *
  *  \note The returned list of extensions will contain \c VK_KHR_surface
  *        and zero or more platform specific extensions
@@ -147,12 +164,13 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  \note The extension names queried here must be enabled when calling
  *        VkCreateInstance, otherwise surface creation will fail.
  *
- *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag.
+ *  \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag
+ *        or be \c NULL
  *
  *  \code
  *  unsigned int count;
  *  // get count of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, NULL))
  *      handle_error();
  *
  *  static const char *const additionalExtensions[] =
@@ -166,7 +184,7 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *      handle_error();
  *
  *  // get names of required extensions
- *  if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names))
+ *  if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, names))
  *      handle_error();
  *
  *  // copy additional extensions after required extensions
@@ -240,6 +258,9 @@ extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_CreateSurface(
  * platform with high-DPI support (Apple calls this "Retina"), and not disabled
  * by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
  *
+ *  \note On macOS high-DPI support must be enabled for an application by
+ *        setting NSHighResolutionCapable to true in its Info.plist.
+ *
  *  \sa SDL_GetWindowSize()
  *  \sa SDL_CreateWindow()
  */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
index 5372d6f04df418acb02bf51cd545c2170bb73849..6c2106246f2583ba711451bc7e39fc2af7e9eec7 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
index 2a352dbb9ec7502c62b561f30bd7433b18e581d1..b3b70a4c833d80305bbffd306c8ac099babdf419 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake b/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
index f5bfc3b797c7bc03dc127c9d096c781d8a5218c3..455d8ed55aa4860f8c85b7be139afe131a36c4fd 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake
@@ -1,11 +1,11 @@
 # sdl2 cmake project-config input for ./configure scripts
 
-set(prefix "/usr/local/x86_64-w64-mingw32") 
+set(prefix "/opt/local/x86_64-w64-mingw32") 
 set(exec_prefix "${prefix}")
 set(libdir "${exec_prefix}/lib")
-set(SDL2_PREFIX "/usr/local/x86_64-w64-mingw32")
-set(SDL2_EXEC_PREFIX "/usr/local/x86_64-w64-mingw32")
+set(SDL2_PREFIX "/opt/local/x86_64-w64-mingw32")
+set(SDL2_EXEC_PREFIX "/opt/local/x86_64-w64-mingw32")
 set(SDL2_LIBDIR "${exec_prefix}/lib")
 set(SDL2_INCLUDE_DIRS "${prefix}/include/SDL2")
-set(SDL2_LIBRARIES "-L${SDL2_LIBDIR}  -lmingw32 -lSDL2main -lSDL2  -mwindows")
+set(SDL2_LIBRARIES "-L${SDL2_LIBDIR}  -lmingw32 -lSDL2main -lSDL2 -mwindows")
 string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a
index d81a9cbcfdb9bfbc18bf3f0808272b47ba616fc8..8279506827fce6c54f19e0d1376ff5d03abe5da3 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a
index 65648749ce65704ec31fc18ad33e2cb5f7b99bca..669b6a6378b8c870c6da55d554d54a6d12061bb5 100755
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la
new file mode 100644
index 0000000000000000000000000000000000000000..d5295eec8bed2925b2151577d8518dc995fb6000
--- /dev/null
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la
@@ -0,0 +1,41 @@
+# libSDL2.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='../bin/SDL2.dll'
+
+# Names of this library.
+library_names='libSDL2.dll.a'
+
+# The name of the static archive.
+old_library='libSDL2.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=' -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2.
+current=9
+age=9
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a
index af32f8689c25e98815a79601e725008161b1374e..fcbdbbf76211f12f77fb4a95bcd0eac68e1aca42 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la
new file mode 100644
index 0000000000000000000000000000000000000000..76ad43f0f49d5e79da26057c43edc4ee4fc00dd5
--- /dev/null
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la
@@ -0,0 +1,41 @@
+# libSDL2_test.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libSDL2_test.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=''
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2_test.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a
index decdd5a0f008f7cb03f17d9137ffbe5c5ad29702..3a26e430db838e098490e496082a80eed9e75679 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la
new file mode 100644
index 0000000000000000000000000000000000000000..5aa4693331f8406263ae893d2a7d8499049b8e50
--- /dev/null
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la
@@ -0,0 +1,41 @@
+# libSDL2main.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libSDL2main.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=''
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2main.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL/SDL2-2.0.9/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc b/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
index d06fc29cd57d3d44c9c4eade58eeb900b89127b1..ae83be160346141441a84d33d2ea33c2e9ce0b7e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
@@ -1,15 +1,15 @@
 # sdl pkg-config source file
 
-prefix=/usr/local/x86_64-w64-mingw32
+prefix=/opt/local/x86_64-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: sdl2
 Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
-Version: 2.0.7
+Version: 2.0.9
 Requires:
 Conflicts:
-Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2  -mwindows
-Libs.private: -lmingw32 -lSDL2main -lSDL2  -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc
+Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2 -mwindows
+Libs.private: -lmingw32 -lSDL2main -lSDL2 -mwindows  -Wl,--no-undefined -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -static-libgcc
 Cflags: -I${includedir}/SDL2  -Dmain=SDL_main
diff --git a/libs/SDL2_mixer/CHANGES.txt b/libs/SDL2_mixer/CHANGES.txt
index 1c99deb8ed1f16397e8a03ced510c176d5cd34db..7760ddfe33b4abb709da995ab957bece3522850c 100644
--- a/libs/SDL2_mixer/CHANGES.txt
+++ b/libs/SDL2_mixer/CHANGES.txt
@@ -1,3 +1,15 @@
+2.0.4:
+Ozkan Sezer - Wed, 10 Oct 2018 14:56:10
+ * Removed smpeg support for mp3 music, now that it's replaced by libmpg123
+Ozkan Sezer - Sun, 07 Oct 2018 08:50:02
+ * Fixed mp3 mad decoder to skip tags, which otherwise would lead to crashes
+Ozkan Sezer - Fri, 15 Jun 2018 05:32:56
+ * Added support for Opus music playback using opusfile library
+
+2.0.3:
+Sam Lantinga - Thu, Mar  1, 2018  9:06:58 AM
+ * Fixed regression where Mix_Init() would return 0 for available music formats
+
 2.0.2:
 Sam Lantinga - Fri Oct 20 22:04:50 PDT 2017
  * Implemented 24-bit and surround sound support for FLAC audio files
diff --git a/libs/SDL2_mixer/COPYING.txt b/libs/SDL2_mixer/COPYING.txt
index 056d0f35256b07c9f108233e1fa28c187dd9998f..234a5a5efd51fd6fca18282cabff68d893cda6ab 100644
--- a/libs/SDL2_mixer/COPYING.txt
+++ b/libs/SDL2_mixer/COPYING.txt
@@ -1,6 +1,6 @@
 /*
   SDL_mixer:  An audio mixer library based on the SDL library
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2_mixer/README.txt b/libs/SDL2_mixer/README.txt
index 14de6e002567608d39d64f0ac268fe40af44158e..a639c37bc6f09c7ce2ce6ea16376e6ff4a5dfd42 100644
--- a/libs/SDL2_mixer/README.txt
+++ b/libs/SDL2_mixer/README.txt
@@ -14,7 +14,7 @@ for documentation on this mixer library.
 The mixer can currently load Microsoft WAVE files and Creative Labs VOC
 files as audio samples, it can load FLAC files with libFLAC, it can load
 Ogg Vorbis files with Ogg Vorbis or Tremor libraries, it can load MP3 files
-using mpg123, SMPEG or libmad, and it can load MIDI files with Timidity,
+using mpg123 or libmad, and it can load MIDI files with Timidity,
 FluidSynth, and natively on Windows, Mac OSX, and Linux, and finally it can
 load the following file formats via ModPlug or MikMod: .MOD .S3M .IT .XM.
 
diff --git a/libs/SDL2_mixer/SRB2NOTE.txt b/libs/SDL2_mixer/SRB2NOTE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7053c44f66de850cde4d6448797dc6a443e29f4b
--- /dev/null
+++ b/libs/SDL2_mixer/SRB2NOTE.txt
@@ -0,0 +1,15 @@
+# SDL Mixer Development Libaries
+
+Download both the VC and MinGW packages and extract them here.
+
+https://www.libsdl.org/projects/SDL_mixer/
+
+## VC Package
+
+* include
+* lib
+
+## MinGW Package
+
+* i686-w64-mingw32
+* x86_64-w64-mingw32
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.FLAC.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.FLAC.txt
index 94fd3aa692d3d4759fec1b13522d5db404e4508b..2e67b77cbb6ed89bd8c78b5d6a7f8e43974bf6f2 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.FLAC.txt
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.FLAC.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_mixer/file/default/external
 ---
 
 Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.modplug.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.modplug.txt
index 59fbf826c3b3a602bec0a23e347202be0f618aba..a89532db83cd3b7fa8575b38ce08065e92132856 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.modplug.txt
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.modplug.txt
@@ -1 +1,5 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 ModPlug-XMMS and libmodplug are now in the public domain.
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.mpg123.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.mpg123.txt
index d7bb85fc3be6d8a00bc8e875569d30deb9f0dceb..2111cd79fafac286df4728c833cc0268c960e328 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.mpg123.txt
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.mpg123.txt
@@ -1,3 +1,7 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 This is the file that contains the terms of use, copying, etc. for the mpg123 distribution package.
 
 Main message, to include in "About ..." boxes, etc:
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.ogg-vorbis.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
index c2cb6d56eb51b788c61183f83133283f22383926..6456dc4ed17fb4de76e4f19318de3c0021b63684 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_image/file/default/external
 ---
 
 Copyright (c) 2002-2008 Xiph.org Foundation
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opus.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opus.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adb56a854b6eff6d2afa846d13d38128e62c40c6
--- /dev/null
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opus.txt
@@ -0,0 +1,48 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+                    Jean-Marc Valin, Timothy B. Terriberry,
+                    CSIRO, Gregory Maxwell, Mark Borgerding,
+                    Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the 
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opusfile.txt b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opusfile.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfc9681fcf54ba50bc0ee265bdc1ed9386840846
--- /dev/null
+++ b/libs/SDL2_mixer/i686-w64-mingw32/bin/LICENSE.opusfile.txt
@@ -0,0 +1,32 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.Org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/SDL2_mixer.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/SDL2_mixer.dll
index 54ebbb1d48d0fbc7300678d5368ebb57ad493795..96abfa1ab759933e80342a202f1b80928d14858d 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/SDL2_mixer.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/SDL2_mixer.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libFLAC-8.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libFLAC-8.dll
index 1c55ad4966a52c673e54be638bf97196ad7bf2fa..b56ea2a8c3d9fea131c88d0d3f6c3419b8e01166 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libFLAC-8.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libFLAC-8.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libmodplug-1.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libmodplug-1.dll
index a2cba0d6b5cf20d7fa854a1c698dfc1b2b45d714..d66a317ddfe8d56309ff2e63fe66d62edb68a710 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libmodplug-1.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libmodplug-1.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libmpg123-0.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libmpg123-0.dll
index ca7de300d7db8875d19fc379dd36a37504bd70ca..240298bbfc04835998085ab5054ee5111e83c702 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libmpg123-0.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libmpg123-0.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libogg-0.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libogg-0.dll
index 3abe6ebfca1a9a96b2b679aa971302dcb5f66743..233c0f42a8379b75b3aeb681436519379079fa8e 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libogg-0.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libogg-0.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libopus-0.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libopus-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..94ea541d283adca154b853671e78101ad2625c90
Binary files /dev/null and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libopus-0.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libopusfile-0.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libopusfile-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..260796b6aa5a7da89c729a465141d8ff7036695b
Binary files /dev/null and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libopusfile-0.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbis-0.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbis-0.dll
index 4e44ef0886511997ef9f14a2a3a49b3b5291c336..4e4aaa543b55575edb1bda0d6c1c5dd341a7727f 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbis-0.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbis-0.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbisfile-3.dll b/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbisfile-3.dll
index e757eb6ded42f8a14b0e3cdb1ad4b76a4fac6f12..5d90a235c988cb15b0f9dc2deb7b065a25b47f2e 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbisfile-3.dll and b/libs/SDL2_mixer/i686-w64-mingw32/bin/libvorbisfile-3.dll differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/include/SDL2/SDL_mixer.h b/libs/SDL2_mixer/i686-w64-mingw32/include/SDL2/SDL_mixer.h
index cbb8ae6b65ad8325c961f3fc664e6fd8a1bbfd6f..009d8a2da6725c58c87a11b09e08ee5bc8e6a2da 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/include/SDL2/SDL_mixer.h
+++ b/libs/SDL2_mixer/i686-w64-mingw32/include/SDL2/SDL_mixer.h
@@ -1,6 +1,6 @@
 /*
   SDL_mixer:  An audio mixer library based on the SDL library
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -38,7 +38,7 @@ extern "C" {
 */
 #define SDL_MIXER_MAJOR_VERSION 2
 #define SDL_MIXER_MINOR_VERSION 0
-#define SDL_MIXER_PATCHLEVEL    2
+#define SDL_MIXER_PATCHLEVEL    4
 
 /* This macro can be used to fill a version structure with the compile-time
  * version of the SDL_mixer library.
@@ -80,7 +80,8 @@ typedef enum
     MIX_INIT_MOD    = 0x00000002,
     MIX_INIT_MP3    = 0x00000008,
     MIX_INIT_OGG    = 0x00000010,
-    MIX_INIT_MID    = 0x00000020
+    MIX_INIT_MID    = 0x00000020,
+    MIX_INIT_OPUS   = 0x00000040
 } MIX_InitFlags;
 
 /* Loads dynamic libraries and prepares them for use.  Flags should be
@@ -134,7 +135,8 @@ typedef enum {
     MUS_MP3,
     MUS_MP3_MAD_UNUSED,
     MUS_FLAC,
-    MUS_MODPLUG_UNUSED
+    MUS_MODPLUG_UNUSED,
+    MUS_OPUS
 } Mix_MusicType;
 
 /* The internal format for a music chunk interpreted via mikmod */
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.a b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.a
index 9cc3ed19c47a87da0addd390ee03268bb186407d..5c780be5148ee4805f223a3c96d636098608e65c 100644
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.a and b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.a differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.dll.a b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.dll.a
index 6b63de0ee7b7ddfb5f3e716f6340c08546957219..ac90388f2af7c0bc6ff1008b2bc3d210517539fb 100755
Binary files a/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.dll.a and b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.dll.a differ
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.la b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.la
new file mode 100644
index 0000000000000000000000000000000000000000..f8179ea8cd40a65ca0e80c40dd8565a53a7e1af4
--- /dev/null
+++ b/libs/SDL2_mixer/i686-w64-mingw32/lib/libSDL2_mixer.la
@@ -0,0 +1,41 @@
+# libSDL2_mixer.la - a libtool library file
+# Generated by ltmain.sh (GNU libtool) 2.2.6
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='../bin/SDL2_mixer.dll'
+
+# Names of this library.
+library_names='libSDL2_mixer.dll.a'
+
+# The name of the static archive.
+old_library='libSDL2_mixer.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=' -L/opt/local/i686-w64-mingw32/lib -lmingw32 /opt/local/i686-w64-mingw32/lib/libSDL2.la -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -lwinmm'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2_mixer.
+current=2
+age=2
+revision=2
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL_mixer/SDL2_mixer-2.0.4/i686-w64-mingw32/lib'
diff --git a/libs/SDL2_mixer/i686-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc b/libs/SDL2_mixer/i686-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
index 76ba57fab61143f0ca31ff68d1193522b44239cf..0b8410993f73f82ff7d6f8f93f1c8e2721e049fb 100644
--- a/libs/SDL2_mixer/i686-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
+++ b/libs/SDL2_mixer/i686-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
@@ -1,11 +1,11 @@
-prefix=/usr/local/i686-w64-mingw32
+prefix=/opt/local/i686-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: SDL2_mixer
 Description: mixer library for Simple DirectMedia Layer
-Version: 2.0.2
+Version: 2.0.4
 Requires: sdl2 >= 2.0.7
 Libs: -L${libdir} -lSDL2_mixer
 Cflags: -I${includedir}/SDL2
diff --git a/libs/SDL2_mixer/include/SDL_mixer.h b/libs/SDL2_mixer/include/SDL_mixer.h
index cbb8ae6b65ad8325c961f3fc664e6fd8a1bbfd6f..009d8a2da6725c58c87a11b09e08ee5bc8e6a2da 100644
--- a/libs/SDL2_mixer/include/SDL_mixer.h
+++ b/libs/SDL2_mixer/include/SDL_mixer.h
@@ -1,6 +1,6 @@
 /*
   SDL_mixer:  An audio mixer library based on the SDL library
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -38,7 +38,7 @@ extern "C" {
 */
 #define SDL_MIXER_MAJOR_VERSION 2
 #define SDL_MIXER_MINOR_VERSION 0
-#define SDL_MIXER_PATCHLEVEL    2
+#define SDL_MIXER_PATCHLEVEL    4
 
 /* This macro can be used to fill a version structure with the compile-time
  * version of the SDL_mixer library.
@@ -80,7 +80,8 @@ typedef enum
     MIX_INIT_MOD    = 0x00000002,
     MIX_INIT_MP3    = 0x00000008,
     MIX_INIT_OGG    = 0x00000010,
-    MIX_INIT_MID    = 0x00000020
+    MIX_INIT_MID    = 0x00000020,
+    MIX_INIT_OPUS   = 0x00000040
 } MIX_InitFlags;
 
 /* Loads dynamic libraries and prepares them for use.  Flags should be
@@ -134,7 +135,8 @@ typedef enum {
     MUS_MP3,
     MUS_MP3_MAD_UNUSED,
     MUS_FLAC,
-    MUS_MODPLUG_UNUSED
+    MUS_MODPLUG_UNUSED,
+    MUS_OPUS
 } Mix_MusicType;
 
 /* The internal format for a music chunk interpreted via mikmod */
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.FLAC.txt b/libs/SDL2_mixer/lib/x64/LICENSE.FLAC.txt
index 94fd3aa692d3d4759fec1b13522d5db404e4508b..2e67b77cbb6ed89bd8c78b5d6a7f8e43974bf6f2 100644
--- a/libs/SDL2_mixer/lib/x64/LICENSE.FLAC.txt
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.FLAC.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_mixer/file/default/external
 ---
 
 Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.modplug.txt b/libs/SDL2_mixer/lib/x64/LICENSE.modplug.txt
index 59fbf826c3b3a602bec0a23e347202be0f618aba..a89532db83cd3b7fa8575b38ce08065e92132856 100644
--- a/libs/SDL2_mixer/lib/x64/LICENSE.modplug.txt
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.modplug.txt
@@ -1 +1,5 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 ModPlug-XMMS and libmodplug are now in the public domain.
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.mpg123.txt b/libs/SDL2_mixer/lib/x64/LICENSE.mpg123.txt
index d7bb85fc3be6d8a00bc8e875569d30deb9f0dceb..2111cd79fafac286df4728c833cc0268c960e328 100644
--- a/libs/SDL2_mixer/lib/x64/LICENSE.mpg123.txt
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.mpg123.txt
@@ -1,3 +1,7 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 This is the file that contains the terms of use, copying, etc. for the mpg123 distribution package.
 
 Main message, to include in "About ..." boxes, etc:
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.ogg-vorbis.txt b/libs/SDL2_mixer/lib/x64/LICENSE.ogg-vorbis.txt
index c2cb6d56eb51b788c61183f83133283f22383926..6456dc4ed17fb4de76e4f19318de3c0021b63684 100644
--- a/libs/SDL2_mixer/lib/x64/LICENSE.ogg-vorbis.txt
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.ogg-vorbis.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_image/file/default/external
 ---
 
 Copyright (c) 2002-2008 Xiph.org Foundation
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.opus.txt b/libs/SDL2_mixer/lib/x64/LICENSE.opus.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adb56a854b6eff6d2afa846d13d38128e62c40c6
--- /dev/null
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.opus.txt
@@ -0,0 +1,48 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+                    Jean-Marc Valin, Timothy B. Terriberry,
+                    CSIRO, Gregory Maxwell, Mark Borgerding,
+                    Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the 
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/libs/SDL2_mixer/lib/x64/LICENSE.opusfile.txt b/libs/SDL2_mixer/lib/x64/LICENSE.opusfile.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfc9681fcf54ba50bc0ee265bdc1ed9386840846
--- /dev/null
+++ b/libs/SDL2_mixer/lib/x64/LICENSE.opusfile.txt
@@ -0,0 +1,32 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.Org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libs/SDL2_mixer/lib/x64/SDL2_mixer.dll b/libs/SDL2_mixer/lib/x64/SDL2_mixer.dll
old mode 100755
new mode 100644
index 116bb1df6f93e2afddac4d97269348f4e1531528..40bb1c14638d0cd2e0cd3b00ceee416326fcd3ed
Binary files a/libs/SDL2_mixer/lib/x64/SDL2_mixer.dll and b/libs/SDL2_mixer/lib/x64/SDL2_mixer.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/SDL2_mixer.lib b/libs/SDL2_mixer/lib/x64/SDL2_mixer.lib
old mode 100755
new mode 100644
diff --git a/libs/SDL2_mixer/lib/x64/libFLAC-8.dll b/libs/SDL2_mixer/lib/x64/libFLAC-8.dll
old mode 100755
new mode 100644
index b5603902d5ff26bc57d0f0025757b6f0d28a06a4..71f2e19d9cac86400bcfb3bb68a659b9773925ad
Binary files a/libs/SDL2_mixer/lib/x64/libFLAC-8.dll and b/libs/SDL2_mixer/lib/x64/libFLAC-8.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libmodplug-1.dll b/libs/SDL2_mixer/lib/x64/libmodplug-1.dll
old mode 100755
new mode 100644
index 31509378b5078d6b24c0b0a435a8d8dba7a94b2c..7c0512674e8e43019777928ca42aca50081a8795
Binary files a/libs/SDL2_mixer/lib/x64/libmodplug-1.dll and b/libs/SDL2_mixer/lib/x64/libmodplug-1.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libmpg123-0.dll b/libs/SDL2_mixer/lib/x64/libmpg123-0.dll
old mode 100755
new mode 100644
index d222d2dc500d2ab30b18a8dfa139ad71fa3dccfe..c7809b163f5e1d305341bba3e65874efac205792
Binary files a/libs/SDL2_mixer/lib/x64/libmpg123-0.dll and b/libs/SDL2_mixer/lib/x64/libmpg123-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libogg-0.dll b/libs/SDL2_mixer/lib/x64/libogg-0.dll
old mode 100755
new mode 100644
index 7b94e60325918c92b4b764cb738dd8f5c0c3379a..51334815979b8fe3a74fa39c3cc54eb4cd70c6ce
Binary files a/libs/SDL2_mixer/lib/x64/libogg-0.dll and b/libs/SDL2_mixer/lib/x64/libogg-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libopus-0.dll b/libs/SDL2_mixer/lib/x64/libopus-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..9ba6c3860c6daa71ae9646f01b43003dac3798f0
Binary files /dev/null and b/libs/SDL2_mixer/lib/x64/libopus-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libopusfile-0.dll b/libs/SDL2_mixer/lib/x64/libopusfile-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..97a88b6108980d2450acd66cb36193e4cfbaa30a
Binary files /dev/null and b/libs/SDL2_mixer/lib/x64/libopusfile-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libvorbis-0.dll b/libs/SDL2_mixer/lib/x64/libvorbis-0.dll
old mode 100755
new mode 100644
index 8d8d6537b1fc243e1926ec03a7be842b6a5d6fed..f5ae1bf754671625ec44f9992efb55e0ad5c2dec
Binary files a/libs/SDL2_mixer/lib/x64/libvorbis-0.dll and b/libs/SDL2_mixer/lib/x64/libvorbis-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x64/libvorbisfile-3.dll b/libs/SDL2_mixer/lib/x64/libvorbisfile-3.dll
old mode 100755
new mode 100644
index 08f8f7aa82ede72a588bb10daef73cd94dad137b..d0787368a3e30fd363c1324423c78d7e06add0be
Binary files a/libs/SDL2_mixer/lib/x64/libvorbisfile-3.dll and b/libs/SDL2_mixer/lib/x64/libvorbisfile-3.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.FLAC.txt b/libs/SDL2_mixer/lib/x86/LICENSE.FLAC.txt
index 94fd3aa692d3d4759fec1b13522d5db404e4508b..2e67b77cbb6ed89bd8c78b5d6a7f8e43974bf6f2 100644
--- a/libs/SDL2_mixer/lib/x86/LICENSE.FLAC.txt
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.FLAC.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_mixer/file/default/external
 ---
 
 Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.modplug.txt b/libs/SDL2_mixer/lib/x86/LICENSE.modplug.txt
index 59fbf826c3b3a602bec0a23e347202be0f618aba..a89532db83cd3b7fa8575b38ce08065e92132856 100644
--- a/libs/SDL2_mixer/lib/x86/LICENSE.modplug.txt
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.modplug.txt
@@ -1 +1,5 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 ModPlug-XMMS and libmodplug are now in the public domain.
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.mpg123.txt b/libs/SDL2_mixer/lib/x86/LICENSE.mpg123.txt
index d7bb85fc3be6d8a00bc8e875569d30deb9f0dceb..2111cd79fafac286df4728c833cc0268c960e328 100644
--- a/libs/SDL2_mixer/lib/x86/LICENSE.mpg123.txt
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.mpg123.txt
@@ -1,3 +1,7 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 This is the file that contains the terms of use, copying, etc. for the mpg123 distribution package.
 
 Main message, to include in "About ..." boxes, etc:
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.ogg-vorbis.txt b/libs/SDL2_mixer/lib/x86/LICENSE.ogg-vorbis.txt
index c2cb6d56eb51b788c61183f83133283f22383926..6456dc4ed17fb4de76e4f19318de3c0021b63684 100644
--- a/libs/SDL2_mixer/lib/x86/LICENSE.ogg-vorbis.txt
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.ogg-vorbis.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_image/file/default/external
 ---
 
 Copyright (c) 2002-2008 Xiph.org Foundation
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.opus.txt b/libs/SDL2_mixer/lib/x86/LICENSE.opus.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adb56a854b6eff6d2afa846d13d38128e62c40c6
--- /dev/null
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.opus.txt
@@ -0,0 +1,48 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+                    Jean-Marc Valin, Timothy B. Terriberry,
+                    CSIRO, Gregory Maxwell, Mark Borgerding,
+                    Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the 
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/libs/SDL2_mixer/lib/x86/LICENSE.opusfile.txt b/libs/SDL2_mixer/lib/x86/LICENSE.opusfile.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfc9681fcf54ba50bc0ee265bdc1ed9386840846
--- /dev/null
+++ b/libs/SDL2_mixer/lib/x86/LICENSE.opusfile.txt
@@ -0,0 +1,32 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.Org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libs/SDL2_mixer/lib/x86/SDL2_mixer.dll b/libs/SDL2_mixer/lib/x86/SDL2_mixer.dll
old mode 100755
new mode 100644
index 54ebbb1d48d0fbc7300678d5368ebb57ad493795..96abfa1ab759933e80342a202f1b80928d14858d
Binary files a/libs/SDL2_mixer/lib/x86/SDL2_mixer.dll and b/libs/SDL2_mixer/lib/x86/SDL2_mixer.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/SDL2_mixer.lib b/libs/SDL2_mixer/lib/x86/SDL2_mixer.lib
old mode 100755
new mode 100644
diff --git a/libs/SDL2_mixer/lib/x86/libFLAC-8.dll b/libs/SDL2_mixer/lib/x86/libFLAC-8.dll
old mode 100755
new mode 100644
index 1c55ad4966a52c673e54be638bf97196ad7bf2fa..b56ea2a8c3d9fea131c88d0d3f6c3419b8e01166
Binary files a/libs/SDL2_mixer/lib/x86/libFLAC-8.dll and b/libs/SDL2_mixer/lib/x86/libFLAC-8.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libmodplug-1.dll b/libs/SDL2_mixer/lib/x86/libmodplug-1.dll
old mode 100755
new mode 100644
index a2cba0d6b5cf20d7fa854a1c698dfc1b2b45d714..d66a317ddfe8d56309ff2e63fe66d62edb68a710
Binary files a/libs/SDL2_mixer/lib/x86/libmodplug-1.dll and b/libs/SDL2_mixer/lib/x86/libmodplug-1.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libmpg123-0.dll b/libs/SDL2_mixer/lib/x86/libmpg123-0.dll
old mode 100755
new mode 100644
index ca7de300d7db8875d19fc379dd36a37504bd70ca..240298bbfc04835998085ab5054ee5111e83c702
Binary files a/libs/SDL2_mixer/lib/x86/libmpg123-0.dll and b/libs/SDL2_mixer/lib/x86/libmpg123-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libogg-0.dll b/libs/SDL2_mixer/lib/x86/libogg-0.dll
old mode 100755
new mode 100644
index 3abe6ebfca1a9a96b2b679aa971302dcb5f66743..233c0f42a8379b75b3aeb681436519379079fa8e
Binary files a/libs/SDL2_mixer/lib/x86/libogg-0.dll and b/libs/SDL2_mixer/lib/x86/libogg-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libopus-0.dll b/libs/SDL2_mixer/lib/x86/libopus-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..94ea541d283adca154b853671e78101ad2625c90
Binary files /dev/null and b/libs/SDL2_mixer/lib/x86/libopus-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libopusfile-0.dll b/libs/SDL2_mixer/lib/x86/libopusfile-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..260796b6aa5a7da89c729a465141d8ff7036695b
Binary files /dev/null and b/libs/SDL2_mixer/lib/x86/libopusfile-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libvorbis-0.dll b/libs/SDL2_mixer/lib/x86/libvorbis-0.dll
old mode 100755
new mode 100644
index 4e44ef0886511997ef9f14a2a3a49b3b5291c336..4e4aaa543b55575edb1bda0d6c1c5dd341a7727f
Binary files a/libs/SDL2_mixer/lib/x86/libvorbis-0.dll and b/libs/SDL2_mixer/lib/x86/libvorbis-0.dll differ
diff --git a/libs/SDL2_mixer/lib/x86/libvorbisfile-3.dll b/libs/SDL2_mixer/lib/x86/libvorbisfile-3.dll
old mode 100755
new mode 100644
index e757eb6ded42f8a14b0e3cdb1ad4b76a4fac6f12..5d90a235c988cb15b0f9dc2deb7b065a25b47f2e
Binary files a/libs/SDL2_mixer/lib/x86/libvorbisfile-3.dll and b/libs/SDL2_mixer/lib/x86/libvorbisfile-3.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.FLAC.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.FLAC.txt
index 94fd3aa692d3d4759fec1b13522d5db404e4508b..2e67b77cbb6ed89bd8c78b5d6a7f8e43974bf6f2 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.FLAC.txt
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.FLAC.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_mixer/file/default/external
 ---
 
 Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.modplug.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.modplug.txt
index 59fbf826c3b3a602bec0a23e347202be0f618aba..a89532db83cd3b7fa8575b38ce08065e92132856 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.modplug.txt
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.modplug.txt
@@ -1 +1,5 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 ModPlug-XMMS and libmodplug are now in the public domain.
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.mpg123.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.mpg123.txt
index d7bb85fc3be6d8a00bc8e875569d30deb9f0dceb..2111cd79fafac286df4728c833cc0268c960e328 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.mpg123.txt
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.mpg123.txt
@@ -1,3 +1,7 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
 This is the file that contains the terms of use, copying, etc. for the mpg123 distribution package.
 
 Main message, to include in "About ..." boxes, etc:
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.ogg-vorbis.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
index c2cb6d56eb51b788c61183f83133283f22383926..6456dc4ed17fb4de76e4f19318de3c0021b63684 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.ogg-vorbis.txt
@@ -1,5 +1,5 @@
 The source code to this library used with SDL_mixer can be found here:
-http://www.libsdl.org/projects/SDL_mixer/libs/
+https://hg.libsdl.org/SDL_image/file/default/external
 ---
 
 Copyright (c) 2002-2008 Xiph.org Foundation
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opus.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opus.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adb56a854b6eff6d2afa846d13d38128e62c40c6
--- /dev/null
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opus.txt
@@ -0,0 +1,48 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+                    Jean-Marc Valin, Timothy B. Terriberry,
+                    CSIRO, Gregory Maxwell, Mark Borgerding,
+                    Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the 
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opusfile.txt b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opusfile.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfc9681fcf54ba50bc0ee265bdc1ed9386840846
--- /dev/null
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/LICENSE.opusfile.txt
@@ -0,0 +1,32 @@
+The source code to this library used with SDL_mixer can be found here:
+https://hg.libsdl.org/SDL_mixer/file/default/external
+---
+
+Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.Org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/SDL2_mixer.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/SDL2_mixer.dll
index 116bb1df6f93e2afddac4d97269348f4e1531528..40bb1c14638d0cd2e0cd3b00ceee416326fcd3ed 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/SDL2_mixer.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/SDL2_mixer.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libFLAC-8.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libFLAC-8.dll
index b5603902d5ff26bc57d0f0025757b6f0d28a06a4..71f2e19d9cac86400bcfb3bb68a659b9773925ad 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libFLAC-8.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libFLAC-8.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmodplug-1.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmodplug-1.dll
index 31509378b5078d6b24c0b0a435a8d8dba7a94b2c..7c0512674e8e43019777928ca42aca50081a8795 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmodplug-1.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmodplug-1.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmpg123-0.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmpg123-0.dll
index d222d2dc500d2ab30b18a8dfa139ad71fa3dccfe..c7809b163f5e1d305341bba3e65874efac205792 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmpg123-0.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libmpg123-0.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libogg-0.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libogg-0.dll
index 7b94e60325918c92b4b764cb738dd8f5c0c3379a..51334815979b8fe3a74fa39c3cc54eb4cd70c6ce 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libogg-0.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libogg-0.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopus-0.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopus-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..9ba6c3860c6daa71ae9646f01b43003dac3798f0
Binary files /dev/null and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopus-0.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopusfile-0.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopusfile-0.dll
new file mode 100644
index 0000000000000000000000000000000000000000..97a88b6108980d2450acd66cb36193e4cfbaa30a
Binary files /dev/null and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libopusfile-0.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbis-0.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbis-0.dll
index 8d8d6537b1fc243e1926ec03a7be842b6a5d6fed..f5ae1bf754671625ec44f9992efb55e0ad5c2dec 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbis-0.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbis-0.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbisfile-3.dll b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbisfile-3.dll
index 08f8f7aa82ede72a588bb10daef73cd94dad137b..d0787368a3e30fd363c1324423c78d7e06add0be 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbisfile-3.dll and b/libs/SDL2_mixer/x86_64-w64-mingw32/bin/libvorbisfile-3.dll differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2/SDL_mixer.h b/libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2/SDL_mixer.h
index cbb8ae6b65ad8325c961f3fc664e6fd8a1bbfd6f..009d8a2da6725c58c87a11b09e08ee5bc8e6a2da 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2/SDL_mixer.h
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2/SDL_mixer.h
@@ -1,6 +1,6 @@
 /*
   SDL_mixer:  An audio mixer library based on the SDL library
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -38,7 +38,7 @@ extern "C" {
 */
 #define SDL_MIXER_MAJOR_VERSION 2
 #define SDL_MIXER_MINOR_VERSION 0
-#define SDL_MIXER_PATCHLEVEL    2
+#define SDL_MIXER_PATCHLEVEL    4
 
 /* This macro can be used to fill a version structure with the compile-time
  * version of the SDL_mixer library.
@@ -80,7 +80,8 @@ typedef enum
     MIX_INIT_MOD    = 0x00000002,
     MIX_INIT_MP3    = 0x00000008,
     MIX_INIT_OGG    = 0x00000010,
-    MIX_INIT_MID    = 0x00000020
+    MIX_INIT_MID    = 0x00000020,
+    MIX_INIT_OPUS   = 0x00000040
 } MIX_InitFlags;
 
 /* Loads dynamic libraries and prepares them for use.  Flags should be
@@ -134,7 +135,8 @@ typedef enum {
     MUS_MP3,
     MUS_MP3_MAD_UNUSED,
     MUS_FLAC,
-    MUS_MODPLUG_UNUSED
+    MUS_MODPLUG_UNUSED,
+    MUS_OPUS
 } Mix_MusicType;
 
 /* The internal format for a music chunk interpreted via mikmod */
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.a b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.a
index 7d39a1f6360a2221f689c06bf4245694d7649031..b6483716ebd9dc29a36426d08b618c6f4caa563b 100644
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.a and b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.a differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.dll.a b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.dll.a
index d812f5c85acfe1a72901963c0a030e48f202071b..82a4bef080902ad394f7bed9b2506c1cf6e3906a 100755
Binary files a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.dll.a and b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.dll.a differ
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.la b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.la
new file mode 100644
index 0000000000000000000000000000000000000000..dba212c5a1ce6f6e270904d2d5f62a3914dc903e
--- /dev/null
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/libSDL2_mixer.la
@@ -0,0 +1,41 @@
+# libSDL2_mixer.la - a libtool library file
+# Generated by ltmain.sh (GNU libtool) 2.2.6
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='../bin/SDL2_mixer.dll'
+
+# Names of this library.
+library_names='libSDL2_mixer.dll.a'
+
+# The name of the static archive.
+old_library='libSDL2_mixer.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=' -L/opt/local/x86_64-w64-mingw32/lib -lmingw32 /opt/local/x86_64-w64-mingw32/lib/libSDL2.la -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -lwinmm'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libSDL2_mixer.
+current=2
+age=2
+revision=2
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/Users/valve/release/SDL_mixer/SDL2_mixer-2.0.4/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
index 56c30ccfe773f6ed0c7ff160a3f59037a3e3f3ba..b7984169ff65c983662c4d618d79227a01740795 100644
--- a/libs/SDL2_mixer/x86_64-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
+++ b/libs/SDL2_mixer/x86_64-w64-mingw32/lib/pkgconfig/SDL2_mixer.pc
@@ -1,11 +1,11 @@
-prefix=/usr/local/x86_64-w64-mingw32
+prefix=/opt/local/x86_64-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: SDL2_mixer
 Description: mixer library for Simple DirectMedia Layer
-Version: 2.0.2
+Version: 2.0.4
 Requires: sdl2 >= 2.0.7
 Libs: -L${libdir} -lSDL2_mixer
 Cflags: -I${includedir}/SDL2
diff --git a/libs/gme/win64/libgme.dll.a b/libs/gme/win64/libgme.dll.a
new file mode 100644
index 0000000000000000000000000000000000000000..38079dc2a2c01b010c94e78d5285ba3781c7eb9e
Binary files /dev/null and b/libs/gme/win64/libgme.dll.a differ
diff --git a/src/Makefile b/src/Makefile
index c33e42daad30003c53b223f4d44d8f81fa718312..8dda87564f185ec320101087df16bf8cd248a38c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -144,6 +144,11 @@ ifdef MINGW
 include win32/Makefile.cfg
 endif #ifdef MINGW
 
+ifdef MINGW64
+MINGW=1
+include win32/Makefile.cfg
+endif #ifdef MINGW64
+
 ifdef UNIX
 UNIXCOMMON=1
 endif
@@ -608,7 +613,6 @@ $(BIN)/s_openal.so: $(OBJDIR)/s_openal.o
 	-$(MKDIR) $(BIN)
 	@echo Linking S_OpenAL.so...
 	$(CC) --shared $^ -o $@ -g --nostartfiles -lm -lopenal
-
 endif
 
 else
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index da4f220a974c938cfe64903758f6823de6c8aa94..6a136727591a9f531ccf684afc669da04222fdfb 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -221,6 +221,7 @@ ifndef LINUX
 ifndef FREEBSD
 ifndef CYGWIN32
 ifndef MINGW
+ifndef MINGW64
 ifndef SDL
 ifndef DUMMY
 	DJGPPDOS=1
@@ -230,6 +231,7 @@ endif
 endif
 endif
 endif
+endif
 
 #determine the interface directory (where you put all i_*.c)
 i_cdmus_o=$(OBJDIR)/i_cdmus.o
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index b720dbf16eceb09b90f5904134baf883523c3c82..af2c1f7622f5177c9f9fcbd5f82ad43e7fd97fcd 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -2407,7 +2407,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
 			}
 		}
 	}
-	
+
 #ifdef HAVE_BLUA
 	LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting
 #endif
@@ -2822,7 +2822,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
 		case KICK_MSG_PLAYER_QUIT:
 			if (netgame) // not splitscreen/bots
 				CONS_Printf(M_GetText("left the game\n"));
-				kickreason = KR_LEAVE;
+			kickreason = KR_LEAVE;
 			break;
 		case KICK_MSG_BANNED:
 			CONS_Printf(M_GetText("has been banned (Don't come back)\n"));
@@ -3121,16 +3121,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
 			displayplayer = newplayernum;
 			secondarydisplayplayer = newplayernum;
 			DEBFILE("spawning me\n");
-			// Apply player flags as soon as possible!
-			players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE);
-			if (cv_flipcam.value)
-				players[newplayernum].pflags |= PF_FLIPCAM;
-			if (cv_analog.value)
-				players[newplayernum].pflags |= PF_ANALOGMODE;
-			if (cv_directionchar.value)
-				players[newplayernum].pflags |= PF_DIRECTIONCHAR;
-			if (cv_autobrake.value)
-				players[newplayernum].pflags |= PF_AUTOBRAKE;
 		}
 		else
 		{
@@ -3138,16 +3128,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
 			DEBFILE("spawning my brother\n");
 			if (botingame)
 				players[newplayernum].bot = 1;
-			// Same goes for player 2 when relevant
-			players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE);
-			if (cv_flipcam2.value)
-				players[newplayernum].pflags |= PF_FLIPCAM;
-			if (cv_analog2.value)
-				players[newplayernum].pflags |= PF_ANALOGMODE;
-			if (cv_directionchar2.value)
-				players[newplayernum].pflags |= PF_DIRECTIONCHAR;
-			if (cv_autobrake2.value)
-				players[newplayernum].pflags |= PF_AUTOBRAKE;
 		}
 		D_SendPlayerConfig();
 		addedtogame = true;
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index a0afb34c698c656c0cc84b92fcaa5e0d62aa4146..d5edd79d79e6ba7f010d5e9b5ce74f7c7d1576ba 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -459,10 +459,10 @@ typedef enum
 	KR_KICK          = 1, //Kicked by server
 	KR_PINGLIMIT     = 2, //Broke Ping Limit
 	KR_SYNCH         = 3, //Synch Failure
-	KR_TIMEOUT       = 4, //Connection Timeout 
+	KR_TIMEOUT       = 4, //Connection Timeout
 	KR_BAN           = 5, //Banned by server
 	KR_LEAVE         = 6, //Quit the game
-	
+
 } kickreason_t;
 
 extern boolean server;
diff --git a/src/d_main.c b/src/d_main.c
index 282ab4ae91996e3416735007c1f16c7e8bc16dec..391f3d4471b9c79c1a8e47cedaa50282ec61b07c 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -281,7 +281,7 @@ static void D_Display(void)
 		if (rendermode != render_none)
 		{
 			// Fade to black first
-			if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) // fades to black on its own timing, always
+			if ((wipegamestate != (gamestate_t)-2) // fades to black on its own timing, always
 			 && wipedefs[wipedefindex] != UINT8_MAX)
 			{
 				F_WipeStartScreen();
@@ -359,89 +359,96 @@ static void D_Display(void)
 			break;
 	}
 
-	// clean up border stuff
-	// see if the border needs to be initially drawn
-	if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))
+	// STUPID race condition...
+	if (wipegamestate == GS_INTRO && gamestate == GS_TITLESCREEN)
+		wipegamestate = -2;
+	else
 	{
-		// draw the view directly
+		wipegamestate = gamestate;
 
-		if (!automapactive && !dedicated && cv_renderview.value)
+		// clean up border stuff
+		// see if the border needs to be initially drawn
+		if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))
 		{
-			if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
-			{
-				topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
-				objectsdrawn = 0;
-#ifdef HWRENDER
-				if (rendermode != render_soft)
-					HWR_RenderPlayerView(0, &players[displayplayer]);
-				else
-#endif
-				if (rendermode != render_none)
-					R_RenderPlayerView(&players[displayplayer]);
-			}
+			// draw the view directly
 
-			// render the second screen
-			if (splitscreen && players[secondarydisplayplayer].mo)
+			if (!automapactive && !dedicated && cv_renderview.value)
 			{
-#ifdef HWRENDER
-				if (rendermode != render_soft)
-					HWR_RenderPlayerView(1, &players[secondarydisplayplayer]);
-				else
-#endif
-				if (rendermode != render_none)
+				if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
 				{
-					viewwindowy = vid.height / 2;
-					M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
-
 					topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
+					objectsdrawn = 0;
+	#ifdef HWRENDER
+					if (rendermode != render_soft)
+						HWR_RenderPlayerView(0, &players[displayplayer]);
+					else
+	#endif
+					if (rendermode != render_none)
+						R_RenderPlayerView(&players[displayplayer]);
+				}
 
-					R_RenderPlayerView(&players[secondarydisplayplayer]);
+				// render the second screen
+				if (splitscreen && players[secondarydisplayplayer].mo)
+				{
+	#ifdef HWRENDER
+					if (rendermode != render_soft)
+						HWR_RenderPlayerView(1, &players[secondarydisplayplayer]);
+					else
+	#endif
+					if (rendermode != render_none)
+					{
+						viewwindowy = vid.height / 2;
+						M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
+
+						topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
+
+						R_RenderPlayerView(&players[secondarydisplayplayer]);
+
+						viewwindowy = 0;
+						M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
+					}
+				}
 
-					viewwindowy = 0;
-					M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
+				// Image postprocessing effect
+				if (rendermode == render_soft)
+				{
+					if (postimgtype)
+						V_DoPostProcessor(0, postimgtype, postimgparam);
+					if (postimgtype2)
+						V_DoPostProcessor(1, postimgtype2, postimgparam2);
 				}
 			}
 
-			// Image postprocessing effect
-			if (rendermode == render_soft)
+			if (lastdraw)
 			{
-				if (postimgtype)
-					V_DoPostProcessor(0, postimgtype, postimgparam);
-				if (postimgtype2)
-					V_DoPostProcessor(1, postimgtype2, postimgparam2);
+				if (rendermode == render_soft)
+				{
+					VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
+					usebuffer = true;
+				}
+				lastdraw = false;
 			}
-		}
 
-		if (lastdraw)
-		{
-			if (rendermode == render_soft)
+			if (gamestate == GS_LEVEL)
 			{
-				VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
-				usebuffer = true;
+				ST_Drawer();
+				F_TextPromptDrawer();
+				HU_Drawer();
 			}
-			lastdraw = false;
-		}
-
-		if (gamestate == GS_LEVEL)
-		{
-			ST_Drawer();
-			F_TextPromptDrawer();
-			HU_Drawer();
+			else
+				F_TitleScreenDrawer();
 		}
-		else
-			F_TitleScreenDrawer();
 	}
 
 	// change gamma if needed
 	// (GS_LEVEL handles this already due to level-specific palettes)
-	if (forcerefresh && gamestate != GS_LEVEL)
+	if (forcerefresh && !(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
 		V_SetPalette(0);
 
-	wipegamestate = gamestate;
-
 	// draw pause pic
 	if (paused && cv_showhud.value && (!menuactive || netgame))
 	{
+#if 0
 		INT32 py;
 		patch_t *patch;
 		if (automapactive)
@@ -450,6 +457,11 @@ static void D_Display(void)
 			py = viewwindowy + 4;
 		patch = W_CachePatchName("M_PAUSE", PU_CACHE);
 		V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - SHORT(patch->width))/2, py, 0, patch);
+#else
+		INT32 y = ((automapactive) ? (32) : (BASEVIDHEIGHT/2));
+		M_DrawTextBox((BASEVIDWIDTH/2) - (60), y - (16), 13, 2);
+		V_DrawCenteredString(BASEVIDWIDTH/2, y - (4), V_YELLOWMAP, "Game Paused");
+#endif
 	}
 
 	// vid size change is now finished if it was on...
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index bb33eb133ed5df2f2cb16481253e78824f3f8a82..d17860243652f82ec399b1a67f49a0e60161e447 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1439,13 +1439,13 @@ void SendWeaponPref(void)
 	UINT8 buf[1];
 
 	buf[0] = 0;
-	if (players[consoleplayer].pflags & PF_FLIPCAM)
+	if (cv_flipcam.value)
 		buf[0] |= 1;
-	if (players[consoleplayer].pflags & PF_ANALOGMODE)
+	if (cv_analog.value)
 		buf[0] |= 2;
-	if (players[consoleplayer].pflags & PF_DIRECTIONCHAR)
+	if (cv_directionchar.value)
 		buf[0] |= 4;
-	if (players[consoleplayer].pflags & PF_AUTOBRAKE)
+	if (cv_autobrake.value)
 		buf[0] |= 8;
 	SendNetXCmd(XD_WEAPONPREF, buf, 1);
 }
@@ -1455,13 +1455,13 @@ void SendWeaponPref2(void)
 	UINT8 buf[1];
 
 	buf[0] = 0;
-	if (players[secondarydisplayplayer].pflags & PF_FLIPCAM)
+	if (cv_flipcam2.value)
 		buf[0] |= 1;
-	if (players[secondarydisplayplayer].pflags & PF_ANALOGMODE)
+	if (cv_analog2.value)
 		buf[0] |= 2;
-	if (players[secondarydisplayplayer].pflags & PF_DIRECTIONCHAR)
+	if (cv_directionchar2.value)
 		buf[0] |= 4;
-	if (players[secondarydisplayplayer].pflags & PF_AUTOBRAKE)
+	if (cv_autobrake2.value)
 		buf[0] |= 8;
 	SendNetXCmd2(XD_WEAPONPREF, buf, 1);
 }
@@ -3105,26 +3105,14 @@ static void Command_Addfile(void)
 		if (*p == '\\' || *p == '/' || *p == ':')
 			break;
 	++p;
+
 	// check total packet size and no of files currently loaded
+	// See W_LoadWadFile in w_wad.c
+	if ((numwadfiles >= MAX_WADFILES)
+	|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8)))
 	{
-		size_t packetsize = 0;
-		serverinfo_pak *dummycheck = NULL;
-
-		// Shut the compiler up.
-		(void)dummycheck;
-
-		// See W_LoadWadFile in w_wad.c
-		for (i = 0; i < numwadfiles; i++)
-			packetsize += nameonlylength(wadfiles[i]->filename) + 22;
-
-		packetsize += nameonlylength(fn) + 22;
-
-		if ((numwadfiles >= MAX_WADFILES)
-		|| (packetsize > sizeof(dummycheck->fileneeded)))
-		{
-			CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
-			return;
-		}
+		CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
+		return;
 	}
 
 	WRITESTRINGN(buf_p,p,240);
@@ -3174,11 +3162,6 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
 	boolean kick = false;
 	boolean toomany = false;
 	INT32 i;
-	size_t packetsize = 0;
-	serverinfo_pak *dummycheck = NULL;
-
-	// Shut the compiler up.
-	(void)dummycheck;
 
 	READSTRINGN(*cp, filename, 240);
 	READMEM(*cp, md5sum, 16);
@@ -3205,13 +3188,8 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
 	}
 
 	// See W_LoadWadFile in w_wad.c
-	for (i = 0; i < numwadfiles; i++)
-		packetsize += nameonlylength(wadfiles[i]->filename) + 22;
-
-	packetsize += nameonlylength(filename) + 22;
-
 	if ((numwadfiles >= MAX_WADFILES)
-	|| (packetsize > sizeof(dummycheck->fileneeded)))
+	|| ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8)))
 		toomany = true;
 	else
 		ncs = findfile(filename,md5sum,true);
@@ -3364,6 +3342,9 @@ static void Command_Playintro_f(void)
 	if (netgame)
 		return;
 
+	if (dirmenu)
+		closefilemenu(true);
+
 	F_StartIntro();
 }
 
@@ -4012,6 +3993,9 @@ void Command_ExitGame_f(void)
 	cv_debug = 0;
 	emeralds = 0;
 
+	if (dirmenu)
+		closefilemenu(true);
+
 	if (!modeattacking)
 		D_StartTitle();
 }
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index 435ca64a5b1f4f87cc467ddc22bfe9b083a4ee88..3ffa3f3f19defffd13b4d5a1370ef995019c6665 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -200,4 +200,4 @@ void D_SetPassword(const char *pw);
 // used for the player setup menu
 UINT8 CanChangeSkin(INT32 playernum);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 889de9466760b858e2129d934375cb2ca713de77..92ecab950f91b3a0aefb31eb7a0100a43ffb93c2 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -87,7 +87,7 @@ static filetran_t transfer[MAXNETNODES];
 // Receiver structure
 INT32 fileneedednum; // Number of files needed to join the server
 fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
-char downloaddir[256] = "DOWNLOAD";
+char downloaddir[512] = "DOWNLOAD";
 
 #ifdef CLIENT_LOADINGSCREEN
 // for cl loading screen
@@ -324,10 +324,6 @@ INT32 CL_CheckFiles(void)
 	INT32 ret = 1;
 	size_t packetsize = 0;
 	size_t filestoget = 0;
-	serverinfo_pak *dummycheck = NULL;
-
-	// Shut the compiler up.
-	(void)dummycheck;
 
 //	if (M_CheckParm("-nofiles"))
 //		return 1;
@@ -371,8 +367,7 @@ INT32 CL_CheckFiles(void)
 	}
 
 	// See W_LoadWadFile in w_wad.c
-	for (i = 0; i < numwadfiles; i++)
-		packetsize += nameonlylength(wadfiles[i]->filename) + 22;
+	packetsize = packetsizetally;
 
 	for (i = 1; i < fileneedednum; i++)
 	{
@@ -396,7 +391,7 @@ INT32 CL_CheckFiles(void)
 		packetsize += nameonlylength(fileneeded[i].filename) + 22;
 
 		if ((numwadfiles+filestoget >= MAX_WADFILES)
-		|| (packetsize > sizeof(dummycheck->fileneeded)))
+		|| (packetsize > MAXFILENEEDED*sizeof(UINT8)))
 			return 3;
 
 		filestoget++;
@@ -899,10 +894,11 @@ void nameonly(char *s)
 		{
 			ns = &(s[j+1]);
 			len = strlen(ns);
-			if (false)
-				M_Memcpy(s, ns, len+1);
-			else
-				memmove(s, ns, len+1);
+#if 0
+			M_Memcpy(s, ns, len+1);
+#else
+			memmove(s, ns, len+1);
+#endif
 			return;
 		}
 }
diff --git a/src/d_netfil.h b/src/d_netfil.h
index 6fdd0a8a1e3cbf2995a748c91e865fe7a06ff1fb..28d9d5a63702b312c3cfa96855313e278c51a159 100644
--- a/src/d_netfil.h
+++ b/src/d_netfil.h
@@ -47,7 +47,7 @@ typedef struct
 
 extern INT32 fileneedednum;
 extern fileneeded_t fileneeded[MAX_WADFILES];
-extern char downloaddir[256];
+extern char downloaddir[512];
 
 #ifdef CLIENT_LOADINGSCREEN
 extern INT32 lastfilenum;
diff --git a/src/d_player.h b/src/d_player.h
index dd0643bd41bc4a95cb5c257ed8b2774721abd850..0b271ec2ffc5fd7cec9371705370c5d6f4802d4f 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -455,6 +455,8 @@ typedef struct player_s
 	UINT8 drilldelay;
 	boolean bonustime; // Capsule destroyed, now it's bonus time!
 	mobj_t *capsule; // Go inside the capsule
+	mobj_t *drone; // Move center to the drone
+	fixed_t oldscale; // Pre-Nightserize scale
 	UINT8 mare; // Current mare
 	UINT8 marelap; // Current mare lap
 	UINT8 marebonuslap; // Current mare lap starting from bonus time
diff --git a/src/dehacked.c b/src/dehacked.c
index 7e246201d4276598916fb4582be3131f32941c19..b33c4f539b3346f2ef9ed34c9f1d3ebc9e52f860 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -3234,7 +3234,7 @@ static void readmaincfg(MYFILE *f)
 				strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder)));
 				timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0';
 
-				strncpy(savegamename, timeattackfolder, sizeof (timeattackfolder));
+				strncpy(savegamename, timeattackfolder, strlen(timeattackfolder));
 				strlcat(savegamename, "%u.ssg", sizeof(savegamename));
 				// can't use sprintf since there is %u in savegamename
 				strcatbf(savegamename, srb2home, PATHSEP);
@@ -6423,8 +6423,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_TOAD",
 
 	// Nights-specific stuff
-	"S_NIGHTSDRONE1",
-	"S_NIGHTSDRONE2",
+	"S_NIGHTSDRONE_MAN1",
+	"S_NIGHTSDRONE_MAN2",
 	"S_NIGHTSDRONE_SPARKLING1",
 	"S_NIGHTSDRONE_SPARKLING2",
 	"S_NIGHTSDRONE_SPARKLING3",
@@ -6441,10 +6441,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_NIGHTSDRONE_SPARKLING14",
 	"S_NIGHTSDRONE_SPARKLING15",
 	"S_NIGHTSDRONE_SPARKLING16",
-	"S_NIGHTSGOAL1",
-	"S_NIGHTSGOAL2",
-	"S_NIGHTSGOAL3",
-	"S_NIGHTSGOAL4",
+	"S_NIGHTSDRONE_GOAL1",
+	"S_NIGHTSDRONE_GOAL2",
+	"S_NIGHTSDRONE_GOAL3",
+	"S_NIGHTSDRONE_GOAL4",
 
 	"S_NIGHTSPARKLE1",
 	"S_NIGHTSPARKLE2",
@@ -7315,7 +7315,9 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_AXISTRANSFER",
 	"MT_AXISTRANSFERLINE",
 	"MT_NIGHTSDRONE",
-	"MT_NIGHTSGOAL",
+	"MT_NIGHTSDRONE_MAN",
+	"MT_NIGHTSDRONE_SPARKLING",
+	"MT_NIGHTSDRONE_GOAL",
 	"MT_NIGHTSPARKLE",
 	"MT_NIGHTSLOOPHELPER",
 	"MT_NIGHTSBUMPER", // NiGHTS Bumper
@@ -7332,6 +7334,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_NIGHTSEXTRATIME",
 	"MT_NIGHTSLINKFREEZE",
 	"MT_EGGCAPSULE",
+	"MT_IDEYAANCHOR",
 	"MT_NIGHTOPIANHELPER", // the actual helper object that orbits you
 	"MT_PIAN", // decorative singing friend
 	"MT_SHLEEP", // almost-decorative sleeping enemy
diff --git a/src/doomdef.h b/src/doomdef.h
index c067a71ee9d7d0d4f0d934b85e7569a5941cf70a..42ecdb57a4b117e0d29445c70482e79649246d3d 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -448,7 +448,7 @@ extern INT32 cv_debug;
 
 #define DBG_BASIC       0x0001
 #define DBG_DETAILED    0x0002
-#define DBG_RANDOMIZER  0x0004
+#define DBG_PLAYER      0x0004
 #define DBG_RENDER      0x0008
 #define DBG_NIGHTSBASIC 0x0010
 #define DBG_NIGHTS      0x0020
@@ -458,6 +458,7 @@ extern INT32 cv_debug;
 #define DBG_MEMORY      0x0200
 #define DBG_SETUP       0x0400
 #define DBG_LUA         0x0800
+#define DBG_RANDOMIZER  0x1000
 
 // =======================
 // Misc stuff for later...
diff --git a/src/f_finale.c b/src/f_finale.c
index 76eecb378029700f1d13fbc72bb1d2e223b1d425..f82b0f777bc15a31a174340d199466e87b89b8ae 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -29,6 +29,7 @@
 #include "g_input.h"
 #include "console.h"
 #include "m_random.h"
+#include "m_misc.h" // moviemode functionality
 #include "y_inter.h"
 #include "m_cond.h"
 #include "p_local.h"
@@ -331,7 +332,7 @@ void F_StartIntro(void)
 	introtext[2] = M_GetText(
 	"As it was about to drain the rings\n"
 	"away from the planet, Sonic burst into\n"
-	"the Satellite and for what he thought\n"
+	"the control room and for what he thought\n"
 	"would be the last time,\xB4 defeated\n"
 	"Dr. Eggman.\n#");
 
@@ -341,11 +342,11 @@ void F_StartIntro(void)
 	"return,\xB8 bringing an all new threat.\n#");
 
 	introtext[4] = M_GetText(
-	"\xA8""About once every year, a strange asteroid\n"
+	"\xA8""About every five years, a strange asteroid\n"
 	"hovers around the planet.\xBF It suddenly\n"
 	"appears from nowhere, circles around, and\n"
 	"\xB6- just as mysteriously as it arrives -\xB6\n"
-	"vanishes after about one week.\xBF\n"
+	"vanishes after only one week.\xBF\n"
 	"No one knows why it appears, or how.\n#");
 
 	introtext[5] = M_GetText(
@@ -398,7 +399,7 @@ void F_StartIntro(void)
 	"\xA5\"6...\xD2""5...\xD2""4...\"\xA8\xD2\n"
 	"Sonic knew he was getting closer to the\n"
 	"zone, and pushed himself harder.\xB4 Finally,\n"
-	"the mountain appeared in the horizon.\xD2\xD2\n"
+	"the mountain appeared on the horizon.\xD2\xD2\n"
 	"\xA5\"3...\xD2""2...\xD2""1...\xD2""Zero.\"\n#");
 
 	introtext[11] = M_GetText(
@@ -831,18 +832,27 @@ void F_IntroDrawer(void)
 
 			// Stay on black for a bit. =)
 			{
-				tic_t quittime;
-				quittime = I_GetTime() + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds
-				while (quittime > I_GetTime())
+				tic_t nowtime, quittime, lasttime;
+				nowtime = lasttime = I_GetTime();
+				quittime = nowtime + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds
+				while (quittime > nowtime)
 				{
+					while (!((nowtime = I_GetTime()) - lasttime))
+						I_Sleep();
+					lasttime = nowtime;
+
 					I_OsPolling();
 					I_UpdateNoBlit();
 					M_Drawer(); // menu is drawn even on top of wipes
 					I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
+
+					if (moviemode) // make sure we save frames for the white hold too
+						M_SaveFrame();
 				}
 			}
 
 			D_StartTitle();
+			wipegamestate = GS_INTRO;
 			return;
 		}
 		F_NewCutscene(introtext[++intro_scenenum]);
@@ -1547,7 +1557,7 @@ void F_TitleScreenDrawer(void)
 	if (!titlemapinaction)
 		F_SkyScroll(titlescrollspeed);
 
-	// Don't draw outside of the title screewn, or if the patch isn't there.
+	// Don't draw outside of the title screen, or if the patch isn't there.
 	if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS))
 		return;
 
@@ -1893,6 +1903,9 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 
 	G_SetGamestate(GS_CUTSCENE);
 
+	if (wipegamestate == GS_CUTSCENE)
+		wipegamestate = -1;
+
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
diff --git a/src/filesrch.c b/src/filesrch.c
index 2b5493642789272e551c30bb48e7a3ece8fab175..c1abccde3c2d488c33febee9945a7aaa2f4f0eee 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -306,9 +306,14 @@ closedir (DIR * dirp)
 }
 #endif
 
-static CV_PossibleValue_t addons_cons_t[] = {{0, "SRB2 Folder"}, /*{1, "HOME"}, {2, "SRB2 Folder"},*/ {3, "CUSTOM"}, {0, NULL}};
-consvar_t cv_addons_option = {"addons_option", "SRB2 Folder", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_addons_folder = {"addons_folder", "./", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
+#if 1
+												{1, "HOME"}, {2, "SRB2"},
+#endif
+													{3, "CUSTOM"}, {0, NULL}};
+
+consvar_t cv_addons_option = {"addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_folder = {"addons_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}};
 consvar_t cv_addons_md5 = {"addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -326,10 +331,11 @@ size_t menudepthleft = menudepth;
 
 char menusearch[MAXSTRINGLENGTH+1];
 
-char **dirmenu;
-size_t sizedirmenu;
+char **dirmenu, **coredirmenu; // core only local for this file
+size_t sizedirmenu, sizecoredirmenu; // ditto
 size_t dir_on[menudepth];
 UINT8 refreshdirmenu = 0;
+char *refreshdirname = NULL;
 
 size_t packetsizetally = 0;
 size_t mainwadstally = 0;
@@ -362,9 +368,9 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
 		return FS_NOTFOUND;
 	}
 
-	if (searchpath[searchpathindex[depthleft]-2] != '/')
+	if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
 	{
-		searchpath[searchpathindex[depthleft]-1] = '/';
+		searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
 		searchpath[searchpathindex[depthleft]] = 0;
 	}
 	else
@@ -406,7 +412,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
 					depthleft++;
 			}
 
-			searchpath[searchpathindex[depthleft]-1]='/';
+			searchpath[searchpathindex[depthleft]-1]=PATHSEP[0];
 			searchpath[searchpathindex[depthleft]]=0;
 		}
 		else if (!strcasecmp(searchname, dent->d_name))
@@ -446,7 +452,7 @@ char exttable[NUM_EXT_TABLE][5] = {
 char filenamebuf[MAX_WADFILES][MAX_WADPATH];
 
 
-static boolean filemenusearch(char *haystack, char *needle)
+static boolean filemenucmp(char *haystack, char *needle)
 {
 	static char localhaystack[128];
 	strlcpy(localhaystack, haystack, 128);
@@ -457,21 +463,151 @@ static boolean filemenusearch(char *haystack, char *needle)
 		: (!strncmp(localhaystack, needle, menusearch[0])));
 }
 
-#define searchdir if (menusearch[0] && !filemenusearch(dent->d_name, localmenusearch))\
-					{\
-						rejected++;\
-						continue;\
-					}\
+void closefilemenu(boolean validsize)
+{
+	// search
+	if (dirmenu)
+	{
+		if (dirmenu != coredirmenu)
+		{
+			if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
+			{
+				Z_Free(dirmenu[0]);
+				dirmenu[0] = NULL;
+			}
+			Z_Free(dirmenu);
+		}
+		dirmenu = NULL;
+		sizedirmenu = 0;
+	}
+
+	if (coredirmenu)
+	{
+		// core
+		if (validsize)
+		{
+			for (; sizecoredirmenu > 0; sizecoredirmenu--)
+			{
+				Z_Free(coredirmenu[sizecoredirmenu-1]);
+				coredirmenu[sizecoredirmenu-1] = NULL;
+			}
+		}
+		else
+			sizecoredirmenu = 0;
+
+		Z_Free(coredirmenu);
+		coredirmenu = NULL;
+	}
+
+	if (refreshdirname)
+		Z_Free(refreshdirname);
+	refreshdirname = NULL;
+}
+
+void searchfilemenu(char *tempname)
+{
+	size_t i, first;
+	char localmenusearch[MAXSTRINGLENGTH] = "";
+
+	if (dirmenu)
+	{
+		if (dirmenu != coredirmenu)
+		{
+			if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
+			{
+				Z_Free(dirmenu[0]);
+				dirmenu[0] = NULL;
+			}
+			//Z_Free(dirmenu); -- Z_Realloc later tho...
+		}
+		else
+			dirmenu = NULL;
+	}
+
+	first = (((UINT8)(coredirmenu[0][DIR_TYPE]) == EXT_UP) ? 1 : 0); // skip UP...
+
+	if (!menusearch[0])
+	{
+		if (dirmenu)
+			Z_Free(dirmenu);
+		dirmenu = coredirmenu;
+		sizedirmenu = sizecoredirmenu;
+
+		if (tempname)
+		{
+			for (i = first; i < sizedirmenu; i++)
+			{
+				if (!strcmp(dirmenu[i]+DIR_STRING, tempname))
+				{
+					dir_on[menudepthleft] = i;
+					break;
+				}
+			}
+
+			if (i == sizedirmenu)
+				dir_on[menudepthleft] = first;
+
+			Z_Free(tempname);
+		}
+
+		return;
+	}
+
+	strcpy(localmenusearch, menusearch+1);
+	if (!cv_addons_search_case.value)
+		strupr(localmenusearch);
+
+	sizedirmenu = 0;
+	for (i = first; i < sizecoredirmenu; i++)
+	{
+		if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
+			sizedirmenu++;
+	}
+
+	if (!sizedirmenu) // no results...
+	{
+		if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL)))
+			|| !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS))))
+				I_Error("Ran out of memory whilst preparing add-ons menu");
+		sizedirmenu = 1;
+		dir_on[menudepthleft] = 0;
+		if (tempname)
+			Z_Free(tempname);
+		return;
+	}
+
+	if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL)))
+		I_Error("Ran out of memory whilst preparing add-ons menu");
+
+	sizedirmenu = 0;
+	for (i = first; i < sizecoredirmenu; i++)
+	{
+		if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
+		{
+			if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname))
+			{
+				dir_on[menudepthleft] = sizedirmenu;
+				Z_Free(tempname);
+				tempname = NULL;
+			}
+			dirmenu[sizedirmenu++] = coredirmenu[i]; // pointer reuse
+		}
+	}
+
+	if (tempname)
+	{
+		dir_on[menudepthleft] = 0;
+		Z_Free(tempname);
+	}
+}
 
 boolean preparefilemenu(boolean samedepth)
 {
 	DIR *dirhandle;
 	struct dirent *dent;
 	struct stat fsstat;
-	size_t pos = 0, folderpos = 0, numfolders = 0, rejected = 0;
+	size_t pos = 0, folderpos = 0, numfolders = 0;
 	char *tempname = NULL;
-	boolean noresults = false;
-	char localmenusearch[MAXSTRINGLENGTH] = "";
 
 	if (samedepth)
 	{
@@ -481,20 +617,16 @@ boolean preparefilemenu(boolean samedepth)
 	else
 		menusearch[0] = menusearch[1] = 0; // clear search
 
-	for (; sizedirmenu > 0; sizedirmenu--) // clear out existing items
-	{
-		Z_Free(dirmenu[sizedirmenu-1]);
-		dirmenu[sizedirmenu-1] = NULL;
-	}
-
 	if (!(dirhandle = opendir(menupath))) // get directory
+	{
+		closefilemenu(true);
 		return false;
+	}
 
-	if (menusearch[0])
+	for (; sizecoredirmenu > 0; sizecoredirmenu--) // clear out existing items
 	{
-		strcpy(localmenusearch, menusearch+1);
-		if (!cv_addons_search_case.value)
-			strupr(localmenusearch);
+		Z_Free(coredirmenu[sizecoredirmenu-1]);
+		coredirmenu[sizecoredirmenu-1] = NULL;
 	}
 
 	while (true)
@@ -526,43 +658,42 @@ boolean preparefilemenu(boolean samedepth)
 						if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison
 					if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file
 				}
-				searchdir;
 			}
 			else // directory
-			{
-				searchdir;
 				numfolders++;
-			}
-			sizedirmenu++;
+
+			sizecoredirmenu++;
 		}
 	}
 
-	if (!rejected && !sizedirmenu)
+	if (!sizecoredirmenu)
 	{
+		closedir(dirhandle);
+		closefilemenu(false);
 		if (tempname)
 			Z_Free(tempname);
-		closedir(dirhandle);
 		return false;
 	}
 
-	if (((noresults = (menusearch[0] && !sizedirmenu)))
-		|| (!menusearch[0] && menudepthleft != menudepth-1)) // Make room for UP... or search entry
+	if (menudepthleft != menudepth-1) // Make room for UP...
 	{
-		sizedirmenu++;
+		sizecoredirmenu++;
 		numfolders++;
 		folderpos++;
 	}
 
-	if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL)))
+	if (dirmenu && dirmenu == coredirmenu)
+		dirmenu = NULL;
+
+	if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL)))
 	{
 		closedir(dirhandle); // just in case
 		I_Error("Ran out of memory whilst preparing add-ons menu");
 	}
 
-	rejected = 0;
 	rewinddir(dirhandle);
 
-	while ((pos+folderpos) < sizedirmenu)
+	while ((pos+folderpos) < sizecoredirmenu)
 	{
 		menupath[menupathindex[menudepthleft]] = 0;
 		dent = readdir(dirhandle);
@@ -588,14 +719,12 @@ boolean preparefilemenu(boolean samedepth)
 
 			if (!S_ISDIR(fsstat.st_mode)) // file
 			{
-				if (!((numfolders+pos) < sizedirmenu)) continue; // crash prevention
+				if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention
 				for (; ext < NUM_EXT_TABLE; ext++)
 					if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison
 				if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file
 				ext += EXT_START; // moving to be appropriate position
 
-				searchdir;
-
 				if (ext >= EXT_LOADSTART)
 				{
 					size_t i;
@@ -628,10 +757,7 @@ boolean preparefilemenu(boolean samedepth)
 				folder = 0;
 			}
 			else // directory
-			{
-				searchdir;
 				len += (folder = 1);
-			}
 
 			if (len > 255)
 				len = 255;
@@ -643,46 +769,31 @@ boolean preparefilemenu(boolean samedepth)
 			strlcpy(temp+DIR_STRING, dent->d_name, len);
 			if (folder)
 			{
-				strcpy(temp+len, "/");
-				dirmenu[folderpos++] = temp;
+				strcpy(temp+len, PATHSEP);
+				coredirmenu[folderpos++] = temp;
 			}
 			else
-				dirmenu[numfolders + pos++] = temp;
+				coredirmenu[numfolders + pos++] = temp;
 		}
 	}
 
 	closedir(dirhandle);
 
-	if (noresults) // no results
-		dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS));
-	else if (!menusearch[0] &&menudepthleft != menudepth-1) // now for UP... entry
-		dirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP));
+	if ((menudepthleft != menudepth-1) // now for UP... entry
+		&& !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP))))
+			I_Error("Ran out of memory whilst preparing add-ons menu");
 
 	menupath[menupathindex[menudepthleft]] = 0;
-	sizedirmenu = (numfolders+pos); // just in case things shrink between opening and rewind
-
-	if (tempname)
-	{
-		size_t i;
-		for (i = 0; i < sizedirmenu; i++)
-		{
-			if (!strcmp(dirmenu[i]+DIR_STRING, tempname))
-			{
-				dir_on[menudepthleft] = i;
-				break;
-			}
-		}
-		Z_Free(tempname);
-	}
+	sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind
 
-	if (!sizedirmenu)
+	if (!sizecoredirmenu)
 	{
 		dir_on[menudepthleft] = 0;
-		Z_Free(dirmenu);
+		closefilemenu(false);
 		return false;
 	}
-	else if (dir_on[menudepthleft] >= sizedirmenu)
-		dir_on[menudepthleft] = sizedirmenu-1;
+
+	searchfilemenu(tempname);
 
 	return true;
 }
diff --git a/src/filesrch.h b/src/filesrch.h
index e88242698d49f284e0b3efd59f1ae6be4b774abc..41dc80d1377ed9a1bd76406dc5bdaa6f406bfbfb 100644
--- a/src/filesrch.h
+++ b/src/filesrch.h
@@ -40,6 +40,7 @@ extern char **dirmenu;
 extern size_t sizedirmenu;
 extern size_t dir_on[menudepth];
 extern UINT8 refreshdirmenu;
+extern char *refreshdirname;
 
 extern size_t packetsizetally;
 extern size_t mainwadstally;
@@ -87,6 +88,8 @@ typedef enum
 	REFRESHDIR_MAX = 32
 } refreshdir_enum;
 
+void closefilemenu(boolean validsize);
+void searchfilemenu(char *tempname);
 boolean preparefilemenu(boolean samedepth);
 
 #endif // __FILESRCH_H__
diff --git a/src/g_game.c b/src/g_game.c
index 67780e303722aa5a0102002dca74c8db75744c82..363ccf8dc34bc28c61cb0d123b99c0be4d9434ab 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -329,19 +329,21 @@ static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
 consvar_t cv_crosshair = {"crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_alwaysfreelook = {"alwaysmlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mousemove = {"mousemove", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mousemove2 = {"mousemove2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_analog = {"analog", "Off", CV_CALL, CV_OnOff, Analog_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_analog2 = {"analog2", "Off", CV_CALL, CV_OnOff, Analog2_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_useranalog = {"useranalog", "Off", CV_SAVE|CV_CALL, CV_OnOff, UserAnalog_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_useranalog2 = {"useranalog2", "Off", CV_SAVE|CV_CALL, CV_OnOff, UserAnalog2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mousemove2 = {"mousemove2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-static CV_PossibleValue_t directionchar_cons_t[] = {{0, "Camera"}, {1, "Movement"}, {0, NULL}};
+// previously "analog", "analog2", "useranalog", and "useranalog2", invalidating 2.1-era copies of config.cfg
+// changed because it'd be nice to see people try out our actually good controls with gamepads now autobrake exists
+consvar_t cv_analog = {"sessionanalog", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_analog2 = {"sessionanalog2", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_useranalog = {"configanalog", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_useranalog2 = {"configanalog2", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 // deez New User eXperiences
+static CV_PossibleValue_t directionchar_cons_t[] = {{0, "Camera"}, {1, "Movement"}, {0, NULL}};
 consvar_t cv_directionchar = {"directionchar", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar_OnChange, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_directionchar2 = {"directionchar2", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar2_OnChange, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_autobrake = {"autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange, 0, NULL, NULL, 0, 0, NULL};
@@ -1532,11 +1534,6 @@ static void Analog_OnChange(void)
 		return;
 	}
 
-	if (cv_analog.value)
-		players[consoleplayer].pflags |= PF_ANALOGMODE;
-	else
-		players[consoleplayer].pflags &= ~PF_ANALOGMODE;
-
 	SendWeaponPref();
 }
 
@@ -1552,51 +1549,26 @@ static void Analog2_OnChange(void)
 		return;
 	}
 
-	if (cv_analog2.value)
-		players[secondarydisplayplayer].pflags |= PF_ANALOGMODE;
-	else
-		players[secondarydisplayplayer].pflags &= ~PF_ANALOGMODE;
-
 	SendWeaponPref2();
 }
 
 static void DirectionChar_OnChange(void)
 {
-	if (cv_directionchar.value)
-		players[consoleplayer].pflags |= PF_DIRECTIONCHAR;
-	else
-		players[consoleplayer].pflags &= ~PF_DIRECTIONCHAR;
-
 	SendWeaponPref();
 }
 
 static void DirectionChar2_OnChange(void)
 {
-	if (cv_directionchar2.value)
-		players[secondarydisplayplayer].pflags |= PF_DIRECTIONCHAR;
-	else
-		players[secondarydisplayplayer].pflags &= ~PF_DIRECTIONCHAR;
-
 	SendWeaponPref2();
 }
 
 static void AutoBrake_OnChange(void)
 {
-	if (cv_autobrake.value)
-		players[consoleplayer].pflags |= PF_AUTOBRAKE;
-	else
-		players[consoleplayer].pflags &= ~PF_AUTOBRAKE;
-
 	SendWeaponPref();
 }
 
 static void AutoBrake2_OnChange(void)
 {
-	if (cv_autobrake2.value)
-		players[secondarydisplayplayer].pflags |= PF_AUTOBRAKE;
-	else
-		players[secondarydisplayplayer].pflags &= ~PF_AUTOBRAKE;
-
 	SendWeaponPref2();
 }
 
@@ -1681,7 +1653,8 @@ void G_DoLoadLevel(boolean resetplayer)
 	CON_ClearHUD();
 }
 
-static INT32 pausedelay = 0;
+INT32 pausedelay = 0;
+boolean pausebreakkey = false;
 static INT32 camtoggledelay, camtoggledelay2 = 0;
 
 //
@@ -1829,19 +1802,35 @@ boolean G_Responder(event_t *ev)
 	{
 		case ev_keydown:
 			if (ev->data1 == gamecontrol[gc_pause][0]
-				|| ev->data1 == gamecontrol[gc_pause][1])
+				|| ev->data1 == gamecontrol[gc_pause][1]
+				|| ev->data1 == KEY_PAUSE)
 			{
-				if (!pausedelay)
+				if (modeattacking && !demoplayback && (gamestate == GS_LEVEL))
 				{
-					// don't let busy scripts prevent pausing
-					pausedelay = NEWTICRATE/7;
+					pausebreakkey = (ev->data1 == KEY_PAUSE);
+					if (menuactive || pausedelay < 0 || leveltime < 2)
+						return true;
 
-					// command will handle all the checks for us
-					COM_ImmedExecute("pause");
-					return true;
+					if (pausedelay < 1+(NEWTICRATE/2))
+						pausedelay = 1+(NEWTICRATE/2);
+					else if (++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3))
+					{
+						G_SetRetryFlag();
+						return true;
+					}
+					pausedelay++; // counteract subsequent subtraction this frame
 				}
 				else
-					pausedelay = NEWTICRATE/7;
+				{
+					INT32 oldpausedelay = pausedelay;
+					pausedelay = (NEWTICRATE/7);
+					if (!oldpausedelay)
+					{
+						// command will handle all the checks for us
+						COM_ImmedExecute("pause");
+						return true;
+					}
+				}
 			}
 			if (ev->data1 == gamecontrol[gc_camtoggle][0]
 				|| ev->data1 == gamecontrol[gc_camtoggle][1])
@@ -1901,11 +1890,19 @@ void G_Ticker(boolean run)
 		{
 			G_ClearRetryFlag();
 
-			// Costs a life to retry ... unless the player in question is dead already.
-			if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE)
-				players[consoleplayer].lives -= 1;
+			if (modeattacking)
+			{
+				pausedelay = INT32_MIN;
+				M_ModeAttackRetry(0);
+			}
+			else
+			{
+				// Costs a life to retry ... unless the player in question is dead already.
+				if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES)
+					players[consoleplayer].lives -= 1;
 
-			G_DoReborn(consoleplayer);
+				G_DoReborn(consoleplayer);
+			}
 		}
 
 		for (i = 0; i < MAXPLAYERS; i++)
@@ -2004,8 +2001,13 @@ void G_Ticker(boolean run)
 
 	if (run)
 	{
-		if (pausedelay)
-			pausedelay--;
+		if (pausedelay && pausedelay != INT32_MIN)
+		{
+			if (pausedelay > 0)
+				pausedelay--;
+			else
+				pausedelay++;
+		}
 
 		if (camtoggledelay)
 			camtoggledelay--;
@@ -2940,6 +2942,9 @@ static void G_DoCompleted(void)
 
 	tokenlist = 0; // Reset the list
 
+	if (modeattacking && pausedelay)
+		pausedelay = 0;
+
 	gameaction = ga_nothing;
 
 	if (metalplayback)
diff --git a/src/g_game.h b/src/g_game.h
index 9e8580d139c8e94b0c31183746723b62bbf32f65..1e30831d8f5059f71ef1d87f88aa521843dfb29f 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -53,6 +53,8 @@ extern INT16 prevmap, nextmap;
 extern INT32 gameovertics;
 extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
 extern INT16 rw_maximums[NUM_WEAPONS];
+extern INT32 pausedelay;
+extern boolean pausebreakkey;
 
 // used in game menu
 extern consvar_t cv_tutorialprompt;
diff --git a/src/g_input.c b/src/g_input.c
index 4f7296cd5a5a92d4dafe7650719b60b488b3b800..4686f57ced0b82dddc96a6696314db51065a187b 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -709,7 +709,7 @@ void G_DefineDefaultControls(void)
 		gamecontroldefault[i][gc_teamkey    ][0] = 'y';
 		gamecontroldefault[i][gc_scores     ][0] = KEY_TAB;
 		gamecontroldefault[i][gc_console    ][0] = KEY_CONSOLE;
-		gamecontroldefault[i][gc_pause      ][0] = KEY_PAUSE;
+		gamecontroldefault[i][gc_pause      ][0] = 'p';
 	}
 }
 
@@ -814,11 +814,31 @@ static void setcontrol(INT32 (*gc)[2], INT32 na)
 		return;
 	}
 	keynum = G_KeyStringtoNum(COM_Argv(2));
+
+	if (keynum == KEY_PAUSE) // fail silently; pause is hardcoded
+	{
+		if (na == 4)
+		{
+			na--;
+			keynum = G_KeyStringtoNum(COM_Argv(3));
+			if (keynum == KEY_PAUSE)
+				return;
+		}
+		else
+			return;
+	}
+
 	G_CheckDoubleUsage(keynum);
 	gc[numctrl][0] = keynum;
 
 	if (na == 4)
-		gc[numctrl][1] = G_KeyStringtoNum(COM_Argv(3));
+	{
+		keynum = G_KeyStringtoNum(COM_Argv(3));
+		if (keynum != KEY_PAUSE)
+			gc[numctrl][1] = keynum;
+		else
+			gc[numctrl][1] = 0;
+	}
 	else
 		gc[numctrl][1] = 0;
 }
diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c
index fa5bce308eff82bf52021c98bc19e1797ceb87ee..04afb9be91b1bfacf5e53f3c7e2804c62ea0f68a 100644
--- a/src/hardware/hw_bsp.c
+++ b/src/hardware/hw_bsp.c
@@ -29,6 +29,7 @@
 #include "../m_argv.h"
 #include "../i_video.h"
 #include "../w_wad.h"
+#include "../p_setup.h" // levelfadecol
 
 // --------------------------------------------------------------------------
 // This is global data for planes rendering
@@ -644,7 +645,7 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b
 				sprintf(s, "%d%%", (++ls_percent)<<1);
 				x = BASEVIDWIDTH/2;
 				y = BASEVIDHEIGHT/2;
-				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect
+				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); // Background to match fade in effect
 				//V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright.
 				M_DrawTextBox(x-58, y-8, 13, 1);
 				V_DrawString(x-50, y, V_YELLOWMAP, "Loading...");
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index 4efd49817789fdbedf48244eaf7ac71417c1cdb7..100bb1180e7af9eb1d28651b37578651a83d07c7 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -296,7 +296,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 				Z_Free(realpatch);
 			}
 			// centre screen
-			if (vid.width != BASEVIDWIDTH * vid.dupx)
+			if ((float)vid.width != (float)BASEVIDWIDTH * dupx)
 			{
 				if (option & V_SNAPTORIGHT)
 					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
@@ -307,7 +307,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 				else if (perplayershuffle & 8)
 					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
 			}
-			if (vid.height != BASEVIDHEIGHT * vid.dupy)
+			if ((float)vid.height != (float)BASEVIDHEIGHT * dupy)
 			{
 				if (option & V_SNAPTOBOTTOM)
 					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
@@ -452,14 +452,14 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
 				Z_Free(realpatch);
 			}
 			// centre screen
-			if (vid.width != BASEVIDWIDTH * vid.dupx)
+			if ((float)vid.width != (float)BASEVIDWIDTH * dupx)
 			{
 				if (option & V_SNAPTORIGHT)
 					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
 				else if (!(option & V_SNAPTOLEFT))
 					cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
 			}
-			if (vid.height != BASEVIDHEIGHT * vid.dupy)
+			if ((float)vid.height != (float)BASEVIDHEIGHT * dupy)
 			{
 				if (option & V_SNAPTOBOTTOM)
 					cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
@@ -1022,7 +1022,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 		fw *= dupx;
 		fh *= dupy;
 
-		if (vid.width != BASEVIDWIDTH * vid.dupx)
+		if ((float)vid.width != (float)BASEVIDWIDTH * dupx)
 		{
 			if (color & V_SNAPTORIGHT)
 				fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
@@ -1033,7 +1033,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 			else if (perplayershuffle & 8)
 				fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
 		}
-		if (vid.height != BASEVIDHEIGHT * dupy)
+		if ((float)vid.height != (float)BASEVIDHEIGHT * dupy)
 		{
 			// same thing here
 			if (color & V_SNAPTOBOTTOM)
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 349103602c460c509ab9d8934f74bc6c33a8a12b..3a152562bee861bea3b61288e86aa9aad1babdce 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1063,7 +1063,7 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
 //
 // HWR_SplitWall
 //
-static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, UINT32 cutflag, ffloor_t *pfloor)
+static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor)
 {
 	/* SoM: split up and light walls according to the
 	 lightlist. This may also include leaving out parts
@@ -5731,7 +5731,7 @@ static void HWR_DrawSkyBackground(player_t *player)
 
 	dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
 
-	v[0].sow = v[3].sow = ((float) (-angle) / ((ANGLE_90-1)*dimensionmultiply)); // left
+	v[0].sow = v[3].sow = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
 	v[2].sow = v[1].sow = v[0].sow + (1.0f/dimensionmultiply); // right (or left + 1.0f)
 	// use +angle and -1.0f above instead if you wanted old backwards behavior
 
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 6697eb09bdd9ea8966ab721b7b37a81c8c3c4ff2..6e17b939d4624f72a8d4369404c54d9824e3d40d 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1040,25 +1040,29 @@ UINT16 hu_demorings;
 
 static void HU_DrawDemoInfo(void)
 {
-	V_DrawString(4, 188-24, V_YELLOWMAP, va(M_GetText("%s's replay"), player_names[0]));
+	INT32 h = 188;
+	if (modeattacking == ATTACKING_NIGHTS)
+		h -= 12;
+
+	V_DrawString(4, h-24, V_YELLOWMAP|V_ALLOWLOWERCASE, va(M_GetText("%s's replay"), player_names[0]));
 	if (modeattacking)
 	{
-		V_DrawString(4, 188-16, V_YELLOWMAP|V_MONOSPACE, "SCORE:");
-		V_DrawRightAlignedString(120, 188-16, V_MONOSPACE, va("%d", hu_demoscore));
+		V_DrawString(4, h-16, V_YELLOWMAP|V_MONOSPACE, "SCORE:");
+		V_DrawRightAlignedString(120, h-16, V_MONOSPACE, va("%d", hu_demoscore));
 
-		V_DrawString(4, 188- 8, V_YELLOWMAP|V_MONOSPACE, "TIME:");
+		V_DrawString(4, h-8, V_YELLOWMAP|V_MONOSPACE, "TIME:");
 		if (hu_demotime != UINT32_MAX)
-			V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, va("%i:%02i.%02i",
+			V_DrawRightAlignedString(120, h-8, V_MONOSPACE, va("%i:%02i.%02i",
 				G_TicsToMinutes(hu_demotime,true),
 				G_TicsToSeconds(hu_demotime),
 				G_TicsToCentiseconds(hu_demotime)));
 		else
-			V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, "--:--.--");
+			V_DrawRightAlignedString(120, h-8, V_MONOSPACE, "--:--.--");
 
 		if (modeattacking == ATTACKING_RECORD)
 		{
-			V_DrawString(4, 188   , V_YELLOWMAP|V_MONOSPACE, "RINGS:");
-			V_DrawRightAlignedString(120, 188   , V_MONOSPACE, va("%d", hu_demorings));
+			V_DrawString(4, h, V_YELLOWMAP|V_MONOSPACE, "RINGS:");
+			V_DrawRightAlignedString(120, h, V_MONOSPACE, va("%d", hu_demorings));
 		}
 	}
 }
@@ -1127,6 +1131,31 @@ void HU_Drawer(void)
 
 		V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
 	}
+
+	if (modeattacking && pausedelay > 0 && !pausebreakkey)
+	{
+		INT32 strength = ((pausedelay - 1 - NEWTICRATE/2)*10)/(NEWTICRATE/3);
+		INT32 y = hudinfo[HUD_LIVES].y - 13;
+
+		if (players[consoleplayer].powers[pw_carry] == CR_NIGHTSMODE)
+			y -= 16;
+		else
+		{
+			if (players[consoleplayer].pflags & PF_AUTOBRAKE)
+				y -= 8;
+			if (players[consoleplayer].pflags & PF_ANALOGMODE)
+				y -= 8;
+		}
+
+		V_DrawThinString(hudinfo[HUD_LIVES].x-2, y,
+			hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_SKYMAP : V_BLUEMAP),
+			"HOLD TO RETRY...");
+
+		if (strength > 9)
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
+		else if (strength > 0)
+			V_DrawFadeScreen(0, strength);
+	}
 }
 
 //======================================================================
diff --git a/src/i_sound.h b/src/i_sound.h
index 3dc0d0d1f0350582f71098cfab951989f59a8388..96839bff39b684c4ea2bb628909ea07a0abfbd84 100644
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -288,4 +288,4 @@ void I_PlayCD(UINT8 track, UINT8 looping);
 */
 boolean I_SetVolumeCD(INT32 volume);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/info.c b/src/info.c
index 72abcede1dad474b81a74f197dda5f3345e5836f..769d27e880aa8af2bf909fb1c494f2efad45e163 100644
--- a/src/info.c
+++ b/src/info.c
@@ -3278,8 +3278,8 @@ state_t states[NUMSTATES] =
 	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TOAD
 
 	// Nights Drone
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE2}, // S_NIGHTSDRONE1
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE1}, // S_NIGHTSDRONE2
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN2}, // S_NIGHTSDRONE_MAN1
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN1}, // S_NIGHTSDRONE_MAN2
 
 	// Sparkling point (RETURN TO THE GOAL, etc)
 	{SPR_IVSP, 0, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING2},   // S_NIGHTSDRONE_SPARKLING1
@@ -3300,10 +3300,10 @@ state_t states[NUMSTATES] =
 	{SPR_IVSP, 30, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING1}, // S_NIGHTSDRONE_SPARKLING16
 
 	// NiGHTS GOAL banner (inside the sparkles!)
-	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSGOAL2}, // S_NIGHTSGOAL1
-	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSGOAL3}, // S_NIGHTSGOAL2
-	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSGOAL4}, // S_NIGHTSGOAL3
-	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSGOAL1}, // S_NIGHTSGOAL4
+	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL2}, // S_NIGHTSDRONE_GOAL1
+	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL3}, // S_NIGHTSDRONE_GOAL2
+	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL4}, // S_NIGHTSDRONE_GOAL3
+	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL1}, // S_NIGHTSDRONE_GOAL4
 
 	// Nights Sparkle
 	{SPR_NSPK, FF_FULLBRIGHT, 140, {NULL}, 0, 0, S_NIGHTSPARKLE2},   // S_NIGHTSPARKLE1
@@ -16652,7 +16652,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_NIGHTSDRONE
 		1703,           // doomednum
-		S_NIGHTSDRONE1, // spawnstate
+		S_INVISIBLE,  // spawnstate
 		120,            // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -16668,18 +16668,45 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		sfx_None,       // deathsound
 		0,              // speed
 		16*FRACUNIT,    // radius
-		56*FRACUNIT,    // height
+		80*FRACUNIT,    // height
 		1,              // display offset
 		1000,           // mass
 		0,              // damage
 		sfx_ideya,      // activesound
-		MF_SPECIAL,     // flags
+		MF_NOGRAVITY|MF_NOCLIP|MF_SPECIAL, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_NIGHTSDRONE_MAN
+		-1,           // doomednum
+		S_INVISIBLE,  // spawnstate
+		120,            // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		255,            // painchance
+		sfx_None,       // painsound
+		S_NIGHTSDRONE_MAN1, // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		16*FRACUNIT,    // radius
+		56*FRACUNIT,    // height
+		1,              // display offset
+		1000,           // mass
+		0,              // damage
+		sfx_None,      // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_NIGHTSGOAL
+	{           // MT_NIGHTSDRONE_SPARKLING
 		-1,             // doomednum
-		S_NIGHTSGOAL1,  // spawnstate
+		S_INVISIBLE,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -16688,14 +16715,41 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // painstate
 		255,            // painchance
 		sfx_None,       // painsound
-		S_NULL,         // meleestate
+		S_NIGHTSDRONE_SPARKLING1, // meleestate
 		S_NULL,         // missilestate
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		0,              // speed
 		16*FRACUNIT,    // radius
-		56*FRACUNIT,    // height
+		24*FRACUNIT,    // height
+		1,              // display offset
+		1000,           // mass
+		0,              // damage
+		sfx_None,      // activesound
+		MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_NIGHTSDRONE_GOAL
+		-1,             // doomednum
+		S_INVISIBLE,   // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		255,            // painchance
+		sfx_None,       // painsound
+		S_NIGHTSDRONE_GOAL1,  // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		16*FRACUNIT,    // radius
+		24*FRACUNIT,    // height
 		-1,             // display offset
 		1000,           // mass
 		0,              // damage
@@ -17136,6 +17190,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_IDEYAANCHOR
+		1714,           // doomednum
+		S_INVISIBLE,    // spawnstate
+		0,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		1*FRACUNIT,     // radius
+		2*FRACUNIT,     // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_NIGHTOPIANHELPER
 		-1,             // doomednum
 		S_NIGHTOPIANHELPER1, // spawnstate
diff --git a/src/info.h b/src/info.h
index c9de82541c64f16e0b76b79b1ad43121f0750c73..8baafbd87d3efcaf246b485be9bf7b7e219fc97d 100644
--- a/src/info.h
+++ b/src/info.h
@@ -3344,8 +3344,8 @@ typedef enum state
 	S_TOAD,
 
 	// Nights-specific stuff
-	S_NIGHTSDRONE1,
-	S_NIGHTSDRONE2,
+	S_NIGHTSDRONE_MAN1,
+	S_NIGHTSDRONE_MAN2,
 	S_NIGHTSDRONE_SPARKLING1,
 	S_NIGHTSDRONE_SPARKLING2,
 	S_NIGHTSDRONE_SPARKLING3,
@@ -3362,10 +3362,10 @@ typedef enum state
 	S_NIGHTSDRONE_SPARKLING14,
 	S_NIGHTSDRONE_SPARKLING15,
 	S_NIGHTSDRONE_SPARKLING16,
-	S_NIGHTSGOAL1,
-	S_NIGHTSGOAL2,
-	S_NIGHTSGOAL3,
-	S_NIGHTSGOAL4,
+	S_NIGHTSDRONE_GOAL1,
+	S_NIGHTSDRONE_GOAL2,
+	S_NIGHTSDRONE_GOAL3,
+	S_NIGHTSDRONE_GOAL4,
 
 	S_NIGHTSPARKLE1,
 	S_NIGHTSPARKLE2,
@@ -4256,7 +4256,9 @@ typedef enum mobj_type
 	MT_AXISTRANSFER,
 	MT_AXISTRANSFERLINE,
 	MT_NIGHTSDRONE,
-	MT_NIGHTSGOAL,
+	MT_NIGHTSDRONE_MAN,
+	MT_NIGHTSDRONE_SPARKLING,
+	MT_NIGHTSDRONE_GOAL,
 	MT_NIGHTSPARKLE,
 	MT_NIGHTSLOOPHELPER,
 	MT_NIGHTSBUMPER, // NiGHTS Bumper
@@ -4273,6 +4275,7 @@ typedef enum mobj_type
 	MT_NIGHTSEXTRATIME,
 	MT_NIGHTSLINKFREEZE,
 	MT_EGGCAPSULE,
+	MT_IDEYAANCHOR,
 	MT_NIGHTOPIANHELPER, // the actual helper object that orbits you
 	MT_PIAN, // decorative singing friend
 	MT_SHLEEP, // almost-decorative sleeping enemy
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index bb1f59729e90de227c87bf044e88e7fcbc749194..14c9b401cb8bdd0e8ba726b9ef6661e2a4443b5f 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -200,6 +200,8 @@ static int lib_addHook(lua_State *L)
 	case hook_JumpSpinSpecial:
 	case hook_PlayerSpawn:
 	case hook_FollowMobj:
+	case hook_ShieldSpawn:
+	case hook_ShieldSpecial:
 		lastp = &playerhooks;
 		break;
 	case hook_LinedefExecute:
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index f973061f1d6ca7c928b303129208ad279fb9048d..4919883c4c10744fdea50e2dc53006310d65e871 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -288,6 +288,10 @@ static int player_get(lua_State *L)
 		lua_pushboolean(L, plr->bonustime);
 	else if (fastcmp(field,"capsule"))
 		LUA_PushUserdata(L, plr->capsule, META_MOBJ);
+	else if (fastcmp(field,"drone"))
+		LUA_PushUserdata(L, plr->drone, META_MOBJ);
+	else if (fastcmp(field,"oldscale"))
+		lua_pushfixed(L, plr->oldscale);
 	else if (fastcmp(field,"mare"))
 		lua_pushinteger(L, plr->mare);
 	else if (fastcmp(field,"marelap"))
@@ -586,6 +590,15 @@ static int player_set(lua_State *L)
 			mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
 		P_SetTarget(&plr->capsule, mo);
 	}
+	else if (fastcmp(field,"drone"))
+	{
+		mobj_t *mo = NULL;
+		if (!lua_isnil(L, 3))
+			mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+		P_SetTarget(&plr->drone, mo);
+	}
+	else if (fastcmp(field,"oldscale"))
+		plr->oldscale = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"mare"))
 		plr->mare = (UINT8)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"marelap"))
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 473209350899e4a5390c5ba73adb2d4dc43a3599..79a52fe9f0aab5ed42d9a32c250e23492eea9a1f 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -571,7 +571,7 @@ void Command_Teleport_f(void)
 		}
 		else // scan the thinkers to find starposts...
 		{
-			mobj_t *mo2;
+			mobj_t *mo2 = NULL;
 			thinker_t *th;
 
 			INT32 starpostmax = 0;
diff --git a/src/m_menu.c b/src/m_menu.c
index e973cea551ab692d44f76a62ee44f9d9b4460c61..c44d74eb4a8be3fa7051a70d4ad70764fe4d3f2c 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -283,7 +283,6 @@ static void M_Statistics(INT32 choice);
 static void M_ReplayTimeAttack(INT32 choice);
 static void M_ChooseTimeAttack(INT32 choice);
 static void M_ChooseNightsAttack(INT32 choice);
-static void M_ModeAttackRetry(INT32 choice);
 static void M_ModeAttackEndGame(INT32 choice);
 static void M_SetGuestReplay(INT32 choice);
 static void M_HandleChoosePlayerMenu(INT32 choice);
@@ -343,7 +342,6 @@ static void M_EraseData(INT32 choice);
 static void M_Addons(INT32 choice);
 static void M_AddonsOptions(INT32 choice);
 static patch_t *addonsp[NUM_EXT+6];
-static UINT8 addonsresponselimit = 0;
 
 #define numaddonsshown 4
 
@@ -1077,10 +1075,10 @@ static menuitem_t OP_ChangeControlsMenu[] =
 	{IT_CALL | IT_STRING2, NULL, "Spin",             M_ChangeControl, gc_use     },
 	{IT_HEADER, NULL, "Camera", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
-	{IT_CALL | IT_STRING2, NULL, "Camera Up",        M_ChangeControl, gc_lookup      },
-	{IT_CALL | IT_STRING2, NULL, "Camera Down",      M_ChangeControl, gc_lookdown    },
-	{IT_CALL | IT_STRING2, NULL, "Camera Left",      M_ChangeControl, gc_turnleft    },
-	{IT_CALL | IT_STRING2, NULL, "Camera Right",     M_ChangeControl, gc_turnright   },
+	{IT_CALL | IT_STRING2, NULL, "Look Up",        M_ChangeControl, gc_lookup      },
+	{IT_CALL | IT_STRING2, NULL, "Look Down",      M_ChangeControl, gc_lookdown    },
+	{IT_CALL | IT_STRING2, NULL, "Look Left",      M_ChangeControl, gc_turnleft    },
+	{IT_CALL | IT_STRING2, NULL, "Look Right",     M_ChangeControl, gc_turnright   },
 	{IT_CALL | IT_STRING2, NULL, "Center View",      M_ChangeControl, gc_centerview  },
 	{IT_CALL | IT_STRING2, NULL, "Toggle Mouselook", M_ChangeControl, gc_mouseaiming },
 	{IT_CALL | IT_STRING2, NULL, "Toggle Third-Person", M_ChangeControl, gc_camtoggle},
@@ -1089,7 +1087,7 @@ static menuitem_t OP_ChangeControlsMenu[] =
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
 	{IT_CALL | IT_STRING2, NULL, "Game Status",
     M_ChangeControl, gc_scores      },
-	{IT_CALL | IT_STRING2, NULL, "Pause",            M_ChangeControl, gc_pause       },
+	{IT_CALL | IT_STRING2, NULL, "Pause / Run Retry", M_ChangeControl, gc_pause       },
 	{IT_CALL | IT_STRING2, NULL, "Console",          M_ChangeControl, gc_console     },
 	{IT_HEADER, NULL, "Multiplayer", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
@@ -2128,15 +2126,19 @@ static void M_GoBack(INT32 choice)
 		if (!Playing() && netgame && multiplayer)
 		{
 			MSCloseUDPSocket();		// Clean up so we can re-open the connection later.
-			netgame = false;
-			multiplayer = false;
+			netgame = multiplayer = false;
 		}
 
 		if ((currentMenu->prevMenu == &MainDef) && (currentMenu == &SP_TimeAttackDef || currentMenu == &SP_NightsAttackDef))
 		{
 			// D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate.
-			Z_Free(levelselect.rows);
-			levelselect.rows = NULL;
+
+			if (levelselect.rows)
+			{
+				Z_Free(levelselect.rows);
+				levelselect.rows = NULL;
+			}
+
 			menuactive = false;
 			D_StartTitle();
 		}
@@ -4777,22 +4779,24 @@ static void M_Addons(INT32 choice)
 
 	(void)choice;
 
-	/*if (cv_addons_option.value == 0)
-		pathname = srb2home; usehome ? srb2home : srb2path;
+#if 1
+	if (cv_addons_option.value == 0)
+		pathname = usehome ? srb2home : srb2path;
 	else if (cv_addons_option.value == 1)
 		pathname = srb2home;
 	else if (cv_addons_option.value == 2)
 		pathname = srb2path;
-	else*/
+	else
+#endif
 	if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0')
 		pathname = cv_addons_folder.string;
 
 	strlcpy(menupath, pathname, 1024);
 	menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath) + 1;
 
-	if (menupath[menupathindex[menudepthleft]-2] != '/')
+	if (menupath[menupathindex[menudepthleft]-2] != PATHSEP[0])
 	{
-		menupath[menupathindex[menudepthleft]-1] = '/';
+		menupath[menupathindex[menudepthleft]-1] = PATHSEP[0];
 		menupath[menupathindex[menudepthleft]] = 0;
 	}
 	else
@@ -4886,11 +4890,7 @@ static char *M_AddonsHeaderPath(void)
 	UINT32 len;
 	static char header[1024];
 
-	if (menupath[0] == '.')
-		strlcpy(header, va("SRB2 folder%s", menupath+1), 1024);
-	else
-		strcpy(header, menupath);
-
+	strlcpy(header, va("%s folder%s", cv_addons_option.string, menupath+menupathindex[menudepth-1]-1), 1024);
 	len = strlen(header);
 	if (len > 34)
 	{
@@ -4907,6 +4907,15 @@ static char *M_AddonsHeaderPath(void)
 		M_SetupNextMenu(MISC_AddonsDef.prevMenu);\
 		M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING)
 
+#define CLEARNAME Z_Free(refreshdirname);\
+					refreshdirname = NULL
+
+static void M_AddonsClearName(INT32 choice)
+{
+	CLEARNAME;
+	M_StopMessage(choice);
+}
+
 // returns whether to do message draw
 static boolean M_AddonsRefresh(void)
 {
@@ -4918,35 +4927,35 @@ static boolean M_AddonsRefresh(void)
 
 	if (refreshdirmenu & REFRESHDIR_ADDFILE)
 	{
-		addonsresponselimit = 0;
+		char *message = NULL;
 
 		if (refreshdirmenu & REFRESHDIR_NOTLOADED)
 		{
-			char *message = NULL;
 			S_StartSound(NULL, sfx_lose);
 			if (refreshdirmenu & REFRESHDIR_MAX)
-				message = va("\x82%s\x80\nMaximum number of add-ons reached.\nThis file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING);
+				message = va("\x82%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", refreshdirname);
 			else
-				message = va("\x82%s\x80\nThe file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING);
-			M_StartMessage(message,NULL,MM_NOTHING);
-			return true;
+				message = va("\x82%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", refreshdirname);
 		}
-
-		if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR))
+		else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR))
 		{
 			S_StartSound(NULL, sfx_skid);
-			M_StartMessage(va("\x82%s\x80\nThe file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")),NULL,MM_NOTHING);
+			message = va("\x82%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings"));
+		}
+
+		if (message)
+		{
+			M_StartMessage(message,M_AddonsClearName,MM_EVENTHANDLER);
 			return true;
 		}
 
 		S_StartSound(NULL, sfx_strpst);
+		CLEARNAME;
 	}
 
 	return false;
 }
 
-#define offs 1
-
 #ifdef FIXUPO0
 #pragma GCC optimize ("0")
 #endif
@@ -4964,9 +4973,6 @@ static void M_DrawAddons(void)
 		return;
 	}
 
-	if (addonsresponselimit)
-		addonsresponselimit--;
-
 	if (Playing())
 		topstr = "\x85""Adding files mid-game may cause problems.";
 	else if (savemoddata)
@@ -4976,7 +4982,7 @@ static void M_DrawAddons(void)
 	else
 		topstr = LOCATIONSTRING;
 
-	V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, topstr);
+	V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, topstr);
 
 	if (numwadfiles <= mainwads+1)
 		y = 0;
@@ -4996,7 +5002,7 @@ static void M_DrawAddons(void)
 
 	// DRAW MENU
 	x = currentMenu->x;
-	y = currentMenu->y + offs;
+	y = currentMenu->y + 1;
 
 	//M_DrawLevelPlatterHeader(y - 16, M_AddonsHeaderPath(), true, true); -- wanted different width
 	V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), V_YELLOWMAP|V_ALLOWLOWERCASE, M_AddonsHeaderPath());
@@ -5004,7 +5010,7 @@ static void M_DrawAddons(void)
 	V_DrawFill(x-21 + (MAXSTRINGLENGTH*8+6 - 1), (y - 16) + (lsheadingheight - 3), 1, 1, 26);
 	V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 26);
 
-	V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, (BASEVIDHEIGHT - currentMenu->y + 1 + offs) - (y - 1), 159);
+	V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1), 159);
 
 	// get bottom...
 	max = dir_on[menudepthleft] + numaddonsshown + 1;
@@ -5060,7 +5066,7 @@ static void M_DrawAddons(void)
 	if (max != (ssize_t)sizedirmenu)
 		V_DrawString(19, y-12 + (skullAnimCounter/5), V_YELLOWMAP, "\x1B");
 
-	y = BASEVIDHEIGHT - currentMenu->y + offs;
+	y = BASEVIDHEIGHT - currentMenu->y + 1;
 
 	M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1);
 	if (menusearch[0])
@@ -5074,21 +5080,17 @@ static void M_DrawAddons(void)
 	x -= (21 + 5 + 16);
 	V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]);
 
-#define CANSAVE (!modifiedgame || savemoddata)
 	x = BASEVIDWIDTH - x - 16;
-	V_DrawSmallScaledPatch(x, y + 4, (CANSAVE ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+5]);
+	V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+5]);
 
 	if (modifiedgame)
 		V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+3]);
-#undef CANSAVE
 }
 
 #ifdef FIXUPO0
 #pragma GCC reset_options
 #endif
 
-#undef offs
-
 static void M_AddonExec(INT32 ch)
 {
 	if (ch != 'y' && ch != KEY_ENTER)
@@ -5140,16 +5142,17 @@ static void M_HandleAddons(INT32 choice)
 {
 	boolean exitmenu = false; // exit to previous menu
 
-	if (addonsresponselimit)
-		return;
-
 	if (M_ChangeStringAddons(choice))
 	{
-		if (!preparefilemenu(true))
+		char *tempname = NULL;
+		if (dirmenu && dirmenu[dir_on[menudepthleft]])
+			tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL
+		searchfilemenu(tempname);
+		/*if (!preparefilemenu(true))
 		{
 			UNEXIST;
 			return;
-		}
+		}*/
 	}
 
 	switch (choice)
@@ -5248,7 +5251,6 @@ static void M_HandleAddons(INT32 choice)
 						case EXT_WAD:
 						case EXT_PK3:
 							COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
-							addonsresponselimit = 5;
 							break;
 						default:
 							S_StartSound(NULL, sfx_lose);
@@ -5268,14 +5270,7 @@ static void M_HandleAddons(INT32 choice)
 	}
 	if (exitmenu)
 	{
-		for (; sizedirmenu > 0; sizedirmenu--)
-		{
-			Z_Free(dirmenu[sizedirmenu-1]);
-			dirmenu[sizedirmenu-1] = NULL;
-		}
-
-		Z_Free(dirmenu);
-		dirmenu = NULL;
+		closefilemenu(true);
 
 		// secrets disabled by addfile...
 		MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
@@ -7980,9 +7975,10 @@ static void M_SetGuestReplay(INT32 choice)
 		which(0);
 }
 
-static void M_ModeAttackRetry(INT32 choice)
+void M_ModeAttackRetry(INT32 choice)
 {
 	(void)choice;
+	// todo -- maybe seperate this out and G_SetRetryFlag() here instead? is just calling this from the menu 100% safe?
 	G_CheckDemoStatus(); // Cancel recording
 	if (modeattacking == ATTACKING_RECORD)
 		M_ChooseTimeAttack(0);
@@ -9384,6 +9380,7 @@ static void M_DrawControl(void)
 #undef controlbuffer
 
 static INT32 controltochange;
+static char controltochangetext[55];
 
 static void M_ChangecontrolResponse(event_t *ev)
 {
@@ -9391,8 +9388,8 @@ static void M_ChangecontrolResponse(event_t *ev)
 	INT32        found;
 	INT32        ch = ev->data1;
 
-	// ESCAPE cancels
-	if (ch != KEY_ESCAPE)
+	// ESCAPE cancels; dummy out PAUSE
+	if (ch != KEY_ESCAPE && ch != KEY_PAUSE)
 	{
 
 		switch (ev->type)
@@ -9453,6 +9450,24 @@ static void M_ChangecontrolResponse(event_t *ev)
 		}
 		S_StartSound(NULL, sfx_strpst);
 	}
+	else if (ch == KEY_PAUSE)
+	{
+		static char tmp[155];
+		menu_t *prev = currentMenu->prevMenu;
+
+		if (controltochange == gc_pause)
+			sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit cannot be used to retry runs \nduring Record Attack. \n\nHit another key for\n%s\nESC for Cancel"),
+				controltochangetext);
+		else
+			sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit is not configurable. \n\nHit another key for\n%s\nESC for Cancel"),
+				controltochangetext);
+
+		M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
+		currentMenu->prevMenu = prev;
+
+		S_StartSound(NULL, sfx_s3k42);
+		return;
+	}
 	else
 		S_StartSound(NULL, sfx_skid);
 
@@ -9469,6 +9484,7 @@ static void M_ChangeControl(INT32 choice)
 	controltochange = currentMenu->menuitems[choice].alphaKey;
 	sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"),
 		currentMenu->menuitems[choice].text);
+	strncpy(controltochangetext, currentMenu->menuitems[choice].text, 55);
 
 	M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
 }
diff --git a/src/m_menu.h b/src/m_menu.h
index ad32de1b155120b2d82cacb74a17c28b7ee51207..894abbe746f7631a251c22b9ee893bfca6c1f216 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -235,7 +235,7 @@ extern INT16 startmap;
 extern INT32 ultimate_selectable;
 extern INT16 char_on, startchar;
 
-#define MAXSAVEGAMES 31 //note: last save game is "no save"
+#define MAXSAVEGAMES 31
 #define NOSAVESLOT 0 //slot where Play Without Saving appears
 
 #define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he
@@ -246,6 +246,8 @@ void M_ForceSaveSlotSelected(INT32 sslot);
 
 void M_CheatActivationResponder(INT32 ch);
 
+void M_ModeAttackRetry(INT32 choice);
+
 // Level select updating
 void Nextmap_OnChange(void);
 
diff --git a/src/m_misc.c b/src/m_misc.c
index 92c2aeea9dd3458d66edc0f8495119542859998c..fb3ffa5a70d5c75674db0e6db56cdf08fab61777 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -672,11 +672,11 @@ static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_
 static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_byte movie)
 {
 #ifdef PNG_TEXT_SUPPORTED
-#define SRB2PNGTXT 10 //PNG_KEYWORD_MAX_LENGTH(79) is the max
+#define SRB2PNGTXT 11 //PNG_KEYWORD_MAX_LENGTH(79) is the max
 	png_text png_infotext[SRB2PNGTXT];
 	char keytxt[SRB2PNGTXT][12] = {
 	"Title", "Description", "Playername", "Mapnum", "Mapname",
-	"Location", "Interface", "Revision", "Build Date", "Build Time"};
+	"Location", "Interface", "Render Mode", "Revision", "Build Date", "Build Time"};
 	char titletxt[] = "Sonic Robo Blast 2 " VERSIONSTRING;
 	png_charp playertxt =  cv_playername.zstring;
 	char desctxt[] = "SRB2 Screenshot";
@@ -692,6 +692,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 #else
 	 "Unknown";
 #endif
+	char rendermodetxt[9];
 	char maptext[8];
 	char lvlttltext[48];
 	char locationtxt[40];
@@ -699,6 +700,19 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 	char ctdate[40];
 	char cttime[40];
 
+	switch (rendermode)
+	{
+		case render_soft:
+			strcpy(rendermodetxt, "Software");
+			break;
+		case render_opengl:
+			strcpy(rendermodetxt, "OpenGL");
+			break;
+		default: // Just in case
+			strcpy(rendermodetxt, "None");
+			break;
+	}
+
 	if (gamestate == GS_LEVEL)
 		snprintf(maptext, 8, "%s", G_BuildMapName(gamemap));
 	else
@@ -736,9 +750,10 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 	png_infotext[4].text = lvlttltext;
 	png_infotext[5].text = locationtxt;
 	png_infotext[6].text = interfacetxt;
-	png_infotext[7].text = strncpy(ctrevision, comprevision, sizeof(ctrevision)-1);
-	png_infotext[8].text = strncpy(ctdate, compdate, sizeof(ctdate)-1);
-	png_infotext[9].text = strncpy(cttime, comptime, sizeof(cttime)-1);
+	png_infotext[7].text = rendermodetxt;
+	png_infotext[8].text = strncpy(ctrevision, comprevision, sizeof(ctrevision)-1);
+	png_infotext[9].text = strncpy(ctdate, compdate, sizeof(ctdate)-1);
+	png_infotext[10].text = strncpy(cttime, comptime, sizeof(cttime)-1);
 
 	png_set_text(png_ptr, png_info_ptr, png_infotext, SRB2PNGTXT);
 #undef SRB2PNGTXT
diff --git a/src/p_enemy.c b/src/p_enemy.c
index bd5b3ac19a8cb5725fe42dc1523a5a3b0d48217b..c6807f07d18c0a4ecd26ef6097f12e501a57cf54 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1,11843 +1,11872 @@
-// SONIC ROBO BLAST 2
-//-----------------------------------------------------------------------------
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-// Copyright (C) 1999-2016 by Sonic Team Junior.
-//
-// This program is free software distributed under the
-// terms of the GNU General Public License, version 2.
-// See the 'LICENSE' file for more details.
-//-----------------------------------------------------------------------------
-/// \file  p_enemy.c
-/// \brief Enemy thinking, AI
-///        Action Pointer Functions that are associated with states/frames
-
-#include "doomdef.h"
-#include "g_game.h"
-#include "p_local.h"
-#include "r_main.h"
-#include "r_state.h"
-#include "s_sound.h"
-#include "m_random.h"
-#include "m_misc.h"
-#include "r_things.h"
-#include "i_video.h"
-#include "lua_hook.h"
-
-#ifdef HW3SOUND
-#include "hardware/hw3sound.h"
-#endif
-
-#ifdef HAVE_BLUA
-boolean LUA_CallAction(const char *action, mobj_t *actor);
-#endif
-
-player_t *stplyr;
-INT32 var1;
-INT32 var2;
-
-//
-// P_NewChaseDir related LUT.
-//
-static dirtype_t opposite[] =
-{
-	DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
-	DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
-};
-
-static dirtype_t diags[] =
-{
-	DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
-};
-
-//Real Prototypes to A_*
-void A_Fall(mobj_t *actor);
-void A_Look(mobj_t *actor);
-void A_Chase(mobj_t *actor);
-void A_FaceStabChase(mobj_t *actor);
-void A_FaceStabRev(mobj_t *actor);
-void A_FaceStabHurl(mobj_t *actor);
-void A_FaceStabMiss(mobj_t *actor);
-void A_StatueBurst(mobj_t *actor);
-void A_JetJawRoam(mobj_t *actor);
-void A_JetJawChomp(mobj_t *actor);
-void A_PointyThink(mobj_t *actor);
-void A_CheckBuddy(mobj_t *actor);
-void A_HoodFire(mobj_t *actor);
-void A_HoodThink(mobj_t *actor);
-void A_HoodFall(mobj_t *actor);
-void A_ArrowBonks(mobj_t *actor);
-void A_SnailerThink(mobj_t *actor);
-void A_SharpChase(mobj_t *actor);
-void A_SharpSpin(mobj_t *actor);
-void A_SharpDecel(mobj_t *actor);
-void A_CrushstaceanWalk(mobj_t *actor);
-void A_CrushstaceanPunch(mobj_t *actor);
-void A_CrushclawAim(mobj_t *actor);
-void A_CrushclawLaunch(mobj_t *actor);
-void A_VultureVtol(mobj_t *actor);
-void A_VultureCheck(mobj_t *actor);
-void A_SkimChase(mobj_t *actor);
-void A_FaceTarget(mobj_t *actor);
-void A_FaceTracer(mobj_t *actor);
-void A_LobShot(mobj_t *actor);
-void A_FireShot(mobj_t *actor);
-void A_SuperFireShot(mobj_t *actor);
-void A_BossFireShot(mobj_t *actor);
-void A_Boss7FireMissiles(mobj_t *actor);
-void A_Boss1Laser(mobj_t *actor);
-void A_FocusTarget(mobj_t *actor);
-void A_Boss4Reverse(mobj_t *actor);
-void A_Boss4SpeedUp(mobj_t *actor);
-void A_Boss4Raise(mobj_t *actor);
-void A_SkullAttack(mobj_t *actor);
-void A_BossZoom(mobj_t *actor);
-void A_BossScream(mobj_t *actor);
-void A_Scream(mobj_t *actor);
-void A_Pain(mobj_t *actor);
-void A_1upThinker(mobj_t *actor);
-void A_MonitorPop(mobj_t *actor);
-void A_GoldMonitorPop(mobj_t *actor);
-void A_GoldMonitorRestore(mobj_t *actor);
-void A_GoldMonitorSparkle(mobj_t *actor);
-void A_Explode(mobj_t *actor);
-void A_BossDeath(mobj_t *actor);
-void A_CustomPower(mobj_t *actor);
-void A_GiveWeapon(mobj_t *actor);
-void A_RingBox(mobj_t *actor);
-void A_Invincibility(mobj_t *actor);
-void A_SuperSneakers(mobj_t *actor);
-void A_AwardScore(mobj_t *actor);
-void A_ExtraLife(mobj_t *actor);
-void A_GiveShield(mobj_t *actor);
-void A_GravityBox(mobj_t *actor);
-void A_ScoreRise(mobj_t *actor);
-void A_BunnyHop(mobj_t *actor);
-void A_BubbleSpawn(mobj_t *actor);
-void A_FanBubbleSpawn(mobj_t *actor);
-void A_BubbleRise(mobj_t *actor);
-void A_BubbleCheck(mobj_t *actor);
-void A_AttractChase(mobj_t *actor);
-void A_DropMine(mobj_t *actor);
-void A_FishJump(mobj_t *actor);
-void A_ThrownRing(mobj_t *actor);
-void A_SetSolidSteam(mobj_t *actor);
-void A_UnsetSolidSteam(mobj_t *actor);
-void A_SignPlayer(mobj_t *actor);
-void A_OverlayThink(mobj_t *actor);
-void A_JetChase(mobj_t *actor);
-void A_JetbThink(mobj_t *actor);
-void A_JetgShoot(mobj_t *actor);
-void A_JetgThink(mobj_t *actor);
-void A_ShootBullet(mobj_t *actor);
-void A_MinusDigging(mobj_t *actor);
-void A_MinusPopup(mobj_t *actor);
-void A_MinusCheck(mobj_t *actor);
-void A_ChickenCheck(mobj_t *actor);
-void A_MouseThink(mobj_t *actor);
-void A_DetonChase(mobj_t *actor);
-void A_CapeChase(mobj_t *actor);
-void A_RotateSpikeBall(mobj_t *actor);
-void A_SlingAppear(mobj_t *actor);
-void A_UnidusBall(mobj_t *actor);
-void A_RockSpawn(mobj_t *actor);
-void A_SetFuse(mobj_t *actor);
-void A_CrawlaCommanderThink(mobj_t *actor);
-void A_RingExplode(mobj_t *actor);
-void A_OldRingExplode(mobj_t *actor);
-void A_MixUp(mobj_t *actor);
-void A_RecyclePowers(mobj_t *actor);
-void A_Boss2TakeDamage(mobj_t *actor);
-void A_Boss7Chase(mobj_t *actor);
-void A_GoopSplat(mobj_t *actor);
-void A_Boss2PogoSFX(mobj_t *actor);
-void A_Boss2PogoTarget(mobj_t *actor);
-void A_EggmanBox(mobj_t *actor);
-void A_TurretFire(mobj_t *actor);
-void A_SuperTurretFire(mobj_t *actor);
-void A_TurretStop(mobj_t *actor);
-void A_SparkFollow(mobj_t *actor);
-void A_BuzzFly(mobj_t *actor);
-void A_GuardChase(mobj_t *actor);
-void A_EggShield(mobj_t *actor);
-void A_SetReactionTime(mobj_t *actor);
-void A_Boss1Spikeballs(mobj_t *actor);
-void A_Boss3TakeDamage(mobj_t *actor);
-void A_Boss3Path(mobj_t *actor);
-void A_LinedefExecute(mobj_t *actor);
-void A_PlaySeeSound(mobj_t *actor);
-void A_PlayAttackSound(mobj_t *actor);
-void A_PlayActiveSound(mobj_t *actor);
-void A_SmokeTrailer(mobj_t *actor);
-void A_SpawnObjectAbsolute(mobj_t *actor);
-void A_SpawnObjectRelative(mobj_t *actor);
-void A_ChangeAngleRelative(mobj_t *actor);
-void A_ChangeAngleAbsolute(mobj_t *actor);
-void A_PlaySound(mobj_t *actor);
-void A_FindTarget(mobj_t *actor);
-void A_FindTracer(mobj_t *actor);
-void A_SetTics(mobj_t *actor);
-void A_SetRandomTics(mobj_t *actor);
-void A_ChangeColorRelative(mobj_t *actor);
-void A_ChangeColorAbsolute(mobj_t *actor);
-void A_MoveRelative(mobj_t *actor);
-void A_MoveAbsolute(mobj_t *actor);
-void A_Thrust(mobj_t *actor);
-void A_ZThrust(mobj_t *actor);
-void A_SetTargetsTarget(mobj_t *actor);
-void A_SetObjectFlags(mobj_t *actor);
-void A_SetObjectFlags2(mobj_t *actor);
-void A_RandomState(mobj_t *actor);
-void A_RandomStateRange(mobj_t *actor);
-void A_DualAction(mobj_t *actor);
-void A_RemoteAction(mobj_t *actor);
-void A_ToggleFlameJet(mobj_t *actor);
-void A_OrbitNights(mobj_t *actor);
-void A_GhostMe(mobj_t *actor);
-void A_SetObjectState(mobj_t *actor);
-void A_SetObjectTypeState(mobj_t *actor);
-void A_KnockBack(mobj_t *actor);
-void A_PushAway(mobj_t *actor);
-void A_RingDrain(mobj_t *actor);
-void A_SplitShot(mobj_t *actor);
-void A_MissileSplit(mobj_t *actor);
-void A_MultiShot(mobj_t *actor);
-void A_InstaLoop(mobj_t *actor);
-void A_Custom3DRotate(mobj_t *actor);
-void A_SearchForPlayers(mobj_t *actor);
-void A_CheckRandom(mobj_t *actor);
-void A_CheckTargetRings(mobj_t *actor);
-void A_CheckRings(mobj_t *actor);
-void A_CheckTotalRings(mobj_t *actor);
-void A_CheckHealth(mobj_t *actor);
-void A_CheckRange(mobj_t *actor);
-void A_CheckHeight(mobj_t *actor);
-void A_CheckTrueRange(mobj_t *actor);
-void A_CheckThingCount(mobj_t *actor);
-void A_CheckAmbush(mobj_t *actor);
-void A_CheckCustomValue(mobj_t *actor);
-void A_CheckCusValMemo(mobj_t *actor);
-void A_SetCustomValue(mobj_t *actor);
-void A_UseCusValMemo(mobj_t *actor);
-void A_RelayCustomValue(mobj_t *actor);
-void A_CusValAction(mobj_t *actor);
-void A_ForceStop(mobj_t *actor);
-void A_ForceWin(mobj_t *actor);
-void A_SpikeRetract(mobj_t *actor);
-void A_InfoState(mobj_t *actor);
-void A_Repeat(mobj_t *actor);
-void A_SetScale(mobj_t *actor);
-void A_RemoteDamage(mobj_t *actor);
-void A_HomingChase(mobj_t *actor);
-void A_TrapShot(mobj_t *actor);
-void A_Boss1Chase(mobj_t *actor);
-void A_Boss2Chase(mobj_t *actor);
-void A_Boss2Pogo(mobj_t *actor);
-void A_BossJetFume(mobj_t *actor);
-void A_VileTarget(mobj_t *actor);
-void A_VileAttack(mobj_t *actor);
-void A_VileFire(mobj_t *actor);
-void A_BrakChase(mobj_t *actor);
-void A_BrakFireShot(mobj_t *actor);
-void A_BrakLobShot(mobj_t *actor);
-void A_NapalmScatter(mobj_t *actor);
-void A_SpawnFreshCopy(mobj_t *actor);
-void A_FlickySpawn(mobj_t *actor);
-void A_FlickyCenter(mobj_t *actor);
-void A_FlickyAim(mobj_t *actor);
-void A_FlickyFly(mobj_t *actor);
-void A_FlickySoar(mobj_t *actor);
-void A_FlickyCoast(mobj_t *actor);
-void A_FlickyHop(mobj_t *actor);
-void A_FlickyFlounder(mobj_t *actor);
-void A_FlickyCheck(mobj_t *actor);
-void A_FlickyHeightCheck(mobj_t *actor);
-void A_FlickyFlutter(mobj_t *actor);
-void A_FlameParticle(mobj_t *actor);
-void A_FadeOverlay(mobj_t *actor);
-void A_Boss5Jump(mobj_t *actor);
-void A_LightBeamReset(mobj_t *actor);
-void A_MineExplode(mobj_t *actor);
-void A_MineRange(mobj_t *actor);
-void A_ConnectToGround(mobj_t *actor);
-void A_SpawnParticleRelative(mobj_t *actor);
-void A_MultiShotDist(mobj_t *actor);
-void A_WhoCaresIfYourSonIsABee(mobj_t *actor);
-void A_ParentTriesToSleep(mobj_t *actor);
-void A_CryingToMomma(mobj_t *actor);
-void A_CheckFlags2(mobj_t *actor);
-//for p_enemy.c
-
-//
-// ENEMY THINKING
-// Enemies are always spawned with targetplayer = -1, threshold = 0
-// Most monsters are spawned unaware of all players, but some can be made preaware.
-//
-
-//
-// P_CheckMeleeRange
-//
-boolean P_CheckMeleeRange(mobj_t *actor)
-{
-	mobj_t *pl;
-	fixed_t dist;
-
-	if (!actor->target)
-		return false;
-
-	pl = actor->target;
-	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
-
-	if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius)
-		return false;
-
-	// check height now, so that damn crawlas cant attack
-	// you if you stand on a higher ledge.
-	if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))
-		return false;
-
-	if (!P_CheckSight(actor, actor->target))
-		return false;
-
-	return true;
-}
-
-// P_CheckMeleeRange for Jettysyn Bomber.
-boolean P_JetbCheckMeleeRange(mobj_t *actor)
-{
-	mobj_t *pl;
-	fixed_t dist;
-
-	if (!actor->target)
-		return false;
-
-	pl = actor->target;
-	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
-
-	if (dist >= (actor->radius + pl->radius)*2)
-		return false;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-	{
-		if (pl->z < actor->z + actor->height + FixedMul(40<<FRACBITS, actor->scale))
-			return false;
-	}
-	else
-	{
-		if (pl->z + pl->height > actor->z - FixedMul(40<<FRACBITS, actor->scale))
-			return false;
-	}
-
-	return true;
-}
-
-// P_CheckMeleeRange for CastleBot FaceStabber.
-boolean P_FaceStabCheckMeleeRange(mobj_t *actor)
-{
-	mobj_t *pl;
-	fixed_t dist;
-
-	if (!actor->target)
-		return false;
-
-	pl = actor->target;
-	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
-
-	if (dist >= (actor->radius + pl->radius)*4)
-		return false;
-
-	if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))
-		return false;
-
-	if (!P_CheckSight(actor, actor->target))
-		return false;
-
-	return true;
-}
-
-// P_CheckMeleeRange for Skim.
-boolean P_SkimCheckMeleeRange(mobj_t *actor)
-{
-	mobj_t *pl;
-	fixed_t dist;
-
-	if (!actor->target)
-		return false;
-
-	pl = actor->target;
-	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
-
-	if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius)
-		return false;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-	{
-		if (pl->z < actor->z + actor->height + FixedMul(24<<FRACBITS, actor->scale))
-			return false;
-	}
-	else
-	{
-		if (pl->z + pl->height > actor->z - FixedMul(24<<FRACBITS, actor->scale))
-			return false;
-	}
-
-	return true;
-}
-
-//
-// P_CheckMissileRange
-//
-boolean P_CheckMissileRange(mobj_t *actor)
-{
-	fixed_t dist;
-
-	if (!actor->target)
-		return false;
-
-	if (actor->reactiontime)
-		return false; // do not attack yet
-
-	if (!P_CheckSight(actor, actor->target))
-		return false;
-
-	// OPTIMIZE: get this from a global checksight
-	dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - FixedMul(64*FRACUNIT, actor->scale);
-
-	if (!actor->info->meleestate)
-		dist -= FixedMul(128*FRACUNIT, actor->scale); // no melee attack, so fire more
-
-	dist >>= FRACBITS;
-
-	if (actor->type == MT_EGGMOBILE)
-		dist >>= 1;
-
-	if (dist > 200)
-		dist = 200;
-
-	if (actor->type == MT_EGGMOBILE && dist > 160)
-		dist = 160;
-
-	if (P_RandomByte() < dist)
-		return false;
-
-	return true;
-}
-
-/** Checks for water in a sector.
-  * Used by Skim movements.
-  *
-  * \param x X coordinate on the map.
-  * \param y Y coordinate on the map.
-  * \return True if there's water at this location, false if not.
-  * \sa ::MT_SKIM
-  */
-static boolean P_WaterInSector(mobj_t *mobj, fixed_t x, fixed_t y)
-{
-	sector_t *sector;
-
-	sector = R_PointInSubsector(x, y)->sector;
-
-	if (sector->ffloors)
-	{
-		ffloor_t *rover;
-
-		for (rover = sector->ffloors; rover; rover = rover->next)
-		{
-			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE))
-				continue;
-
-			if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z)
-				return true; // we found water!!
-		}
-	}
-
-	return false;
-}
-
-static const fixed_t xspeed[NUMDIRS] = {FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS)), 0, 46341>>(16-FRACBITS)};
-static const fixed_t yspeed[NUMDIRS] = {0, 46341>>(16-FRACBITS), FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS))};
-
-/** Moves an actor in its current direction.
-  *
-  * \param actor Actor object to move.
-  * \return False if the move is blocked, otherwise true.
-  */
-boolean P_Move(mobj_t *actor, fixed_t speed)
-{
-	fixed_t tryx, tryy;
-	dirtype_t movedir = actor->movedir;
-
-	if (movedir == DI_NODIR || !actor->health)
-		return false;
-
-	I_Assert(movedir < NUMDIRS);
-
-	tryx = actor->x + FixedMul(speed*xspeed[movedir], actor->scale);
-	if (twodlevel || actor->flags2 & MF2_TWOD)
-		tryy = actor->y;
-	else
-		tryy = actor->y + FixedMul(speed*yspeed[movedir], actor->scale);
-
-	if (actor->type == MT_SKIM && !P_WaterInSector(actor, tryx, tryy)) // bail out if sector lacks water
-		return false;
-
-	if (!P_TryMove(actor, tryx, tryy, false))
-	{
-		if (actor->flags & MF_FLOAT && floatok)
-		{
-			// must adjust height
-			if (actor->z < tmfloorz)
-				actor->z += FixedMul(FLOATSPEED, actor->scale);
-			else
-				actor->z -= FixedMul(FLOATSPEED, actor->scale);
-
-			if (actor->type == MT_JETJAW && actor->z + actor->height > actor->watertop)
-				actor->z = actor->watertop - actor->height;
-
-			actor->flags2 |= MF2_INFLOAT;
-			return true;
-		}
-
-		return false;
-	}
-	else
-		actor->flags2 &= ~MF2_INFLOAT;
-
-	return true;
-}
-
-/** Attempts to move an actor on in its current direction.
-  * If the move succeeds, the actor's move count is reset
-  * randomly to a value from 0 to 15.
-  *
-  * \param actor Actor to move.
-  * \return True if the move succeeds, false if the move is blocked.
-  */
-static boolean P_TryWalk(mobj_t *actor)
-{
-	if (!P_Move(actor, actor->info->speed))
-		return false;
-	actor->movecount = P_RandomByte() & 15;
-	return true;
-}
-
-void P_NewChaseDir(mobj_t *actor)
-{
-	fixed_t deltax, deltay;
-	dirtype_t d[3];
-	dirtype_t tdir = DI_NODIR, olddir, turnaround;
-
-	I_Assert(actor->target != NULL);
-	I_Assert(!P_MobjWasRemoved(actor->target));
-
-	olddir = actor->movedir;
-
-	if (olddir >= NUMDIRS)
-		olddir = DI_NODIR;
-
-	if (olddir != DI_NODIR)
-		turnaround = opposite[olddir];
-	else
-		turnaround = olddir;
-
-	deltax = actor->target->x - actor->x;
-	deltay = actor->target->y - actor->y;
-
-	if (deltax > FixedMul(10*FRACUNIT, actor->scale))
-		d[1] = DI_EAST;
-	else if (deltax < -FixedMul(10*FRACUNIT, actor->scale))
-		d[1] = DI_WEST;
-	else
-		d[1] = DI_NODIR;
-
-	if (twodlevel || actor->flags2 & MF2_TWOD)
-		d[2] = DI_NODIR;
-	if (deltay < -FixedMul(10*FRACUNIT, actor->scale))
-		d[2] = DI_SOUTH;
-	else if (deltay > FixedMul(10*FRACUNIT, actor->scale))
-		d[2] = DI_NORTH;
-	else
-		d[2] = DI_NODIR;
-
-	// try direct route
-	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
-	{
-		dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)];
-
-		actor->movedir = newdir;
-		if ((newdir != turnaround) && P_TryWalk(actor))
-			return;
-	}
-
-	// try other directions
-	if (P_RandomChance(25*FRACUNIT/32) || abs(deltay) > abs(deltax))
-	{
-		tdir = d[1];
-		d[1] = d[2];
-		d[2] = tdir;
-	}
-
-	if (d[1] == turnaround)
-		d[1] = DI_NODIR;
-	if (d[2] == turnaround)
-		d[2] = DI_NODIR;
-
-	if (d[1] != DI_NODIR)
-	{
-		actor->movedir = d[1];
-
-		if (P_TryWalk(actor))
-			return; // either moved forward or attacked
-	}
-
-	if (d[2] != DI_NODIR)
-	{
-		actor->movedir = d[2];
-
-		if (P_TryWalk(actor))
-			return;
-	}
-
-	// there is no direct path to the player, so pick another direction.
-	if (olddir != DI_NODIR)
-	{
-		actor->movedir =olddir;
-
-		if (P_TryWalk(actor))
-			return;
-	}
-
-	// randomly determine direction of search
-	if (P_RandomChance(FRACUNIT/2))
-	{
-		for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
-		{
-			if (tdir != turnaround)
-			{
-				actor->movedir = tdir;
-
-				if (P_TryWalk(actor))
-					return;
-			}
-		}
-	}
-	else
-	{
-		for (tdir = DI_SOUTHEAST; tdir >= DI_EAST; tdir--)
-		{
-			if (tdir != turnaround)
-			{
-				actor->movedir = tdir;
-
-				if (P_TryWalk(actor))
-					return;
-			}
-		}
-	}
-
-	if (turnaround != DI_NODIR)
-	{
-		actor->movedir = turnaround;
-
-		if (P_TryWalk(actor))
-			return;
-	}
-
-	actor->movedir = (angle_t)DI_NODIR; // cannot move
-}
-
-/** Looks for players to chase after, aim at, or whatever.
-  *
-  * \param actor     The object looking for flesh.
-  * \param allaround Look all around? If false, only players in a 180-degree
-  *                  range in front will be spotted.
-  * \param dist      If > 0, checks distance
-  * \return True if a player is found, otherwise false.
-  * \sa P_SupermanLook4Players
-  */
-boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist)
-{
-	INT32 c = 0, stop;
-	player_t *player;
-	angle_t an;
-
-	// BP: first time init, this allow minimum lastlook changes
-	if (actor->lastlook < 0)
-		actor->lastlook = P_RandomByte();
-
-	actor->lastlook %= MAXPLAYERS;
-
-	stop = (actor->lastlook - 1) & PLAYERSMASK;
-
-	for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK)
-	{
-		// done looking
-		if (actor->lastlook == stop)
-			return false;
-
-		if (!playeringame[actor->lastlook])
-			continue;
-
-		if (c++ == 2)
-			return false;
-
-		player = &players[actor->lastlook];
-
-		if ((netgame || multiplayer) && player->spectator)
-			continue;
-
-		if (player->pflags & PF_INVIS)
-			continue; // ignore notarget
-
-		if (!player->mo || P_MobjWasRemoved(player->mo))
-			continue;
-
-		if (player->mo->health <= 0)
-			continue; // dead
-
-		if (dist > 0
-			&& P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist)
-			continue; // Too far away
-
-		if (!allaround)
-		{
-			an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle;
-			if (an > ANGLE_90 && an < ANGLE_270)
-			{
-				dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y);
-				// if real close, react anyway
-				if (dist > FixedMul(MELEERANGE, actor->scale))
-					continue; // behind back
-			}
-		}
-
-		if (!P_CheckSight(actor, player->mo))
-			continue; // out of sight
-
-		if (tracer)
-			P_SetTarget(&actor->tracer, player->mo);
-		else
-			P_SetTarget(&actor->target, player->mo);
-		return true;
-	}
-
-	//return false;
-}
-
-/** Looks for a player with a ring shield.
-  * Used by rings.
-  *
-  * \param actor Ring looking for a shield to be attracted to.
-  * \return True if a player with ring shield is found, otherwise false.
-  * \sa A_AttractChase
-  */
-static boolean P_LookForShield(mobj_t *actor)
-{
-	INT32 c = 0, stop;
-	player_t *player;
-
-	// BP: first time init, this allow minimum lastlook changes
-	if (actor->lastlook < 0)
-		actor->lastlook = P_RandomByte();
-
-	actor->lastlook %= MAXPLAYERS;
-
-	stop = (actor->lastlook - 1) & PLAYERSMASK;
-
-	for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK))
-	{
-		// done looking
-		if (actor->lastlook == stop)
-			return false;
-
-		if (!playeringame[actor->lastlook])
-			continue;
-
-		if (c++ == 2)
-			return false;
-
-		player = &players[actor->lastlook];
-
-		if (!player->mo || player->mo->health <= 0)
-			continue; // dead
-
-		//When in CTF, don't pull rings that you cannot pick up.
-		if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) ||
-			(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
-			continue;
-
-		if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
-			&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale)))
-		{
-			P_SetTarget(&actor->tracer, player->mo);
-
-			if (actor->hnext)
-				P_SetTarget(&actor->hnext->hprev, actor->hprev);
-			if (actor->hprev)
-				P_SetTarget(&actor->hprev->hnext, actor->hnext);
-
-			return true;
-		}
-	}
-
-	//return false;
-}
-
-#ifdef WEIGHTEDRECYCLER
-// Compares players to see who currently has the "best" items, etc.
-static int P_RecycleCompare(const void *p1, const void *p2)
-{
-	player_t *player1 = &players[*(const UINT8 *)p1];
-	player_t *player2 = &players[*(const UINT8 *)p2];
-
-	// Non-shooting gametypes
-	if (!G_PlatformGametype())
-	{
-		// Invincibility.
-		if (player1->powers[pw_invulnerability] > player2->powers[pw_invulnerability]) return -1;
-		else if (player2->powers[pw_invulnerability] > player1->powers[pw_invulnerability]) return 1;
-
-		// One has a shield, the other doesn't.
-		if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1;
-		else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1;
-
-		// Sneakers.
-		if (player1->powers[pw_sneakers] > player2->powers[pw_sneakers]) return -1;
-		else if (player2->powers[pw_sneakers] > player1->powers[pw_sneakers]) return 1;
-	}
-	else // Match, Team Match, CTF, Tag, Etc.
-	{
-		UINT8 player1_em = M_CountBits((UINT32)player1->powers[pw_emeralds], 7);
-		UINT8 player2_em = M_CountBits((UINT32)player2->powers[pw_emeralds], 7);
-
-		UINT8 player1_rw = M_CountBits((UINT32)player1->ringweapons, NUM_WEAPONS-1);
-		UINT8 player2_rw = M_CountBits((UINT32)player2->ringweapons, NUM_WEAPONS-1);
-
-		UINT16 player1_am = player1->powers[pw_infinityring]          // max 800
-		                  + player1->powers[pw_automaticring]         // max 300
-		                  + (player1->powers[pw_bouncering]    * 3)   // max 100
-		                  + (player1->powers[pw_explosionring] * 6)   // max 50
-		                  + (player1->powers[pw_scatterring]   * 3)   // max 100
-		                  + (player1->powers[pw_grenadering]   * 6)   // max 50
-		                  + (player1->powers[pw_railring]      * 6);  // max 50
-		UINT16 player2_am = player2->powers[pw_infinityring]          // max 800
-		                  + player2->powers[pw_automaticring]         // max 300
-		                  + (player2->powers[pw_bouncering]    * 3)   // max 100
-		                  + (player2->powers[pw_explosionring] * 6)   // max 50
-		                  + (player2->powers[pw_scatterring]   * 3)   // max 100
-		                  + (player2->powers[pw_grenadering]   * 6)   // max 50
-		                  + (player2->powers[pw_railring]      * 6);  // max 50
-
-		// Super trumps everything.
-		if (player1->powers[pw_super] && !player2->powers[pw_super]) return -1;
-		else if (player2->powers[pw_super] && !player1->powers[pw_super]) return 1;
-
-		// Emerald count if neither player is Super.
-		if (player1_em > player2_em) return -1;
-		else if (player1_em < player2_em) return 1;
-
-		// One has a shield, the other doesn't.
-		// (the likelihood of a shielded player being worse off than one without one is low.)
-		if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1;
-		else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1;
-
-		// Ring weapons count
-		if (player1_rw > player2_rw) return -1;
-		else if (player1_rw < player2_rw) return 1;
-
-		// Ring ammo if they have the same number of weapons
-		if (player1_am > player2_am) return -1;
-		else if (player1_am < player2_am) return 1;
-	}
-
-	// Identical for our purposes
-	return 0;
-}
-#endif
-
-// Handles random monitor weights via console.
-static mobjtype_t P_DoRandomBoxChances(void)
-{
-	mobjtype_t spawnchance[256];
-	INT32 numchoices = 0, i = 0;
-
-	if (!(netgame || multiplayer))
-	{
-		switch (P_RandomKey(10))
-		{
-			case 0:
-				return MT_RING_ICON;
-			case 1:
-				return MT_SNEAKERS_ICON;
-			case 2:
-				return MT_INVULN_ICON;
-			case 3:
-				return MT_WHIRLWIND_ICON;
-			case 4:
-				return MT_ELEMENTAL_ICON;
-			case 5:
-				return MT_ATTRACT_ICON;
-			case 6:
-				return MT_FORCE_ICON;
-			case 7:
-				return MT_ARMAGEDDON_ICON;
-			case 8:
-				return MT_1UP_ICON;
-			case 9:
-				return MT_EGGMAN_ICON;
-		}
-		return MT_NULL;
-	}
-
-#define QUESTIONBOXCHANCES(type, cvar) \
-for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
-	QUESTIONBOXCHANCES(MT_RING_ICON,       cv_superring);
-	QUESTIONBOXCHANCES(MT_SNEAKERS_ICON,   cv_supersneakers);
-	QUESTIONBOXCHANCES(MT_INVULN_ICON,     cv_invincibility);
-	QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON,  cv_jumpshield);
-	QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON,  cv_watershield);
-	QUESTIONBOXCHANCES(MT_ATTRACT_ICON,    cv_ringshield);
-	QUESTIONBOXCHANCES(MT_FORCE_ICON,      cv_forceshield);
-	QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield);
-	QUESTIONBOXCHANCES(MT_1UP_ICON,        cv_1up);
-	QUESTIONBOXCHANCES(MT_EGGMAN_ICON,     cv_eggmanbox);
-	QUESTIONBOXCHANCES(MT_MIXUP_ICON,      cv_teleporters);
-	QUESTIONBOXCHANCES(MT_RECYCLER_ICON,   cv_recycler);
-#undef QUESTIONBOXCHANCES
-
-	if (numchoices == 0) return MT_NULL;
-	return spawnchance[P_RandomKey(numchoices)];
-}
-
-//
-// ACTION ROUTINES
-//
-
-// Function: A_Look
-//
-// Description: Look for a player and set your target to them.
-//
-// var1:
-//		lower 16 bits = look all around
-//		upper 16 bits = distance limit
-// var2 = If 1, only change to seestate. If 2, only play seesound. If 0, do both.
-//
-void A_Look(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Look", actor))
-		return;
-#endif
-
-	if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)))
-		return;
-
-	// go into chase state
-	if (!locvar2)
-	{
-		P_SetMobjState(actor, actor->info->seestate);
-		A_PlaySeeSound(actor);
-	}
-	else if (locvar2 == 1) // Only go into seestate
-		P_SetMobjState(actor, actor->info->seestate);
-	else if (locvar2 == 2) // Only play seesound
-		A_PlaySeeSound(actor);
-}
-
-// Function: A_Chase
-//
-// Description: Chase after your target.
-//
-// var1:
-//		1 = don't check meleestate
-//		2 = don't check missilestate
-//		3 = don't check meleestate and missilestate
-// var2 = unused
-//
-void A_Chase(mobj_t *actor)
-{
-	INT32 delta;
-	INT32 locvar1 = var1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Chase", actor))
-		return;
-#endif
-
-	I_Assert(actor != NULL);
-	I_Assert(!P_MobjWasRemoved(actor));
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjStateNF(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// do not attack twice in a row
-	if (actor->flags2 & MF2_JUSTATTACKED)
-	{
-		actor->flags2 &= ~MF2_JUSTATTACKED;
-		P_NewChaseDir(actor);
-		return;
-	}
-
-	// check for melee attack
-	if (!(locvar1 & 1) && actor->info->meleestate && P_CheckMeleeRange(actor))
-	{
-		if (actor->info->attacksound)
-			S_StartAttackSound(actor, actor->info->attacksound);
-
-		P_SetMobjState(actor, actor->info->meleestate);
-		return;
-	}
-
-	// check for missile attack
-	if (!(locvar1 & 2) && actor->info->missilestate)
-	{
-		if (actor->movecount || !P_CheckMissileRange(actor))
-			goto nomissile;
-
-		P_SetMobjState(actor, actor->info->missilestate);
-		actor->flags2 |= MF2_JUSTATTACKED;
-		return;
-	}
-
-nomissile:
-	// possibly choose another target
-	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-		&& P_LookForPlayers(actor, true, false, 0))
-		return; // got a new target
-
-	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-		P_NewChaseDir(actor);
-}
-
-// Function: A_FaceStabChase
-//
-// Description: Unused variant of A_Chase for Castlebot Facestabber.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_FaceStabChase(mobj_t *actor)
-{
-	INT32 delta;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceStabChase", actor))
-		return;
-#endif
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjStateNF(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// do not attack twice in a row
-	if (actor->flags2 & MF2_JUSTATTACKED)
-	{
-		actor->flags2 &= ~MF2_JUSTATTACKED;
-		P_NewChaseDir(actor);
-		return;
-	}
-
-	// check for melee attack
-	if (actor->info->meleestate && P_FaceStabCheckMeleeRange(actor))
-	{
-		if (actor->info->attacksound)
-			S_StartAttackSound(actor, actor->info->attacksound);
-
-		P_SetMobjState(actor, actor->info->meleestate);
-		return;
-	}
-
-	// check for missile attack
-	if (actor->info->missilestate)
-	{
-		if (actor->movecount || !P_CheckMissileRange(actor))
-			goto nomissile;
-
-		P_SetMobjState(actor, actor->info->missilestate);
-		actor->flags2 |= MF2_JUSTATTACKED;
-		return;
-	}
-
-nomissile:
-	// possibly choose another target
-	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-		&& P_LookForPlayers(actor, true, false, 0))
-		return; // got a new target
-
-	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-		P_NewChaseDir(actor);
-}
-
-static void P_SharpDust(mobj_t *actor, mobjtype_t type, angle_t ang)
-{
-	mobj_t *dust;
-
-	if (!type || !P_IsObjectOnGround(actor))
-		return;
-
-	dust = P_SpawnMobjFromMobj(actor,
-			-P_ReturnThrustX(actor, ang, 16<<FRACBITS),
-			-P_ReturnThrustY(actor, ang, 16<<FRACBITS),
-			0, type);
-	P_SetObjectMomZ(dust, P_RandomRange(1, 4)<<FRACBITS, false);
-}
-
-static void P_FaceStabFlume(mobj_t *actor)
-{
-	mobj_t *flume;
-	if (leveltime & 1)
-		return;
-
-	flume = P_SpawnMobjFromMobj(actor,
-		-P_ReturnThrustX(actor, actor->angle, actor->radius),
-		-P_ReturnThrustY(actor, actor->angle, actor->radius),
-		actor->height/3,
-		MT_PARTICLE);
-	flume->destscale = actor->scale*3;
-	P_SetScale(flume, flume->destscale);
-	P_SetTarget(&flume->target, actor);
-	flume->sprite = SPR_JETF;
-	flume->frame = FF_FULLBRIGHT;
-	flume->tics = 2;
-}
-
-// Function: A_FaceStabRev
-//
-// Description: Facestabber rev action
-//
-// var1 = effective duration
-// var2 = effective nextstate
-//
-void A_FaceStabRev(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceStabRev", actor))
-		return;
-#endif
-
-	if (!actor->target)
-	{
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	actor->extravalue1 = 0;
-
-	if (!actor->reactiontime)
-	{
-		actor->reactiontime = locvar1;
-		S_StartSound(actor, actor->info->activesound);
-	}
-	else
-	{
-		if ((--actor->reactiontime) == 0)
-		{
-			S_StartSound(actor, actor->info->attacksound);
-			P_SetMobjState(actor, locvar2);
-		}
-		else
-		{
-			P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<<FRACBITS), actor->y - P_ReturnThrustY(actor, actor->angle, 2<<FRACBITS), false);
-			P_FaceStabFlume(actor);
-		}
-	}
-}
-
-// Function: A_FaceStabHurl
-//
-// Description: Facestabber hurl action
-//
-// var1 = homing strength (recommended strength between 0-8)
-// var2 = effective nextstate
-//
-void A_FaceStabHurl(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceStabHurl", actor))
-		return;
-#endif
-
-	if (actor->target)
-	{
-		angle_t visang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-		// Calculate new direction.
-		angle_t dirang = actor->angle;
-		angle_t diffang = visang - dirang;
-
-		if (locvar1) // Allow homing?
-		{
-			if (diffang > ANGLE_180)
-			{
-				angle_t workang = locvar1*(InvAngle(diffang)>>5);
-				diffang += InvAngle(workang);
-			}
-			else
-				diffang += (locvar1*(diffang>>5));
-		}
-		diffang += ANGLE_45;
-
-		// Check the sight cone.
-		if (diffang < ANGLE_90)
-		{
-			actor->angle = dirang;
-			if (++actor->extravalue2 < 4)
-				actor->extravalue2 = 4;
-			else if (actor->extravalue2 > 26)
-				actor->extravalue2 = 26;
-
-			if (P_TryMove(actor,
-				actor->x + P_ReturnThrustX(actor, dirang, actor->extravalue2<<FRACBITS),
-				actor->y + P_ReturnThrustY(actor, dirang, actor->extravalue2<<FRACBITS),
-				false))
-			{
-				// Do the spear damage.
-#define NUMSTEPS 3
-#define NUMGRADS 5
-#define MAXVAL (NUMSTEPS*NUMGRADS)
-				SINT8 step = (++actor->extravalue1);
-				fixed_t basesize = FRACUNIT/MAXVAL;
-				mobj_t *hwork = actor;
-				INT32 dist = 113;
-				fixed_t xo = P_ReturnThrustX(actor, actor->angle, dist*basesize);
-				fixed_t yo = P_ReturnThrustY(actor, actor->angle, dist*basesize);
-
-				while (step > 0)
-				{
-					if (!hwork->hnext)
-						P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR));
-					hwork = hwork->hnext;
-					hwork->angle = actor->angle + ANGLE_90;
-					hwork->destscale = FixedSqrt(step*basesize);
-					P_SetScale(hwork, hwork->destscale);
-					hwork->fuse = 2;
-					P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
-					step -= NUMGRADS;
-				}
-
-				if (actor->extravalue1 >= MAXVAL)
-					actor->extravalue1 -= NUMGRADS;
-
-				if ((step % 5) == 0)
-					P_SharpDust(actor, MT_SPINDUST, actor->angle);
-
-				P_FaceStabFlume(actor);
-				return;
-#undef MAXVAL
-#undef NUMGRADS
-#undef NUMSTEPS
-			}
-		}
-	}
-
-	P_SetMobjState(actor, locvar2);
-	actor->reactiontime = actor->info->reactiontime;
-}
-
-// Function: A_FaceStabMiss
-//
-// Description: Facestabber miss action
-//
-// var1 = unused
-// var2 = effective nextstate
-//
-void A_FaceStabMiss(mobj_t *actor)
-{
-	//INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceStabMiss", actor))
-		return;
-#endif
-
-	if (++actor->extravalue1 >= 3)
-	{
-		actor->extravalue2 -= 2;
-		actor->extravalue1 = 0;
-		S_StartSound(actor, sfx_s3k47);
-		P_SharpDust(actor, MT_SPINDUST, actor->angle);
-	}
-
-	if (actor->extravalue2 <= 0 || !P_TryMove(actor,
-		actor->x + P_ReturnThrustX(actor, actor->angle, actor->extravalue2<<FRACBITS),
-		actor->y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<<FRACBITS),
-		false))
-	{
-		actor->extravalue2 = 0;
-		P_SetMobjState(actor, locvar2);
-	}
-}
-
-// Function: A_StatueBurst
-//
-// Description: For suspicious statues only...
-//
-// var1 = object to create
-// var2 = effective nextstate for created object
-//
-void A_StatueBurst(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobjtype_t chunktype = (mobjtype_t)actor->info->raisestate;
-	mobj_t *new;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_StatueBurst", actor))
-		return;
-#endif
-
-	if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1)))
-		return;
-
-	new->angle = actor->angle;
-	new->target = actor->target;
-	if (locvar2)
-		P_SetMobjState(new, (statenum_t)locvar2);
-	S_StartSound(new, new->info->attacksound);
-	S_StopSound(actor);
-	S_StartSound(actor, sfx_s3k96);
-
-	{
-		fixed_t a, b;
-		fixed_t c = (actor->height>>2) - FixedMul(actor->scale, mobjinfo[chunktype].height>>1);
-		fixed_t v = 4<<FRACBITS;
-		const fixed_t r = (actor->radius>>1);
-		mobj_t *spawned;
-		UINT8 i;
-		for (i = 0; i < 8; i++)
-		{
-			a = ((i & 1) ? r : (-r));
-			b = ((i & 2) ? r : (-r));
-			if (i == 4)
-			{
-				c += (actor->height>>1);
-				v = 8<<FRACBITS;
-			}
-
-			spawned = P_SpawnMobjFromMobj(actor, a, b, c, chunktype);
-
-			P_InstaThrust(spawned, R_PointToAngle2(0, 0, a, b), 8<<FRACBITS);
-			P_SetObjectMomZ(spawned, v, false);
-
-			spawned->fuse = 3*TICRATE;
-		}
-	}
-}
-
-// Function: A_JetJawRoam
-//
-// Description: Roaming routine for JetJaw
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetJawRoam(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetJawRoam", actor))
-		return;
-#endif
-	if (actor->reactiontime)
-	{
-		actor->reactiontime--;
-		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed*FRACUNIT/4, actor->scale));
-	}
-	else
-	{
-		actor->reactiontime = actor->info->reactiontime;
-		actor->angle += ANGLE_180;
-	}
-
-	if (P_LookForPlayers(actor, false, false, actor->radius * 16))
-		P_SetMobjState(actor, actor->info->seestate);
-}
-
-// Function: A_JetJawChomp
-//
-// Description: Chase and chomp at the target, as long as it is in view
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetJawChomp(mobj_t *actor)
-{
-	INT32 delta;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetJawChomp", actor))
-		return;
-#endif
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	// Stop chomping if target's dead or you can't see it
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
-		|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-	{
-		P_SetMobjStateNF(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-		P_NewChaseDir(actor);
-}
-
-// Function: A_PointyThink
-//
-// Description: Thinker function for Pointy
-//
-// var1 = unused
-// var2 = unused
-//
-void A_PointyThink(mobj_t *actor)
-{
-	INT32 i;
-	player_t *player = NULL;
-	mobj_t *ball;
-	TVector v;
-	TVector *res;
-	angle_t fa;
-	fixed_t radius = FixedMul(actor->info->radius*actor->info->reactiontime, actor->scale);
-	boolean firsttime = true;
-	INT32 sign;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PointyThink", actor))
-		return;
-#endif
-	actor->momx = actor->momy = actor->momz = 0;
-
-	// Find nearest player
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (!playeringame[i] || players[i].spectator)
-			continue;
-
-		if (!players[i].mo)
-			continue;
-
-		if (!players[i].mo->health)
-			continue;
-
-		if (!P_CheckSight(actor, players[i].mo))
-			continue;
-
-		if (firsttime)
-		{
-			firsttime = false;
-			player = &players[i];
-		}
-		else
-		{
-			if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) <
-				P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y))
-				player = &players[i];
-		}
-	}
-
-	if (!player)
-		return;
-
-	// Okay, we found the closest player. Let's move based on his movement.
-	P_SetTarget(&actor->target, player->mo);
-	A_FaceTarget(actor);
-
-	if (P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) < P_AproxDistance(player->mo->x + player->mo->momx - actor->x, player->mo->y + player->mo->momy - actor->y))
-		sign = -1; // Player is moving away
-	else
-		sign = 1; // Player is moving closer
-
-	if (player->mo->momx || player->mo->momy)
-	{
-		P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y), FixedMul(actor->info->speed*sign, actor->scale));
-
-		// Rotate our spike balls
-		actor->lastlook += actor->info->damage;
-		actor->lastlook %= FINEANGLES/4;
-	}
-
-	if (!actor->tracer) // For some reason we do not have spike balls...
-		return;
-
-	// Position spike balls relative to the value of 'lastlook'.
-	ball = actor->tracer;
-
-	i = 0;
-	while (ball)
-	{
-		fa = actor->lastlook+i;
-		v[0] = FixedMul(FINECOSINE(fa),radius);
-		v[1] = 0;
-		v[2] = FixedMul(FINESINE(fa),radius);
-		v[3] = FRACUNIT;
-
-		res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->lastlook+i)));
-		M_Memcpy(&v, res, sizeof (v));
-		res = VectorMatrixMultiply(v, *RotateZMatrix(actor->angle+ANGLE_180));
-		M_Memcpy(&v, res, sizeof (v));
-
-		P_UnsetThingPosition(ball);
-		ball->x = actor->x + v[0];
-		ball->y = actor->y + v[1];
-		ball->z = actor->z + (actor->height>>1) + v[2];
-		P_SetThingPosition(ball);
-
-		ball = ball->tracer;
-		i += ANGLE_90 >> ANGLETOFINESHIFT;
-	}
-}
-
-// Function: A_CheckBuddy
-//
-// Description: Checks if target/tracer exists/has health. If not, the object removes itself.
-//
-// var1:
-//		0 = target
-//		1 = tracer
-// var2 = unused
-//
-void A_CheckBuddy(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckBuddy", actor))
-		return;
-#endif
-	if (locvar1 && (!actor->tracer || actor->tracer->health <= 0))
-		P_RemoveMobj(actor);
-	else if (!locvar1 && (!actor->target || actor->target->health <= 0))
-		P_RemoveMobj(actor);
-}
-
-// Helper function for the Robo Hood.
-// Don't ask me how it works. Nev3r made it with dark majyks.
-static void P_ParabolicMove(mobj_t *actor, fixed_t x, fixed_t y, fixed_t z, fixed_t speed)
-{
-	fixed_t dh;
-
-	x -= actor->x;
-	y -= actor->y;
-	z -= actor->z;
-
-	dh = P_AproxDistance(x, y);
-
-	actor->momx = FixedMul(FixedDiv(x, dh), speed);
-	actor->momy = FixedMul(FixedDiv(y, dh), speed);
-
-	if (!gravity)
-		return;
-
-	dh = FixedDiv(FixedMul(dh, gravity), speed);
-	actor->momz = (dh>>1) + FixedDiv(z, dh<<1);
-}
-
-// Function: A_HoodFire
-//
-// Description: Firing Robo-Hood
-//
-// var1 = object type to fire
-// var2 = unused
-//
-void A_HoodFire(mobj_t *actor)
-{
-	mobj_t *arrow;
-	INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_HoodFire", actor))
-		return;
-#endif
-
-	// Check target first.
-	if (!actor->target)
-	{
-		actor->reactiontime = actor->info->reactiontime;
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	A_FaceTarget(actor);
-
-	if (!(arrow = P_SpawnMissile(actor, actor->target, (mobjtype_t)locvar1)))
-		return;
-
-	// Set a parabolic trajectory for the arrow.
-	P_ParabolicMove(arrow, actor->target->x, actor->target->y, actor->target->z, arrow->info->speed);
-}
-
-// Function: A_HoodThink
-//
-// Description: Thinker for Robo-Hood
-//
-// var1 = unused
-// var2 = unused
-//
-void A_HoodThink(mobj_t *actor)
-{
-	fixed_t dx, dy, dz, dm;
-	boolean checksight;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_HoodThink", actor))
-		return;
-#endif
-
-	// Check target first.
-	if (!actor->target)
-	{
-		actor->reactiontime = actor->info->reactiontime;
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	dx = (actor->target->x - actor->x), dy = (actor->target->y - actor->y), dz = (actor->target->z - actor->z);
-	dm = P_AproxDistance(dx, dy);
-	// Target dangerously close to robohood, retreat then.
-	if ((dm < 256<<FRACBITS) && (abs(dz) < 128<<FRACBITS))
-	{
-		P_SetMobjState(actor, actor->info->raisestate);
-		return;
-	}
-
-	// If target on sight, look at it.
-	if ((checksight = P_CheckSight(actor, actor->target)))
-	{
-		angle_t dang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-		if (actor->angle >= ANGLE_180)
-		{
-			actor->angle = InvAngle(actor->angle)>>1;
-			actor->angle = InvAngle(actor->angle);
-		}
-		else
-			actor->angle >>= 1;
-
-		if (dang >= ANGLE_180)
-		{
-			dang = InvAngle(dang)>>1;
-			dang = InvAngle(dang);
-		}
-		else
-			dang >>= 1;
-
-		actor->angle += dang;
-	}
-
-	// Check whether to do anything.
-	if ((--actor->reactiontime) <= 0)
-	{
-		actor->reactiontime = actor->info->reactiontime;
-
-		// If way too far, don't shoot.
-		if ((dm < (3072<<FRACBITS)) && checksight)
-		{
-			P_SetMobjState(actor, actor->info->missilestate);
-			return;
-		}
-	}
-}
-
-// Function: A_HoodFall
-//
-// Description: Falling Robo-Hood
-//
-// var1 = unused
-// var2 = unused
-//
-void A_HoodFall(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_HoodFall", actor))
-		return;
-#endif
-
-	if (!P_IsObjectOnGround(actor))
-		return;
-
-	actor->momx = actor->momy = 0;
-	actor->reactiontime = actor->info->reactiontime;
-	P_SetMobjState(actor, actor->info->seestate);
-}
-
-// Function: A_ArrowBonks
-//
-// Description: Arrow momentum setting on collision
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ArrowBonks(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ArrowBonks", actor))
-		return;
-#endif
-
-	if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)
-		|| (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz))
-		actor->angle += ANGLE_180;
-
-	P_SetObjectMomZ(actor, 8*actor->scale, false);
-	P_InstaThrust(actor, actor->angle, -6*actor->scale);
-
-	actor->flags = (actor->flags|MF_NOCLIPHEIGHT) & ~MF_NOGRAVITY;
-	actor->z += P_MobjFlip(actor);
-}
-
-// Function: A_SnailerThink
-//
-// Description: Thinker function for Snailer
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SnailerThink(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SnailerThink", actor))
-		return;
-#endif
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (!P_LookForPlayers(actor, true, false, 0))
-			return;
-	}
-
-	// We now have a target. Oh bliss, rapture, and contentment!
-
-	if (actor->target->z + actor->target->height > actor->z - FixedMul(32*FRACUNIT, actor->scale)
-		&& actor->target->z < actor->z + actor->height + FixedMul(32*FRACUNIT, actor->scale)
-		&& !(leveltime % (TICRATE*2)))
-	{
-		angle_t an;
-		fixed_t z;
-
-		// Actor shouldn't face target, so we'll do things a bit differently here
-
-		an = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle;
-
-		z = actor->z + actor->height/2;
-
-		if (an > ANGLE_45 && an < ANGLE_315) // fire as close as you can to the target, even if too sharp an angle from your front
-		{
-			fixed_t dist;
-			fixed_t dx, dy;
-
-			dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y);
-
-			if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left
-			{
-				dx = actor->x + P_ReturnThrustX(actor, actor->angle + ANGLE_45, dist);
-				dy = actor->y + P_ReturnThrustY(actor, actor->angle + ANGLE_45, dist);
-			}
-			else if (an >= ANGLE_270 && an < ANGLE_315) // fire at 45 degrees to the right
-			{
-				dx = actor->x + P_ReturnThrustX(actor, actor->angle - ANGLE_45, dist);
-				dy = actor->y + P_ReturnThrustY(actor, actor->angle - ANGLE_45, dist);
-			}
-			else // fire straight ahead
-			{
-				dx = actor->x + P_ReturnThrustX(actor, actor->angle, dist);
-				dy = actor->y + P_ReturnThrustY(actor, actor->angle, dist);
-			}
-
-			P_SpawnPointMissile(actor, dx, dy, actor->target->z, MT_ROCKET, actor->x, actor->y, z);
-		}
-		else
-			P_SpawnXYZMissile(actor, actor->target, MT_ROCKET, actor->x, actor->y, z);
-	}
-
-	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z > actor->z)
-	|| (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) > (actor->z + actor->height)))
-		actor->momz += FixedMul(actor->info->speed, actor->scale);
-	else if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z < actor->z)
-	|| (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) < (actor->z + actor->height)))
-		actor->momz -= FixedMul(actor->info->speed, actor->scale);
-
-	actor->momz /= 2;
-}
-
-// Function: A_SharpChase
-//
-// Description: Thinker/Chase routine for Spincushions
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SharpChase(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SharpChase", actor))
-		return;
-#endif
-
-	if (actor->reactiontime)
-	{
-		INT32 delta;
-
-		actor->reactiontime--;
-
-		// turn towards movement direction if not there yet
-		if (actor->movedir < NUMDIRS)
-		{
-			actor->angle &= (7<<29);
-			delta = actor->angle - (actor->movedir << 29);
-
-			if (delta > 0)
-				actor->angle -= ANGLE_45;
-			else if (delta < 0)
-				actor->angle += ANGLE_45;
-		}
-
-		if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-		{
-			// look for a new target
-			if (P_LookForPlayers(actor, true, false, 0))
-				return; // got a new target
-
-			P_SetMobjState(actor, actor->info->spawnstate);
-			return;
-		}
-
-		// chase towards player
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-			P_NewChaseDir(actor);
-	}
-	else
-	{
-		actor->threshold = actor->info->painchance;
-		P_SetMobjState(actor, actor->info->missilestate);
-		S_StartSound(actor, actor->info->attacksound);
-	}
-}
-
-// Function: A_SharpSpin
-//
-// Description: Spin chase routine for Spincushions
-//
-// var1 = object # to spawn as dust (if not provided not done)
-// var2 = if nonzero, do the old-style spinning using this as the angle difference
-//
-void A_SharpSpin(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	angle_t oldang = actor->angle;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SharpSpin", actor))
-		return;
-#endif
-
-	if (actor->threshold && actor->target)
-	{
-		angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-		P_Thrust(actor, ang, actor->info->speed*actor->scale);
-		if (locvar2)
-			actor->angle += locvar2; // ANGLE_22h;
-		else
-			actor->angle = ang;
-		actor->threshold--;
-		if (leveltime & 1)
-			S_StartSound(actor, actor->info->painsound);
-	}
-	else
-	{
-		actor->reactiontime = actor->info->reactiontime;
-		P_SetMobjState(actor, actor->info->meleestate);
-	}
-
-	P_SharpDust(actor, locvar1, oldang);
-}
-
-// Function: A_SharpDecel
-//
-// Description: Slow down the Spincushion
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SharpDecel(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SharpDecel", actor))
-		return;
-#endif
-
-	if (actor->momx > 2 || actor->momy > 2)
-	{
-		actor->momx >>= 1;
-		actor->momy >>= 1;
-	}
-	else
-		P_SetMobjState(actor, actor->info->xdeathstate);
-}
-
-// Function: A_CrushstaceanWalk
-//
-// Description: Crushstacean movement
-//
-// var1 = speed (actor info's speed if 0)
-// var2 = state to switch to when blocked (spawnstate if 0)
-//
-void A_CrushstaceanWalk(mobj_t *actor)
-{
-	INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed);
-	INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate);
-	angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CrushstaceanWalk", actor))
-		return;
-#endif
-
-	actor->reactiontime--;
-
-	if (!P_TryMove(actor,
-		actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale),
-		actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale),
-		false)
-	|| (actor->reactiontime-- <= 0))
-	{
-		actor->flags2 ^= MF2_AMBUSH;
-		P_SetMobjState(actor, locvar2);
-		actor->reactiontime = actor->info->reactiontime;
-	}
-}
-
-// Function: A_CrushstaceanPunch
-//
-// Description: Crushstacean attack
-//
-// var1 = unused
-// var2 = state to go to if unsuccessful (spawnstate if 0)
-//
-void A_CrushstaceanPunch(mobj_t *actor)
-{
-	//INT32 locvar1 = var1;
-	INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CrushstaceanPunch", actor))
-		return;
-#endif
-
-	if (!actor->tracer)
-		return;
-
-	if (!actor->target)
-	{
-		P_SetMobjState(actor, locvar2);
-		return;
-	}
-
-	actor->tracer->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-	P_SetMobjState(actor->tracer, actor->tracer->info->missilestate);
-	actor->tracer->extravalue1 = actor->tracer->extravalue2 = 0;
-	S_StartSound(actor, actor->info->attacksound);
-}
-
-// Function: A_CrushclawAim
-//
-// Description: Crushstacean claw aiming
-//
-// var1 = sideways offset
-// var2 = vertical offset
-//
-void A_CrushclawAim(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *crab = actor->tracer;
-	angle_t ang;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CrushclawAim", actor))
-		return;
-#endif
-
-	if (!crab)
-	{
-		P_RemoveMobj(actor);
-		return; // there is only one step and it is crab
-	}
-
-	if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale))
-		ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y);
-	else
-		ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);
-	ang -= actor->angle;
-
-#define anglimit ANGLE_22h
-#define angfactor 5
-	if (ang < ANGLE_180)
-	{
-		if (ang > anglimit)
-			ang = anglimit;
-		ang /= angfactor;
-	}
-	else
-	{
-		ang = InvAngle(ang);
-		if (ang > anglimit)
-			ang = anglimit;
-		ang = InvAngle(ang/angfactor);
-	}
-	actor->angle += ang;
-#undef anglimit
-#undef angfactor
-
-	P_TeleportMove(actor,
-		crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale),
-		crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale),
-		crab->z + locvar2*crab->scale);
-
-	if (!crab->target || !crab->info->missilestate || (statenum_t)(crab->state-states) == crab->info->missilestate)
-		return;
-
-	if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale)
-		P_SetMobjState(crab, crab->info->missilestate);
-}
-
-// Function: A_CrushclawLaunch
-//
-// Description: Crushstacean claw launching
-//
-// var1:
-//		0 - forwards
-//		anything else - backwards
-// var2 = state to change to when done
-//
-void A_CrushclawLaunch(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *crab = actor->tracer;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CrushclawLaunch", actor))
-		return;
-#endif
-
-	if (!crab)
-	{
-		mobj_t *chainnext;
-		while (actor)
-		{
-			chainnext = actor->target;
-			P_RemoveMobj(actor);
-			actor = chainnext;
-		}
-		return; // there is only one step and it is crab
-	}
-
-	if (!actor->extravalue1)
-	{
-		S_StartSound(actor, actor->info->activesound);
-		actor->extravalue1 = ((locvar1) ? -1 : 32);
-	}
-	else if (actor->extravalue1 != 1)
-		actor->extravalue1 -= 1;
-
-#define CSEGS 5
-	if (!actor->target)
-	{
-		mobj_t *prevchain = actor;
-		UINT8 i = 0;
-		for (i = 0; (i < CSEGS); i++)
-		{
-			mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate);
-			prevchain->target = newchain;
-			prevchain = newchain;
-		}
-		actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y);
-	}
-
-	if ((!locvar1) && crab->target)
-	{
-#define anglimit ANGLE_22h
-#define angfactor 7
-		angle_t ang = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y) - actor->target->angle;
-		if (ang < ANGLE_180)
-		{
-			if (ang > anglimit)
-				ang = anglimit;
-			ang /= angfactor;
-		}
-		else
-		{
-			ang = InvAngle(ang);
-			if (ang > anglimit)
-				ang = anglimit;
-			ang /= angfactor;
-			ang = InvAngle(ang);
-		}
-		actor->target->angle += ang;
-		actor->angle = actor->target->angle;
-	}
-
-	actor->extravalue2 += actor->extravalue1;
-
-	if (!P_TryMove(actor,
-		actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale),
-		actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale),
-		true)
-		&& !locvar1)
-	{
-		actor->extravalue1 = 0;
-		actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS;
-		P_SetMobjState(actor, locvar2);
-		S_StopSound(actor);
-		S_StartSound(actor, sfx_s3k49);
-	}
-	else
-	{
-		actor->z = actor->target->z;
-		if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16)))
-		{
-			if (locvar1) // In case of retracting, resume crab and remove the chain.
-			{
-				mobj_t *chain = actor->target, *chainnext;
-				while (chain)
-				{
-					chainnext = chain->target;
-					P_RemoveMobj(chain);
-					chain = chainnext;
-				}
-				actor->extravalue2 = 0;
-				actor->angle = R_PointToAngle2(crab->x, crab->y, actor->x, actor->y);
-				P_SetTarget(&actor->target, NULL);
-				P_SetTarget(&crab->target, NULL);
-				P_SetMobjState(crab, crab->state->nextstate);
-			}
-			actor->extravalue1 = 0;
-			P_SetMobjState(actor, locvar2);
-			S_StopSound(actor);
-			if (!locvar1)
-				S_StartSound(actor, sfx_s3k64);
-		}
-	}
-
-	if (!actor->target)
-		return;
-
-	{
-		mobj_t *chain = actor->target->target;
-		fixed_t dx = (actor->x - actor->target->x)/CSEGS, dy = (actor->y - actor->target->y)/CSEGS, dz = (actor->z - actor->target->z)/CSEGS;
-		fixed_t idx = dx, idy = dy, idz = dz;
-		while (chain)
-		{
-			P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz);
-			chain->watertop = chain->z;
-			idx += dx;
-			idy += dy;
-			idz += dz;
-			chain = chain->target;
-		}
-	}
-#undef CSEGS
-}
-
-// Function: A_VultureVtol
-//
-// Description: Vulture rising up to match target's height
-//
-// var1 = unused
-// var2 = unused
-//
-void A_VultureVtol(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_VultureVtol", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	actor->flags |= MF_NOGRAVITY;
-	actor->flags |= MF_FLOAT;
-
-	A_FaceTarget(actor);
-
-	S_StopSound(actor);
-
-	if (actor->z < actor->target->z+(actor->target->height/4) && actor->z + actor->height < actor->ceilingz)
-		actor->momz = FixedMul(2*FRACUNIT, actor->scale);
-	else if (actor->z > (actor->target->z+(actor->target->height/4)*3) && actor->z > actor->floorz)
-		actor->momz = FixedMul(-2*FRACUNIT, actor->scale);
-	else
-	{
-		// Attack!
-		actor->momz = 0;
-		P_SetMobjState(actor, actor->info->missilestate);
-		S_StartSound(actor, actor->info->activesound);
-	}
-}
-
-// Function: A_VultureCheck
-//
-// Description: If the vulture is stopped, look for a new target
-//
-// var1 = unused
-// var2 = unused
-//
-void A_VultureCheck(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_VultureCheck", actor))
-		return;
-#endif
-
-	if (actor->momx || actor->momy)
-		return;
-
-	actor->flags &= ~MF_NOGRAVITY; // Fall down
-
-	if (actor->z <= actor->floorz)
-	{
-		actor->angle -= ANGLE_180; // turn around
-		P_SetMobjState(actor, actor->info->spawnstate);
-	}
-}
-
-// Function: A_SkimChase
-//
-// Description: Thinker/Chase routine for Skims
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SkimChase(mobj_t *actor)
-{
-	INT32 delta;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SkimChase", actor))
-		return;
-#endif
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		P_LookForPlayers(actor, true, false, 0);
-
-		// the spawnstate for skims already calls this function so just return either way
-		// without changing state
-		return;
-	}
-
-	// do not attack twice in a row
-	if (actor->flags2 & MF2_JUSTATTACKED)
-	{
-		actor->flags2 &= ~MF2_JUSTATTACKED;
-		P_NewChaseDir(actor);
-		return;
-	}
-
-	// check for melee attack
-	if (actor->info->meleestate && P_SkimCheckMeleeRange(actor))
-	{
-		if (actor->info->attacksound)
-			S_StartAttackSound(actor, actor->info->attacksound);
-
-		P_SetMobjState(actor, actor->info->meleestate);
-		return;
-	}
-
-	// check for missile attack
-	if (actor->info->missilestate)
-	{
-		if (actor->movecount || !P_CheckMissileRange(actor))
-			goto nomissile;
-
-		P_SetMobjState(actor, actor->info->missilestate);
-		actor->flags2 |= MF2_JUSTATTACKED;
-		return;
-	}
-
-nomissile:
-	// possibly choose another target
-	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-		&& P_LookForPlayers(actor, true, false, 0))
-		return; // got a new target
-
-	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-		P_NewChaseDir(actor);
-}
-
-// Function: A_FaceTarget
-//
-// Description: Immediately turn to face towards your target.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_FaceTarget(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceTarget", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-}
-
-// Function: A_FaceTracer
-//
-// Description: Immediately turn to face towards your tracer.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_FaceTracer(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FaceTracer", actor))
-		return;
-#endif
-	if (!actor->tracer)
-		return;
-
-	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
-}
-
-// Function: A_LobShot
-//
-// Description: Lob an object at your target.
-//
-// var1 = object # to lob
-// var2:
-//		var2 >> 16 = height offset
-//		var2 & 65535 = airtime
-//
-void A_LobShot(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2 >> 16;
-	mobj_t *shot, *hitspot;
-	angle_t an;
-	fixed_t z;
-	fixed_t dist;
-	fixed_t vertical, horizontal;
-	fixed_t airtime = var2 & 65535;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_LobShot", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-	{
-		z = actor->z + actor->height - FixedMul(locvar2*FRACUNIT, actor->scale);
-		if (actor->type == MT_BLACKEGGMAN)
-			z -= FixedMul(mobjinfo[locvar1].height, actor->scale/2);
-		else
-			z -= FixedMul(mobjinfo[locvar1].height, actor->scale);
-	}
-	else
-		z = actor->z + FixedMul(locvar2*FRACUNIT, actor->scale);
-
-	shot = P_SpawnMobj(actor->x, actor->y, z, locvar1);
-
-	if (actor->type == MT_BLACKEGGMAN)
-	{
-		shot->destscale = actor->scale/2;
-		P_SetScale(shot, actor->scale/2);
-	}
-	else
-	{
-		shot->destscale = actor->scale;
-		P_SetScale(shot, actor->scale);
-	}
-
-	// Keep track of where it's going to land
-	hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL);
-	hitspot->tics = airtime;
-	P_SetTarget(&shot->tracer, hitspot);
-
-	P_SetTarget(&shot->target, actor); // where it came from
-
-	shot->angle = an = actor->angle;
-	an >>= ANGLETOFINESHIFT;
-
-	dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y);
-
-	horizontal = dist / airtime;
-	vertical = FixedMul((gravity*airtime)/2, shot->scale);
-
-	shot->momx = FixedMul(horizontal, FINECOSINE(an));
-	shot->momy = FixedMul(horizontal, FINESINE(an));
-	shot->momz = vertical;
-
-/* Try to adjust when destination is not the same height
-	if (actor->z != actor->target->z)
-	{
-		fixed_t launchhyp;
-		fixed_t diff;
-		fixed_t orig;
-
-		diff = actor->z - actor->target->z;
-		{
-			launchhyp = P_AproxDistance(horizontal, vertical);
-
-			orig = FixedMul(FixedDiv(vertical, horizontal), diff);
-
-			CONS_Debug(DBG_GAMELOGIC, "orig: %d\n", (orig)>>FRACBITS);
-
-			horizontal = dist / airtime;
-			vertical = (gravity*airtime)/2;
-		}
-		dist -= orig;
-		shot->momx = FixedMul(horizontal, FINECOSINE(an));
-		shot->momy = FixedMul(horizontal, FINESINE(an));
-		shot->momz = vertical;
-*/
-
-	if (shot->info->seesound)
-		S_StartSound(shot, shot->info->seesound);
-
-	if (!(actor->flags & MF_BOSS))
-	{
-		if (ultimatemode)
-			actor->reactiontime = actor->info->reactiontime*TICRATE;
-		else
-			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-	}
-}
-
-// Function: A_FireShot
-//
-// Description: Shoot an object at your target.
-//
-// var1 = object # to shoot
-// var2 = height offset
-//
-void A_FireShot(mobj_t *actor)
-{
-	fixed_t z;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FireShot", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-
-	P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z);
-
-	if (!(actor->flags & MF_BOSS))
-	{
-		if (ultimatemode)
-			actor->reactiontime = actor->info->reactiontime*TICRATE;
-		else
-			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-	}
-}
-
-// Function: A_SuperFireShot
-//
-// Description: Shoot an object at your target that will even stall Super Sonic.
-//
-// var1 = object # to shoot
-// var2 = height offset
-//
-void A_SuperFireShot(mobj_t *actor)
-{
-	fixed_t z;
-	mobj_t *mo;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SuperFireShot", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-
-	mo = P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z);
-
-	if (mo)
-		mo->flags2 |= MF2_SUPERFIRE;
-
-	if (!(actor->flags & MF_BOSS))
-	{
-		if (ultimatemode)
-			actor->reactiontime = actor->info->reactiontime*TICRATE;
-		else
-			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-	}
-}
-
-// Function: A_BossFireShot
-//
-// Description: Shoot an object at your target ala Bosses:
-//
-// var1 = object # to shoot
-// var2:
-//		0 - Boss 1 Left side
-//		1 - Boss 1 Right side
-//		2 - Boss 3 Left side upper
-//		3 - Boss 3 Left side lower
-//		4 - Boss 3 Right side upper
-//		5 - Boss 3 Right side lower
-//
-void A_BossFireShot(mobj_t *actor)
-{
-	fixed_t x, y, z;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BossFireShot", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	switch (locvar2)
-	{
-		case 0:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(48*FRACUNIT, actor->scale);
-			break;
-		case 1:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(48*FRACUNIT, actor->scale);
-			break;
-		case 2:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(42*FRACUNIT, actor->scale);
-			break;
-		case 3:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(30*FRACUNIT, actor->scale);
-			break;
-		case 4:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(42*FRACUNIT, actor->scale);
-			break;
-		case 5:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale);
-			else
-				z = actor->z + FixedMul(30*FRACUNIT, actor->scale);
-			break;
-		default:
-			x = actor->x;
-			y = actor->y;
-			z = actor->z + actor->height/2;
-			break;
-	}
-
-	P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
-}
-
-// Function: A_Boss7FireMissiles
-//
-// Description: Shoot 4 missiles of a specific object type at your target ala Black Eggman
-//
-// var1 = object # to shoot
-// var2 = firing sound
-//
-void A_Boss7FireMissiles(mobj_t *actor)
-{
-	mobj_t dummymo;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss7FireMissiles", actor))
-		return;
-#endif
-
-	if (!actor->target)
-	{
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	A_FaceTarget(actor);
-
-	S_StartSound(NULL, locvar2);
-
-	// set dummymo's coordinates
-	dummymo.x = actor->target->x;
-	dummymo.y = actor->target->y;
-	dummymo.z = actor->target->z + FixedMul(16*FRACUNIT, actor->scale); // raised height
-
-	P_SpawnXYZMissile(actor, &dummymo, locvar1,
-		actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->z + FixedDiv(actor->height, 3*FRACUNIT/2));
-
-	P_SpawnXYZMissile(actor, &dummymo, locvar1,
-		actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->z + FixedDiv(actor->height, 3*FRACUNIT/2));
-
-	P_SpawnXYZMissile(actor, &dummymo, locvar1,
-		actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->z + actor->height/2);
-
-	P_SpawnXYZMissile(actor, &dummymo, locvar1,
-		actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
-		actor->z + actor->height/2);
-}
-
-// Function: A_Boss1Laser
-//
-// Description: Shoot an object at your target ala Bosses:
-//
-// var1 = object # to shoot
-// var2:
-//		0 - Boss 1 Left side
-//		1 - Boss 1 Right side
-//
-void A_Boss1Laser(mobj_t *actor)
-{
-	fixed_t x, y, z, floorz, speed;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	INT32 i;
-	angle_t angle;
-	mobj_t *point;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss1Laser", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	switch (locvar2)
-	{
-		case 0:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height;
-			else
-				z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
-			break;
-		case 1:
-			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
-			if (actor->eflags & MFE_VERTICALFLIP)
-				z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height;
-			else
-				z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
-			break;
-		default:
-			x = actor->x;
-			y = actor->y;
-			z = actor->z + actor->height/2;
-			break;
-	}
-
-	if (!(actor->flags2 & MF2_FIRING))
-	{
-		actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);
-		if (mobjinfo[locvar1].seesound)
-			S_StartSound(actor, mobjinfo[locvar1].seesound);
-		if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
-		{
-			point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET);
-			point->angle = actor->angle;
-			point->fuse = actor->tics+1;
-			P_SetTarget(&point->target, actor->target);
-			P_SetTarget(&actor->target, point);
-		}
-	}
-	/* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path
-	else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
-		actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/
-
-	if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)
-		angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT);
-	else
-		angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y));
-	point = P_SpawnMobj(x, y, z, locvar1);
-	P_SetTarget(&point->target, actor);
-	point->angle = actor->angle;
-	speed = point->radius*2;
-	point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed);
-	point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed));
-	point->momy = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINESINE(point->angle>>ANGLETOFINESHIFT), speed));
-
-	for (i = 0; i < 256; i++)
-	{
-		mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type);
-		mo->angle = point->angle;
-		P_UnsetThingPosition(mo);
-		mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY;
-		P_SetThingPosition(mo);
-
-		x = point->x, y = point->y, z = point->z;
-		if (P_RailThinker(point))
-			break;
-	}
-
-	floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height);
-	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
-	{
-		point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
-		point->target = actor;
-		point->destscale = 3*FRACUNIT;
-		point->scalespeed = FRACUNIT>>2;
-		point->fuse = TICRATE;
-	}
-
-	if (actor->tics > 1)
-		actor->flags2 |= MF2_FIRING;
-	else
-		actor->flags2 &= ~MF2_FIRING;
-}
-
-// Function: A_FocusTarget
-//
-// Description: Home in on your target.
-//
-// var1:
-//		0 - accelerative focus with friction
-//		1 - steady focus with fixed movement speed
-//      anything else - don't move
-// var2:
-//		0 - don't trace target, just move forwards
-//      & 1 - change horizontal angle
-//      & 2 - change vertical angle
-//
-void A_FocusTarget(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FocusTarget", actor))
-		return;
-#endif
-
-	if (actor->target)
-	{
-		fixed_t speed = FixedMul(actor->info->speed, actor->scale);
-		fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1);
-		angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle);
-		angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90);
-		switch(locvar1)
-		{
-		case 0:
-			{
-				actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4;
-				actor->momz += FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed);
-				actor->momx += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed));
-				actor->momy += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed));
-			}
-			break;
-		case 1:
-			if (dist > speed)
-			{
-				actor->momz = FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed);
-				actor->momx = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed));
-				actor->momy = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed));
-			}
-			else
-			{
-				actor->momx = 0, actor->momy = 0, actor->momz = 0;
-				actor->z = actor->target->z + (actor->target->height>>1);
-				P_TryMove(actor, actor->target->x, actor->target->y, true);
-			}
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-// Function: A_Boss4Reverse
-//
-// Description: Reverse arms direction.
-//
-// var1 = sfx to play
-// var2 = unused
-//
-void A_Boss4Reverse(mobj_t *actor)
-{
-	sfxenum_t locvar1 = (sfxenum_t)var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss4Reverse", actor))
-		return;
-#endif
-	S_StartSound(NULL, locvar1);
-	actor->reactiontime = 0;
-	if (actor->movedir == 1)
-		actor->movedir = 2;
-	else
-		actor->movedir = 1;
-}
-
-// Function: A_Boss4SpeedUp
-//
-// Description: Speed up arms
-//
-// var1 = sfx to play
-// var2 = unused
-//
-void A_Boss4SpeedUp(mobj_t *actor)
-{
-	sfxenum_t locvar1 = (sfxenum_t)var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss4SpeedUp", actor))
-		return;
-#endif
-	S_StartSound(NULL, locvar1);
-	actor->reactiontime = 2;
-}
-
-// Function: A_Boss4Raise
-//
-// Description: Raise helmet
-//
-// var1 = sfx to play
-// var2 = unused
-//
-void A_Boss4Raise(mobj_t *actor)
-{
-	sfxenum_t locvar1 = (sfxenum_t)var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss4Raise", actor))
-		return;
-#endif
-	S_StartSound(NULL, locvar1);
-	actor->reactiontime = 1;
-}
-
-// Function: A_SkullAttack
-//
-// Description: Fly at the player like a missile.
-//
-// var1:
-//		0 - Fly at the player
-//		1 - Fly away from the player
-//		2 - Strafe in relation to the player
-// var2:
-//		0 - Fly horizontally and vertically
-//		1 - Fly horizontal-only (momz = 0)
-//
-#define SKULLSPEED (20*FRACUNIT)
-
-void A_SkullAttack(mobj_t *actor)
-{
-	mobj_t *dest;
-	angle_t an;
-	INT32 dist;
-	INT32 speed;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SkullAttack", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	speed = FixedMul(SKULLSPEED, actor->scale);
-
-	dest = actor->target;
-	actor->flags2 |= MF2_SKULLFLY;
-	if (actor->info->activesound)
-		S_StartSound(actor, actor->info->activesound);
-	A_FaceTarget(actor);
-
-	if (locvar1 == 1)
-		actor->angle += ANGLE_180;
-	else if (locvar1 == 2)
-		actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90;
-
-	an = actor->angle >> ANGLETOFINESHIFT;
-
-	actor->momx = FixedMul(speed, FINECOSINE(an));
-	actor->momy = FixedMul(speed, FINESINE(an));
-	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
-	dist = dist / speed;
-
-	if (dist < 1)
-		dist = 1;
-
-	actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist;
-
-	if (locvar1 == 1)
-		actor->momz = -actor->momz;
-	if (locvar2 == 1)
-		actor->momz = 0;
-}
-
-// Function: A_BossZoom
-//
-// Description: Like A_SkullAttack, but used by Boss 1.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_BossZoom(mobj_t *actor)
-{
-	mobj_t *dest;
-	angle_t an;
-	INT32 dist;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BossZoom", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	dest = actor->target;
-	actor->flags2 |= MF2_SKULLFLY;
-	if (actor->info->attacksound)
-		S_StartAttackSound(actor, actor->info->attacksound);
-	A_FaceTarget(actor);
-	an = actor->angle >> ANGLETOFINESHIFT;
-	actor->momx = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINECOSINE(an));
-	actor->momy = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINESINE(an));
-	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
-	dist = dist / FixedMul(actor->info->speed*5*FRACUNIT, actor->scale);
-
-	if (dist < 1)
-		dist = 1;
-	actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist;
-}
-
-// Function: A_BossScream
-//
-// Description: Spawns explosions and plays appropriate sounds around the defeated boss.
-//
-// var1:
-//		0 - Use movecount to spawn explosions evenly
-//		1 - Use P_Random to spawn explosions at complete random
-// var2 = Object to spawn. Default is MT_BOSSEXPLODE.
-//
-void A_BossScream(mobj_t *actor)
-{
-	mobj_t *mo;
-	fixed_t x, y, z;
-	angle_t fa;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobjtype_t explodetype;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BossScream", actor))
-		return;
-#endif
-	switch (locvar1)
-	{
-	default:
-	case 0:
-		actor->movecount += 4*16;
-		actor->movecount %= 360;
-		fa = (FixedAngle(actor->movecount*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
-		break;
-	case 1:
-		fa = (FixedAngle(P_RandomKey(360)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
-		break;
-	}
-	x = actor->x + FixedMul(FINECOSINE(fa),actor->radius);
-	y = actor->y + FixedMul(FINESINE(fa),actor->radius);
-
-	// Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default.
-	if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES)
-		explodetype = MT_BOSSEXPLODE;
-	else
-		explodetype = (mobjtype_t)locvar2;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - mobjinfo[explodetype].height - FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale);
-
-	mo = P_SpawnMobj(x, y, z, explodetype);
-	if (actor->eflags & MFE_VERTICALFLIP)
-		mo->flags2 |= MF2_OBJECTFLIP;
-	mo->destscale = actor->scale;
-	P_SetScale(mo, mo->destscale);
-	if (actor->info->deathsound)
-		S_StartSound(mo, actor->info->deathsound);
-}
-
-// Function: A_Scream
-//
-// Description: Starts the death sound of the object.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Scream(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Scream", actor))
-		return;
-#endif
-	if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL))
-		S_StartScreamSound(actor, sfx_mario2);
-	else if (actor->info->deathsound)
-		S_StartScreamSound(actor, actor->info->deathsound);
-}
-
-// Function: A_Pain
-//
-// Description: Starts the pain sound of the object.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Pain(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Pain", actor))
-		return;
-#endif
-	if (actor->info->painsound)
-		S_StartSound(actor, actor->info->painsound);
-
-	actor->flags2 &= ~MF2_FIRING;
-	actor->flags2 &= ~MF2_SUPERFIRE;
-}
-
-// Function: A_Fall
-//
-// Description: Changes a dying object's flags to reflect its having fallen to the ground.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Fall(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Fall", actor))
-		return;
-#endif
-	// actor is on ground, it can be walked over
-	actor->flags &= ~MF_SOLID;
-
-	// fall through the floor
-	actor->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY;
-
-	// So change this if corpse objects
-	// are meant to be obstacles.
-}
-
-#define LIVESBOXDISPLAYPLAYER // Use displayplayer instead of closest player
-
-// Function: A_1upThinker
-//
-// Description: Used by the 1up box to show the player's face.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_1upThinker(mobj_t *actor)
-{
-	INT32 i;
-	fixed_t dist = INT32_MAX;
-	fixed_t temp;
-	INT32 closestplayer = -1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_1upThinker", actor))
-		return;
-#endif
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (!playeringame[i] || players[i].bot || players[i].spectator)
-			continue;
-
-		if (!players[i].mo)
-			continue;
-
-		if ((netgame || multiplayer) && players[i].playerstate != PST_LIVE)
-			continue;
-
-		temp = P_AproxDistance(players[i].mo->x-actor->x, players[i].mo->y-actor->y);
-
-		if (temp < dist)
-		{
-			closestplayer = i;
-			dist = temp;
-		}
-	}
-
-	if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0)
-	{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
-		if (actor->tracer) {
-			P_RemoveMobj(actor->tracer);
-			actor->tracer = NULL;
-		}
-		return;
-	}
-
-	// We're using the overlay, so use the overlay 1up box (no text)
-	actor->sprite = SPR_TV1P;
-
-	if (!actor->tracer)
-	{
-		P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY));
-		P_SetTarget(&actor->tracer->target, actor);
-		actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame
-		P_SetMobjState(actor->tracer, actor->info->seestate);
-
-		// The overlay is going to be one tic early turning off and on
-		// because it's going to get its thinker run the frame we spawned it.
-		// So make it take one tic longer if it just spawned.
-		++actor->tracer->tics;
-	}
-
-	actor->tracer->color = players[closestplayer].mo->color;
-	actor->tracer->skin = &skins[players[closestplayer].skin];
-}
-
-// Function: A_MonitorPop
-//
-// Description: Used by monitors when they explode.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MonitorPop(mobj_t *actor)
-{
-	mobjtype_t item = 0;
-	mobj_t *newmobj;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MonitorPop", actor))
-		return;
-#endif
-
-	// Spawn the "pop" explosion.
-	if (actor->info->deathsound)
-		S_StartSound(actor, actor->info->deathsound);
-	P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE);
-
-	// We're dead now. De-solidify.
-	actor->health = 0;
-	P_UnsetThingPosition(actor);
-	actor->flags &= ~MF_SOLID;
-	actor->flags |= MF_NOCLIP;
-	P_SetThingPosition(actor);
-
-	if (actor->info->damage == MT_UNKNOWN)
-	{
-		// MT_UNKNOWN is random. Because it's unknown to us... get it?
-		item = P_DoRandomBoxChances();
-
-		if (item == MT_NULL)
-		{
-			CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
-			return;
-		}
-	}
-	else
-		item = actor->info->damage;
-
-	if (item == 0)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n");
-		return;
-	}
-
-	newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item);
-	P_SetTarget(&newmobj->target, actor->target); // Transfer target
-
-	if (item == MT_1UP_ICON)
-	{
-		if (actor->tracer) // Remove the old lives icon.
-			P_RemoveMobj(actor->tracer);
-
-		if (!newmobj->target
-		 || !newmobj->target->player
-		 || !newmobj->target->skin
-		 || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
-			{} // No lives icon for this player, use the default.
-		else
-		{ // Spawn the lives icon.
-			mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
-			P_SetTarget(&livesico->target, newmobj);
-			P_SetTarget(&newmobj->tracer, livesico);
-
-			livesico->color = newmobj->target->player->mo->color;
-			livesico->skin = &skins[newmobj->target->player->skin];
-			P_SetMobjState(livesico, newmobj->info->seestate);
-
-			// We're using the overlay, so use the overlay 1up sprite (no text)
-			newmobj->sprite = SPR_TV1P;
-		}
-	}
-
-	// Run a linedef executor immediately upon popping
-	// You may want to delay your effects by 18 tics to sync with the reward giving
-	if (actor->spawnpoint && actor->lastlook)
-		P_LinedefExecute(actor->lastlook, actor->target, NULL);
-}
-
-// Function: A_GoldMonitorPop
-//
-// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know...
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GoldMonitorPop(mobj_t *actor)
-{
-	mobjtype_t item = 0;
-	mobj_t *newmobj;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GoldMonitorPop", actor))
-		return;
-#endif
-
-	// Don't spawn the "pop" explosion, because the monitor isn't broken.
-	if (actor->info->deathsound)
-		S_StartSound(actor, actor->info->deathsound);
-	//P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE);
-
-	// Remove our flags for a bit.
-	// Players can now stand on top of us.
-	P_UnsetThingPosition(actor);
-	actor->flags  &= ~(MF_MONITOR|MF_SHOOTABLE);
-	P_SetThingPosition(actor);
-
-	// Don't count this box in statistics. Sorry.
-	if (actor->target && actor->target->player)
-		--actor->target->player->numboxes;
-	actor->fuse = 0; // Don't let the monitor code screw us up.
-
-	if (actor->info->damage == MT_UNKNOWN)
-	{
-		// MT_UNKNOWN is random. Because it's unknown to us... get it?
-		item = P_DoRandomBoxChances();
-
-		if (item == MT_NULL)
-		{
-			CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
-			return;
-		}
-	}
-	else
-		item = actor->info->damage;
-
-	if (item == 0)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n");
-		return;
-	}
-
-	// Note: the icon spawns 1 fracunit higher
-	newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item);
-	P_SetTarget(&newmobj->target, actor->target); // Transfer target
-
-	if (item == MT_1UP_ICON)
-	{
-		if (actor->tracer) // Remove the old lives icon.
-			P_RemoveMobj(actor->tracer);
-
-		if (!newmobj->target
-		 || !newmobj->target->player
-		 || !newmobj->target->skin
-		 || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
-			{} // No lives icon for this player, use the default.
-		else
-		{ // Spawn the lives icon.
-			mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
-			P_SetTarget(&livesico->target, newmobj);
-			P_SetTarget(&newmobj->tracer, livesico);
-
-			livesico->color = newmobj->target->player->mo->color;
-			livesico->skin = &skins[newmobj->target->player->skin];
-			P_SetMobjState(livesico, newmobj->info->seestate);
-
-			// We're using the overlay, so use the overlay 1up sprite (no text)
-			newmobj->sprite = SPR_TV1P;
-		}
-	}
-
-	// Run a linedef executor immediately upon popping
-	// You may want to delay your effects by 18 tics to sync with the reward giving
-	if (actor->spawnpoint && actor->lastlook)
-		P_LinedefExecute(actor->lastlook, actor->target, NULL);
-}
-
-// Function: A_GoldMonitorRestore
-//
-// Description: A repeating monitor is coming back to life. Reset monitor flags, etc.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GoldMonitorRestore(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GoldMonitorRestore", actor))
-		return;
-#endif
-
-	actor->flags |= MF_MONITOR|MF_SHOOTABLE;
-	actor->health = 1; // Just in case.
-}
-
-// Function: A_GoldMonitorSparkle
-//
-// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it?
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GoldMonitorSparkle(mobj_t *actor)
-{
-	fixed_t i, ngangle, xofs, yofs;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GoldMonitorSparkle", actor))
-		return;
-#endif
-
-	ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS);
-	xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK)   * (actor->radius>>FRACBITS);
-	yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS);
-
-	for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2)
-		P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false);
-}
-
-// Function: A_Explode
-//
-// Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range.
-//
-// var1 = damagetype
-// var2 = unused
-//
-void A_Explode(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Explode", actor))
-		return;
-#endif
-	P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1);
-}
-
-// Function: A_BossDeath
-//
-// Description: Possibly trigger special effects when boss dies.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_BossDeath(mobj_t *mo)
-{
-	thinker_t *th;
-	mobj_t *mo2;
-	line_t junk;
-	INT32 i;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BossDeath", mo))
-		return;
-#endif
-
-	P_LinedefExecute(LE_BOSSDEAD, mo, NULL);
-	mo->health = 0;
-
-	// Boss is dead (but not necessarily fleeing...)
-	// Lua may use this to ignore bosses after they start fleeing
-	mo->flags2 |= MF2_BOSSDEAD;
-
-	// make sure there is a player alive for victory
-	for (i = 0; i < MAXPLAYERS; i++)
-		if (playeringame[i] && ((players[i].mo && players[i].mo->health)
-			|| ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
-			break;
-
-	if (i == MAXPLAYERS)
-		return; // no one left alive, so do not end game
-
-	// scan the remaining thinkers to see
-	// if all bosses are dead
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-		if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0)
-			goto bossjustdie; // other boss not dead - just go straight to dying!
-	}
-
-	// victory!
-	P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL);
-	if (mo->flags2 & MF2_BOSSNOTRAP)
-	{
-		for (i = 0; i < MAXPLAYERS; i++)
-			P_DoPlayerExit(&players[i]);
-	}
-	else
-	{
-		// Bring the egg trap up to the surface
-		junk.tag = 680;
-		EV_DoElevator(&junk, elevateHighest, false);
-		junk.tag = 681;
-		EV_DoElevator(&junk, elevateUp, false);
-		junk.tag = 682;
-		EV_DoElevator(&junk, elevateHighest, false);
-
-		if (mapheaderinfo[gamemap-1]->muspostbossname[0] &&
-			S_MusicExists(mapheaderinfo[gamemap-1]->muspostbossname, !midi_disabled, !digital_disabled))
-		{
-			// Touching the egg trap button calls P_DoPlayerExit, which calls P_RestoreMusic.
-			// So just park ourselves in the mapmus variables.
-			boolean changed = strnicmp(mapheaderinfo[gamemap-1]->musname, mapmusname, 7);
-			strncpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, 7);
-			mapmusname[6] = 0;
-			mapmusflags = (mapheaderinfo[gamemap-1]->muspostbosstrack & MUSIC_TRACKMASK) | MUSIC_RELOADRESET;
-			mapmusposition = mapheaderinfo[gamemap-1]->muspostbosspos;
-
-			// don't change if we're in another tune
-			// but in case we're in jingle, use our parked mapmus variables so the correct track restores
-			if (!changed)
-				S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, (1*MUSICRATE)+(MUSICRATE/2),
-					mapheaderinfo[gamemap-1]->muspostbossfadein);
-		}
-	}
-
-bossjustdie:
-#ifdef HAVE_BLUA
-	if (LUAh_BossDeath(mo))
-		return;
-	else if (P_MobjWasRemoved(mo))
-		return;
-#endif
-	if (mo->type == MT_BLACKEGGMAN || mo->type == MT_CYBRAKDEMON)
-	{
-		mo->flags |= MF_NOCLIP;
-		mo->flags &= ~MF_SPECIAL;
-
-		S_StartSound(NULL, sfx_befall);
-	}
-	else if (mo->type == MT_KOOPA)
-	{
-		junk.tag = 650;
-		EV_DoCeiling(&junk, raiseToHighest);
-		return;
-	}
-	else // eggmobiles
-	{
-		// Stop exploding and prepare to run.
-		P_SetMobjState(mo, mo->info->xdeathstate);
-		if (P_MobjWasRemoved(mo))
-			return;
-
-		P_SetTarget(&mo->target, NULL);
-
-		// Flee! Flee! Find a point to escape to! If none, just shoot upward!
-		// scan the thinkers to find the runaway point
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
-		{
-			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-				continue;
-
-			mo2 = (mobj_t *)th;
-
-			if (mo2->type == MT_BOSSFLYPOINT)
-			{
-				// If this one's closer then the last one, go for it.
-				if (!mo->target ||
-					P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) <
-					P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z))
-						P_SetTarget(&mo->target, mo2);
-				// Otherwise... Don't!
-			}
-		}
-
-		mo->flags |= MF_NOGRAVITY|MF_NOCLIP;
-		mo->flags |= MF_NOCLIPHEIGHT;
-
-		if (mo->target)
-		{
-			mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
-			mo->flags2 |= MF2_BOSSFLEE;
-			mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale));
-		}
-		else
-			mo->momz = FixedMul(2*FRACUNIT, mo->scale);
-	}
-
-	if (mo->type == MT_EGGMOBILE2)
-	{
-		mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
-			mo->y + P_ReturnThrustY(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
-			mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK1].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK1); // Right tank
-		mo2->angle = mo->angle;
-		mo2->destscale = mo->scale;
-		P_SetScale(mo2, mo2->destscale);
-		if (mo->eflags & MFE_VERTICALFLIP)
-		{
-			mo2->eflags |= MFE_VERTICALFLIP;
-			mo2->flags2 |= MF2_OBJECTFLIP;
-		}
-		P_InstaThrust(mo2, mo2->angle - ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale));
-		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
-
-		mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
-			mo->y + P_ReturnThrustY(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
-			mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK2].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK2); // Left tank
-		mo2->angle = mo->angle;
-		mo2->destscale = mo->scale;
-		P_SetScale(mo2, mo2->destscale);
-		if (mo->eflags & MFE_VERTICALFLIP)
-		{
-			mo2->eflags |= MFE_VERTICALFLIP;
-			mo2->flags2 |= MF2_OBJECTFLIP;
-		}
-		P_InstaThrust(mo2, mo2->angle + ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale));
-		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
-
-		mo2 = P_SpawnMobj(mo->x, mo->y,
-			mo->z + ((mo->eflags & MFE_VERTICALFLIP)? mobjinfo[MT_BOSSSPIGOT].height-FixedMul(32*FRACUNIT,mo->scale): mo->height + FixedMul(32*FRACUNIT, mo->scale)), MT_BOSSSPIGOT);
-		mo2->angle = mo->angle;
-		mo2->destscale = mo->scale;
-		P_SetScale(mo2, mo2->destscale);
-		if (mo->eflags & MFE_VERTICALFLIP)
-		{
-			mo2->eflags |= MFE_VERTICALFLIP;
-			mo2->flags2 |= MF2_OBJECTFLIP;
-		}
-		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
-		return;
-	}
-}
-
-// Function: A_CustomPower
-//
-// Description: Provides a custom powerup. Target (must be a player) is awarded the powerup. Reactiontime of the object is used as an index to the powers array.
-//
-// var1 = Power index #
-// var2 = Power duration in tics
-//
-void A_CustomPower(mobj_t *actor)
-{
-	player_t *player;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	boolean spawnshield = false;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CustomPower", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	if (locvar1 >= NUMPOWERS)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Power #%d out of range!\n", locvar1);
-		return;
-	}
-
-	player = actor->target->player;
-
-	if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2)
-		spawnshield = true;
-
-	player->powers[locvar1] = (UINT16)locvar2;
-	if (actor->info->seesound)
-		S_StartSound(player->mo, actor->info->seesound);
-
-	if (spawnshield) //workaround for a bug
-		P_SpawnShieldOrb(player);
-}
-
-// Function: A_GiveWeapon
-//
-// Description: Gives the player the specified weapon panels.
-//
-// var1 = Weapon index #
-// var2 = unused
-//
-void A_GiveWeapon(mobj_t *actor)
-{
-	player_t *player;
-	INT32 locvar1 = var1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GiveWeapon", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	if (locvar1 >= 1<<(NUM_WEAPONS-1))
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Weapon #%d out of range!\n", locvar1);
-		return;
-	}
-
-	player = actor->target->player;
-
-	player->ringweapons |= locvar1;
-	if (actor->info->seesound)
-		S_StartSound(player->mo, actor->info->seesound);
-}
-
-// Function: A_RingBox
-//
-// Description: Awards the player 10 rings.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_RingBox(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RingBox", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	P_GivePlayerRings(player, actor->info->reactiontime);
-	if (actor->info->seesound)
-		S_StartSound(player->mo, actor->info->seesound);
-}
-
-// Function: A_Invincibility
-//
-// Description: Awards the player invincibility.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Invincibility(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Invincibility", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-	player->powers[pw_invulnerability] = invulntics + 1;
-
-	if (P_IsLocalPlayer(player) && !player->powers[pw_super])
-	{
-		S_StopMusic();
-		if (mariomode)
-			G_GhostAddColor(GHC_INVINCIBLE);
-		strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
-		S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
-		S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
-	}
-}
-
-// Function: A_SuperSneakers
-//
-// Description: Awards the player super sneakers.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SuperSneakers(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SuperSneakers", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	actor->target->player->powers[pw_sneakers] = sneakertics + 1;
-
-	if (P_IsLocalPlayer(player) && !player->powers[pw_super])
-	{
-		if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
-			S_SpeedMusic(1.4f);
-		else
-		{
-			S_StopMusic();
-			S_ChangeMusicInternal("_shoes", false);
-		}
-		strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
-		S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
-	}
-}
-
-// Function: A_AwardScore
-//
-// Description: Adds a set amount of points to the player's score.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_AwardScore(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_AwardScore", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	P_AddPlayerScore(player, actor->info->reactiontime);
-	if (actor->info->seesound)
-		S_StartSound(player->mo, actor->info->seesound);
-}
-
-// Function: A_ExtraLife
-//
-// Description: Awards the player an extra life.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ExtraLife(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ExtraLife", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	if (actor->type == MT_1UP_ICON && actor->tracer)
-	{
-		// We're using the overlay, so use the overlay 1up sprite (no text)
-		actor->sprite = SPR_TV1P;
-	}
-
-	if (ultimatemode) //I don't THINK so!
-	{
-		S_StartSound(player->mo, sfx_lose);
-		return;
-	}
-
-	P_GiveCoopLives(player, 1, true);
-}
-
-// Function: A_GiveShield
-//
-// Description: Awards the player a specified shield.
-//
-// var1 = Shield type (make with SH_ constants)
-// var2 = unused
-//
-void A_GiveShield(mobj_t *actor)
-{
-	player_t *player;
-	UINT16 locvar1 = var1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GiveShield", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	P_SwitchShield(player, locvar1);
-	S_StartSound(player->mo, actor->info->seesound);
-}
-
-// Function: A_GravityBox
-//
-// Description: Awards the player gravity boots.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GravityBox(mobj_t *actor)
-{
-	player_t *player;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GravityBox", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	player = actor->target->player;
-
-	S_StartSound(player, actor->info->activesound);
-
-	player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
-}
-
-// Function: A_ScoreRise
-//
-// Description: Makes the little score logos rise. Speed value sets speed.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ScoreRise(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ScoreRise", actor))
-		return;
-#endif
-	// make logo rise!
-	P_SetObjectMomZ(actor, actor->info->speed, false);
-}
-
-// Function: A_BunnyHop
-//
-// Description: Makes object hop like a bunny.
-//
-// var1 = jump strength
-// var2 = horizontal movement
-//
-void A_BunnyHop(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BunnyHop", actor))
-		return;
-#endif
-	if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)
-		|| (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz))
-	{
-		P_SetObjectMomZ(actor, locvar1*FRACUNIT, false);
-		P_InstaThrust(actor, actor->angle, FixedMul(locvar2*FRACUNIT, actor->scale)); // Launch the hopping action! PHOOM!!
-	}
-}
-
-// Function: A_BubbleSpawn
-//
-// Description: Spawns a randomly sized bubble from the object's location. Only works underwater.
-//
-// var1 = Distance to look for players.  If no player is in this distance, bubbles aren't spawned. (Ambush overrides)
-// var2 = unused
-//
-void A_BubbleSpawn(mobj_t *actor)
-{
-	INT32 i, locvar1 = var1;
-	UINT8 prandom;
-	mobj_t *bubble = NULL;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BubbleSpawn", actor))
-		return;
-#endif
-	if (!(actor->eflags & MFE_UNDERWATER))
-	{
-		// Don't draw or spawn bubbles above water
-		actor->flags2 |= MF2_DONTDRAW;
-		return;
-	}
-	actor->flags2 &= ~MF2_DONTDRAW;
-
-	if (!(actor->flags2 & MF2_AMBUSH))
-	{
-		// Quick! Look through players!
-		// Don't spawn bubbles unless a player is relatively close by (var1).
-		for (i = 0; i < MAXPLAYERS; ++i)
-			if (playeringame[i] && players[i].mo
-			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<<FRACBITS))
-				break; // Stop looking.
-		if (i == MAXPLAYERS)
-			return; // don't make bubble!
-	}
-
-	prandom = P_RandomByte();
-
-	if (leveltime % (3*TICRATE) < 8)
-		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_EXTRALARGEBUBBLE);
-	else if (prandom > 128)
-		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_SMALLBUBBLE);
-	else if (prandom < 128 && prandom > 96)
-		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE);
-
-	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
-}
-
-// Function: A_FanBubbleSpawn
-//
-// Description: Spawns bubbles from fans, if they're underwater.
-//
-// var1 = Distance to look for players.  If no player is in this distance, bubbles aren't spawned. (Ambush overrides)
-// var2 = unused
-//
-void A_FanBubbleSpawn(mobj_t *actor)
-{
-	INT32 i, locvar1 = var1;
-	UINT8 prandom;
-	mobj_t *bubble = NULL;
-	fixed_t hz = actor->z + (4*actor->height)/5;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FanBubbleSpawn", actor))
-		return;
-#endif
-	if (!(actor->eflags & MFE_UNDERWATER))
-		return;
-
-	if (!(actor->flags2 & MF2_AMBUSH))
-	{
-	// Quick! Look through players!
-	// Don't spawn bubbles unless a player is relatively close by (var2).
-		for (i = 0; i < MAXPLAYERS; ++i)
-			if (playeringame[i] && players[i].mo
-			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<<FRACBITS))
-				break; // Stop looking.
-		if (i == MAXPLAYERS)
-			return; // don't make bubble!
-	}
-
-	prandom = P_RandomByte();
-
-	if ((prandom & 0x7) == 0x7)
-		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_SMALLBUBBLE);
-	else if ((prandom & 0xF0) == 0xF0)
-		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE);
-
-	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
-}
-
-// Function: A_BubbleRise
-//
-// Description: Raises a bubble
-//
-// var1:
-//		0 = Bend around the water abit, looking more realistic
-//		1 = Rise straight up
-// var2 = rising speed
-//
-void A_BubbleRise(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BubbleRise", actor))
-		return;
-#endif
-	if (actor->type == MT_EXTRALARGEBUBBLE)
-		P_SetObjectMomZ(actor, FixedDiv(6*FRACUNIT,5*FRACUNIT), false); // make bubbles rise!
-	else
-	{
-		P_SetObjectMomZ(actor, locvar2, true); // make bubbles rise!
-
-		// Move around slightly to make it look like it's bending around the water
-		if (!locvar1)
-		{
-			UINT8 prandom = P_RandomByte();
-			if (!(prandom & 0x7)) // *****000
-			{
-				P_InstaThrust(actor, prandom & 0x70 ? actor->angle + ANGLE_90 : actor->angle,
-					FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale));
-			}
-			else if (!(prandom & 0x38)) // **000***
-			{
-				P_InstaThrust(actor, prandom & 0x70 ? actor->angle - ANGLE_90 : actor->angle - ANGLE_180,
-					FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale));
-			}
-		}
-	}
-}
-
-// Function: A_BubbleCheck
-//
-// Description: Checks if a bubble should be drawn or not. Bubbles are not drawn above water.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_BubbleCheck(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BubbleCheck", actor))
-		return;
-#endif
-	if (actor->eflags & MFE_UNDERWATER)
-		actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw
-	else
-		actor->flags2 |= MF2_DONTDRAW; // above water so don't draw
-}
-
-// Function: A_AttractChase
-//
-// Description: Makes a ring chase after a player with a ring shield and also causes spilled rings to flicker.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_AttractChase(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_AttractChase", actor))
-		return;
-#endif
-	if (actor->flags2 & MF2_NIGHTSPULL || !actor->health)
-		return;
-
-	// spilled rings flicker before disappearing
-	if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE)
-		actor->flags2 |= MF2_DONTDRAW;
-	else
-		actor->flags2 &= ~MF2_DONTDRAW;
-
-	// Turn flingrings back into regular rings if attracted.
-	if (actor->tracer && actor->tracer->player
-		&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
-	{
-		mobj_t *newring;
-		newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
-		newring->momx = actor->momx;
-		newring->momy = actor->momy;
-		newring->momz = actor->momz;
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	P_LookForShield(actor); // Go find 'em, boy!
-
-	if (!actor->tracer
-		|| !actor->tracer->player
-		|| !actor->tracer->health
-		|| !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta
-	{
-		// Lost attracted rings don't through walls anymore.
-		actor->flags &= ~MF_NOCLIP;
-		P_SetTarget(&actor->tracer, NULL);
-		return;
-	}
-
-	// If a FlingRing gets attracted by a shield, change it into a normal ring.
-	if (actor->type == (mobjtype_t)actor->info->reactiontime)
-	{
-		P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance);
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	// Keep stuff from going down inside floors and junk
-	actor->flags &= ~MF_NOCLIPHEIGHT;
-
-	// Let attracted rings move through walls and such.
-	actor->flags |= MF_NOCLIP;
-
-	P_Attract(actor, actor->tracer, false);
-}
-
-// Function: A_DropMine
-//
-// Description: Drops a mine. Raisestate specifies the object # to use for the mine.
-//
-// var1 = height offset
-// var2:
-//		lower 16 bits = proximity check distance (0 disables)
-//		upper 16 bits = 0 to check proximity with target, 1 for tracer
-//
-void A_DropMine(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t z;
-	mobj_t *mine;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_DropMine", actor))
-		return;
-#endif
-
-	if (locvar2 & 65535)
-	{
-		fixed_t dist;
-		mobj_t *target;
-
-		if (locvar2 >> 16)
-			target = actor->tracer;
-		else
-			target = actor->target;
-
-		if (!target)
-			return;
-
-		dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)>>FRACBITS;
-
-		if (dist > FixedMul((locvar2 & 65535), actor->scale))
-			return;
-	}
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - mobjinfo[actor->info->raisestate].height - FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale);
-
-	// Use raisestate instead of MT_MINE
-	mine = P_SpawnMobj(actor->x, actor->y, z, (mobjtype_t)actor->info->raisestate);
-	if (actor->eflags & MFE_VERTICALFLIP)
-		mine->eflags |= MFE_VERTICALFLIP;
-	mine->momz = actor->momz + actor->pmomz;
-
-	S_StartSound(actor, actor->info->attacksound);
-}
-
-// Function: A_FishJump
-//
-// Description: Makes the stupid harmless fish in Greenflower Zone jump.
-//
-// var1 = Jump strength (in FRACBITS), if specified. Otherwise, uses the angle value.
-// var2 = unused
-//
-void A_FishJump(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FishJump", actor))
-		return;
-#endif
-
-	if (locvar2)
-	{
-		fixed_t rad = actor->radius>>FRACBITS;
-		P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
-	}
-
-	if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale)))
-	{
-		fixed_t jumpval;
-
-		if (locvar1)
-			jumpval = var1;
-		else
-			jumpval = FixedMul(AngleFixed(actor->angle)/4, actor->scale);
-
-		if (!jumpval) jumpval = FixedMul(44*(FRACUNIT/4), actor->scale);
-		actor->momz = jumpval;
-		P_SetMobjStateNF(actor, actor->info->seestate);
-	}
-
-	if (actor->momz < 0
-		&& (actor->state < &states[actor->info->meleestate] || actor->state > &states[actor->info->xdeathstate]))
-		P_SetMobjStateNF(actor, actor->info->meleestate);
-}
-
-// Function:A_ThrownRing
-//
-// Description: Thinker for thrown rings/sparkle trail
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ThrownRing(mobj_t *actor)
-{
-	INT32 c = 0;
-	INT32 stop;
-	player_t *player;
-	fixed_t dist;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ThrownRing", actor))
-		return;
-#endif
-
-	if (leveltime % (TICRATE/7) == 0)
-	{
-		mobj_t *ring = NULL;
-
-		if (actor->flags2 & MF2_EXPLOSION)
-		{
-			if (actor->momx != 0 || actor->momy != 0)
-				ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOKE);
-			// Else spawn nothing because it's totally stationary and constantly smoking would be weird -SH
-		}
-		else if (actor->flags2 & MF2_AUTOMATIC)
-			ring = P_SpawnGhostMobj(actor);
-		else if (!(actor->flags2 & MF2_RAILRING))
-			ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPARK);
-
-		if (ring)
-		{
-			/*
-			P_SetTarget(&ring->target, actor);
-			ring->color = actor->color; //copy color
-			*/
-			ring->destscale = actor->scale;
-			P_SetScale(ring, actor->scale);
-		}
-	}
-
-	// A_GrenadeRing beeping lives once moooooore -SH
-	if (actor->type == MT_THROWNGRENADE && actor->fuse % TICRATE == 0)
-		S_StartSound(actor, actor->info->attacksound);
-
-	// decrement bounce ring time
-	if (actor->flags2 & MF2_BOUNCERING)
-	{
-		if (actor->fuse)
-			actor->fuse--;
-		else {
-			P_RemoveMobj(actor);
-			return;
-		}
-	}
-
-	// spilled rings (and thrown bounce) flicker before disappearing
-	if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE
-		&& actor->type != MT_THROWNGRENADE)
-		actor->flags2 |= MF2_DONTDRAW;
-	else
-		actor->flags2 &= ~MF2_DONTDRAW;
-
-	if (actor->tracer && actor->tracer->health <= 0)
-		P_SetTarget(&actor->tracer, NULL);
-
-	// Updated homing ring special capability
-	// If you have a ring shield, all rings thrown
-	// at you become homing (except rail)!
-	if (actor->tracer)
-	{
-		// A non-homing ring getting attracted by a
-		// magnetic player. If he gets too far away, make
-		// sure to stop the attraction!
-		if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC)
-		    && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
-		    actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
-		{
-			P_SetTarget(&actor->tracer, NULL);
-		}
-
-		if (actor->tracer && (actor->tracer->health)
-			&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
-		{
-			const INT32 temp = actor->threshold;
-			actor->threshold = 32000;
-			P_HomingAttack(actor, actor->tracer);
-			actor->threshold = temp;
-			return;
-		}
-	}
-
-	// first time init, this allow minimum lastlook changes
-	if (actor->lastlook < 0)
-		actor->lastlook = P_RandomByte();
-
-	actor->lastlook %= MAXPLAYERS;
-
-	stop = (actor->lastlook - 1) & PLAYERSMASK;
-
-	for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK)
-	{
-		// done looking
-		if (actor->lastlook == stop)
-			return;
-
-		if (!playeringame[actor->lastlook])
-			continue;
-
-		if (c++ == 2)
-			return;
-
-		player = &players[actor->lastlook];
-
-		if (!player->mo)
-			continue;
-
-		if (player->mo->health <= 0)
-			continue; // dead
-
-		if ((netgame || multiplayer) && player->spectator)
-			continue; // spectator
-
-		if (actor->target && actor->target->player)
-		{
-			if (player->mo == actor->target)
-				continue;
-
-			// Don't home in on teammates.
-			if (gametype == GT_CTF
-				&& actor->target->player->ctfteam == player->ctfteam)
-				continue;
-		}
-
-		dist = P_AproxDistance(P_AproxDistance(player->mo->x-actor->x,
-			player->mo->y-actor->y), player->mo->z-actor->z);
-
-		// check distance
-		if (actor->flags2 & MF2_RAILRING)
-		{
-			if (dist > FixedMul(RING_DIST/2, player->mo->scale))
-				continue;
-		}
-		else if (dist > FixedMul(RING_DIST, player->mo->scale))
-			continue;
-
-		// do this after distance check because it's more computationally expensive
-		if (!P_CheckSight(actor, player->mo))
-			continue; // out of sight
-
-		if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
-			&& dist < FixedMul(RING_DIST/4, player->mo->scale))
-			P_SetTarget(&actor->tracer, player->mo);
-		return;
-	}
-
-	return;
-}
-
-// Function: A_SetSolidSteam
-//
-// Description: Makes steam solid so it collides with the player to boost them.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SetSolidSteam(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetSolidSteam", actor))
-		return;
-#endif
-	actor->flags &= ~MF_NOCLIP;
-	actor->flags |= MF_SOLID;
-	if (!(actor->flags2 & MF2_AMBUSH))
-	{
-		if (P_RandomChance(FRACUNIT/8))
-		{
-			if (actor->info->deathsound)
-				S_StartSound(actor, actor->info->deathsound); // Hiss!
-		}
-		else
-		{
-			if (actor->info->painsound)
-				S_StartSound(actor, actor->info->painsound);
-		}
-	}
-
-	P_SetObjectMomZ (actor, 1, true);
-}
-
-// Function: A_UnsetSolidSteam
-//
-// Description: Makes an object non-solid and also noclip. Used by the steam.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_UnsetSolidSteam(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_UnsetSolidSteam", actor))
-		return;
-#endif
-	actor->flags &= ~MF_SOLID;
-	actor->flags |= MF_NOCLIP;
-}
-
-// Function: A_SignPlayer
-//
-// Description: Changes the state of a level end sign to reflect the player that hit it.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SignPlayer(mobj_t *actor)
-{
-	mobj_t *ov;
-	skin_t *skin;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SignPlayer", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	if (!actor->target->player)
-		return;
-
-	skin = &skins[actor->target->player->skin];
-
-	if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor?
-	{
-		actor->color = skin->prefoppositecolor;
-		/*
-		If you're here from the comment above Color_Opposite,
-		the following line is the one which is dependent on the
-		array being symmetrical. It gets the opposite of the
-		opposite of your desired colour just so it can get the
-		brightness frame for the End Sign. It's not a great
-		design choice, but it's constant time array access and
-		the idea that the colours should be OPPOSITES is kind
-		of in the name. If you have a better idea, feel free
-		to let me know. ~toast 2016/07/20
-		*/
-		actor->frame += (15 - Color_Opposite[(Color_Opposite[(skin->prefoppositecolor - 1)*2] - 1)*2 + 1]);
-	}
-	else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor.
-	{
-		actor->color = Color_Opposite[(actor->target->player->skincolor - 1)*2];
-		actor->frame += (15 - Color_Opposite[(actor->target->player->skincolor - 1)*2 + 1]);
-	}
-
-	if (skin->sprites[SPR2_SIGN].numframes)
-	{
-		// spawn an overlay of the player's face.
-		ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
-		P_SetTarget(&ov->target, actor);
-		ov->color = actor->target->player->skincolor;
-		ov->skin = skin;
-		P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
-	}
-}
-
-// Function: A_OverlayThink
-//
-// Description: Moves the overlay to the position of its target.
-//
-// var1 = unused
-// var2 = invert, z offset
-//
-void A_OverlayThink(mobj_t *actor)
-{
-	fixed_t destx, desty;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_OverlayThink", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	if (!splitscreen && rendermode != render_soft)
-	{
-		angle_t viewingangle;
-
-		if (players[displayplayer].awayviewtics)
-			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y);
-		else if (!camera.chase && players[displayplayer].mo)
-			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y);
-		else
-			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera.x, camera.y);
-
-		destx = actor->target->x + P_ReturnThrustX(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale));
-		desty = actor->target->y + P_ReturnThrustY(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale));
-	}
-	else
-	{
-		destx = actor->target->x;
-		desty = actor->target->y;
-	}
-	P_UnsetThingPosition(actor);
-	actor->x = destx;
-	actor->y = desty;
-	P_SetThingPosition(actor);
-	if (actor->eflags & MFE_VERTICALFLIP)
-		actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height  - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
-	else
-		actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
-	actor->angle = actor->target->angle;
-	actor->eflags = actor->target->eflags;
-
-	actor->momx = actor->target->momx;
-	actor->momy = actor->target->momy;
-	actor->momz = actor->target->momz; // assume target has correct momz! Do not use P_SetObjectMomZ!
-}
-
-// Function: A_JetChase
-//
-// Description: A_Chase for Jettysyns
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetChase(mobj_t *actor)
-{
-	fixed_t thefloor;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetChase", actor))
-		return;
-#endif
-
-	if (actor->flags2 & MF2_AMBUSH)
-		return;
-
-	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
-		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
-		thefloor = actor->watertop;
-	else
-		thefloor = actor->floorz;
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	if (P_RandomChance(FRACUNIT/32))
-	{
-		actor->momx = actor->momx / 2;
-		actor->momy = actor->momy / 2;
-		actor->momz = actor->momz / 2;
-	}
-
-	// Bounce if too close to floor or ceiling -
-	// ideal for Jetty-Syns above you on 3d floors
-	if (actor->momz && ((actor->z - FixedMul((32<<FRACBITS), actor->scale)) < thefloor) && !((thefloor + FixedMul(32*FRACUNIT, actor->scale) + actor->height) > actor->ceilingz))
-		actor->momz = -actor->momz/2;
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		actor->momx = actor->momy = actor->momz = 0;
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	// turn towards movement direction if not there yet
-	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-
-	if ((multiplayer || netgame) && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)))
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-	// If the player is over 3072 fracunits away, then look for another player
-	if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y),
-		actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)))
-	{
-		return; // got a new target
-	}
-
-	// chase towards player
-	if (ultimatemode)
-		P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/2, actor->scale));
-	else
-		P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/4, actor->scale));
-
-	// must adjust height
-	if (ultimatemode)
-	{
-		if (actor->z < (actor->target->z + actor->target->height + FixedMul((64<<FRACBITS), actor->scale)))
-			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
-		else
-			actor->momz -= FixedMul(FRACUNIT/2, actor->scale);
-	}
-	else
-	{
-		if (actor->z < (actor->target->z + actor->target->height + FixedMul((32<<FRACBITS), actor->scale)))
-			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
-		else
-			actor->momz -= FixedMul(FRACUNIT/2, actor->scale);
-	}
-}
-
-// Function: A_JetbThink
-//
-// Description: Thinker for Jetty-Syn bombers
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetbThink(mobj_t *actor)
-{
-	sector_t *nextsector;
-	fixed_t thefloor;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetbThink", actor))
-		return;
-#endif
-
-	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
-		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
-		thefloor = actor->watertop;
-	else
-		thefloor = actor->floorz;
-
-	if (actor->target)
-	{
-		A_JetChase(actor);
-		// check for melee attack
-		if (actor->info->raisestate
-			&& (actor->z > (actor->floorz + FixedMul((32<<FRACBITS), actor->scale)))
-			&& P_JetbCheckMeleeRange(actor) && !actor->reactiontime
-			&& (actor->target->z >= actor->floorz))
-		{
-			mobj_t *bomb;
-			if (actor->info->attacksound)
-				S_StartAttackSound(actor, actor->info->attacksound);
-
-			// use raisestate instead of MT_MINE
-			bomb = P_SpawnMobj(actor->x, actor->y, actor->z - FixedMul((32<<FRACBITS), actor->scale), (mobjtype_t)actor->info->raisestate);
-
-			P_SetTarget(&bomb->target, actor);
-			bomb->destscale = actor->scale;
-			P_SetScale(bomb, actor->scale);
-			actor->reactiontime = TICRATE; // one second
-			S_StartSound(actor, actor->info->attacksound);
-		}
-	}
-	else if (((actor->z - FixedMul((32<<FRACBITS), actor->scale)) < thefloor) && !((thefloor + FixedMul((32<<FRACBITS), actor->scale) + actor->height) > actor->ceilingz))
-			actor->z = thefloor+FixedMul((32<<FRACBITS), actor->scale);
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
-
-	// Move downwards or upwards to go through a passageway.
-	if (nextsector->ceilingheight < actor->z + actor->height)
-		actor->momz -= FixedMul(5*FRACUNIT, actor->scale);
-	else if (nextsector->floorheight > actor->z)
-		actor->momz += FixedMul(5*FRACUNIT, actor->scale);
-}
-
-// Function: A_JetgShoot
-//
-// Description: Firing function for Jetty-Syn gunners.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetgShoot(mobj_t *actor)
-{
-	fixed_t dist;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetgShoot", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	if (actor->reactiontime)
-		return;
-
-	dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
-
-	if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale))
-		return;
-
-	if (dist < FixedMul(64*FRACUNIT, actor->scale))
-		return;
-
-	A_FaceTarget(actor);
-	P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate);
-
-	if (ultimatemode)
-		actor->reactiontime = actor->info->reactiontime*TICRATE;
-	else
-		actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-
-	if (actor->info->attacksound)
-		S_StartSound(actor, actor->info->attacksound);
-}
-
-// Function: A_ShootBullet
-//
-// Description: Shoots a bullet. Raisestate defines object # to use as projectile.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ShootBullet(mobj_t *actor)
-{
-	fixed_t dist;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ShootBullet", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
-
-	if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale))
-		return;
-
-	A_FaceTarget(actor);
-	P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate);
-
-	if (actor->info->attacksound)
-		S_StartSound(actor, actor->info->attacksound);
-}
-
-// Function: A_MinusDigging
-//
-// Description: Minus digging in the ground.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MinusDigging(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MinusDigging", actor))
-		return;
-#endif
-	actor->flags &= ~MF_SPECIAL;
-	actor->flags &= ~MF_SHOOTABLE;
-
-	if (!actor->target)
-	{
-		A_Look(actor);
-		return;
-	}
-
-	if (actor->reactiontime)
-	{
-		actor->reactiontime--;
-		return;
-	}
-
-	// Dirt trail
-	P_SpawnGhostMobj(actor);
-
-	actor->flags |= MF_NOCLIPTHING;
-	var1 = 3;
-	A_Chase(actor);
-	actor->flags &= ~MF_NOCLIPTHING;
-
-	// Play digging sound
-	if (!(leveltime & 15))
-		S_StartSound(actor, actor->info->activesound);
-
-	// If we're close enough to our target, pop out of the ground
-	if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius
-		&& abs(actor->target->z - actor->z) < 2*actor->height)
-		P_SetMobjState(actor, actor->info->missilestate);
-
-	// Snap to ground
-	if (actor->eflags & MFE_VERTICALFLIP)
-		actor->z = actor->ceilingz - actor->height;
-	else
-		actor->z = actor->floorz;
-}
-
-// Function: A_MinusPopup
-//
-// Description: Minus popping out of the ground.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MinusPopup(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MinusPopup", actor))
-		return;
-#endif
-	P_SetObjectMomZ(actor, 10*FRACUNIT, false);
-
-	actor->flags |= MF_SPECIAL;
-	actor->flags |= MF_SHOOTABLE;
-
-	// Sound for busting out of the ground.
-	S_StartSound(actor, actor->info->attacksound);
-}
-
-// Function: A_MinusCheck
-//
-// Description: If the minus hits the floor, dig back into the ground.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MinusCheck(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MinusCheck", actor))
-		return;
-#endif
-	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
-	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))
-	{
-		actor->flags &= ~MF_SPECIAL;
-		actor->flags &= ~MF_SHOOTABLE;
-		actor->reactiontime = TICRATE;
-		P_SetMobjState(actor, actor->info->seestate);
-		return;
-	}
-
-	// 'Falling' animation
-	if (P_MobjFlip(actor)*actor->momz < 0 && actor->state < &states[actor->info->meleestate])
-		P_SetMobjState(actor, actor->info->meleestate);
-}
-
-// Function: A_ChickenCheck
-//
-// Description: Resets the chicken once it hits the floor again.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ChickenCheck(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChickenCheck", actor))
-		return;
-#endif
-	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
-	|| (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz))
-	{
-		if (!(actor->momx || actor->momy || actor->momz)
-			&& actor->state > &states[actor->info->seestate])
-		{
-			A_Chase(actor);
-			P_SetMobjState(actor, actor->info->seestate);
-		}
-
-		actor->momx >>= 2;
-		actor->momy >>= 2;
-	}
-}
-
-// Function: A_JetgThink
-//
-// Description: Thinker for Jetty-Syn Gunners
-//
-// var1 = unused
-// var2 = unused
-//
-void A_JetgThink(mobj_t *actor)
-{
-	sector_t *nextsector;
-
-	fixed_t thefloor;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_JetgThink", actor))
-		return;
-#endif
-
-	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
-		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
-		thefloor = actor->watertop;
-	else
-		thefloor = actor->floorz;
-
-	if (actor->target)
-	{
-		if (P_RandomChance(FRACUNIT/8) && !actor->reactiontime)
-			P_SetMobjState(actor, actor->info->missilestate);
-		else
-			A_JetChase (actor);
-	}
-	else if (actor->z - FixedMul((32<<FRACBITS), actor->scale) < thefloor && !(thefloor + FixedMul((32<<FRACBITS), actor->scale)
-		+ actor->height > actor->ceilingz))
-	{
-		actor->z = thefloor + FixedMul((32<<FRACBITS), actor->scale);
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
-
-	// Move downwards or upwards to go through a passageway.
-	if (nextsector->ceilingheight < actor->z + actor->height)
-		actor->momz -= FixedMul(5*FRACUNIT, actor->scale);
-	else if (nextsector->floorheight > actor->z)
-		actor->momz += FixedMul(5*FRACUNIT, actor->scale);
-}
-
-// Function: A_MouseThink
-//
-// Description: Thinker for scurrying mice.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MouseThink(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MouseThink", actor))
-		return;
-#endif
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z == actor->floorz)
-		|| (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height == actor->ceilingz))
-		&& !actor->reactiontime)
-	{
-		if (twodlevel || actor->flags2 & MF2_TWOD)
-		{
-			if (P_RandomChance(FRACUNIT/2))
-				actor->angle += ANGLE_180;
-		}
-		else if (P_RandomChance(FRACUNIT/2))
-			actor->angle += ANGLE_90;
-		else
-			actor->angle -= ANGLE_90;
-
-		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale));
-		actor->reactiontime = TICRATE/5;
-	}
-}
-
-// Function: A_DetonChase
-//
-// Description: Chases a Deton after a player.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_DetonChase(mobj_t *actor)
-{
-	angle_t exact;
-	fixed_t xydist, dist;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_DetonChase", actor))
-		return;
-#endif
-
-	// modify tracer threshold
-	if (!actor->tracer || actor->tracer->health <= 0)
-		actor->threshold = 0;
-	else
-		actor->threshold = 1;
-
-	if (!actor->tracer || !(actor->tracer->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, true, 0))
-			return; // got a new target
-
-		actor->momx = actor->momy = actor->momz = 0;
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	if (multiplayer && !actor->threshold && P_LookForPlayers(actor, true, true, 0))
-		return; // got a new target
-
-	// Face movement direction if not doing so
-	exact = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
-	actor->angle = exact;
-	/*if (exact != actor->angle)
-	{
-		if (exact - actor->angle > ANGLE_180)
-		{
-			actor->angle -= actor->info->raisestate;
-			if (exact - actor->angle < ANGLE_180)
-				actor->angle = exact;
-		}
-		else
-		{
-			actor->angle += actor->info->raisestate;
-			if (exact - actor->angle > ANGLE_180)
-				actor->angle = exact;
-		}
-	}*/
-	// movedir is up/down angle: how much it has to go up as it goes over to the player
-	xydist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
-	exact = R_PointToAngle2(0, 0, xydist, actor->tracer->z - actor->z);
-	actor->movedir = exact;
-	/*if (exact != actor->movedir)
-	{
-		if (exact - actor->movedir > ANGLE_180)
-		{
-			actor->movedir -= actor->info->raisestate;
-			if (exact - actor->movedir < ANGLE_180)
-				actor->movedir = exact;
-		}
-		else
-		{
-			actor->movedir += actor->info->raisestate;
-			if (exact - actor->movedir > ANGLE_180)
-				actor->movedir = exact;
-		}
-	}*/
-
-	// check for melee attack
-	if (actor->tracer)
-	{
-		if (P_AproxDistance(actor->tracer->x-actor->x, actor->tracer->y-actor->y) < actor->radius+actor->tracer->radius)
-		{
-			if (!((actor->tracer->z > actor->z + actor->height) || (actor->z > actor->tracer->z + actor->tracer->height)))
-			{
-				P_ExplodeMissile(actor);
-				return;
-			}
-		}
-	}
-
-	// chase towards player
-	if ((dist = P_AproxDistance(xydist, actor->tracer->z-actor->z))
-		> FixedMul((actor->info->painchance << FRACBITS), actor->scale))
-	{
-		P_SetTarget(&actor->tracer, NULL); // Too far away
-		return;
-	}
-
-	if (actor->reactiontime == 0)
-	{
-		actor->reactiontime = actor->info->reactiontime;
-		return;
-	}
-
-	if (actor->reactiontime > 1)
-	{
-		actor->reactiontime--;
-		return;
-	}
-
-	if (actor->reactiontime > 0)
-	{
-		actor->reactiontime = -42;
-
-		if (actor->info->seesound)
-			S_StartScreamSound(actor, actor->info->seesound);
-	}
-
-	if (actor->reactiontime == -42)
-	{
-		fixed_t xyspeed;
-
-		actor->reactiontime = -42;
-
-		exact = actor->movedir>>ANGLETOFINESHIFT;
-		xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact));
-		actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact));
-
-		exact = actor->angle>>ANGLETOFINESHIFT;
-		actor->momx = FixedMul(xyspeed, FINECOSINE(exact));
-		actor->momy = FixedMul(xyspeed, FINESINE(exact));
-
-		// Variable re-use
-		xyspeed = (P_AproxDistance(actor->tracer->x - actor->x, P_AproxDistance(actor->tracer->y - actor->y, actor->tracer->z - actor->z))>>(FRACBITS+6));
-
-		if (xyspeed < 1)
-			xyspeed = 1;
-
-		if (leveltime % xyspeed == 0)
-			S_StartSound(actor, sfx_deton);
-	}
-}
-
-// Function: A_CapeChase
-//
-// Description: Set an object's location to its target or tracer.
-//
-// var1:
-//		0 = Use target
-//		1 = Use tracer
-//		upper 16 bits = Z offset
-// var2:
-//		upper 16 bits = forward/backward offset
-//		lower 16 bits = sideways offset
-//
-void A_CapeChase(mobj_t *actor)
-{
-	mobj_t *chaser;
-	fixed_t foffsetx, foffsety, boffsetx, boffsety;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	angle_t angle;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CapeChase", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	if (locvar1 & 65535)
-		chaser = actor->tracer;
-	else
-		chaser = actor->target;
-
-	if (!chaser || (chaser->health <= 0))
-	{
-		if (chaser)
-			CONS_Debug(DBG_GAMELOGIC, "Hmm, the guy I'm chasing (object type %d) has no health.. so I'll die too!\n", chaser->type);
-
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	angle = (chaser->player ? chaser->player->drawangle : chaser->angle);
-
-	foffsetx = P_ReturnThrustX(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
-	foffsety = P_ReturnThrustY(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
-
-	boffsetx = P_ReturnThrustX(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale));
-	boffsety = P_ReturnThrustY(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale));
-
-	P_UnsetThingPosition(actor);
-	actor->x = chaser->x + foffsetx + boffsetx;
-	actor->y = chaser->y + foffsety + boffsety;
-	if (chaser->eflags & MFE_VERTICALFLIP)
-	{
-		actor->eflags |= MFE_VERTICALFLIP;
-		actor->flags2 |= MF2_OBJECTFLIP;
-		actor->z = chaser->z + chaser->height - actor->height - FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale);
-	}
-	else
-	{
-		actor->eflags &= ~MFE_VERTICALFLIP;
-		actor->flags2 &= ~MF2_OBJECTFLIP;
-		actor->z = chaser->z + FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale);
-	}
-	actor->angle = angle;
-	P_SetThingPosition(actor);
-}
-
-// Function: A_RotateSpikeBall
-//
-// Description: Rotates a spike ball around its target/tracer.
-//
-// var1:
-//		0 = Use target
-//		1 = Use tracer
-// var2 = unused
-//
-void A_RotateSpikeBall(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RotateSpikeBall", actor))
-		return;
-#endif
-
-	if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen.
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Spikeball has no target\n");
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	if (!actor->info->speed)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Object has no speed.\n");
-		return;
-	}
-
-	actor->angle += FixedAngle(actor->info->speed);
-	P_UnsetThingPosition(actor);
-	{
-		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
-		if (!locvar1)
-		{
-			actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius);
-			actor->y = actor->target->y + FixedMul(FINESINE(fa),radius);
-			actor->z = actor->target->z + actor->target->height/2;
-		}
-		else
-		{
-			actor->x = actor->tracer->x + FixedMul(FINECOSINE(fa),radius);
-			actor->y = actor->tracer->y + FixedMul(FINESINE(fa),radius);
-			actor->z = actor->tracer->z + actor->tracer->height/2;
-		}
-		P_SetThingPosition(actor);
-	}
-}
-
-// Function: A_UnidusBall
-//
-// Description: Rotates a spike ball around its target.
-//
-// var1:
-//		0 = Don't throw
-//		1 = Throw
-//		2 = Throw when target leaves MF2_SKULLFLY.
-// var2 = unused
-//
-void A_UnidusBall(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	boolean canthrow = false;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_UnidusBall", actor))
-		return;
-#endif
-
-	actor->angle += ANGLE_11hh;
-
-	if (actor->movecount)
-	{
-		if (P_AproxDistance(actor->momx, actor->momy) < FixedMul(actor->info->damage/2, actor->scale))
-			P_ExplodeMissile(actor);
-		return;
-	}
-
-	if (!actor->target || !actor->target->health)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_UnidusBall: Removing unthrown spikeball from nonexistant Unidus\n");
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	P_UnsetThingPosition(actor);
-	{
-		const angle_t angle = actor->movedir + FixedAngle(actor->info->speed*(leveltime%360));
-		const UINT16 fa = angle>>ANGLETOFINESHIFT;
-
-		actor->x = actor->target->x + FixedMul(FINECOSINE(fa),actor->threshold);
-		actor->y = actor->target->y + FixedMul(  FINESINE(fa),actor->threshold);
-		actor->z = actor->target->z + actor->target->height/2 - actor->height/2;
-
-		if (locvar1 == 1 && actor->target->target)
-		{
-			const angle_t tang = R_PointToAngle2(actor->target->x, actor->target->y, actor->target->target->x, actor->target->target->y);
-			const angle_t mina = tang-ANGLE_11hh;
-			canthrow = (angle-mina < FixedAngle(actor->info->speed*3));
-		}
-	}
-	P_SetThingPosition(actor);
-
-	if (locvar1 == 1 && canthrow)
-	{
-		if (P_AproxDistance(actor->target->target->x - actor->target->x, actor->target->target->y - actor->target->y) > FixedMul(MISSILERANGE>>1, actor->scale)
-		|| !P_CheckSight(actor, actor->target->target))
-			return;
-
-		actor->movecount = actor->info->damage>>FRACBITS;
-		actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING);
-		P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->target->x, actor->target->target->y), FixedMul(actor->info->damage, actor->scale));
-	}
-	else if (locvar1 == 2)
-	{
-		boolean skull = (actor->target->flags2 & MF2_SKULLFLY) == MF2_SKULLFLY;
-		if (actor->target->state == &states[actor->target->info->painstate])
-		{
-			P_KillMobj(actor, NULL, NULL, 0);
-			return;
-		}
-		switch(actor->extravalue2)
-		{
-		case 0: // at least one frame where not dashing
-			if (!skull) ++actor->extravalue2;
-			else break;
-			/* FALLTHRU */
-		case 1: // at least one frame where ARE dashing
-			if (skull) ++actor->extravalue2;
-			else break;
-			/* FALLTHRU */
-		case 2: // not dashing again?
-			if (skull) break;
-			// launch.
-		{
-			mobj_t *target = actor->target;
-			if (actor->target->target)
-				target = actor->target->target;
-			actor->movecount = actor->info->damage>>FRACBITS;
-			actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING);
-			P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, target->x, target->y), FixedMul(actor->info->damage, actor->scale));
-		}
-		default: // from our compiler appeasement program (CAP).
-			break;
-		}
-	}
-}
-
-// Function: A_RockSpawn
-//
-// Spawns rocks at a specified interval
-//
-// var1 = unused
-// var2 = unused
-void A_RockSpawn(mobj_t *actor)
-{
-	mobj_t *mo;
-	mobjtype_t type;
-	INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1);
-	line_t *line;
-	fixed_t dist;
-	fixed_t randomoomph;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RockSpawn", actor))
-		return;
-#endif
-
-	if (i == -1)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Unable to find parameter line 12 (tag %d)!\n", actor->threshold);
-		return;
-	}
-
-	line = &lines[i];
-
-	if (!(sides[line->sidenum[0]].textureoffset >> FRACBITS))
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: No X-offset detected! (tag %d)!\n", actor->threshold);
-		return;
-	}
-
-	dist = P_AproxDistance(line->dx, line->dy)/16;
-
-	if (dist < 1)
-		dist = 1;
-
-	type = MT_ROCKCRUMBLE1 + (sides[line->sidenum[0]].rowoffset >> FRACBITS);
-
-	if (line->flags & ML_NOCLIMB)
-		randomoomph = P_RandomByte() * (FRACUNIT/32);
-	else
-		randomoomph = 0;
-
-	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK);
-	P_SetMobjState(mo, mobjinfo[type].spawnstate);
-	mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y);
-
-	P_InstaThrust(mo, mo->angle, dist + randomoomph);
-	mo->momz = dist + randomoomph;
-
-	var1 = sides[line->sidenum[0]].textureoffset >> FRACBITS;
-	A_SetTics(actor);
-}
-
-//
-// Function: A_SlingAppear
-//
-// Appears a sling.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SlingAppear(mobj_t *actor)
-{
-	UINT8 mlength = 4;
-	mobj_t *spawnee, *hprev;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SlingAppear", actor))
-		return;
-#endif
-
-	P_UnsetThingPosition(actor);
-	actor->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT);
-	P_SetThingPosition(actor);
-	actor->lastlook = 128;
-	actor->movecount = actor->lastlook;
-	actor->threshold = 0;
-	actor->movefactor = actor->threshold;
-	actor->friction = 128;
-
-	hprev = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLGRABCHAIN);
-	P_SetTarget(&hprev->tracer, actor);
-	P_SetTarget(&hprev->hprev, actor);
-	P_SetTarget(&actor->hnext, hprev);
-	hprev->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
-	hprev->movecount = mlength;
-
-	mlength--;
-
-	while (mlength > 0)
-	{
-		spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN);
-		P_SetTarget(&spawnee->tracer, actor);
-		P_SetTarget(&spawnee->hprev, hprev);
-		P_SetTarget(&hprev->hnext, spawnee);
-		hprev = spawnee;
-
-		spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
-		spawnee->movecount = mlength;
-
-		mlength--;
-	}
-}
-
-// Function: A_SetFuse
-//
-// Description: Sets the actor's fuse timer if not set already. May also change state when fuse reaches the last tic, otherwise by default the actor will die or disappear. (Replaces A_SnowBall)
-//
-// var1 = fuse timer duration (in tics).
-// var2:
-//		lower 16 bits = if > 0, state to change to when fuse = 1
-//		upper 16 bits: 0 = (default) don't set fuse unless 0, 1 = force change, 2 = force no change
-//
-void A_SetFuse(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetFuse", actor))
-		return;
-#endif
-
-	if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value
-		actor->fuse = locvar1;
-
-	if (actor->fuse == 1 && (locvar2 & 65535)) // change state on the very last tic (fuse is handled before actions in P_MobjThinker)
-	{
-		actor->fuse = 0; // don't die/disappear the next tic!
-		P_SetMobjState(actor, locvar2 & 65535);
-	}
-}
-
-// Function: A_CrawlaCommanderThink
-//
-// Description: Thinker for Crawla Commander.
-//
-// var1 = shoot bullets?
-// var2 = "pogo mode" speed
-//
-void A_CrawlaCommanderThink(mobj_t *actor)
-{
-	fixed_t dist;
-	sector_t *nextsector;
-	fixed_t thefloor;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	boolean hovermode = (actor->health > 1 || actor->fuse);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CrawlaCommanderThink", actor))
-		return;
-#endif
-
-	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
-		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
-		thefloor = actor->watertop;
-	else
-		thefloor = actor->floorz;
-
-	if (!actor->fuse && actor->flags2 & MF2_FRET)
-	{
-		if (actor->info->painsound)
-			S_StartSound(actor, actor->info->painsound);
-
-		actor->fuse = TICRATE/2;
-		actor->momz = 0;
-
-		P_InstaThrust(actor, actor->angle-ANGLE_180, FixedMul(5*FRACUNIT, actor->scale));
-	}
-
-	if (actor->reactiontime > 0)
-		actor->reactiontime--;
-
-	if (actor->fuse < 2)
-	{
-		actor->fuse = 0;
-		actor->flags2 &= ~MF2_FRET;
-	}
-
-	// Hover mode
-	if (hovermode)
-	{
-		if (actor->z < thefloor + FixedMul(16*FRACUNIT, actor->scale))
-			actor->momz += FixedMul(FRACUNIT, actor->scale);
-		else if (actor->z < thefloor + FixedMul(32*FRACUNIT, actor->scale))
-			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
-		else
-			actor->momz += FixedMul(16, actor->scale);
-	}
-
-	if (!actor->target)
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		if (actor->state != &states[actor->info->spawnstate])
-			P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y);
-
-	if (actor->target->player && (!hovermode || actor->reactiontime <= 2*TICRATE))
-	{
-		if (dist < FixedMul(64<<(FRACBITS+(hovermode ? 1 : 0)), actor->scale)
-			&& ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING)))
-		{
-			// Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!!
-			P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale));
-			return;
-		}
-	}
-
-	if (locvar1)
-	{
-		if (actor->health < 2 && P_RandomChance(FRACUNIT/128))
-			P_SpawnMissile(actor, actor->target, locvar1);
-	}
-
-	// Face the player
-	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-
-	if (actor->threshold && dist > FixedMul(256*FRACUNIT, actor->scale))
-		actor->momx = actor->momy = 0;
-
-	if (actor->reactiontime && actor->reactiontime <= 2*TICRATE && dist > actor->target->radius - FixedMul(FRACUNIT, actor->scale))
-	{
-		actor->threshold = 0;
-
-		// Roam around, somewhat in the player's direction.
-		actor->angle += (P_RandomByte()<<10);
-		actor->angle -= (P_RandomByte()<<10);
-
-		if (hovermode)
-		{
-			fixed_t mom;
-			P_Thrust(actor, actor->angle, 2*actor->scale);
-			mom = P_AproxDistance(actor->momx, actor->momy);
-			if (mom > 20*actor->scale)
-			{
-				mom += 20*actor->scale;
-				mom >>= 1;
-				P_InstaThrust(actor, R_PointToAngle2(0, 0, actor->momx, actor->momy), mom);
-			}
-		}
-	}
-	else if (!actor->reactiontime)
-	{
-		if (hovermode && !(actor->flags2 & MF2_FRET)) // Hover Mode
-		{
-			if (dist < FixedMul(512*FRACUNIT, actor->scale))
-			{
-				actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-				P_InstaThrust(actor, actor->angle, FixedMul(40*FRACUNIT, actor->scale));
-				actor->threshold = 1;
-				if (actor->info->attacksound)
-					S_StartSound(actor, actor->info->attacksound);
-			}
-		}
-		actor->reactiontime = 3*TICRATE + (P_RandomByte()>>2);
-	}
-
-	if (actor->health == 1)
-		P_Thrust(actor, actor->angle, 1);
-
-	// Pogo Mode
-	if (!hovermode && actor->z <= actor->floorz)
-	{
-		if (actor->info->activesound)
-			S_StartSound(actor, actor->info->activesound);
-
-		if (dist < FixedMul(256*FRACUNIT, actor->scale))
-		{
-			actor->momz = FixedMul(locvar2, actor->scale);
-			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-			P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale));
-			// pogo on player
-		}
-		else
-		{
-			UINT8 prandom = P_RandomByte();
-			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom);
-			P_InstaThrust(actor, actor->angle, FixedDiv(FixedMul(locvar2, actor->scale), 3*FRACUNIT/2));
-			actor->momz = FixedMul(locvar2, actor->scale); // Bounce up in air
-		}
-	}
-
-	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
-
-	// Move downwards or upwards to go through a passageway.
-	if (nextsector->floorheight > actor->z && nextsector->floorheight - actor->z < FixedMul(128*FRACUNIT, actor->scale))
-		actor->momz += (nextsector->floorheight - actor->z) / 4;
-}
-
-// Function: A_RingExplode
-//
-// Description: An explosion ring exploding
-//
-// var1 = unused
-// var2 = unused
-//
-void A_RingExplode(mobj_t *actor)
-{
-	mobj_t *mo2;
-	thinker_t *th;
-	angle_t d;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RingExplode", actor))
-		return;
-#endif
-
-	for (d = 0; d < 16; d++)
-		P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true);
-
-	S_StartSound(actor, sfx_prloop);
-
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2 == actor) // Don't explode yourself! Endless loop!
-			continue;
-
-		if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > FixedMul(actor->info->painchance, actor->scale))
-			continue;
-
-		if (mo2->flags & MF_SHOOTABLE)
-		{
-			actor->flags2 |= MF2_DEBRIS;
-			P_DamageMobj(mo2, actor, actor->target, 1, 0);
-			continue;
-		}
-	}
-	return;
-}
-
-// Function: A_OldRingExplode
-//
-// Description: An explosion ring exploding, 1.09.4 style
-//
-// var1 = object # to explode as debris
-// var2 = unused
-//
-void A_OldRingExplode(mobj_t *actor) {
-	UINT8 i;
-	mobj_t *mo;
-	const fixed_t ns = FixedMul(20 * FRACUNIT, actor->scale);
-	INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-	boolean changecolor = (actor->target && actor->target->player);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_OldRingExplode", actor))
-		return;
-#endif
-
-	for (i = 0; i < 32; i++)
-	{
-		const angle_t fa = (i*FINEANGLES/16) & FINEMASK;
-
-		mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
-		P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points
-
-		mo->momx = FixedMul(FINECOSINE(fa),ns);
-		mo->momy = FixedMul(FINESINE(fa),ns);
-
-		if (i > 15)
-		{
-			if (i & 1)
-				mo->momz = ns;
-			else
-				mo->momz = -ns;
-		}
-
-		mo->flags2 |= MF2_DEBRIS;
-		mo->fuse = TICRATE/5;
-
-		if (changecolor)
-		{
-			if (gametype != GT_CTF)
-				mo->color = actor->target->color; //copy color
-			else if (actor->target->player->ctfteam == 2)
-				mo->color = skincolor_bluering;
-		}
-	}
-
-	mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
-
-	P_SetTarget(&mo->target, actor->target);
-	mo->momz = ns;
-	mo->flags2 |= MF2_DEBRIS;
-	mo->fuse = TICRATE/5;
-
-	if (changecolor)
-	{
-		if (gametype != GT_CTF)
-			mo->color = actor->target->color; //copy color
-		else if (actor->target->player->ctfteam == 2)
-			mo->color = skincolor_bluering;
-	}
-
-	mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
-
-	P_SetTarget(&mo->target, actor->target);
-	mo->momz = -ns;
-	mo->flags2 |= MF2_DEBRIS;
-	mo->fuse = TICRATE/5;
-
-	if (changecolor)
-	{
-		if (gametype != GT_CTF)
-			mo->color = actor->target->color; //copy color
-		else if (actor->target->player->ctfteam == 2)
-			mo->color = skincolor_bluering;
-	}
-}
-
-// Function: A_MixUp
-//
-// Description: Mix up all of the player positions.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MixUp(mobj_t *actor)
-{
-	boolean teleported[MAXPLAYERS];
-	INT32 i, numplayers = 0, prandom = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MixUp", actor))
-		return;
-#else
-	(void)actor;
-#endif
-
-	if (!multiplayer)
-		return;
-
-	// No mix-up monitors in hide and seek or time only race.
-	// The random factor is okay for other game modes, but in these, it is cripplingly unfair.
-	if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE)
-	{
-		S_StartSound(actor, sfx_lose);
-		return;
-	}
-
-	numplayers = 0;
-	memset(teleported, 0, sizeof (teleported));
-
-	// Count the number of players in the game
-	// and grab their xyz coords
-	for (i = 0; i < MAXPLAYERS; i++)
-		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
-			&& !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
-		{
-			if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
-				continue;
-
-			numplayers++;
-		}
-
-	if (numplayers <= 1) // Not enough players to mix up.
-	{
-		S_StartSound(actor, sfx_lose);
-		return;
-	}
-	else if (numplayers == 2) // Special case -- simple swap
-	{
-		fixed_t x, y, z;
-		angle_t angle;
-		INT32 one = -1, two = 0; // default value 0 to make the compiler shut up
-
-		// Zoom tube stuff
-		mobj_t *tempthing = NULL; //tracer
-		UINT16 carry1,carry2;     //carry
-		INT32 transspeed;         //player speed
-
-		// Starpost stuff
-		INT16 starpostx, starposty, starpostz;
-		INT32 starpostnum;
-		tic_t starposttime;
-		angle_t starpostangle;
-
-		INT32 mflags2;
-
-		for (i = 0; i < MAXPLAYERS; i++)
-			if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
-				&& !players[i].exiting && !players[i].powers[pw_super])
-			{
-				if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
-					continue;
-
-				if (one == -1)
-					one = i;
-				else
-				{
-					two = i;
-					break;
-				}
-			}
-
-		//get this done first!
-		tempthing = players[one].mo->tracer;
-		P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer);
-		P_SetTarget(&players[two].mo->tracer, tempthing);
-
-		//zoom tubes use player->speed to determine direction and speed
-		transspeed = players[one].speed;
-		players[one].speed = players[two].speed;
-		players[two].speed = transspeed;
-
-		//set flags variables now but DON'T set them.
-		carry1 = (players[one].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[one].powers[pw_carry]);
-		carry2 = (players[two].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[two].powers[pw_carry]);
-
-		x = players[one].mo->x;
-		y = players[one].mo->y;
-		z = players[one].mo->z;
-		angle = players[one].mo->angle;
-
-		starpostx = players[one].starpostx;
-		starposty = players[one].starposty;
-		starpostz = players[one].starpostz;
-		starpostangle = players[one].starpostangle;
-		starpostnum = players[one].starpostnum;
-		starposttime = players[one].starposttime;
-
-		mflags2 = players[one].mo->flags2;
-
-		P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle,
-				players[two].starpostx, players[two].starposty, players[two].starpostz,
-				players[two].starpostnum, players[two].starposttime, players[two].starpostangle,
-				players[two].mo->flags2);
-
-		P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz,
-				starpostnum, starposttime, starpostangle,
-				mflags2);
-
-		//carry set after mixup.  Stupid P_ResetPlayer() takes away some of the stuff we look for...
-		//but not all of it!  So we need to make sure they aren't set wrong or anything.
-		players[one].powers[pw_carry] = carry2;
-		players[two].powers[pw_carry] = carry1;
-
-		teleported[one] = true;
-		teleported[two] = true;
-	}
-	else
-	{
-		fixed_t position[MAXPLAYERS][3];
-		angle_t anglepos[MAXPLAYERS];
-		INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0;
-
-		// Zoom tube stuff
-		mobj_t *transtracer[MAXPLAYERS];  //tracer
-		//pflags_t transflag[MAXPLAYERS]; //cyan pink white pink cyan
-		UINT16 transcarry[MAXPLAYERS];    //player carry
-		INT32 transspeed[MAXPLAYERS];     //player speed
-
-		// Star post stuff
-		INT16 spposition[MAXPLAYERS][3];
-		INT32 starpostnum[MAXPLAYERS];
-		tic_t starposttime[MAXPLAYERS];
-		angle_t starpostangle[MAXPLAYERS];
-
-		INT32 flags2[MAXPLAYERS];
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			position[i][0] = position[i][1] = position[i][2] = anglepos[i] = pindex[i] = -1;
-			teleported[i] = false;
-		}
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (playeringame[i] && players[i].playerstate == PST_LIVE
-				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
-			{
-				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
-					continue;
-
-				position[counter][0] = players[i].mo->x;
-				position[counter][1] = players[i].mo->y;
-				position[counter][2] = players[i].mo->z;
-				pindex[counter] = i;
-				anglepos[counter] = players[i].mo->angle;
-				players[i].mo->momx = players[i].mo->momy = players[i].mo->momz =
-					players[i].rmomx = players[i].rmomy = 1;
-				players[i].cmomx = players[i].cmomy = 0;
-
-				transcarry[counter] = (players[i].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[i].powers[pw_carry]);
-				transspeed[counter] = players[i].speed;
-				transtracer[counter] = players[i].mo->tracer;
-
-				spposition[counter][0] = players[i].starpostx;
-				spposition[counter][1] = players[i].starposty;
-				spposition[counter][2] = players[i].starpostz;
-				starpostnum[counter] = players[i].starpostnum;
-				starposttime[counter] = players[i].starposttime;
-				starpostangle[counter] = players[i].starpostangle;
-
-				flags2[counter] = players[i].mo->flags2;
-
-				counter++;
-			}
-		}
-
-		counter = 0;
-
-		// Mix them up!
-		for (;;)
-		{
-			if (counter > 255) // fail-safe to avoid endless loop
-				break;
-			prandom = P_RandomByte();
-			prandom %= numplayers; // I love modular arithmetic, don't you?
-			if (prandom) // Make sure it's not a useless mix
-				break;
-			counter++;
-		}
-
-		counter = 0;
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (playeringame[i] && players[i].playerstate == PST_LIVE
-				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
-			{
-				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
-					continue;
-
-				teleportfrom = (counter + prandom) % numplayers;
-
-				//speed and tracer come before...
-				players[i].speed = transspeed[teleportfrom];
-				P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]);
-
-				P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom],
-					spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2],
-					starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom],
-					flags2[teleportfrom]);
-
-				//...carry after.  same reasoning.
-				players[i].powers[pw_carry] = transcarry[teleportfrom];
-
-				teleported[i] = true;
-				counter++;
-			}
-		}
-	}
-
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (teleported[i])
-		{
-			if (playeringame[i] && players[i].playerstate == PST_LIVE
-				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
-			{
-				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
-					continue;
-
-				P_SetThingPosition(players[i].mo);
-
-#ifdef ESLOPE
-				players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
-				players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
-#else
-				players[i].mo->floorz = players[i].mo->subsector->sector->floorheight;
-				players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight;
-#endif
-
-				P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y);
-			}
-		}
-	}
-
-	// Play the 'bowrwoosh!' sound
-	S_StartSound(NULL, sfx_mixup);
-}
-
-// Function: A_RecyclePowers
-//
-// Description: Take all player's powers, and swap 'em.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_RecyclePowers(mobj_t *actor)
-{
-	INT32 i, j, k, numplayers = 0;
-
-#ifdef WEIGHTEDRECYCLER
-	UINT8 beneficiary = 255;
-#endif
-	UINT8 playerslist[MAXPLAYERS];
-	UINT8 postscramble[MAXPLAYERS];
-
-	UINT16 powers[MAXPLAYERS][NUMPOWERS];
-	INT32 weapons[MAXPLAYERS];
-	INT32 weaponheld[MAXPLAYERS];
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RecyclePowers", actor))
-		return;
-#endif
-
-#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA)
-	// actor is used in all scenarios but this one, funny enough
-	(void)actor;
-#endif
-
-	if (!multiplayer)
-	{
-		S_StartSound(actor, sfx_lose);
-		return;
-	}
-
-	numplayers = 0;
-
-	// Count the number of players in the game
-	for (i = 0, j = 0; i < MAXPLAYERS; i++)
-	{
-		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
-			&& !players[i].exiting && !((netgame || multiplayer) && players[i].spectator))
-		{
-#ifndef WEIGHTEDRECYCLER
-			if (players[i].powers[pw_super])
-				continue; // Ignore super players
-#endif
-
-			numplayers++;
-			postscramble[j] = playerslist[j] = (UINT8)i;
-
-#ifdef WEIGHTEDRECYCLER
-			// The guy who started the recycle gets the best result
-			if (actor && actor->target && actor->target->player && &players[i] == actor->target->player)
-				beneficiary = (UINT8)i;
-#endif
-
-			// Save powers
-			for (k = 0; k < NUMPOWERS; k++)
-				powers[i][k] = players[i].powers[k];
-			//1.1: ring weapons too
-			weapons[i] = players[i].ringweapons;
-			weaponheld[i] = players[i].currentweapon;
-
-			j++;
-		}
-	}
-
-	if (numplayers <= 1)
-	{
-		S_StartSound(actor, sfx_lose);
-		return; //nobody to touch!
-	}
-
-	//shuffle the post scramble list, whee!
-	// hardcoded 0-1 to 1-0 for two players
-	if (numplayers == 2)
-	{
-		postscramble[0] = playerslist[1];
-		postscramble[1] = playerslist[0];
-	}
-	else
-	for (j = 0; j < numplayers; j++)
-	{
-		UINT8 tempint;
-
-		i = j + ((P_RandomByte() + leveltime) % (numplayers - j));
-		tempint = postscramble[j];
-		postscramble[j] = postscramble[i];
-		postscramble[i] = tempint;
-	}
-
-#ifdef WEIGHTEDRECYCLER
-	//the joys of qsort...
-	if (beneficiary != 255) {
-		qsort(playerslist, numplayers, sizeof(UINT8), P_RecycleCompare);
-
-		// now, make sure the benificiary is in the best slot
-		// swap out whatever poor sap was going to get the best items
-		for (i = 0; i < numplayers; i++)
-		{
-			if (postscramble[i] == beneficiary)
-			{
-				postscramble[i] = postscramble[0];
-				postscramble[0] = beneficiary;
-				break;
-			}
-		}
-	}
-#endif
-
-	// now assign!
-	for (i = 0; i < numplayers; i++)
-	{
-		UINT8 send_pl = playerslist[i];
-		UINT8 recv_pl = postscramble[i];
-
-		// debugF
-		CONS_Debug(DBG_GAMELOGIC, "sending player %hu's items to %hu\n", (UINT16)send_pl, (UINT16)recv_pl);
-
-		for (j = 0; j < NUMPOWERS; j++)
-		{
-			if (j == pw_flashing || j == pw_underwater || j == pw_spacetime || j == pw_carry
-			    || j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super)
-				continue;
-			players[recv_pl].powers[j] = powers[send_pl][j];
-		}
-
-		//1.1: weapon rings too
-		players[recv_pl].ringweapons = weapons[send_pl];
-		players[recv_pl].currentweapon = weaponheld[send_pl];
-
-		P_SpawnShieldOrb(&players[recv_pl]);
-		if (P_IsLocalPlayer(&players[recv_pl]))
-			P_RestoreMusic(&players[recv_pl]);
-		P_FlashPal(&players[recv_pl], PAL_RECYCLE, 10);
-	}
-
-	S_StartSound(NULL, sfx_gravch); //heh, the sound effect I used is already in
-}
-
-// Function: A_Boss1Chase
-//
-// Description: Like A_Chase, but for Boss 1.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss1Chase(mobj_t *actor)
-{
-	INT32 delta;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss1Chase", actor))
-		return;
-#endif
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjStateNF(actor, actor->info->spawnstate);
-		return;
-	}
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	// do not attack twice in a row
-	if (actor->flags2 & MF2_JUSTATTACKED)
-	{
-		actor->flags2 &= ~MF2_JUSTATTACKED;
-		P_NewChaseDir(actor);
-		return;
-	}
-
-	if (actor->movecount)
-		goto nomissile;
-
-	if (!P_CheckMissileRange(actor))
-		goto nomissile;
-
-	if (actor->reactiontime <= 0)
-	{
-		if (actor->health > actor->info->damage)
-		{
-			if (P_RandomChance(FRACUNIT/2))
-				P_SetMobjState(actor, actor->info->missilestate);
-			else
-				P_SetMobjState(actor, actor->info->meleestate);
-		}
-		else
-		{
-			P_LinedefExecute(LE_PINCHPHASE, actor, NULL);
-			P_SetMobjState(actor, actor->info->raisestate);
-		}
-
-		actor->flags2 |= MF2_JUSTATTACKED;
-		actor->reactiontime = actor->info->reactiontime;
-		return;
-	}
-
-	// ?
-nomissile:
-	// possibly choose another target
-	if (multiplayer && P_RandomChance(FRACUNIT/128))
-	{
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-	}
-
-	if (actor->flags & MF_FLOAT && !(actor->flags2 & MF2_SKULLFLY))
-	{ // Float up/down to your target's position. Stay above them, but not out of jump range.
-		fixed_t target_min = actor->target->floorz+FixedMul(64*FRACUNIT, actor->scale);
-		if (target_min < actor->target->z - actor->height)
-			target_min = actor->target->z - actor->height;
-		if (target_min < actor->floorz+FixedMul(33*FRACUNIT, actor->scale))
-			target_min = actor->floorz+FixedMul(33*FRACUNIT, actor->scale);
-		if (actor->z > target_min+FixedMul(16*FRACUNIT, actor->scale))
-			actor->momz = FixedMul((-actor->info->speed<<(FRACBITS-1)), actor->scale);
-		else if (actor->z < target_min)
-			actor->momz = FixedMul(actor->info->speed<<(FRACBITS-1), actor->scale);
-		else
-			actor->momz = FixedMul(actor->momz,7*FRACUNIT/8);
-	}
-
-	// chase towards player
-	if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius)
-	{
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-			P_NewChaseDir(actor);
-	}
-	// too close, don't want to chase.
-	else if (--actor->movecount < 0)
-	{
-		// A mini-A_FaceTarget based on P_NewChaseDir.
-		// Yes, it really is this simple when you get down to it.
-		fixed_t deltax, deltay;
-
-		deltax = actor->target->x - actor->x;
-		deltay = actor->target->y - actor->y;
-
-		actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)];
-		actor->movecount = P_RandomByte() & 15;
-	}
-}
-
-// Function: A_Boss2Chase
-//
-// Description: Really doesn't 'chase', but rather goes in a circle.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss2Chase(mobj_t *actor)
-{
-	fixed_t radius;
-	boolean reverse = false;
-	INT32 speedvar;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss2Chase", actor))
-		return;
-#endif
-
-	if (actor->health <= 0)
-		return;
-
-	// Startup randomness
-	if (actor->reactiontime <= -666)
-		actor->reactiontime = 2*TICRATE + P_RandomByte();
-
-	// When reactiontime hits zero, he will go the other way
-	if (--actor->reactiontime <= 0)
-	{
-		reverse = true;
-		actor->reactiontime = 2*TICRATE + P_RandomByte();
-	}
-
-	P_SetTarget(&actor->target, P_GetClosestAxis(actor));
-
-	if (!actor->target) // This should NEVER happen.
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Boss2 has no target!\n");
-		A_BossDeath(actor);
-		return;
-	}
-
-	radius = actor->target->radius;
-
-	if (reverse)
-	{
-		actor->watertop = -actor->watertop;
-		actor->extravalue1 = 18;
-		if (actor->flags2 & MF2_AMBUSH)
-			actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2;
-		actor->extravalue2 = actor->extravalue1;
-	}
-
-	// Turnaround
-	if (actor->extravalue1 > 0)
-	{
-		--actor->extravalue1;
-
-		// Set base angle
-		{
-			const angle_t fa = (actor->target->angle + FixedAngle(actor->watertop))>>ANGLETOFINESHIFT;
-			const fixed_t fc = FixedMul(FINECOSINE(fa),radius);
-			const fixed_t fs = FixedMul(FINESINE(fa),radius);
-			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs);
-		}
-
-		// Now turn you around!
-		// Note that the start position is the final position, we move it back around
-		// to intermediary positions...
-		actor->angle -= FixedAngle(FixedMul(FixedDiv(180<<FRACBITS, actor->extravalue2<<FRACBITS), actor->extravalue1<<FRACBITS));
-	}
-	else
-	{
-		// Only speed up if you have the 'Deaf' flag.
-		if (actor->flags2 & MF2_AMBUSH)
-			speedvar = actor->health;
-		else
-			speedvar = actor->info->spawnhealth;
-
-		actor->target->angle += // Don't use FixedAngleC!
-			FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT));
-
-		P_UnsetThingPosition(actor);
-		{
-			const angle_t fa = actor->target->angle>>ANGLETOFINESHIFT;
-			const fixed_t fc = FixedMul(FINECOSINE(fa),radius);
-			const fixed_t fs = FixedMul(FINESINE(fa),radius);
-			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs);
-			actor->x = actor->target->x + fc;
-			actor->y = actor->target->y + fs;
-		}
-		P_SetThingPosition(actor);
-
-		// Spray goo once every second
-		if (leveltime % (speedvar*15/10)-1 == 0)
-		{
-			const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale);
-			mobj_t *goop;
-			fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale);
-			angle_t fa;
-			// actor->movedir is used to determine the last
-			// direction goo was sprayed in. There are 8 possible
-			// directions to spray. (45-degree increments)
-
-			actor->movedir++;
-			actor->movedir %= NUMDIRS;
-			fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
-
-			goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
-			goop->momx = FixedMul(FINECOSINE(fa),ns);
-			goop->momy = FixedMul(FINESINE(fa),ns);
-			goop->momz = FixedMul(4*FRACUNIT, actor->scale);
-			goop->fuse = 10*TICRATE;
-
-			if (actor->info->attacksound)
-				S_StartAttackSound(actor, actor->info->attacksound);
-
-			if (P_RandomChance(FRACUNIT/2))
-			{
-				goop->momx *= 2;
-				goop->momy *= 2;
-			}
-			else if (P_RandomChance(129*FRACUNIT/256))
-			{
-				goop->momx *= 3;
-				goop->momy *= 3;
-			}
-
-			actor->flags2 |= MF2_JUSTATTACKED;
-		}
-	}
-}
-
-// Function: A_Boss2Pogo
-//
-// Description: Pogo part of Boss 2 AI.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss2Pogo(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss2Pogo", actor))
-		return;
-#endif
-	if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0)
-	{
-		if (actor->state != &states[actor->info->raisestate])
-			P_SetMobjState(actor, actor->info->raisestate);
-		// Pogo Mode
-	}
-	else if (actor->momz < 0 && actor->reactiontime)
-	{
-		const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale);
-		mobj_t *goop;
-		fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale);
-		angle_t fa;
-		INT32 i;
-		// spray in all 8 directions!
-		for (i = 0; i < 8; i++)
-		{
-			actor->movedir++;
-			actor->movedir %= NUMDIRS;
-			fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
-
-			goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
-			goop->momx = FixedMul(FINECOSINE(fa),ns);
-			goop->momy = FixedMul(FINESINE(fa),ns);
-			goop->momz = FixedMul(4*FRACUNIT, actor->scale);
-
-			goop->fuse = 10*TICRATE;
-		}
-		actor->reactiontime = 0; // we already shot goop, so don't do it again!
-		if (actor->info->attacksound)
-			S_StartAttackSound(actor, actor->info->attacksound);
-		actor->flags2 |= MF2_JUSTATTACKED;
-	}
-}
-
-// Function: A_Boss2TakeDamage
-//
-// Description: Special function for Boss 2 so you can't just sit and destroy him.
-//
-// var1 = Invincibility duration
-// var2 = unused
-//
-void A_Boss2TakeDamage(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss2TakeDamage", actor))
-		return;
-#endif
-	A_Pain(actor);
-	actor->reactiontime = 1; // turn around
-	if (locvar1 == 0) // old A_Invincibilerize behavior
-		actor->movecount = TICRATE;
-	else
-		actor->movecount = locvar1; // become flashing invulnerable for this long.
-}
-
-// Function: A_Boss7Chase
-//
-// Description: Like A_Chase, but for Black Eggman
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss7Chase(mobj_t *actor)
-{
-	INT32 delta;
-	INT32 i;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss7Chase", actor))
-		return;
-#endif
-
-	if (actor->z != actor->floorz)
-		return;
-
-	// Self-adjust if stuck on the edge
-	if (actor->tracer)
-	{
-		if (P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y) > 128*FRACUNIT - actor->radius)
-			P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), FRACUNIT);
-	}
-
-	if (actor->flags2 & MF2_FRET)
-	{
-		P_SetMobjState(actor, S_BLACKEGG_DESTROYPLAT1);
-		S_StartSound(0, sfx_s3k53);
-		actor->flags2 &= ~MF2_FRET;
-		return;
-	}
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	// Is a player on top of us?
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (!playeringame[i] || players[i].spectator)
-			continue;
-
-		if (!players[i].mo)
-			continue;
-
-		if (players[i].mo->health <= 0)
-			continue;
-
-		if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) > actor->radius)
-			continue;
-
-		if (players[i].mo->z > actor->z + actor->height - 2*FRACUNIT
-			&& players[i].mo->z < actor->z + actor->height + 32*FRACUNIT)
-		{
-			// Punch him!
-			P_SetMobjState(actor, actor->info->meleestate);
-			S_StartSound(0, sfx_begrnd); // warning sound
-			return;
-		}
-	}
-
-	if (actor->health <= actor->info->damage
-		&& actor->target
-		&& actor->target->player
-		&& (actor->target->player->powers[pw_carry] == CR_GENERIC))
-	{
-		A_FaceTarget(actor);
-		P_SetMobjState(actor, S_BLACKEGG_SHOOT1);
-		actor->movecount = TICRATE + P_RandomByte()/2;
-		return;
-	}
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	if (actor->reactiontime <= 0 && actor->z == actor->floorz)
-	{
-		// Here, we'll call P_RandomByte() and decide what kind of attack to do
-		switch(actor->threshold)
-		{
-			case 0: // Lob cannon balls
-				if (actor->z < 1056*FRACUNIT)
-				{
-					A_FaceTarget(actor);
-					P_SetMobjState(actor, actor->info->xdeathstate);
-					actor->movecount = 7*TICRATE + P_RandomByte();
-					break;
-				}
-				actor->threshold++;
-				/* FALLTHRU */
-			case 1: // Chaingun Goop
-				A_FaceTarget(actor);
-				P_SetMobjState(actor, S_BLACKEGG_SHOOT1);
-
-				if (actor->health > actor->info->damage)
-					actor->movecount = TICRATE + P_RandomByte()/3;
-				else
-					actor->movecount = TICRATE + P_RandomByte()/2;
-				break;
-			case 2: // Homing Missile
-				A_FaceTarget(actor);
-				P_SetMobjState(actor, actor->info->missilestate);
-				S_StartSound(0, sfx_beflap);
-				break;
-		}
-
-		actor->threshold++;
-		actor->threshold %= 3;
-		return;
-	}
-
-	// possibly choose another target
-	if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-		&& P_BossTargetPlayer(actor, false))
-		return; // got a new target
-
-	if (leveltime & 1)
-	{
-		// chase towards player
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-			P_NewChaseDir(actor);
-	}
-}
-
-// Function: A_GoopSplat
-//
-// Description: Black Eggman goop hits a target and sticks around for awhile.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GoopSplat(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GoopSplat", actor))
-		return;
-#endif
-	P_UnsetThingPosition(actor);
-	if (sector_list)
-	{
-		P_DelSeclist(sector_list);
-		sector_list = NULL;
-	}
-	actor->flags = MF_SPECIAL; // Not a typo
-	P_SetThingPosition(actor);
-}
-
-// Function: A_Boss2PogoSFX
-//
-// Description: Pogoing for Boss 2
-//
-// var1 = pogo jump strength
-// var2 = idle pogo speed
-//
-void A_Boss2PogoSFX(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss2PogoSFX", actor))
-		return;
-#endif
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		return;
-	}
-
-	// Boing!
-	if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(256*FRACUNIT, actor->scale))
-	{
-		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale));
-		// pogo on player
-	}
-	else
-	{
-		UINT8 prandom = P_RandomByte();
-		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom);
-		P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale));
-	}
-	if (actor->info->activesound) S_StartSound(actor, actor->info->activesound);
-	actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
-	actor->reactiontime = 1;
-}
-
-// Function: A_Boss2PogoTarget
-//
-// Description: Pogoing for Boss 2, tries to actually land on the player directly.
-//
-// var1 = pogo jump strength
-// var2 = idle pogo speed
-//
-void A_Boss2PogoTarget(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss2PogoTarget", actor))
-		return;
-#endif
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing])
-	|| P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) >= FixedMul(512*FRACUNIT, actor->scale))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 512*FRACUNIT))
-			; // got a new target
-		else if (P_LookForPlayers(actor, true, false, 0))
-			; // got a new target
-		else
-			return;
-	}
-
-	// Target hit, retreat!
-	if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET)
-	{
-		UINT8 prandom = P_RandomByte();
-		actor->z++; // unstick from the floor
-		actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
-		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it.
-		P_InstaThrust(actor, actor->angle+ANGLE_180, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed
-	}
-	// Try to land on top of the player.
-	else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale))
-	{
-		fixed_t airtime, gravityadd, zoffs;
-
-		// check gravity in the sector (for later math)
-		P_CheckGravity(actor, true);
-		gravityadd = actor->momz;
-
-		actor->z++; // unstick from the floor
-		actor->momz = FixedMul(locvar1 + (locvar1>>2), actor->scale); // Bounce up in air
-
-		/*badmath = 0;
-		airtime = 0;
-		do {
-			badmath += momz;
-			momz += gravityadd;
-			airtime++;
-		} while(badmath > 0);
-		airtime = 2*airtime<<FRACBITS;
-		*/
-
-		// Remember, kids!
-		// Reduced down Calculus lets you avoid bad 'logic math' loops!
-		//airtime = FixedDiv(-actor->momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler
-		zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height,
-		airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet
-
-		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-		P_InstaThrust(actor, actor->angle, FixedDiv(P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y), airtime));
-	}
-	// Wander semi-randomly towards the player to get closer.
-	else
-	{
-		UINT8 prandom = P_RandomByte();
-		actor->z++; // unstick from the floor
-		actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
-		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it.
-		P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed
-	}
-	// Boing!
-	if (actor->info->activesound) S_StartSound(actor, actor->info->activesound);
-
-	if (actor->info->missilestate) // spawn the pogo stick collision box
-	{
-		mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
-		pogo->target = actor;
-	}
-
-	actor->reactiontime = 1;
-}
-
-// Function: A_EggmanBox
-//
-// Description: Harms the player
-//
-// var1 = unused
-// var2 = unused
-//
-void A_EggmanBox(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_EggmanBox", actor))
-		return;
-#endif
-	if (!actor->target || !actor->target->player)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
-		return;
-	}
-
-	P_DamageMobj(actor->target, actor, actor, 1, 0); // Ow!
-}
-
-// Function: A_TurretFire
-//
-// Description: Initiates turret fire.
-//
-// var1 = object # to repeatedly fire
-// var2 = distance threshold
-//
-void A_TurretFire(mobj_t *actor)
-{
-	INT32 count = 0;
-	fixed_t dist;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_TurretFire", actor))
-		return;
-#endif
-
-	if (locvar2)
-		dist = FixedMul(locvar2*FRACUNIT, actor->scale);
-	else
-		dist = FixedMul(2048*FRACUNIT, actor->scale);
-
-	if (!locvar1)
-		locvar1 = MT_TURRETLASER;
-
-	while (P_SupermanLook4Players(actor) && count < MAXPLAYERS)
-	{
-		if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist)
-		{
-			actor->flags2 |= MF2_FIRING;
-			actor->extravalue1 = locvar1;
-			break;
-		}
-
-		count++;
-	}
-}
-
-// Function: A_SuperTurretFire
-//
-// Description: Initiates turret fire that even stops Super Sonic.
-//
-// var1 = object # to repeatedly fire
-// var2 = distance threshold
-//
-void A_SuperTurretFire(mobj_t *actor)
-{
-	INT32 count = 0;
-	fixed_t dist;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SuperTurretFire", actor))
-		return;
-#endif
-
-	if (locvar2)
-		dist = FixedMul(locvar2*FRACUNIT, actor->scale);
-	else
-		dist = FixedMul(2048*FRACUNIT, actor->scale);
-
-	if (!locvar1)
-		locvar1 = MT_TURRETLASER;
-
-	while (P_SupermanLook4Players(actor) && count < MAXPLAYERS)
-	{
-		if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist)
-		{
-			actor->flags2 |= MF2_FIRING;
-			actor->flags2 |= MF2_SUPERFIRE;
-			actor->extravalue1 = locvar1;
-			break;
-		}
-
-		count++;
-	}
-}
-
-// Function: A_TurretStop
-//
-// Description: Stops the turret fire.
-//
-// var1 = Don't play activesound?
-// var2 = unused
-//
-void A_TurretStop(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_TurretStop", actor))
-		return;
-#endif
-
-	actor->flags2 &= ~MF2_FIRING;
-	actor->flags2 &= ~MF2_SUPERFIRE;
-
-	if (actor->target && actor->info->activesound && !locvar1)
-		S_StartSound(actor, actor->info->activesound);
-}
-
-// Function: A_SparkFollow
-//
-// Description: Used by the hyper sparks to rotate around their target.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SparkFollow(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SparkFollow", actor))
-		return;
-#endif
-
-	if ((!actor->target || (actor->target->health <= 0))
-		|| (actor->target->player && !actor->target->player->powers[pw_super]))
-	{
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	actor->angle += FixedAngle(actor->info->damage*FRACUNIT);
-	P_UnsetThingPosition(actor);
-	{
-		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
-		actor->x = actor->target->x + FixedMul(FINECOSINE(fa),FixedMul(actor->info->speed, actor->scale));
-		actor->y = actor->target->y + FixedMul(FINESINE(fa),FixedMul(actor->info->speed, actor->scale));
-		if (actor->target->eflags & MFE_VERTICALFLIP)
-			actor->z = actor->target->z + actor->target->height - FixedDiv(actor->target->height,3*FRACUNIT);
-		else
-			actor->z = actor->target->z + FixedDiv(actor->target->height,3*FRACUNIT) - actor->height;
-	}
-	P_SetThingPosition(actor);
-}
-
-// Function: A_BuzzFly
-//
-// Description: Makes an object slowly fly after a player, in the manner of a Buzz.
-//
-// var1 = sfx to play
-// var2 = length of sfx, set to threshold if played
-//
-void A_BuzzFly(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BuzzFly", actor))
-		return;
-#endif
-	if (actor->flags2 & MF2_AMBUSH)
-		return;
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		actor->momz = actor->momy = actor->momx = 0;
-		P_SetMobjState(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// turn towards movement direction if not there yet
-	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-
-	if (actor->target->health <= 0 || (!actor->threshold && !P_CheckSight(actor, actor->target)))
-	{
-		if ((multiplayer || netgame) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)))
-			return; // got a new target
-
-		actor->momx = actor->momy = actor->momz = 0;
-		P_SetMobjState(actor, actor->info->spawnstate); // Go back to looking around
-		return;
-	}
-
-	// If the player is over 3072 fracunits away, then look for another player
-	if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y),
-		actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale))
-	{
-		if (multiplayer || netgame)
-			P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)); // maybe get a new target
-
-		return;
-	}
-
-	// chase towards player
-	{
-		INT32 dist, realspeed;
-		const fixed_t mf = 5*(FRACUNIT/4);
-
-		if (ultimatemode)
-			realspeed = FixedMul(FixedMul(actor->info->speed,mf), actor->scale);
-		else
-			realspeed = FixedMul(actor->info->speed, actor->scale);
-
-		dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x,
-			actor->target->y - actor->y), actor->target->z - actor->z);
-
-		if (dist < 1)
-			dist = 1;
-
-		actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), realspeed);
-		actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), realspeed);
-		actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), realspeed);
-
-		if (actor->z+actor->momz >= actor->waterbottom && actor->watertop > actor->floorz
-			&& actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)
-			&& actor->z+actor->momz <= actor->watertop)
-		{
-			actor->momz = 0;
-			actor->z = actor->watertop;
-		}
-	}
-
-	if (locvar1 != sfx_None && !actor->threshold)
-	{
-		S_StartSound(actor, locvar1);
-		actor->threshold = locvar2;
-	}
-}
-
-// Function: A_GuardChase
-//
-// Description: Modified A_Chase for Egg Guard
-//
-// var1 = unused
-// var2 = unused
-//
-void A_GuardChase(mobj_t *actor)
-{
-	INT32 delta;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GuardChase", actor))
-		return;
-#endif
-
-	if (actor->reactiontime)
-		actor->reactiontime--;
-
-	if (actor->threshold != 42) // In formation...
-	{
-		fixed_t speed;
-
-		if (!actor->tracer || !actor->tracer->health)
-		{
-			P_SetTarget(&actor->tracer, NULL);
-			actor->threshold = 42;
-			P_SetMobjState(actor, actor->info->painstate);
-			actor->flags |= MF_SPECIAL|MF_SHOOTABLE;
-			return;
-		}
-
-		speed = actor->extravalue1*actor->scale;
-
-		if (actor->flags2 & MF2_AMBUSH)
-			speed <<= 1;
-
-		if (speed
-		&& !P_TryMove(actor,
-			actor->x + P_ReturnThrustX(actor, actor->angle, speed),
-			actor->y + P_ReturnThrustY(actor, actor->angle, speed),
-			false)
-		&& speed > 0) // can't be the same check as previous so that P_TryMove gets to happen.
-		{
-			if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL))
-				actor->angle += ANGLE_90;
-			else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA))
-				actor->angle -= ANGLE_90;
-			else
-				actor->angle += ANGLE_180;
-		}
-
-		if (actor->extravalue1 < actor->info->speed)
-			actor->extravalue1++;
-	}
-	else // Break ranks!
-	{
-		// turn towards movement direction if not there yet
-		if (actor->movedir < NUMDIRS)
-		{
-			actor->angle &= (7<<29);
-			delta = actor->angle - (actor->movedir << 29);
-
-			if (delta > 0)
-				actor->angle -= ANGLE_45;
-			else if (delta < 0)
-				actor->angle += ANGLE_45;
-		}
-
-		if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-		{
-			// look for a new target
-			if (P_LookForPlayers(actor, true, false, 0))
-				return; // got a new target
-
-			P_SetMobjStateNF(actor, actor->info->spawnstate);
-			return;
-		}
-
-		// possibly choose another target
-		if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-			&& P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		// chase towards player
-		if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed))
-		{
-			P_NewChaseDir(actor);
-			actor->movecount += 5; // Increase tics before change in direction allowed.
-		}
-	}
-
-	// Now that we've moved, its time for our shield to move!
-	// Otherwise it'll never act as a proper overlay.
-	if (actor->tracer && actor->tracer->state
-	&& actor->tracer->state->action.acp1)
-	{
-		var1 = actor->tracer->state->var1, var2 = actor->tracer->state->var2;
-		actor->tracer->state->action.acp1(actor->tracer);
-	}
-}
-
-// Function: A_EggShield
-//
-// Description: Modified A_Chase for Egg Guard's shield
-//
-// var1 = unused
-// var2 = unused
-//
-void A_EggShield(mobj_t *actor)
-{
-	INT32 i;
-	player_t *player;
-	fixed_t blockdist;
-	fixed_t newx, newy;
-	fixed_t movex, movey;
-	angle_t angle;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_EggShield", actor))
-		return;
-#endif
-
-	if (!actor->target || !actor->target->health)
-	{
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	newx = actor->target->x + P_ReturnThrustX(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale));
-	newy = actor->target->y + P_ReturnThrustY(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale));
-
-	movex = newx - actor->x;
-	movey = newy - actor->y;
-
-	actor->angle = actor->target->angle;
-	if (actor->target->eflags & MFE_VERTICALFLIP)
-	{
-		actor->eflags |= MFE_VERTICALFLIP;
-		actor->z = actor->target->z + actor->target->height - actor->height;
-	}
-	else
-		actor->z = actor->target->z;
-
-	actor->destscale = actor->target->destscale;
-	P_SetScale(actor, actor->target->scale);
-
-	actor->floorz = actor->target->floorz;
-	actor->ceilingz = actor->target->ceilingz;
-
-	if (!movex && !movey)
-		return;
-
-	P_UnsetThingPosition(actor);
-	actor->x = newx;
-	actor->y = newy;
-	P_SetThingPosition(actor);
-
-	// Search for players to push
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (!playeringame[i] || players[i].spectator)
-			continue;
-
-		player = &players[i];
-
-		if (!player->mo)
-			continue;
-
-		if (player->mo->z > actor->z + actor->height)
-			continue;
-
-		if (player->mo->z + player->mo->height < actor->z)
-			continue;
-
-		blockdist = actor->radius + player->mo->radius;
-
-		if (abs(actor->x - player->mo->x) >= blockdist || abs(actor->y - player->mo->y) >= blockdist)
-			continue; // didn't hit it
-
-		angle = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle;
-
-		if (angle > ANGLE_90 && angle < ANGLE_270)
-			continue;
-
-		// Blocked by the shield
-		player->mo->momx += movex;
-		player->mo->momy += movey;
-		return;
-	}
-}
-
-
-// Function: A_SetReactionTime
-//
-// Description: Sets the object's reaction time.
-//
-// var1 = 1 (use value in var2); 0 (use info table value)
-// var2 = if var1 = 1, then value to set
-//
-void A_SetReactionTime(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetReactionTime", actor))
-		return;
-#endif
-	if (var1)
-		actor->reactiontime = var2;
-	else
-		actor->reactiontime = actor->info->reactiontime;
-}
-
-// Function: A_Boss1Spikeballs
-//
-// Description: Boss 1 spikeball spawning loop.
-//
-// var1 = ball number
-// var2 = total balls
-//
-void A_Boss1Spikeballs(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *ball;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss1Spikeballs", actor))
-		return;
-#endif
-
-	ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL);
-	P_SetTarget(&ball->target, actor);
-	ball->movedir = FixedAngle(FixedMul(FixedDiv(locvar1<<FRACBITS, locvar2<<FRACBITS), 360<<FRACBITS));
-	ball->threshold = ball->radius + actor->radius + ball->info->painchance;
-
-	S_StartSound(ball, ball->info->seesound);
-	var1 = ball->state->var1, var2 = ball->state->var2;
-	ball->state->action.acp1(ball);
-}
-
-// Function: A_Boss3TakeDamage
-//
-// Description: Called when Boss 3 takes damage.
-//
-// var1 = movecount value
-// var2 = unused
-//
-void A_Boss3TakeDamage(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss3TakeDamage", actor))
-		return;
-#endif
-	actor->movecount = var1;
-
-	if (actor->target && actor->target->spawnpoint)
-		actor->threshold = actor->target->spawnpoint->extrainfo;
-}
-
-// Function: A_Boss3Path
-//
-// Description: Does pathfinding along Boss 3's nodes.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss3Path(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss3Path", actor))
-		return;
-#endif
-
-	if (actor->tracer && actor->tracer->health && actor->tracer->movecount)
-		actor->movecount |= 1;
-	else if (actor->movecount & 1)
-		actor->movecount = 0;
-
-	if (actor->movecount & 2) // We've reached a firing point?
-	{
-		// Wait here and pretend to be angry or something.
-		actor->momx = 0;
-		actor->momy = 0;
-		actor->momz = 0;
-		P_SetTarget(&actor->target, actor->tracer->target);
-		var1 = 0, var2 = 0;
-		A_FaceTarget(actor);
-		if (actor->tracer->state == &states[actor->tracer->info->missilestate])
-			P_SetMobjState(actor, actor->info->missilestate);
-		return;
-	}
-	else if (actor->threshold >= 0) // Traveling mode
-	{
-		thinker_t *th;
-		mobj_t *mo2;
-		fixed_t dist, dist2;
-		fixed_t speed;
-
-		P_SetTarget(&actor->target, NULL);
-
-		// scan the thinkers
-		// to find a point that matches
-		// the number
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
-		{
-			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-				continue;
-
-			mo2 = (mobj_t *)th;
-			if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold)
-			{
-				P_SetTarget(&actor->target, mo2);
-				break;
-			}
-		}
-
-		if (!actor->target) // Should NEVER happen
-		{
-			CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold);
-			return;
-		}
-
-		dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
-
-		if (dist < 1)
-			dist = 1;
-
-		if (actor->tracer && ((actor->tracer->movedir)
-		|| (actor->tracer->health <= actor->tracer->info->damage)))
-			speed = actor->info->speed * 2;
-		else
-			speed = actor->info->speed;
-
-		actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed);
-		actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed);
-		actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed);
-
-		if (actor->momx != 0 || actor->momy != 0)
-			actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
-
-		dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz));
-
-		if (dist2 < 1)
-			dist2 = 1;
-
-		if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
-		{
-			// If further away, set XYZ of mobj to waypoint location
-			P_UnsetThingPosition(actor);
-			actor->x = actor->target->x;
-			actor->y = actor->target->y;
-			actor->z = actor->target->z;
-			actor->momx = actor->momy = actor->momz = 0;
-			P_SetThingPosition(actor);
-
-			if (actor->threshold == 0)
-			{
-				P_RemoveMobj(actor); // Cycle completed. Dummy removed.
-				return;
-			}
-
-			// Set to next waypoint in sequence
-			if (actor->target->spawnpoint)
-			{
-				// From the center point, choose one of the five paths
-				if (actor->target->spawnpoint->angle == 0)
-				{
-					P_RemoveMobj(actor); // Cycle completed. Dummy removed.
-					return;
-				}
-				else
-					actor->threshold = actor->target->spawnpoint->extrainfo;
-
-				// If the deaf flag is set, go into firing mode
-				if (actor->target->spawnpoint->options & MTF_AMBUSH)
-					actor->movecount |= 2;
-			}
-			else // This should never happen, as well
-				CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n");
-		}
-	}
-}
-
-// Function: A_LinedefExecute
-//
-// Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well.
-//
-// var1 = tag
-// var2 = add angle to tag (optional)
-//
-void A_LinedefExecute(mobj_t *actor)
-{
-	INT32 tagnum;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_LinedefExecute", actor))
-		return;
-#endif
-
-	tagnum = locvar1;
-	// state numbers option is no more, custom states cannot be guaranteed to stay the same number anymore, now that they can be defined by names instead
-
-	if (locvar2)
-		tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS);
-
-	CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum);
-
-	// tag 32768 displayed in map editors is actually tag -32768, tag 32769 is -32767, 65535 is -1 etc.
-	P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector);
-}
-
-// Function: A_PlaySeeSound
-//
-// Description: Plays the object's seesound.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_PlaySeeSound(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PlaySeeSound", actor))
-		return;
-#endif
-	if (actor->info->seesound)
-		S_StartScreamSound(actor, actor->info->seesound);
-}
-
-// Function: A_PlayAttackSound
-//
-// Description: Plays the object's attacksound.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_PlayAttackSound(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PlayAttackSound", actor))
-		return;
-#endif
-	if (actor->info->attacksound)
-		S_StartAttackSound(actor, actor->info->attacksound);
-}
-
-// Function: A_PlayActiveSound
-//
-// Description: Plays the object's activesound.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_PlayActiveSound(mobj_t *actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PlayActiveSound", actor))
-		return;
-#endif
-	if (actor->info->activesound)
-		S_StartSound(actor, actor->info->activesound);
-}
-
-// Function: A_SmokeTrailer
-//
-// Description: Adds smoke trails to an object.
-//
-// var1 = object # to spawn as smoke
-// var2 = unused
-//
-void A_SmokeTrailer(mobj_t *actor)
-{
-	mobj_t *th;
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SmokeTrailer", actor))
-		return;
-#endif
-
-	if (leveltime % 4)
-		return;
-
-	// add the smoke behind the rocket
-	if (actor->eflags & MFE_VERTICALFLIP)
-	{
-		th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z + actor->height - FixedMul(mobjinfo[locvar1].height, actor->scale), locvar1);
-		th->flags2 |= MF2_OBJECTFLIP;
-	}
-	else
-		th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z, locvar1);
-	P_SetObjectMomZ(th, FRACUNIT, false);
-	th->destscale = actor->scale;
-	P_SetScale(th, actor->scale);
-	th->tics -= P_RandomByte() & 3;
-	if (th->tics < 1)
-		th->tics = 1;
-}
-
-// Function: A_SpawnObjectAbsolute
-//
-// Description: Spawns an object at an absolute position
-//
-// var1:
-//		var1 >> 16 = x
-//		var1 & 65535 = y
-// var2:
-//		var2 >> 16 = z
-//		var2 & 65535 = type
-//
-void A_SpawnObjectAbsolute(mobj_t *actor)
-{
-	INT16 x, y, z; // Want to be sure we can use negative values
-	mobjtype_t type;
-	mobj_t *mo;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SpawnObjectAbsolute", actor))
-		return;
-#endif
-
-	x = (INT16)(locvar1>>16);
-	y = (INT16)(locvar1&65535);
-	z = (INT16)(locvar2>>16);
-	type = (mobjtype_t)(locvar2&65535);
-
-	mo = P_SpawnMobj(x<<FRACBITS, y<<FRACBITS, z<<FRACBITS, type);
-
-	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		mo->flags2 |= MF2_OBJECTFLIP;
-}
-
-// Function: A_SpawnObjectRelative
-//
-// Description: Spawns an object relative to the location of the actor
-//
-// var1:
-//		var1 >> 16 = x
-//		var1 & 65535 = y
-// var2:
-//		var2 >> 16 = z
-//		var2 & 65535 = type
-//
-void A_SpawnObjectRelative(mobj_t *actor)
-{
-	INT16 x, y, z; // Want to be sure we can use negative values
-	mobjtype_t type;
-	mobj_t *mo;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SpawnObjectRelative", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	x = (INT16)(locvar1>>16);
-	y = (INT16)(locvar1&65535);
-	z = (INT16)(locvar2>>16);
-	type = (mobjtype_t)(locvar2&65535);
-
-	// Spawn objects correctly in reverse gravity.
-	// NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame
-	mo = P_SpawnMobj(actor->x + FixedMul(x<<FRACBITS, actor->scale),
-		actor->y + FixedMul(y<<FRACBITS, actor->scale),
-		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), type);
-
-	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		mo->flags2 |= MF2_OBJECTFLIP;
-
-}
-
-// Function: A_ChangeAngleRelative
-//
-// Description: Changes the angle to a random relative value between the min and max. Set min and max to the same value to eliminate randomness
-//
-// var1 = min
-// var2 = max
-//
-void A_ChangeAngleRelative(mobj_t *actor)
-{
-	// Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of
-	//  getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result
-	//  rather than the ranges, so <0 and >360 work as possible values. -Red
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	//angle_t angle = (P_RandomByte()+1)<<24;
-	const fixed_t amin = locvar1*FRACUNIT;
-	const fixed_t amax = locvar2*FRACUNIT;
-	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
-	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeAngleRelative", actor))
-		return;
-#endif
-
-#ifdef PARANOIA
-	if (amin > amax)
-		I_Error("A_ChangeAngleRelative: var1 is greater then var2");
-#endif
-/*
-	if (angle < amin)
-		angle = amin;
-	if (angle > amax)
-		angle = amax;*/
-
-	actor->angle += FixedAngle(P_RandomRange(amin, amax));
-}
-
-// Function: A_ChangeAngleAbsolute
-//
-// Description: Changes the angle to a random absolute value between the min and max. Set min and max to the same value to eliminate randomness
-//
-// var1 = min
-// var2 = max
-//
-void A_ChangeAngleAbsolute(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	//angle_t angle = (P_RandomByte()+1)<<24;
-	const fixed_t amin = locvar1*FRACUNIT;
-	const fixed_t amax = locvar2*FRACUNIT;
-	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
-	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeAngleAbsolute", actor))
-		return;
-#endif
-
-#ifdef PARANOIA
-	if (amin > amax)
-		I_Error("A_ChangeAngleAbsolute: var1 is greater then var2");
-#endif
-/*
-	if (angle < amin)
-		angle = amin;
-	if (angle > amax)
-		angle = amax;*/
-
-	actor->angle = FixedAngle(P_RandomRange(amin, amax));
-}
-
-// Function: A_PlaySound
-//
-// Description: Plays a sound
-//
-// var1 = sound # to play
-// var2:
-//		0 = Play sound without an origin
-//		1 = Play sound using calling object as origin
-//
-void A_PlaySound(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PlaySound", actor))
-		return;
-#endif
-
-	S_StartSound(locvar2 ? actor : NULL, locvar1);
-}
-
-// Function: A_FindTarget
-//
-// Description: Finds the nearest/furthest mobj of the specified type and sets actor->target to it.
-//
-// var1 = mobj type
-// var2 = if (0) nearest; else furthest;
-//
-void A_FindTarget(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *targetedmobj = NULL;
-	thinker_t *th;
-	mobj_t *mo2;
-	fixed_t dist1 = 0, dist2 = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FindTarget", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2->type == (mobjtype_t)locvar1)
-		{
-			if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS))
-				continue; // Ignore spectators
-			if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0)
-				continue; // Ignore dead things
-			if (targetedmobj == NULL)
-			{
-				targetedmobj = mo2;
-				dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-			}
-			else
-			{
-				dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-
-				if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2))
-				{
-					targetedmobj = mo2;
-					dist2 = dist1;
-				}
-			}
-		}
-	}
-
-	if (!targetedmobj)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Unable to find the specified object to target.\n");
-		return; // Oops, nothing found..
-	}
-
-	CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Found a target.\n");
-
-	P_SetTarget(&actor->target, targetedmobj);
-}
-
-// Function: A_FindTracer
-//
-// Description: Finds the nearest/furthest mobj of the specified type and sets actor->tracer to it.
-//
-// var1 = mobj type
-// var2 = if (0) nearest; else furthest;
-//
-void A_FindTracer(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *targetedmobj = NULL;
-	thinker_t *th;
-	mobj_t *mo2;
-	fixed_t dist1 = 0, dist2 = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FindTracer", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2->type == (mobjtype_t)locvar1)
-		{
-			if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS))
-				continue; // Ignore spectators
-			if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0)
-				continue; // Ignore dead things
-			if (targetedmobj == NULL)
-			{
-				targetedmobj = mo2;
-				dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-			}
-			else
-			{
-				dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-
-				if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2))
-				{
-					targetedmobj = mo2;
-					dist2 = dist1;
-				}
-			}
-		}
-	}
-
-	if (!targetedmobj)
-	{
-		CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Unable to find the specified object to target.\n");
-		return; // Oops, nothing found..
-	}
-
-	CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Found a target.\n");
-
-	P_SetTarget(&actor->tracer, targetedmobj);
-}
-
-// Function: A_SetTics
-//
-// Description: Sets the animation tics of an object
-//
-// var1 = tics to set to
-// var2 = if this is set, and no var1 is supplied, the mobj's threshold value will be used.
-//
-void A_SetTics(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetTics", actor))
-		return;
-#endif
-
-	if (locvar1)
-		actor->tics = locvar1;
-	else if (locvar2)
-		actor->tics = actor->threshold;
-}
-
-// Function: A_SetRandomTics
-//
-// Description: Sets the animation tics of an object to a random value
-//
-// var1 = lower bound
-// var2 = upper bound
-//
-void A_SetRandomTics(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetRandomTics", actor))
-		return;
-#endif
-
-	actor->tics = P_RandomRange(locvar1, locvar2);
-}
-
-// Function: A_ChangeColorRelative
-//
-// Description: Changes the color of an object
-//
-// var1 = if (var1 > 0), find target and add its color value to yours
-// var2 = if (var1 = 0), color value to add
-//
-void A_ChangeColorRelative(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeColorRelative", actor))
-		return;
-#endif
-
-	if (locvar1)
-	{
-		// Have you ever seen anything so hideous?
-		if (actor->target)
-			actor->color = (UINT8)(actor->color + actor->target->color);
-	}
-	else
-		actor->color = (UINT8)(actor->color + locvar2);
-}
-
-// Function: A_ChangeColorAbsolute
-//
-// Description: Changes the color of an object by an absolute value. Note: 0 is default colormap.
-//
-// var1 = if (var1 > 0), set your color to your target's color
-// var2 = if (var1 = 0), color value to set to
-//
-void A_ChangeColorAbsolute(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeColorAbsolute", actor))
-		return;
-#endif
-
-	if (locvar1)
-	{
-		if (actor->target)
-			actor->color = actor->target->color;
-	}
-	else
-		actor->color = (UINT8)locvar2;
-}
-
-// Function: A_MoveRelative
-//
-// Description: Moves an object (wrapper for P_Thrust)
-//
-// var1 = angle
-// var2 = force
-//
-void A_MoveRelative(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MoveRelative", actor))
-		return;
-#endif
-
-	P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
-}
-
-// Function: A_MoveAbsolute
-//
-// Description: Moves an object (wrapper for P_InstaThrust)
-//
-// var1 = angle
-// var2 = force
-//
-void A_MoveAbsolute(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MoveAbsolute", actor))
-		return;
-#endif
-
-	P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
-}
-
-// Function: A_Thrust
-//
-// Description: Pushes the object horizontally at its current angle.
-//
-// var1 = amount of force
-// var2 = If 1, xy momentum is lost. If 0, xy momentum is kept
-//
-void A_Thrust(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Thrust", actor))
-		return;
-#endif
-
-	if (!locvar1)
-		CONS_Debug(DBG_GAMELOGIC, "A_Thrust: Var1 not specified!\n");
-
-	if (locvar2)
-		P_InstaThrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale));
-	else
-		P_Thrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale));
-}
-
-// Function: A_ZThrust
-//
-// Description: Pushes the object up or down.
-//
-// var1 = amount of force
-// var2:
-//		lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept
-//		upper 16 bits = If 1, z momentum is lost. If 0, z momentum is kept
-//
-void A_ZThrust(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ZThrust", actor))
-		return;
-#endif
-
-	if (!locvar1)
-		CONS_Debug(DBG_GAMELOGIC, "A_ZThrust: Var1 not specified!\n");
-
-	if (locvar2 & 65535)
-		actor->momx = actor->momy = 0;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		actor->z--;
-	else
-		actor->z++;
-
-	P_SetObjectMomZ(actor, locvar1*FRACUNIT, !(locvar2 >> 16));
-}
-
-// Function: A_SetTargetsTarget
-//
-// Description: Sets your target to the object who your target is targeting. Yikes! If it happens to be NULL, you're just out of luck.
-//
-// var1: (Your target)
-//		0 = target
-//		1 = tracer
-// var2: (Your target's target)
-//		0 = target/tracer's target
-//		1 = target/tracer's tracer
-//
-void A_SetTargetsTarget(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *oldtarg = NULL, *newtarg = NULL;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetTargetsTarget", actor))
-		return;
-#endif
-
-	// actor's target
-	if (locvar1) // or tracer
-		oldtarg = actor->tracer;
-	else
-		oldtarg = actor->target;
-
-	if (P_MobjWasRemoved(oldtarg))
-		return;
-
-	// actor's target's target!
-	if (locvar2) // or tracer
-		newtarg = oldtarg->tracer;
-	else
-		newtarg = oldtarg->target;
-
-	if (P_MobjWasRemoved(newtarg))
-		return;
-
-	// set actor's new target
-	if (locvar1) // or tracer
-		P_SetTarget(&actor->tracer, newtarg);
-	else
-		P_SetTarget(&actor->target, newtarg);
-}
-
-// Function: A_SetObjectFlags
-//
-// Description: Sets the flags of an object
-//
-// var1 = flag value to set
-// var2:
-//		if var2 == 2, add the flag to the current flags
-//		else if var2 == 1, remove the flag from the current flags
-//		else if var2 == 0, set the flags to the exact value
-//
-void A_SetObjectFlags(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	boolean unlinkthings = false;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetObjectFlags", actor))
-		return;
-#endif
-
-	if (locvar2 == 2)
-		locvar1 = actor->flags | locvar1;
-	else if (locvar2 == 1)
-		locvar1 = actor->flags & ~locvar1;
-
-	if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
-		unlinkthings = true;
-
-	if (unlinkthings) {
-		P_UnsetThingPosition(actor);
-		if (sector_list)
-		{
-			P_DelSeclist(sector_list);
-			sector_list = NULL;
-		}
-	}
-
-	actor->flags = locvar1;
-
-	if (unlinkthings)
-		P_SetThingPosition(actor);
-}
-
-// Function: A_SetObjectFlags2
-//
-// Description: Sets the flags2 of an object
-//
-// var1 = flag value to set
-// var2:
-//		if var2 == 2, add the flag to the current flags
-//		else if var2 == 1, remove the flag from the current flags
-//		else if var2 == 0, set the flags to the exact value
-//
-void A_SetObjectFlags2(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetObjectFlags2", actor))
-		return;
-#endif
-
-	if (locvar2 == 2)
-		actor->flags2 |= locvar1;
-	else if (locvar2 == 1)
-		actor->flags2 &= ~locvar1;
-	else
-		actor->flags2 = locvar1;
-}
-
-// Function: A_BossJetFume
-//
-// Description: Spawns jet fumes/other attachment miscellany for the boss. To only be used when he is spawned.
-//
-// var1:
-//		0 - Triple jet fume pattern
-//		1 - Boss 3's propeller
-//		2 - Metal Sonic jet fume
-//		3 - Boss 4 jet flame
-// var2 = unused
-//
-void A_BossJetFume(mobj_t *actor)
-{
-	mobj_t *filler;
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BossJetFume", actor))
-		return;
-#endif
-
-	if (locvar1 == 0) // Boss1 jet fumes
-	{
-		fixed_t jetx, jety, jetz;
-
-		jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale));
-		jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale));
-		if (actor->eflags & MFE_VERTICALFLIP)
-			jetz = actor->z + actor->height - FixedMul(38*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale);
-		else
-			jetz = actor->z + FixedMul(38*FRACUNIT, actor->scale);
-
-		filler = P_SpawnMobj(jetx, jety, jetz, MT_JETFUME1);
-		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-		filler->fuse = 56;
-
-		if (actor->eflags & MFE_VERTICALFLIP)
-			jetz = actor->z + actor->height - FixedMul(12*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale);
-		else
-			jetz = actor->z + FixedMul(12*FRACUNIT, actor->scale);
-
-		filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
-				jety + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
-				jetz, MT_JETFUME1);
-		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-		filler->fuse = 57;
-
-		filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
-				jety + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
-				jetz, MT_JETFUME1);
-		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-		filler->fuse = 58;
-
-		P_SetTarget(&actor->tracer, filler);
-	}
-	else if (locvar1 == 1) // Boss 3 propeller
-	{
-		fixed_t jetx, jety, jetz;
-
-		jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
-		jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
-		if (actor->eflags & MFE_VERTICALFLIP)
-			jetz = actor->z + actor->height - FixedMul(17*FRACUNIT + mobjinfo[MT_PROPELLER].height, actor->scale);
-		else
-			jetz = actor->z + FixedMul(17*FRACUNIT, actor->scale);
-
-		filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER);
-		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-		filler->angle = actor->angle - ANGLE_180;
-
-		P_SetTarget(&actor->tracer, filler);
-	}
-	else if (locvar1 == 2) // Metal Sonic jet fumes
-	{
-		filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1);
-		P_SetTarget(&filler->target, actor);
-		filler->fuse = 59;
-		P_SetTarget(&actor->tracer, filler);
-		filler->destscale = actor->scale/2;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-	}
-	else if (locvar1 == 3) // Boss 4 jet flame
-	{
-		fixed_t jetz;
-		if (actor->eflags & MFE_VERTICALFLIP)
-			jetz = actor->z + actor->height + FixedMul(50*FRACUNIT - mobjinfo[MT_JETFLAME].height, actor->scale);
-		else
-			jetz = actor->z - FixedMul(50*FRACUNIT, actor->scale);
-		filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME);
-		P_SetTarget(&filler->target, actor);
-		// Boss 4 already uses its tracer for other things
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
-		if (actor->eflags & MFE_VERTICALFLIP)
-			filler->flags2 |= MF2_OBJECTFLIP;
-	}
-}
-
-// Function: A_RandomState
-//
-// Description: Chooses one of the two state numbers supplied randomly.
-//
-// var1 = state number 1
-// var2 = state number 2
-//
-void A_RandomState(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RandomState", actor))
-		return;
-#endif
-
-	P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2);
-}
-
-// Function: A_RandomStateRange
-//
-// Description: Chooses a random state within the range supplied.
-//
-// var1 = Minimum state number to choose.
-// var2 = Maximum state number to use.
-//
-void A_RandomStateRange(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RandomStateRange", actor))
-		return;
-#endif
-
-	P_SetMobjState(actor, P_RandomRange(locvar1, locvar2));
-}
-
-// Function: A_DualAction
-//
-// Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop.
-//
-// var1 = state # to use 1st action from
-// var2 = state # to use 2nd action from
-//
-void A_DualAction(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_DualAction", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	var1 = states[locvar1].var1;
-	var2 = states[locvar1].var2;
-#ifdef HAVE_BLUA
-	astate = &states[locvar1];
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling First Action (state %d)...\n", locvar1);
-	states[locvar1].action.acp1(actor);
-
-	var1 = states[locvar2].var1;
-	var2 = states[locvar2].var2;
-#ifdef HAVE_BLUA
-	astate = &states[locvar2];
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling Second Action (state %d)...\n", locvar2);
-	states[locvar2].action.acp1(actor);
-}
-
-// Function: A_RemoteAction
-//
-// Description: var1 is the remote object. var2 is the state reference for calling the action called on var1. var1 becomes the actor's target, the action (var2) is called on var1. actor's target is restored
-//
-// var1 = remote object (-2 uses tracer, -1 uses target)
-// var2 = state reference for calling an action
-//
-void A_RemoteAction(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *originaltarget = actor->target; // Hold on to the target for later.
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RemoteAction", actor))
-		return;
-#endif
-
-	// If >=0, find the closest target.
-	if (locvar1 >= 0)
-	{
-		///* DO A_FINDTARGET STUFF *///
-		mobj_t *targetedmobj = NULL;
-		thinker_t *th;
-		mobj_t *mo2;
-		fixed_t dist1 = 0, dist2 = 0;
-
-		// scan the thinkers
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
-		{
-			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-				continue;
-
-			mo2 = (mobj_t *)th;
-
-			if (mo2->type == (mobjtype_t)locvar1)
-			{
-				if (targetedmobj == NULL)
-				{
-					targetedmobj = mo2;
-					dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-				}
-				else
-				{
-					dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
-
-					if ((locvar2 && dist1 < dist2) || (!locvar2 && dist1 > dist2))
-					{
-						targetedmobj = mo2;
-						dist2 = dist1;
-					}
-				}
-			}
-		}
-
-		if (!targetedmobj)
-		{
-			CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Unable to find the specified object to target.\n");
-			return; // Oops, nothing found..
-		}
-
-		CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Found a target.\n");
-
-		P_SetTarget(&actor->target, targetedmobj);
-
-		///* END A_FINDTARGET STUFF *///
-	}
-
-	// If -2, use the tracer as the target
-	else if (locvar1 == -2)
-		P_SetTarget(&actor->target, actor->tracer);
-	// if -1 or anything else, just use the target.
-
-	if (actor->target)
-	{
-		// Steal the var1 and var2 from "locvar2"
-		var1 = states[locvar2].var1;
-		var2 = states[locvar2].var2;
-#ifdef HAVE_BLUA
-		astate = &states[locvar2];
-#endif
-
-		CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Calling action on %p\n"
-				"var1 is %d\nvar2 is %d\n", actor->target, var1, var2);
-		states[locvar2].action.acp1(actor->target);
-	}
-
-	P_SetTarget(&actor->target, originaltarget); // Restore the original target.
-}
-
-// Function: A_ToggleFlameJet
-//
-// Description: Turns a flame jet on and off.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ToggleFlameJet(mobj_t* actor)
-{
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ToggleFlameJet", actor))
-		return;
-#endif
-	// threshold - off delay
-	// movecount - on timer
-
-	if (actor->flags2 & MF2_FIRING)
-	{
-		actor->flags2 &= ~MF2_FIRING;
-
-		if (actor->threshold)
-			actor->tics = actor->threshold;
-	}
-	else
-	{
-		actor->flags2 |= MF2_FIRING;
-
-		if (actor->movecount)
-			actor->tics = actor->movecount;
-	}
-}
-
-// Function: A_OrbitNights
-//
-// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.)
-//
-// var1 = Angle adjustment (aka orbit speed)
-// var2 = Lower four bits: height offset, Upper 4 bits = set if object is Nightopian Helper
-//
-void A_OrbitNights(mobj_t* actor)
-{
-	INT32 ofs = (var2 & 0xFFFF);
-	boolean ishelper = (var2 & 0xFFFF0000);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_OrbitNights", actor))
-		return;
-#endif
-
-	if (!actor->target
-	|| (actor->target->player &&
-		// if NiGHTS special stage and not NiGHTSmode.
-	    (((maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE))
-	    // Also remove this object if they no longer have a NiGHTS helper
-		|| (ishelper && !actor->target->player->powers[pw_nights_helper]))))
-	{
-		P_RemoveMobj(actor);
-		return;
-	}
-	else
-	{
-		actor->extravalue1 += var1;
-		P_UnsetThingPosition(actor);
-		{
-			const angle_t fa  = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT;
-			const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT;
-
-			const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(32*FRACUNIT, actor->scale));
-			const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(20*FRACUNIT, actor->scale));
-			const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(32*FRACUNIT, actor->scale));
-
-			actor->x = actor->target->x + fc;
-			actor->y = actor->target->y + fs;
-			actor->z = actor->target->z + fh + FixedMul(16*FRACUNIT, actor->scale);
-
-			// Semi-lazy hack
-			actor->angle = (angle_t)actor->extravalue1 + ANGLE_90;
-		}
-		P_SetThingPosition(actor);
-
-		if (ishelper && actor->target->player) // Flash a helper that's about to be removed.
-		{
-			if ((actor->target->player->powers[pw_nights_helper] < TICRATE)
-			&& (actor->target->player->powers[pw_nights_helper] & 1))
-				actor->flags2 |= MF2_DONTDRAW;
-			else
-				actor->flags2 &= ~MF2_DONTDRAW;
-		}
-	}
-}
-
-// Function: A_GhostMe
-//
-// Description: Spawns a "ghost" mobj of this actor, ala spindash trails and the minus's digging "trails"
-//
-// var1 = duration in tics
-// var2 = unused
-//
-void A_GhostMe(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	mobj_t *ghost;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_GhostMe", actor))
-		return;
-#endif
-	ghost = P_SpawnGhostMobj(actor);
-	if (ghost && locvar1 > 0)
-		ghost->fuse = locvar1;
-}
-
-// Function: A_SetObjectState
-//
-// Description: Changes the state of an object's target/tracer.
-//
-// var1 = state number
-// var2:
-//		0 = target
-//		1 = tracer
-//
-void A_SetObjectState(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *target;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetObjectState", actor))
-		return;
-#endif
-
-	if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer))
-	{
-		if (cv_debug)
-			CONS_Printf("A_SetObjectState: No target to change state!\n");
-		return;
-	}
-
-	if (!locvar2) // target
-		target = actor->target;
-	else // tracer
-		target = actor->tracer;
-
-	if (target->health > 0)
-	{
-		if (!target->player)
-			P_SetMobjState(target, locvar1);
-		else
-			P_SetPlayerMobjState(target, locvar1);
-	}
-}
-
-// Function: A_SetObjectTypeState
-//
-// Description: Changes the state of all active objects of a certain type in a certain range of the actor.
-//
-// var1 = state number
-// var2:
-//		lower 16 bits = type
-//		upper 16 bits = range (if == 0, across whole map)
-//
-void A_SetObjectTypeState(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
-	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
-
-	thinker_t *th;
-	mobj_t *mo2;
-	fixed_t dist = 0;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetObjectTypeState", actor))
-		return;
-#endif
-
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2->type == (mobjtype_t)loc2lw)
-		{
-			dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y);
-
-			if (mo2->health > 0)
-			{
-				if (loc2up == 0)
-					P_SetMobjState(mo2, locvar1);
-				else
-				{
-					if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale))
-						P_SetMobjState(mo2, locvar1);
-				}
-			}
-		}
-	}
-}
-
-// Function: A_KnockBack
-//
-// Description: Knocks back the object's target at its current speed.
-//
-// var1:
-//		0 = target
-//		1 = tracer
-// var2 = unused
-//
-void A_KnockBack(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	mobj_t *target;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_KnockBack", actor))
-		return;
-#endif
-
-	if (!locvar1)
-		target = actor->target;
-	else
-		target = actor->tracer;
-
-	if (!target)
-	{
-		if(cv_debug)
-			CONS_Printf("A_KnockBack: No target!\n");
-		return;
-	}
-
-	target->momx *= -1;
-	target->momy *= -1;
-}
-
-// Function: A_PushAway
-//
-// Description: Pushes an object's target away from the calling object.
-//
-// var1 = amount of force
-// var2:
-//		lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept
-//		upper 16 bits = 0 - target, 1 - tracer
-//
-void A_PushAway(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *target; // target
-	angle_t an; // actor to target angle
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_PushAway", actor))
-		return;
-#endif
-
-	if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer))
-		return;
-
-	if (!locvar1)
-		CONS_Printf("A_Thrust: Var1 not specified!\n");
-
-	if (!(locvar2 >> 16)) // target
-		target = actor->target;
-	else // tracer
-		target = actor->tracer;
-
-	an = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
-
-	if (locvar2 & 65535)
-		P_InstaThrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale));
-	else
-		P_Thrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale));
-}
-
-// Function: A_RingDrain
-//
-// Description: Drain targeted player's rings.
-//
-// var1 = ammount of drained rings
-// var2 = unused
-//
-void A_RingDrain(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	player_t *player;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RingDrain", actor))
-		return;
-#endif
-
-	if (!actor->target || !actor->target->player)
-	{
-		if(cv_debug)
-			CONS_Printf("A_RingDrain: No player targeted!\n");
-		return;
-	}
-
-	player = actor->target->player;
-	P_GivePlayerRings(player, -min(locvar1, player->rings));
-}
-
-// Function: A_SplitShot
-//
-// Description: Shoots 2 missiles that hit next to the player.
-//
-// var1 = target x-y-offset
-// var2:
-//		lower 16 bits = missile type
-//		upper 16 bits = height offset
-//
-void A_SplitShot(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
-	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
-	const fixed_t offs = (fixed_t)(locvar1*FRACUNIT);
-	const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SplitShot", actor))
-		return;
-#endif
-
-	A_FaceTarget(actor);
-	{
-		const angle_t an = (actor->angle + ANGLE_90) >> ANGLETOFINESHIFT;
-		const fixed_t fasin = FINESINE(an);
-		const fixed_t facos = FINECOSINE(an);
-		fixed_t xs = FixedMul(facos,FixedMul(offs, actor->scale));
-		fixed_t ys = FixedMul(fasin,FixedMul(offs, actor->scale));
-		fixed_t z;
-
-		if (actor->eflags & MFE_VERTICALFLIP)
-			z = actor->z + actor->height - FixedMul(hoffs, actor->scale);
-		else
-			z = actor->z + FixedMul(hoffs, actor->scale);
-
-		P_SpawnPointMissile(actor, actor->target->x+xs, actor->target->y+ys, actor->target->z, loc2lw, actor->x, actor->y, z);
-		P_SpawnPointMissile(actor, actor->target->x-xs, actor->target->y-ys, actor->target->z, loc2lw, actor->x, actor->y, z);
-	}
-}
-
-// Function: A_MissileSplit
-//
-// Description: If the object is a missile it will create a new missile with an alternate flight path owned by the one who shot the former missile.
-//
-// var1 = splitting missile type
-// var2 = splitting angle
-//
-void A_MissileSplit(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MissileSplit", actor))
-		return;
-#endif
-	if (actor->eflags & MFE_VERTICALFLIP)
-		P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z+actor->height, locvar2);
-	else
-		P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z, locvar2);
-}
-
-// Function: A_MultiShot
-//
-// Description: Shoots objects horizontally that spread evenly in all directions.
-//
-// var1:
-//		lower 16 bits = number of missiles
-//		upper 16 bits = missile type #
-// var2 = height offset
-//
-void A_MultiShot(mobj_t *actor)
-{
-	fixed_t z, xr, yr;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
-	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
-	INT32 count = 0;
-	fixed_t ad;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MultiShot", actor))
-		return;
-#endif
-
-	if (actor->target)
-		A_FaceTarget(actor);
-
-	if(loc1lw > 90)
-		ad = FixedMul(90*FRACUNIT, actor->scale);
-	else
-		ad = FixedMul(loc1lw*FRACUNIT, actor->scale);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
-	xr = FixedMul((P_SignedRandom()/3)<<FRACBITS, actor->scale); // please note p_mobj.c's P_Rand() abuse
-	yr = FixedMul((P_SignedRandom()/3)<<FRACBITS, actor->scale); // of rand(), RAND_MAX and signness mess
-
-	while(count <= loc1lw && loc1lw >= 1)
-	{
-		const angle_t fa = FixedAngleC(count*FRACUNIT*360, ad)>>ANGLETOFINESHIFT;
-		const fixed_t rc = FINECOSINE(fa);
-		const fixed_t rs = FINESINE(fa);
-		const fixed_t xrc = FixedMul(xr, rc);
-		const fixed_t yrs = FixedMul(yr, rs);
-		const fixed_t xrs = FixedMul(xr, rs);
-		const fixed_t yrc = FixedMul(yr, rc);
-
-		P_SpawnPointMissile(actor, xrc-yrs+actor->x, xrs+yrc+actor->y, z, loc1up, actor->x, actor->y, z);
-		count++;
-	}
-
-	if (!(actor->flags & MF_BOSS))
-	{
-		if (ultimatemode)
-			actor->reactiontime = actor->info->reactiontime*TICRATE;
-		else
-			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-	}
-}
-
-// Function: A_InstaLoop
-//
-// Description: Makes the object move along a 2d (view angle, z) polygon.
-//
-// var1:
-//		lower 16 bits = current step
-//		upper 16 bits = maximum step #
-// var2 = force
-//
-void A_InstaLoop(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t force = max(locvar2, 1)*FRACUNIT; // defaults to 1 if var2 < 1
-	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
-	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
-	const angle_t fa = FixedAngleC(loc1lw*FRACUNIT*360, loc1up*FRACUNIT)>>ANGLETOFINESHIFT;
-	const fixed_t ac = FINECOSINE(fa);
-	const fixed_t as = FINESINE(fa);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_InstaLoop", actor))
-		return;
-#endif
-
-	P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale)));
-	P_SetObjectMomZ(actor, FixedMul(as, force), false);
-}
-
-// Function: A_Custom3DRotate
-//
-// Description: Rotates the actor around its target in 3 dimensions.
-//
-// var1:
-//		lower 16 bits = radius in fracunits
-//		upper 16 bits = vertical offset
-// var2:
-//		lower 16 bits = vertical rotation speed in 1/10 fracunits per tic
-//		upper 16 bits = horizontal rotation speed in 1/10 fracunits per tic
-//
-void A_Custom3DRotate(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
-	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
-	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
-	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
-
-	const fixed_t radius = FixedMul(loc1lw*FRACUNIT, actor->scale);
-	const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale);
-	const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale);
-	const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Custom3DRotate", actor))
-		return;
-#endif
-
-	if (actor->target->health == 0)
-	{
-		P_RemoveMobj(actor);
-		return;
-	}
-
-	if (!actor->target) // This should NEVER happen.
-	{
-		if (cv_debug)
-			CONS_Printf("Error: Object has no target\n");
-		P_RemoveMobj(actor);
-		return;
-	}
-	if (hspeed==0 && vspeed==0)
-	{
-		CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n");
-		return;
-	}
-
-	actor->angle += FixedAngle(hspeed);
-	actor->movedir += FixedAngle(vspeed);
-	P_UnsetThingPosition(actor);
-	{
-		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
-
-		if (vspeed == 0 && hspeed != 0)
-		{
-			actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius);
-			actor->y = actor->target->y + FixedMul(FINESINE(fa),radius);
-			actor->z = actor->target->z + actor->target->height/2 - actor->height/2 + hOff;
-		}
-		else
-		{
-			const angle_t md = actor->movedir>>ANGLETOFINESHIFT;
-			actor->x = actor->target->x + FixedMul(FixedMul(FINESINE(md),FINECOSINE(fa)),radius);
-			actor->y = actor->target->y + FixedMul(FixedMul(FINESINE(md),FINESINE(fa)),radius);
-			actor->z = actor->target->z + FixedMul(FINECOSINE(md),radius) + actor->target->height/2 - actor->height/2 + hOff;
-		}
-	}
-	P_SetThingPosition(actor);
-}
-
-// Function: A_SearchForPlayers
-//
-// Description: Checks if the actor has targeted a vulnerable player. If not a new player will be searched all around. If no players are available the object can call a specific state. (Useful for not moving enemies)
-//
-// var1:
-//		if var1 == 0, if necessary call state with same state number as var2
-//		else, do not call a specific state if no players are available
-// var2 = state number
-//
-void A_SearchForPlayers(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SearchForPlayers", actor))
-		return;
-#endif
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		if(locvar1==0)
-		{
-			P_SetMobjStateNF(actor, locvar2);
-			return;
-		}
-	}
-}
-
-// Function: A_CheckRandom
-//
-// Description: Calls a state by chance.
-//
-// var1:
-//		lower 16 bits = denominator
-//		upper 16 bits = numerator (defaults to 1 if zero)
-// var2 = state number
-//
-void A_CheckRandom(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t chance = FRACUNIT;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckRandom", actor))
-		return;
-#endif
-	if ((locvar1 & 0xFFFF) == 0)
-		return;
-
-	// The PRNG doesn't suck anymore, OK?
-	if (locvar1 >> 16)
-		chance *= (locvar1 >> 16);
-	chance /= (locvar1 & 0xFFFF);
-
-	if (P_RandomChance(chance))
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckTargetRings
-//
-// Description: Calls a state depending on the ammount of rings currently owned by targeted players.
-//
-// var1 = if player rings >= var1 call state
-// var2 = state number
-//
-void A_CheckTargetRings(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckTargetRings", actor))
-		return;
-#endif
-
-	if (!(actor->target) || !(actor->target->player))
-	   return;
-
-	if (actor->target->player->rings >= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckRings
-//
-// Description: Calls a state depending on the ammount of rings currently owned by all players.
-//
-// var1 = if player rings >= var1 call state
-// var2 = state number
-//
-void A_CheckRings(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	INT32 i, cntr = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckRings", actor))
-		return;
-#endif
-
-	for (i = 0; i < MAXPLAYERS; i++)
-		cntr += players[i].rings;
-
-	if (cntr >= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckTotalRings
-//
-// Description: Calls a state depending on the maximum ammount of rings owned by all players during this try.
-//
-// var1 = if total player rings >= var1 call state
-// var2 = state number
-//
-void A_CheckTotalRings(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-	INT32 i, cntr = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckTotalRings", actor))
-		return;
-#endif
-
-	for (i = 0; i < MAXPLAYERS; i++)
-		cntr += players[i].totalring;
-
-	if (cntr >= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckHealth
-//
-// Description: Calls a state depending on the object's current health.
-//
-// var1 = if health <= var1 call state
-// var2 = state number
-//
-void A_CheckHealth(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckHealth", actor))
-		return;
-#endif
-
-	if (actor->health <= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckRange
-//
-// Description: Calls a state if the object's target is in range.
-//
-// var1:
-//		lower 16 bits = range
-//		upper 16 bits = 0 - target, 1 - tracer
-// var2 = state number
-//
-void A_CheckRange(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t dist;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckRange", actor))
-		return;
-#endif
-
-	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
-		return;
-
-	if (!(locvar1 >> 16)) //target
-		dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
-	else //tracer
-		dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
-
-	if (dist <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckHeight
-//
-// Description: Calls a state if the object and it's target have a height offset <= var1 compared to each other.
-//
-// var1:
-//		lower 16 bits = height offset
-//		upper 16 bits = 0 - target, 1 - tracer
-// var2 = state number
-//
-void A_CheckHeight(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t height;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckHeight", actor))
-		return;
-#endif
-
-	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
-		return;
-
-	if (!(locvar1 >> 16)) // target
-		height = abs(actor->target->z - actor->z);
-	else // tracer
-		height = abs(actor->tracer->z - actor->z);
-
-	if (height <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckTrueRange
-//
-// Description: Calls a state if the object's target is in true range. (Checks height, too.)
-//
-// var1:
-//		lower 16 bits = range
-//		upper 16 bits = 0 - target, 1 - tracer
-// var2 = state number
-//
-void A_CheckTrueRange(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t height; // vertical range
-	fixed_t dist; // horizontal range
-	fixed_t l; // true range
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckTrueRange", actor))
-		return;
-#endif
-
-	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
-		return;
-
-	if (!(locvar1 >> 16)) // target
-	{
-		height = actor->target->z - actor->z;
-		dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
-
-	}
-	else // tracer
-	{
-		height = actor->tracer->z - actor->z;
-		dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
-	}
-
-	l = P_AproxDistance(dist, height);
-
-	if (l <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
-		P_SetMobjState(actor, locvar2);
-
-}
-
-// Function: A_CheckThingCount
-//
-// Description: Calls a state depending on the number of active things in range.
-//
-// var1:
-//		lower 16 bits = number of things
-//		upper 16 bits = thing type
-// var2:
-//		lower 16 bits = state to call
-//		upper 16 bits = range (if == 0, check whole map)
-//
-void A_CheckThingCount(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
-	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
-	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
-	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
-
-	INT32 count = 0;
-	thinker_t *th;
-	mobj_t *mo2;
-	fixed_t dist = 0;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckThingCount", actor))
-		return;
-#endif
-
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2->type == (mobjtype_t)loc1up)
-		{
-			dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y);
-
-			if (loc2up == 0)
-				count++;
-			else
-			{
-				if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale))
-					count++;
-			}
-		}
-	}
-
-	if(loc1lw <= count)
-		P_SetMobjState(actor, loc2lw);
-}
-
-// Function: A_CheckAmbush
-//
-// Description: Calls a state if the actor is behind its targeted player.
-//
-// var1:
-//		0 = target
-//		1 = tracer
-// var2 = state number
-//
-void A_CheckAmbush(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	angle_t at; // angle target is currently facing
-	angle_t atp; // actor to target angle
-	angle_t an; // angle between at and atp
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckAmbush", actor))
-		return;
-#endif
-
-	if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer))
-		return;
-
-	if (!locvar1) // target
-	{
-		at = actor->target->angle;
-		atp = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
-	}
-	else // tracer
-	{
-		at = actor->tracer->angle;
-		atp = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
-	}
-
-	an = atp - at;
-
-	if (an > ANGLE_180) // flip angle if bigger than 180
-		an = InvAngle(an);
-
-	if (an < ANGLE_90+ANGLE_22h) // within an angle of 112.5 from each other?
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckCustomValue
-//
-// Description: Calls a state depending on the object's custom value.
-//
-// var1 = if custom value >= var1, call state
-// var2 = state number
-//
-void A_CheckCustomValue(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckCustomValue", actor))
-		return;
-#endif
-
-	if (actor->cusval >= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_CheckCusValMemo
-//
-// Description: Calls a state depending on the object's custom memory value.
-//
-// var1 = if memory value >= var1, call state
-// var2 = state number
-//
-void A_CheckCusValMemo(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckCusValMemo", actor))
-		return;
-#endif
-
-	if (actor->cvmem >= locvar1)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_SetCustomValue
-//
-// Description: Changes the custom value of an object.
-//
-// var1 = manipulating value
-// var2:
-//      if var2 == 5, multiply the custom value by var1
-//      else if var2 == 4, divide the custom value by var1
-//      else if var2 == 3, apply modulo var1 to the custom value
-//      else if var2 == 2, add var1 to the custom value
-//      else if var2 == 1, substract var1 from the custom value
-//      else if var2 == 0, replace the custom value with var1
-//
-void A_SetCustomValue(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetCustomValue", actor))
-		return;
-#endif
-
-	if (cv_debug)
-		CONS_Printf("Init custom value is %d\n", actor->cusval);
-
-	if (locvar1 == 0 && locvar2 == 4)
-		return; // DON'T DIVIDE BY ZERO
-
-	// no need for a "temp" value here, just modify the cusval directly
-	if (locvar2 == 5) // multiply
-		actor->cusval *= locvar1;
-	else if (locvar2 == 4) // divide
-		actor->cusval /= locvar1;
-	else if (locvar2 == 3) // modulo
-		actor->cusval %= locvar1;
-	else if (locvar2 == 2) // add
-		actor->cusval += locvar1;
-	else if (locvar2 == 1) // subtract
-		actor->cusval -= locvar1;
-	else // replace
-		actor->cusval = locvar1;
-
-	if(cv_debug)
-		CONS_Printf("New custom value is %d\n", actor->cusval);
-}
-
-// Function: A_UseCusValMemo
-//
-// Description: Memorizes or recalls a current custom value.
-//
-// var1:
-//      if var1 == 1, manipulate memory value
-//      else, recall memory value replacing the custom value
-// var2:
-//      if var2 == 5, mem = mem*cv  ||  cv = cv*mem
-//      else if var2 == 4,  mem = mem/cv  ||  cv = cv/mem
-//      else if var2 == 3, mem = mem%cv  ||  cv = cv%mem
-//      else if var2 == 2, mem += cv  ||  cv += mem
-//      else if var2 == 1,  mem -= cv  ||  cv -= mem
-//      else mem = cv  ||  cv = mem
-//
-void A_UseCusValMemo(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-	INT32 temp = actor->cusval; // value being manipulated
-	INT32 tempM = actor->cvmem; // value used to manipulate temp with
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_UseCusValMemo", actor))
-		return;
-#endif
-
-	if (locvar1 == 1) // cvmem being changed using cusval
-	{
-		temp = actor->cvmem;
-		tempM = actor->cusval;
-	}
-	else // cusval being changed with cvmem
-	{
-		temp = actor->cusval;
-		tempM = actor->cvmem;
-	}
-
-	if (tempM == 0 && locvar2 == 4)
-		return; // DON'T DIVIDE BY ZERO
-
-	// now get new value for cusval/cvmem using the other
-	if (locvar2 == 5) // multiply
-		temp *= tempM;
-	else if (locvar2 == 4) // divide
-		temp /= tempM;
-	else if (locvar2 == 3) // modulo
-		temp %= tempM;
-	else if (locvar2 == 2) // add
-		temp += tempM;
-	else if (locvar2 == 1) // subtract
-		temp -= tempM;
-	else // replace
-		temp = tempM;
-
-	// finally, give cusval/cvmem the new value!
-	if (locvar1 == 1)
-		actor->cvmem = temp;
-	else
-		actor->cusval = temp;
-}
-
-// Function: A_RelayCustomValue
-//
-// Description: Manipulates the custom value of the object's target/tracer.
-//
-// var1:
-//		lower 16 bits:
-//					if var1 == 0, use own custom value
-//					else, use var1 value
-//		upper 16 bits = 0 - target, 1 - tracer
-// var2:
-//      if var2 == 5, multiply the target's custom value by var1
-//      else if var2 == 4, divide the target's custom value by var1
-//      else if var2 == 3, apply modulo var1 to the target's custom value
-//      else if var2 == 2, add var1 to the target's custom value
-//      else if var2 == 1, substract var1 from the target's custom value
-//      else if var2 == 0, replace the target's custom value with var1
-//
-void A_RelayCustomValue(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-	INT32 temp; // reference value - var1 lower 16 bits changes this
-	INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RelayCustomValue", actor))
-		return;
-#endif
-
-	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
-		return;
-
-	// reference custom value
-	if ((locvar1 & 65535) == 0)
-		temp = actor->cusval; // your own custom value
-	else
-		temp = (locvar1 & 65535); // var1 value
-
-	if (!(locvar1 >> 16)) // target's custom value
-		tempT = actor->target->cusval;
-	else // tracer's custom value
-		tempT = actor->tracer->cusval;
-
-	if (temp == 0 && locvar2 == 4)
-		return; // DON'T DIVIDE BY ZERO
-
-	// now get new cusval using target's and the reference
-	if (locvar2 == 5) // multiply
-		tempT *= temp;
-	else if (locvar2 == 4) // divide
-		tempT /= temp;
-	else if (locvar2 == 3) // modulo
-		tempT %= temp;
-	else if (locvar2 == 2) // add
-		tempT += temp;
-	else if (locvar2 == 1) // subtract
-		tempT -= temp;
-	else // replace
-		tempT = temp;
-
-	// finally, give target/tracer the new cusval!
-	if (!(locvar1 >> 16)) // target
-		actor->target->cusval = tempT;
-	else // tracer
-		actor->tracer->cusval = tempT;
-}
-
-// Function: A_CusValAction
-//
-// Description: Calls an action from a reference state applying custom value parameters.
-//
-// var1 = state # to use action from
-// var2:
-//      if var2 == 5, only replace new action's var2 with memory value
-//      else if var2 == 4, only replace new action's var1 with memory value
-//      else if var2 == 3, replace new action's var2 with custom value and var1 with memory value
-//      else if var2 == 2, replace new action's var1 with custom value and var2 with memory value
-//      else if var2 == 1, only replace new action's var2 with custom value
-//      else if var2 == 0, only replace new action's var1 with custom value
-//
-void A_CusValAction(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CusValAction", actor))
-		return;
-#endif
-
-	if (locvar2 == 5)
-	{
-		var1 = states[locvar1].var1;
-		var2 = (INT32)actor->cvmem;
-	}
-	else if (locvar2 == 4)
-	{
-		var1 = (INT32)actor->cvmem;
-		var2 = states[locvar1].var2;
-	}
-	else if (locvar2 == 3)
-	{
-		var1 = (INT32)actor->cvmem;
-		var2 = (INT32)actor->cusval;
-	}
-	else if (locvar2 == 2)
-	{
-		var1 = (INT32)actor->cusval;
-		var2 = (INT32)actor->cvmem;
-	}
-	else if (locvar2 == 1)
-	{
-		var1 = states[locvar1].var1;
-		var2 = (INT32)actor->cusval;
-	}
-	else
-	{
-		var1 = (INT32)actor->cusval;
-		var2 = states[locvar1].var2;
-	}
-
-#ifdef HAVE_BLUA
-	astate = &states[locvar1];
-#endif
-	states[locvar1].action.acp1(actor);
-}
-
-// Function: A_ForceStop
-//
-// Description: Actor immediately stops its current movement.
-//
-// var1:
-//      if var1 == 0, stop x-y-z-movement
-//      else, stop x-y-movement only
-// var2 = unused
-//
-void A_ForceStop(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ForceStop", actor))
-		return;
-#endif
-
-	actor->momx = actor->momy = 0;
-	if (locvar1 == 0)
-		actor->momz = 0;
-}
-
-// Function: A_ForceWin
-//
-// Description: Makes all players win the level.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_ForceWin(mobj_t *actor)
-{
-	INT32 i;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ForceWin", actor))
-		return;
-#else
-	(void)actor;
-#endif
-
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (playeringame[i] && ((players[i].mo && players[i].mo->health)
-		    || ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
-			break;
-	}
-
-	if (i == MAXPLAYERS)
-		return;
-
-	for (i = 0; i < MAXPLAYERS; i++)
-		P_DoPlayerExit(&players[i]);
-}
-
-// Function: A_SpikeRetract
-//
-// Description: Toggles actor solid flag.
-//
-// var1:
-//        if var1 == 0, actor no collide
-//        else, actor solid
-// var2 = unused
-//
-void A_SpikeRetract(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SpikeRetract", actor))
-		return;
-#endif
-
-	if (actor->flags & MF_NOBLOCKMAP)
-		return;
-
-	if (locvar1 == 0)
-	{
-		actor->flags &= ~MF_SOLID;
-		actor->flags |= MF_NOCLIPTHING;
-	}
-	else
-	{
-		actor->flags |= MF_SOLID;
-		actor->flags &= ~MF_NOCLIPTHING;
-	}
-	if (actor->flags & MF_SOLID)
-		P_CheckPosition(actor, actor->x, actor->y);
-}
-
-// Function: A_InfoState
-//
-// Description: Set mobj state to one predefined in mobjinfo.
-//
-// var1:
-//        if var1 == 0, set actor to spawnstate
-//        else if var1 == 1, set actor to seestate
-//        else if var1 == 2, set actor to meleestate
-//        else if var1 == 3, set actor to missilestate
-//        else if var1 == 4, set actor to deathstate
-//        else if var1 == 5, set actor to xdeathstate
-//        else if var1 == 6, set actor to raisestate
-// var2 = unused
-//
-void A_InfoState(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	switch (locvar1)
-	{
-	case 0:
-		if (actor->state != &states[actor->info->spawnstate])
-			P_SetMobjState(actor, actor->info->spawnstate);
-		break;
-	case 1:
-		if (actor->state != &states[actor->info->seestate])
-			P_SetMobjState(actor, actor->info->seestate);
-		break;
-	case 2:
-		if (actor->state != &states[actor->info->meleestate])
-			P_SetMobjState(actor, actor->info->meleestate);
-		break;
-	case 3:
-		if (actor->state != &states[actor->info->missilestate])
-			P_SetMobjState(actor, actor->info->missilestate);
-		break;
-	case 4:
-		if (actor->state != &states[actor->info->deathstate])
-			P_SetMobjState(actor, actor->info->deathstate);
-		break;
-	case 5:
-		if (actor->state != &states[actor->info->xdeathstate])
-			P_SetMobjState(actor, actor->info->xdeathstate);
-		break;
-	case 6:
-		if (actor->state != &states[actor->info->raisestate])
-			P_SetMobjState(actor, actor->info->raisestate);
-		break;
-	default:
-		break;
-	}
-}
-
-// Function: A_Repeat
-//
-// Description: Returns to state var2 until animation has been used var1 times, then continues to nextstate.
-//
-// var1 = repeat count
-// var2 = state to return to if extravalue2 > 0
-//
-void A_Repeat(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Repeat", actor))
-		return;
-#endif
-
-	if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1))
-		actor->extravalue2 = locvar1;
-
-	if (--actor->extravalue2 > 0)
-		P_SetMobjState(actor, locvar2);
-}
-
-// Function: A_SetScale
-//
-// Description: Changes the scale of the actor or its target/tracer
-//
-// var1 = new scale (1*FRACUNIT = 100%)
-// var2:
-//        upper 16 bits: 0 = actor, 1 = target, 2 = tracer
-//        lower 16 bits: 0 = instant change, 1 = smooth change
-//
-void A_SetScale(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *target;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SetScale", actor))
-		return;
-#endif
-
-	if (locvar1 <= 0)
-	{
-		if(cv_debug)
-			CONS_Printf("A_SetScale: Valid scale not specified!\n");
-		return;
-	}
-
-	if ((locvar2>>16) == 1)
-		target = actor->target;
-	else if ((locvar2>>16) == 2)
-		target = actor->tracer;
-	else // default to yourself!
-		target = actor;
-
-	if (!target)
-	{
-		if(cv_debug)
-			CONS_Printf("A_SetScale: No target!\n");
-		return;
-	}
-
-	target->destscale = locvar1; // destination scale
-	if (!(locvar2 & 65535))
-		P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway
-}
-
-// Function: A_RemoteDamage
-//
-// Description: Damages, kills or even removes either the actor or its target/tracer. Actor acts as the inflictor/source unless harming itself
-//
-// var1 = Mobj affected: 0 - actor, 1 - target, 2 - tracer
-// var2 = Action: 0 - Damage, 1 - Kill, 2 - Remove
-//
-void A_RemoteDamage(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *target; // we MUST have a target
-	mobj_t *source = NULL; // on the other hand we don't necessarily need a source
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RemoteDamage", actor))
-		return;
-#endif
-	if (locvar1 == 1)
-		target = actor->target;
-	else if (locvar1 == 2)
-		target = actor->tracer;
-	else // default to yourself!
-		target = actor;
-
-	if (locvar1 == 1 || locvar1 == 2)
-		source = actor;
-
-	if (!target)
-	{
-		if(cv_debug)
-			CONS_Printf("A_RemoteDamage: No target!\n");
-		return;
-	}
-
-	if (locvar2 == 1) // Kill mobj!
-	{
-		if (target->player) // players die using P_DamageMobj instead for some reason
-			P_DamageMobj(target, source, source, 1, DMG_INSTAKILL);
-		else
-			P_KillMobj(target, source, source, 0);
-	}
-	else if (locvar2 == 2) // Remove mobj!
-	{
-		if (target->player) //don't remove players!
-			return;
-
-		P_RemoveMobj(target);
-	}
-	else // default: Damage mobj!
-		P_DamageMobj(target, source, source, 1, 0);
-}
-
-// Function: A_HomingChase
-//
-// Description: Actor chases directly towards its destination object
-//
-// var1 = speed multiple
-// var2 = destination: 0 = target, 1 = tracer
-//
-void A_HomingChase(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *dest;
-	fixed_t dist;
-	fixed_t speedmul;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_HomingChase", actor))
-		return;
-#endif
-
-	if (locvar2 == 1)
-		dest = actor->tracer;
-	else //default
-		dest = actor->target;
-
-	if (!dest || !dest->health)
-		return;
-
-	actor->angle = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
-
-	dist = P_AproxDistance(P_AproxDistance(dest->x - actor->x, dest->y - actor->y), dest->z - actor->z);
-
-	if (dist < 1)
-		dist = 1;
-
-	speedmul = FixedMul(locvar1, actor->scale);
-
-	actor->momx = FixedMul(FixedDiv(dest->x - actor->x, dist), speedmul);
-	actor->momy = FixedMul(FixedDiv(dest->y - actor->y, dist), speedmul);
-	actor->momz = FixedMul(FixedDiv(dest->z - actor->z, dist), speedmul);
-}
-
-// Function: A_TrapShot
-//
-// Description: Fires a missile in a particular direction and angle rather than AT something, Trapgoyle-style!
-//
-// var1:
-//        lower 16 bits = object # to fire
-//        upper 16 bits = front offset
-// var2:
-//        lower 15 bits = vertical angle variable
-//        16th bit:
-//			- 0: use vertical angle variable as vertical angle in degrees
-//			- 1: mimic P_SpawnXYZMissile
-//				use z of actor minus z of missile as vertical distance to cover during momz calculation
-//				use vertical angle variable as horizontal distance to cover during momz calculation
-//        upper 16 bits = height offset
-//
-void A_TrapShot(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	boolean oldstyle = (locvar2 & 32768) ? true : false;
-	mobjtype_t type = (mobjtype_t)(locvar1 & 65535);
-	mobj_t *missile;
-	INT16 frontoff = (INT16)(locvar1 >> 16);
-	INT16 vertoff = (INT16)(locvar2 >> 16);
-	fixed_t x, y, z;
-	fixed_t speed;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_TrapShot", actor))
-		return;
-#endif
-
-	x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
-	y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale);
-	else
-		z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale);
-
-	CONS_Debug(DBG_GAMELOGIC, "A_TrapShot: missile no. = %d, front offset = %d, vertical angle = %d, z offset = %d\n",
-		type, frontoff, (INT16)(locvar2 & 65535), vertoff);
-
-	missile = P_SpawnMobj(x, y, z, type);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		missile->flags2 |= MF2_OBJECTFLIP;
-
-	missile->destscale = actor->scale;
-	P_SetScale(missile, actor->scale);
-
-	if (missile->info->seesound)
-		S_StartSound(missile, missile->info->seesound);
-
-	P_SetTarget(&missile->target, actor);
-	missile->angle = actor->angle;
-
-	speed = FixedMul(missile->info->speed, missile->scale);
-
-	if (oldstyle)
-	{
-		missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed);
-		missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed);
-		// The below line basically mimics P_SpawnXYZMissile's momz calculation.
-		missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed);
-		P_CheckMissileSpawn(missile);
-	}
-	else
-	{
-		angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT);
-		if (actor->eflags & MFE_VERTICALFLIP)
-				vertang = InvAngle(vertang); // flip firing angle
-		missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed));
-		missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed));
-		missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed);
-	}
-}
-
-// Function: A_VileTarget
-//
-// Description: Spawns an object directly on the target, and sets this object as the actor's tracer.
-//              Originally used by Archviles to summon a pillar of hellfire, hence the name.
-//
-// var1 = mobj to spawn
-// var2 = If 0, target only the actor's target. Else, target every player, period.
-//
-void A_VileTarget(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *fog;
-	mobjtype_t fogtype;
-	INT32 i;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_VileTarget", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	// Determine object to spawn
-	if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES)
-		fogtype = MT_CYBRAKDEMON_TARGET_RETICULE;
-	else
-		fogtype = (mobjtype_t)locvar1;
-
-	if (!locvar2)
-	{
-		fog = P_SpawnMobj(actor->target->x,
-							actor->target->y,
-							actor->target->z + ((actor->target->eflags & MFE_VERTICALFLIP) ? actor->target->height - mobjinfo[fogtype].height : 0),
-							fogtype);
-		if (actor->target->eflags & MFE_VERTICALFLIP)
-		{
-			fog->eflags |= MFE_VERTICALFLIP;
-			fog->flags2 |= MF2_OBJECTFLIP;
-		}
-		fog->destscale = actor->target->scale;
-		P_SetScale(fog, fog->destscale);
-
-		P_SetTarget(&actor->tracer, fog);
-		P_SetTarget(&fog->target, actor);
-		P_SetTarget(&fog->tracer, actor->target);
-		A_VileFire(fog);
-	}
-	else
-	{
-		// Our "Archvile" here is actually Oprah. "YOU GET A TARGET! YOU GET A TARGET! YOU ALL GET A TARGET!"
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (!playeringame[i] || players[i].spectator)
-				continue;
-
-			if (!players[i].mo)
-				continue;
-
-			if (!players[i].mo->health)
-				continue;
-
-			fog = P_SpawnMobj(players[i].mo->x,
-							players[i].mo->y,
-							players[i].mo->z + ((players[i].mo->eflags & MFE_VERTICALFLIP) ? players[i].mo->height - mobjinfo[fogtype].height : 0),
-							fogtype);
-			if (players[i].mo->eflags & MFE_VERTICALFLIP)
-			{
-				fog->eflags |= MFE_VERTICALFLIP;
-				fog->flags2 |= MF2_OBJECTFLIP;
-			}
-			fog->destscale = players[i].mo->scale;
-			P_SetScale(fog, fog->destscale);
-
-			if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now
-				P_SetTarget(&actor->tracer, fog);
-			P_SetTarget(&fog->target, actor);
-			P_SetTarget(&fog->tracer, players[i].mo);
-			A_VileFire(fog);
-		}
-	}
-}
-
-// Function: A_VileAttack
-//
-// Description: Instantly hurts the actor's target, if it's in the actor's line of sight.
-//              Originally used by Archviles to cause explosions where their hellfire pillars were, hence the name.
-//
-// var1 = sound to play
-// var2:
-//		Lower 16 bits = optional explosion object
-//		Upper 16 bits = If 0, attack only the actor's target. Else, attack all the players. All of them.
-//
-void A_VileAttack(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	sfxenum_t soundtoplay;
-	mobjtype_t explosionType = MT_NULL;
-	mobj_t *fire;
-	INT32 i;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_VileAttack", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	if (locvar1 <= 0 || locvar1 >= NUMSFX)
-		soundtoplay = sfx_brakrx;
-	else
-		soundtoplay = (sfxenum_t)locvar1;
-
-	if ((locvar2 & 0xFFFF) > 0 && (locvar2 & 0xFFFF) <= NUMMOBJTYPES)
-	{
-		explosionType = (mobjtype_t)(locvar2 & 0xFFFF);
-	}
-
-	if (!(locvar2 & 0xFFFF0000)) {
-		if (!P_CheckSight(actor, actor->target))
-			return;
-
-		S_StartSound(actor, soundtoplay);
-		P_DamageMobj(actor->target, actor, actor, 1, 0);
-		//actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it
-		actor->target->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(actor->target); // How we're doing it
-		if (explosionType != MT_NULL)
-		{
-			P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, explosionType);
-		}
-
-		// Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway.
-		fire = actor->tracer;
-
-		if (!fire)
-			return;
-
-		// move the fire between the vile and the player
-		//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
-		//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
-		P_TeleportMove(fire,
-						actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
-						actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
-						fire->z);
-		P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
-	}
-	else
-	{
-		// Oprahvile strikes again, but this time, she brings HOT PAIN
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (!playeringame[i] || players[i].spectator)
-				continue;
-
-			if (!players[i].mo)
-				continue;
-
-			if (!players[i].mo->health)
-				continue;
-
-			if (!P_CheckSight(actor, players[i].mo))
-				continue;
-
-			S_StartSound(actor, soundtoplay);
-			P_DamageMobj(players[i].mo, actor, actor, 1, 0);
-			//actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it
-			players[i].mo->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(players[i].mo); // How we're doing it
-			if (explosionType != MT_NULL)
-			{
-				P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z, explosionType);
-			}
-
-			// Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway.
-			// However, it ONLY applies to the actor's target. Nobody else matters!
-			if (actor->target != players[i].mo)
-				continue;
-
-			fire = actor->tracer;
-
-			if (!fire)
-				continue;
-
-			// move the fire between the vile and the player
-			//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
-			//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
-			P_TeleportMove(fire,
-							actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
-							actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
-							fire->z);
-			P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
-		}
-	}
-
-}
-
-// Function: A_VileFire
-//
-// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it.
-//				Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific).
-//				Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit.
-//
-// var1 = sound to play
-// var2:
-//		Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all)
-//		Upper 16 bits = # to spawn (default is 8)
-//
-void A_VileFire(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	mobj_t *dest;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_VileFire", actor))
-		return;
-#endif
-
-	dest = actor->tracer;
-	if (!dest)
-		return;
-
-	// don't move it if the vile lost sight
-	if (!P_CheckSight(actor->target, dest))
-		return;
-
-	// keep to same scale and gravity as tracer ALWAYS
-	actor->destscale = dest->scale;
-	P_SetScale(actor, actor->destscale);
-	if (dest->eflags & MFE_VERTICALFLIP)
-	{
-		actor->eflags |= MFE_VERTICALFLIP;
-		actor->flags2 |= MF2_OBJECTFLIP;
-	}
-	else
-	{
-		actor->eflags &= ~MFE_VERTICALFLIP;
-		actor->flags2 &= ~MF2_OBJECTFLIP;
-	}
-
-	P_UnsetThingPosition(actor);
-	actor->x = dest->x + P_ReturnThrustX(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale));
-	actor->y = dest->y + P_ReturnThrustY(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale));
-	actor->z = dest->z + ((actor->eflags & MFE_VERTICALFLIP) ? dest->height-actor->height : 0);
-	P_SetThingPosition(actor);
-
-	// Play sound, if one's specified
-	if (locvar1 > 0 && locvar1 < NUMSFX)
-		S_StartSound(actor, (sfxenum_t)locvar1);
-
-	// Now draw the line to the actor's target
-	if (locvar2 & 0xFFFF)
-	{
-		mobjtype_t lineMobj;
-		UINT16 numLineMobjs;
-		fixed_t distX;
-		fixed_t distY;
-		fixed_t distZ;
-		UINT16 i;
-
-		lineMobj = (mobjtype_t)(locvar2 & 0xFFFF);
-		numLineMobjs = (UINT16)(locvar2 >> 16);
-		if (numLineMobjs == 0) {
-			numLineMobjs = 8;
-		}
-
-		// Get distance for each step
-		distX = (actor->target->x - actor->x) / numLineMobjs;
-		distY = (actor->target->y - actor->y) / numLineMobjs;
-		distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs;
-
-		for (i = 1; i <= numLineMobjs; i++)
-		{
-			P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj);
-		}
-	}
-}
-
-// Function: A_BrakChase
-//
-// Description: Chase after your target, but speed and attack are tied to health.
-//
-// Every time this is called, generate a random number from a 1/4 to 3/4 of mobj's spawn health.
-// If health is above that value, use missilestate to attack.
-// If health is at or below that value, use meleestate to attack (default to missile state if not available).
-//
-// Likewise, state will linearly speed up as health goes down.
-// Upper bound will be the frame's normal length.
-// Lower bound defaults to 1 tic (technically 0, but we round up), unless a lower bound is specified in var1.
-//
-// var1 = lower-bound of frame length, in tics
-// var2 = optional sound to play
-//
-void A_BrakChase(mobj_t *actor)
-{
-	INT32 delta;
-	INT32 lowerbound;
-	INT32 newtics;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BrakChase", actor))
-		return;
-#endif
-
-	// Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly
-	if (actor->tics > 1 && locvar1 < actor->tics) // Not much point, otherwise
-	{
-		if (locvar1 < 0)
-			lowerbound = 0;
-		else
-			lowerbound = locvar1;
-
-		newtics = (((actor->tics - lowerbound) * actor->health) / actor->info->spawnhealth) + lowerbound;
-		if (newtics < 1)
-			newtics = 1;
-
-		actor->tics = newtics;
-	}
-
-	if (actor->reactiontime)
-	{
-		actor->reactiontime--;
-		if (actor->reactiontime == 0 && actor->type == MT_CYBRAKDEMON)
-			S_StartSound(0, sfx_bewar1 + P_RandomKey(4));
-	}
-
-	// modify target threshold
-	if (actor->threshold)
-	{
-		if (!actor->target || actor->target->health <= 0)
-			actor->threshold = 0;
-		else
-			actor->threshold--;
-	}
-
-	// turn towards movement direction if not there yet
-	if (actor->movedir < NUMDIRS)
-	{
-		actor->angle &= (7<<29);
-		delta = actor->angle - (actor->movedir << 29);
-
-		if (delta > 0)
-			actor->angle -= ANGLE_45;
-		else if (delta < 0)
-			actor->angle += ANGLE_45;
-	}
-
-	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
-	{
-		// look for a new target
-		if (P_LookForPlayers(actor, true, false, 0))
-			return; // got a new target
-
-		P_SetMobjStateNF(actor, actor->info->spawnstate);
-		return;
-	}
-
-	// do not attack twice in a row
-	if (actor->flags2 & MF2_JUSTATTACKED)
-	{
-		actor->flags2 &= ~MF2_JUSTATTACKED;
-		P_NewChaseDir(actor);
-		return;
-	}
-
-	// Check if we can attack
-	if (P_CheckMissileRange(actor) && !actor->movecount)
-	{
-		// Check if we should use "melee" attack first. (Yes, this still runs outside of melee range. Quiet, you.)
-		if (actor->info->meleestate
-			&& actor->health <= P_RandomRange(actor->info->spawnhealth/4, (actor->info->spawnhealth * 3)/4)) // Guaranteed true if <= 1/4 health, guaranteed false if > 3/4 health
-		{
-			if (actor->info->attacksound)
-				S_StartAttackSound(actor, actor->info->attacksound);
-
-			P_SetMobjState(actor, actor->info->meleestate);
-			actor->flags2 |= MF2_JUSTATTACKED;
-			return;
-		}
-		// Else, check for missile attack.
-		else if (actor->info->missilestate)
-		{
-			P_SetMobjState(actor, actor->info->missilestate);
-			actor->flags2 |= MF2_JUSTATTACKED;
-			return;
-		}
-	}
-
-	// possibly choose another target
-	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
-		&& P_LookForPlayers(actor, true, false, 0))
-		return; // got a new target
-
-	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
-		P_NewChaseDir(actor);
-
-	// Optionally play a sound effect
-	if (locvar2 > 0 && locvar2 < NUMSFX)
-		S_StartSound(actor, (sfxenum_t)locvar2);
-
-	// make active sound
-	if (actor->type != MT_CYBRAKDEMON && actor->info->activesound && P_RandomChance(3*FRACUNIT/256))
-	{
-		S_StartSound(actor, actor->info->activesound);
-	}
-}
-
-// Function: A_BrakFireShot
-//
-// Description: Shoot an object at your target, offset to match where Brak's gun is.
-// Also, sets Brak's reaction time; behaves normally otherwise.
-//
-// var1 = object # to shoot
-// var2 = unused
-//
-void A_BrakFireShot(mobj_t *actor)
-{
-	fixed_t x, y, z;
-	INT32 locvar1 = var1;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BrakFireShot", actor))
-		return;
-#endif
-	if (!actor->target)
-		return;
-
-	A_FaceTarget(actor);
-
-	x = actor->x
-		+ P_ReturnThrustX(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale))
-		+ P_ReturnThrustX(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale));
-	y = actor->y
-		+ P_ReturnThrustY(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale))
-		+ P_ReturnThrustY(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale));
-	if (actor->eflags & MFE_VERTICALFLIP)
-		z = actor->z + actor->height - FixedMul(144*FRACUNIT, actor->scale);
-	else
-		z = actor->z + FixedMul(144*FRACUNIT, actor->scale);
-
-	P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
-
-	if (!(actor->flags & MF_BOSS))
-	{
-		if (ultimatemode)
-			actor->reactiontime = actor->info->reactiontime*TICRATE;
-		else
-			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
-	}
-}
-
-// Function: A_BrakLobShot
-//
-// Description: Lobs an object at the floor about a third of the way toward your target.
-//				Implication is it'll bounce the rest of the way.
-//				(You can also just aim straight at the target, but whatever)
-//				Formula grabbed from http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_required_to_hit_coordinate_.28x.2Cy.29
-//
-// var1 = object # to lob
-// var2:
-//		Lower 16 bits: height offset to shoot from, from the actor's bottom (none that "airtime" malarky)
-//		Upper 16 bits: if 0, aim 1/3 of the way. Else, aim directly at target.
-//
-
-void A_BrakLobShot(mobj_t *actor)
-{
-	fixed_t v; // Velocity to shoot object
-	fixed_t a1, a2, aToUse; // Velocity squared
-	fixed_t g; // Gravity
-	fixed_t x; // Horizontal difference
-	INT32 x_int; // x! But in integer form!
-	fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up)
-	INT32 y_int; // y! But in integer form!
-	INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper.
-	fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number.
-	angle_t theta; // Angle of attack
-	mobjtype_t typeOfShot;
-	mobj_t *shot; // Object to shoot
-	fixed_t newTargetX; // If not aiming directly
-	fixed_t newTargetY; // If not aiming directly
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2 & 0x0000FFFF;
-	INT32 aimDirect = var2 & 0xFFFF0000;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_BrakLobShot", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return; // Don't even bother if we've got nothing to aim at.
-
-	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
-
-	// Look up distance between actor and its target
-	x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
-	if (!aimDirect)
-	{
-		// Distance should actually be a third of the way over
-		x = FixedDiv(x, 3<<FRACBITS);
-		newTargetX = actor->x + P_ReturnThrustX(actor, actor->angle, x);
-		newTargetY = actor->y + P_ReturnThrustY(actor, actor->angle, x);
-		x = P_AproxDistance(newTargetX - actor->x, newTargetY - actor->y);
-		// Look up height difference between actor and the ground 1/3 of the way to its target
-		y = P_FloorzAtPos(newTargetX, newTargetY, actor->target->z, actor->target->height) - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale));
-	}
-	else
-	{
-		// Look up height difference between actor and its target
-		y = actor->target->z - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale));
-	}
-
-	// Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise.
-	x_int = x>>FRACBITS;
-	y_int = y>>FRACBITS;
-	intHypotenuse = (x_int*x_int) + (y_int*y_int);
-	fixedHypotenuse = FixedSqrt(intHypotenuse) *256;
-
-	// a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -.
-	a1 = FixedMul(g,y+fixedHypotenuse);
-	a2 = FixedMul(g,y-fixedHypotenuse);
-
-	// Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v.
-	if (a1 < 0 || a2 < 0)
-	{
-		if (a1 < 0 && a2 < 0)
-		{
-			//Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort!
-			return;
-		}
-		// Just find which one's NOT negative, and use that
-		aToUse = max(a1,a2);
-	}
-	else
-	{
-		// Both are positive; use whichever's smaller so it can decay faster
-		aToUse = min(a1,a2);
-	}
-	v = FixedSqrt(aToUse);
-	// Okay, so we know the velocity. Let's actually find theta.
-	// We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So:
-	//theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS];
-	theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))];
-
-	// Okay, complicated math done. Let's fire our object already, sheesh.
-	A_FaceTarget(actor);
-	if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES)
-		typeOfShot = MT_CANNONBALL;
-	else typeOfShot = (mobjtype_t)locvar1;
-	shot = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(locvar2*FRACUNIT, actor->scale), typeOfShot);
-	if (shot->info->seesound)
-		S_StartSound(shot, shot->info->seesound);
-	P_SetTarget(&shot->target, actor); // where it came from
-
-	shot->angle = actor->angle;
-
-	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
-	shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT));
-	shot->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(shot->angle >> ANGLETOFINESHIFT));
-	// Then the vertical axis. No angle-correction needed here.
-	shot->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT));
-	// I hope that's all that's needed, ugh
-}
-
-// Function: A_NapalmScatter
-//
-// Description: Scatters a specific number of projectiles around in a circle.
-//				Intended for use with objects that are affected by gravity; would be kind of silly otherwise.
-//
-// var1:
-//		Lower 16 bits: object # to lob (TODO: come up with a default)
-//		Upper 16 bits: Number to lob (default 8)
-// var2:
-//		Lower 16 bits: distance to toss them (No default - 0 does just that - but negatives will revert to 128)
-//		Upper 16 bits: airtime in tics (default 16)
-//
-void A_NapalmScatter(mobj_t *actor)
-{
-	mobjtype_t typeOfShot = var1 & 0x0000FFFF; // Type
-	INT32 numToShoot = (var1 & 0xFFFF0000) >> 16; // How many
-	fixed_t distance = (var2 & 0x0000FFFF) << FRACBITS; // How far
-	fixed_t airtime = var2 & 0xFFFF0000; // How long until impact (assuming no obstacles)
-	fixed_t vx; // Horizontal momentum
-	fixed_t vy; // Vertical momentum
-	fixed_t g; // Gravity
-	INT32 i; // for-loop cursor
-	mobj_t *mo; // each and every spawned napalm burst
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_NapalmScatter", actor))
-		return;
-#endif
-
-	// Some quick sanity-checking
-	if (typeOfShot >= NUMMOBJTYPES) // I'd add a <0 check, too, but 0x0000FFFF isn't negative in this case
-		typeOfShot = MT_NULL;
-	if (numToShoot <= 0) // Presumably you forgot to set var1 up; else, why are you calling this to shoot nothing?
-		numToShoot = 8;
-	else if (numToShoot > 8192) // If you seriously need this many objects spawned, stop and ask yourself "Why am I doing this?"
-		numToShoot = 8192;
-	if (distance < 0) // Presumably you thought this was an unsigned integer, you naive fool
-		distance = 32767<<FRACBITS;
-	if (airtime <= 0) // Same deal as distance I guess
-		airtime = 16<<FRACBITS;
-
-	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
-
-	// vy = (g*(airtime-1))/2
-	vy = FixedMul(g,(airtime-(1<<FRACBITS)))>>1;
-	// vx = distance/airtime
-	vx = FixedDiv(distance, airtime);
-
-	for (i = 0; i<numToShoot; i++)
-	{
-		const angle_t fa = (i*FINEANGLES/numToShoot) & FINEMASK;
-
-		mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot);
-		P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot
-
-		mo->angle = fa << ANGLETOFINESHIFT;
-		mo->momx = FixedMul(FINECOSINE(fa),vx);
-		mo->momy = FixedMul(FINESINE(fa),vx);
-		mo->momz = vy;
-	}
-}
-
-// Function: A_SpawnFreshCopy
-//
-// Description: Spawns a copy of the mobj. x, y, z, angle, scale, target and tracer carry over; everything else starts anew.
-//				Mostly writing this because I want to do multiple actions to pass these along in a single frame instead of several.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_SpawnFreshCopy(mobj_t *actor)
-{
-	mobj_t *newObject;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SpawnFreshCopy", actor))
-		return;
-#endif
-
-	newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type);
-	newObject->flags2 = actor->flags2 & MF2_AMBUSH;
-	newObject->angle = actor->angle;
-	newObject->color = actor->color;
-	P_SetTarget(&newObject->target, actor->target);
-	P_SetTarget(&newObject->tracer, actor->tracer);
-
-	if (newObject->info->seesound)
-		S_StartSound(newObject, newObject->info->seesound);
-}
-
-// Internal Flicky spawning function.
-mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers)
-{
-	mobj_t *flicky;
-
-	if (!flickytype)
-	{
-		if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service.
-			return NULL;
-		else
-		{
-			INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies);
-			flickytype = mapheaderinfo[gamemap-1]->flickies[prandom];
-		}
-	}
-
-	flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype);
-	flicky->angle = actor->angle;
-
-	if (flickytype == MT_SEED)
-		flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2;
-
-	if (actor->eflags & MFE_UNDERWATER)
-		momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
-
-	P_SetObjectMomZ(flicky, momz, false);
-	flicky->movedir = (P_RandomChance(FRACUNIT/2) ?  -1 : 1);
-	flicky->fuse = P_RandomRange(595, 700);	// originally 300, 350
-	flicky->threshold = 0;
-
-	if (lookforplayers)
-		P_LookForPlayers(flicky, true, false, 0);
-
-	return flicky;
-}
-
-// Function: A_FlickySpawn
-//
-// Description: Flicky spawning function.
-//
-// var1:
-//		lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
-//		upper 16 bits: if 0, no sound is played. Else, A_Scream is called.
-// var2 = upwards thrust for spawned flicky. If zero, default value is provided.
-//
-void A_FlickySpawn(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickySpawn", actor))
-		return;
-#endif
-
-	if (locvar1 >> 16) {
-		A_Scream(actor); // A shortcut for the truly lazy.
-		locvar1 &= 65535;
-	}
-
-	P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true);
-}
-
-// Internal Flicky color setting
-void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo)
-{
-	UINT8 flickycolors[] = {
-		SKINCOLOR_RED,
-		SKINCOLOR_CYAN,
-		SKINCOLOR_BLUE,
-		SKINCOLOR_VAPOR,
-		SKINCOLOR_PURPLE,
-		SKINCOLOR_BUBBLEGUM,
-		SKINCOLOR_NEON,
-		SKINCOLOR_BLACK,
-		SKINCOLOR_BEIGE,
-		SKINCOLOR_LAVENDER,
-		SKINCOLOR_RUBY,
-		SKINCOLOR_SALMON,
-		SKINCOLOR_SUNSET,
-		SKINCOLOR_ORANGE,
-		SKINCOLOR_YELLOW,
-	};
-
-	if (extrainfo == 0)
-		// until we can customize flicky colors by level header, just stick to SRB2's defaults
-		actor->color = flickycolors[P_RandomKey(2)]; //flickycolors[P_RandomKey(sizeof(flickycolors))];
-	else
-		actor->color = flickycolors[min(extrainfo-1, 14)]; // sizeof(flickycolors)-1
-}
-
-// Function: A_FlickyCenter
-//
-// Description: Place flickies in-level.
-//
-// var1:
-//        Lower 16 bits = if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
-//        Bits 17-20 = Flicky color, up to 15. Applies to fish.
-//        Bit 21 = Flag MF_SLIDEME (see below)
-//        Bit 22 = Flag MF_GRENADEBOUNCE (see below)
-//        Bit 23 = Flag MF_NOCLIPTHING (see below)
-//
-//        If actor is placed from a spawnpoint (map Thing), the Thing's properties take precedence.
-//
-// var2 = maximum default distance away from spawn the flickies are allowed to travel. If angle != 0, then that's the radius.
-//
-// If MTF_EXTRA (MF_SLIDEME): is flagged, Flickies move aimlessly. Else, orbit around the target.
-// If MTF_OBJECTSPECIAL (MF_GRENADEBOUNCE): Flickies stand in-place without gravity (unless they hop, then gravity is applied.)
-// If MTF_AMBUSH (MF_NOCLIPTHING): is flagged, Flickies hop.
-//
-void A_FlickyCenter(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	UINT16 flickytype = (locvar1 & 0xFFFF);
-	UINT8 flickycolor = ((locvar1 >> 16) & 0xFF);
-	UINT8 flickyflags = ((locvar1 >> 20) & 0xF);
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyCenter", actor))
-		return;
-#endif
-
-	if (!actor->tracer)
-	{
-		mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false);
-		P_SetTarget(&flicky->target, actor);
-		P_SetTarget(&actor->tracer, flicky);
-
-		if (actor->spawnpoint)
-		{
-			actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING);
-			actor->flags |= (
-				((actor->spawnpoint->options & MTF_EXTRA) ? MF_SLIDEME : 0)
-				| ((actor->spawnpoint->options & MTF_OBJECTSPECIAL) ? MF_GRENADEBOUNCE : 0)
-				| ((actor->spawnpoint->options & MTF_AMBUSH) ? MF_NOCLIPTHING : 0)
-			);
-			actor->extravalue1 = actor->spawnpoint->angle ? abs(actor->spawnpoint->angle) * FRACUNIT
-				: locvar2 ? abs(locvar2) : 384 * FRACUNIT;
-			actor->extravalue2 = actor->spawnpoint->extrainfo;
-			actor->friction = actor->spawnpoint->x*FRACUNIT;
-			actor->movefactor = actor->spawnpoint->y*FRACUNIT;
-			actor->watertop = actor->spawnpoint->z*FRACUNIT;
-		}
-		else
-		{
-			actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING);
-			actor->flags |= (
-				((flickyflags & 1) ? MF_SLIDEME : 0)
-				| ((flickyflags & 2) ? MF_GRENADEBOUNCE : 0)
-				| ((flickyflags & 4) ? MF_NOCLIPTHING : 0)
-			);
-			actor->extravalue1 = abs(locvar2);
-			actor->extravalue2 = flickycolor;
-			actor->friction = actor->x;
-			actor->movefactor = actor->y;
-			actor->watertop = actor->z;
-			locvar1 = flickytype;
-		}
-
-		if (actor->flags & MF_GRENADEBOUNCE) // in-place
-			actor->tracer->fuse = 0;
-		else if (actor->flags & MF_SLIDEME) // aimless
-		{
-			actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly.
-			actor->tracer->angle = P_RandomKey(180)*ANG2;
-		}
-		else //orbit
-			actor->tracer->fuse = FRACUNIT;
-
-		if (locvar1 == MT_FLICKY_08)
-			P_InternalFlickySetColor(actor->tracer, actor->extravalue2);
-
-		actor->extravalue2 = 0;
-	}
-
-	if (!(actor->flags & MF_SLIDEME) && !(actor->flags & MF_GRENADEBOUNCE))
-	{
-		fixed_t originx = actor->friction;
-		fixed_t originy = actor->movefactor;
-		fixed_t originz = actor->watertop;
-
-		actor->tracer->fuse = FRACUNIT;
-
-		// Impose default home radius if flicky orbits around player
-		if (!actor->extravalue1)
-			actor->extravalue1 = locvar2 ? abs(locvar2) : 384 * FRACUNIT;
-
-		P_LookForPlayers(actor, true, false, actor->extravalue1);
-
-		if (actor->target && P_AproxDistance(actor->target->x - originx, actor->target->y - originy) < actor->extravalue1)
-		{
-			actor->extravalue2 = 1;
-		 	P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z);
-		}
-		else if(actor->extravalue2)
-		{
-			actor->extravalue2 = 0;
-			P_TeleportMove(actor, originx, originy, originz);
-		}
-	}
-}
-
-// Internal Flicky bubbling function.
-void P_InternalFlickyBubble(mobj_t *actor)
-{
-	if (actor->eflags & MFE_UNDERWATER)
-	{
-		mobj_t *overlay;
-
-		if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer)
-			return;
-
-		overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
-		P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate);
-		P_SetTarget(&actor->tracer, overlay);
-		P_SetTarget(&overlay->target, actor);
-		return;
-	}
-
-	if (!actor->tracer || P_MobjWasRemoved(actor->tracer))
-		return;
-
-	P_RemoveMobj(actor->tracer);
-	P_SetTarget(&actor->tracer, NULL);
-}
-
-// Function: A_FlickyAim
-//
-// Description: Flicky aiming function.
-//
-// var1 = how far around the target (in angle constants) the flicky should look
-// var2 = distance from target to aim for
-//
-void A_FlickyAim(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	boolean flickyhitwall = false;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyAim", actor))
-		return;
-#endif
-
-	if ((actor->momx == actor->momy && actor->momy == 0)
-		|| (actor->target && P_IsFlickyCenter(actor->target->type)
-			&& actor->target->extravalue1 && (actor->target->flags & MF_SLIDEME)
-			&& P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) >= actor->target->extravalue1))
-		flickyhitwall = true;
-
-	P_InternalFlickyBubble(actor);
-	P_InstaThrust(actor, 0, 0);
-
-	if (!actor->target)
-	{
-		P_LookForPlayers(actor, true, false, 0);
-		actor->angle = P_RandomKey(36)*ANG10;
-		return;
-	}
-
-	if (actor->fuse > 2*TICRATE)
-	{
-		angle_t posvar;
-		fixed_t chasevar, chasex, chasey;
-
-		if (flickyhitwall)
-			actor->movedir *= -1;
-
-		posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK;
-		chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2;
-
-		chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar);
-		chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar);
-
-		if (P_AproxDistance(chasex - actor->x, chasey - actor->y))
-			actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey);
-	}
-	else if (flickyhitwall)
-	{
-		if (actor->target && P_IsFlickyCenter(actor->target->type))
-			actor->angle = R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + P_RandomRange(112, 248) * ANG1;
-		else
-			actor->angle += P_RandomRange(112, 248)*ANG1;
-		actor->threshold = 0;
-	}
-}
-
-//Internal Flicky flying function. Also usuable as an underwater swim thrust.
-void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez)
-{
-	angle_t vertangle;
-
-	flyspeed = FixedMul(flyspeed, actor->scale);
-	actor->flags |= MF_NOGRAVITY;
-
-	var1 = ANG30;
-	var2 = 32*FRACUNIT;
-	A_FlickyAim(actor);
-
-	chasez *= 8;
-	if (!actor->target || !(actor->fuse > 2*TICRATE))
-		chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT);
-	else
-	{
-		fixed_t add = actor->target->z + (actor->target->height - actor->height)/2;
-		if (add > (actor->ceilingz - 24*actor->scale - actor->height))
-			add = actor->ceilingz - 24*actor->scale - actor->height;
-		else if (add < (actor->floorz + 24*actor->scale))
-			add = actor->floorz + 24*actor->scale;
-		chasez += add;
-	}
-
-	if (!targetdist)
-		targetdist = 16*FRACUNIT; //Default!
-
-	if (actor->target && abs(chasez - actor->z) > targetdist)
-		targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
-
-	if (actor->target
-		&& P_IsFlickyCenter(actor->target->type)
-		&& (actor->target->flags & MF_SLIDEME))
-		vertangle = 0;
-	else
-		vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK;
-
-	P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed));
-	actor->momz = FixedMul(FINESINE(vertangle), flyspeed);
-}
-
-// Function: A_FlickyFly
-//
-// Description: Flicky flying function.
-//
-// var1 = how fast to fly
-// var2 = how far ahead the target should be considered
-//
-void A_FlickyFly(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyFly", actor))
-		return;
-#endif
-	P_InternalFlickyFly(actor, locvar1, locvar2,
-	FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK)
-	);
-}
-
-// Function: A_FlickySoar
-//
-// Description: Flicky soaring function - specific to puffin.
-//
-// var1 = how fast to fly
-// var2 = how far ahead the target should be considered
-//
-void A_FlickySoar(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickySoar", actor))
-		return;
-#endif
-	P_InternalFlickyFly(actor, locvar1, locvar2,
-	2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK)))
-	);
-
-	if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10)
-		actor->frame = 3;
-}
-
-//Function: A_FlickyCoast
-//
-// Description: Flicky swim-coasting function.
-//
-// var1 = speed to change state upon reaching
-// var2 = state to change to upon slowing down
-// the spawnstate of the mobj = state to change to when above water
-//
-void A_FlickyCoast(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyCoast", actor))
-		return;
-#endif
-	if (actor->eflags & MFE_UNDERWATER)
-	{
-		actor->momx = (11*actor->momx)/12;
-		actor->momy = (11*actor->momy)/12;
-		actor->momz = (11*actor->momz)/12;
-
-		if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1)
-			P_SetMobjState(actor, locvar2);
-
-		return;
-	}
-
-	actor->flags &= ~MF_NOGRAVITY;
-	P_SetMobjState(actor, mobjinfo[actor->type].spawnstate);
-}
-
-// Internal Flicky hopping function.
-void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle)
-{
-	if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
-	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
-	{
-		if (momz)
-		{
-			if (actor->eflags & MFE_UNDERWATER)
-				momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
-			P_SetObjectMomZ(actor, momz, false);
-		}
-		P_InstaThrust(actor, angle, FixedMul(momh, actor->scale));
-	}
-}
-
-// Function: A_FlickyHop
-//
-// Description: Flicky hopping function.
-//
-// var1 = vertical thrust
-// var2 = horizontal thrust
-//
-void A_FlickyHop(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyHop", actor))
-		return;
-#endif
-	P_InternalFlickyHop(actor, locvar1, locvar2, actor->angle);
-}
-
-// Function: A_FlickyFlounder
-//
-// Description: Flicky floundering function.
-//
-// var1 = intended vertical thrust
-// var2 = intended horizontal thrust
-//
-void A_FlickyFlounder(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	angle_t hopangle;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyFlounder", actor))
-		return;
-#endif
-	locvar1 *= (P_RandomKey(2) + 1);
-	locvar2 *= (P_RandomKey(2) + 1);
-	hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2);
-	P_InternalFlickyHop(actor, locvar1, locvar2, hopangle);
-}
-
-// Function: A_FlickyCheck
-//
-// Description: Flicky airtime check function.
-//
-// var1 = state to change to upon touching the floor
-// var2 = state to change to upon falling
-// the meleestate of the mobj = state to change to when underwater
-//
-void A_FlickyCheck(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyCheck", actor))
-		return;
-#endif
-	if (actor->target
-		&& P_IsFlickyCenter(actor->target->type)
-		&& (actor->target->flags & MF_GRENADEBOUNCE))
-	{
-		if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping
-		{
-			actor->momz = 0;
-			actor->flags |= MF_NOGRAVITY;
-		}
-		actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY;
-		P_SetMobjState(actor, mobjinfo[actor->type].seestate);
-	}
-	else if (locvar2 && P_MobjFlip(actor)*actor->momz < 1)
-		P_SetMobjState(actor, locvar2);
-	else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
-	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
-		P_SetMobjState(actor, locvar1);
-	else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER))
-		P_SetMobjState(actor, mobjinfo[actor->type].meleestate);
-	P_InternalFlickyBubble(actor);
-}
-
-// Function: A_FlickyHeightCheck
-//
-// Description: Flicky height check function.
-//
-// var1 = state to change to when falling below height relative to target
-// var2 = height relative to target to change state at
-//
-void A_FlickyHeightCheck(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyHeightCheck", actor))
-		return;
-#endif
-	if (actor->target
-		&& P_IsFlickyCenter(actor->target->type)
-		&& (actor->target->flags & MF_GRENADEBOUNCE))
-	{
-		if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping
-		{
-			actor->momz = 0;
-			actor->flags |= MF_NOGRAVITY;
-		}
-		actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY;
-		P_SetMobjState(actor, mobjinfo[actor->type].seestate);
-	}
-	else if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1
-	&& ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2)
-	|| (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz)))
-		P_SetMobjState(actor, locvar1);
-	P_InternalFlickyBubble(actor);
-}
-
-// Function: A_FlickyFlutter
-//
-// Description: Flicky fluttering function - specific to chicken.
-//
-// var1 = state to change to upon touching the floor
-// var2 = state to change to upon falling
-// the meleestate of the mobj = state to change to when underwater
-//
-void A_FlickyFlutter(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlickyFlutter", actor))
-		return;
-#endif
-	var1 = locvar1;
-	var2 = locvar2;
-	A_FlickyCheck(actor);
-
-	var1 = ANG30;
-	var2 = 32*FRACUNIT;
-	A_FlickyAim(actor);
-
-	P_InstaThrust(actor, actor->angle, 2*actor->scale);
-	if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2)
-		actor->momz = -P_MobjFlip(actor)*actor->scale/2;
-}
-
-#undef FLICKYHITWALL
-
-// Function: A_FlameParticle
-//
-// Description: Creates the mobj's painchance at a random position around the object's radius.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_FlameParticle(mobj_t *actor)
-{
-	mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance);
-	fixed_t rad, hei;
-	mobj_t *particle;
-	//INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FlameParticle", actor))
-		return;
-#endif
-
-	if (!type)
-		return;
-
-	rad = actor->radius>>FRACBITS;
-	hei = actor->height>>FRACBITS;
-	particle = P_SpawnMobjFromMobj(actor,
-		P_RandomRange(rad, -rad)<<FRACBITS,
-		P_RandomRange(rad, -rad)<<FRACBITS,
-		P_RandomRange(hei/2, hei)<<FRACBITS,
-		type);
-	P_SetObjectMomZ(particle, 2<<FRACBITS, false);
-}
-
-// Function: A_FadeOverlay
-//
-// Description: Makes a pretty overlay (primarily for super/NiGHTS transformation).
-//
-// var1 = bit 1 = bit 1 = don't make fast, bit 2 = don't set tracer
-// var2 = unused
-//
-void A_FadeOverlay(mobj_t *actor)
-{
-	mobj_t *fade;
-	INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_FadeOverlay", actor))
-		return;
-#endif
-
-	fade = P_SpawnGhostMobj(actor);
-	fade->frame = actor->frame;
-
-	if (!(locvar1 & 1))
-	{
-		fade->fuse = 15;
-		fade->flags2 |= MF2_BOSSNOTRAP;
-	}
-	else
-		fade->fuse = 20;
-
-	if (!(locvar1 & 2))
-		P_SetTarget(&actor->tracer, fade);
-}
-
-// Function: A_Boss5Jump
-//
-// Description: Makes an object jump in an arc to land on their tracer precicely.
-//				Adapted from A_BrakLobShot, see there for explanation.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_Boss5Jump(mobj_t *actor)
-{
-	fixed_t v; // Velocity to jump at
-	fixed_t a1, a2, aToUse; // Velocity squared
-	fixed_t g; // Gravity
-	fixed_t x; // Horizontal difference
-	INT32 x_int; // x! But in integer form!
-	fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up)
-	INT32 y_int; // y! But in integer form!
-	INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper.
-	fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number.
-	angle_t theta; // Angle of attack
-	// INT32 locvar1 = var1;
-	// INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_Boss5Jump", actor))
-		return;
-#endif
-
-	if (!actor->tracer)
-		return; // Don't even bother if we've got nothing to aim at.
-
-	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
-
-	// Look up distance between actor and its tracer
-	x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
-	// Look up height difference between actor and its tracer
-	y = actor->tracer->z - actor->z;
-
-	// Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise.
-	x_int = x>>FRACBITS;
-	y_int = y>>FRACBITS;
-	intHypotenuse = (x_int*x_int) + (y_int*y_int);
-	fixedHypotenuse = FixedSqrt(intHypotenuse) *256;
-
-	// a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -.
-	a1 = FixedMul(g,y+fixedHypotenuse);
-	a2 = FixedMul(g,y-fixedHypotenuse);
-
-	// Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v.
-	if (a1 < 0 || a2 < 0)
-	{
-		if (a1 < 0 && a2 < 0)
-		{
-			//Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort!
-			return;
-		}
-		// Just find which one's NOT negative, and use that
-		aToUse = max(a1,a2);
-	}
-	else
-	{
-		// Both are positive; use whichever's smaller so it can decay faster
-		aToUse = min(a1,a2);
-	}
-	v = FixedSqrt(aToUse);
-	// Okay, so we know the velocity. Let's actually find theta.
-	// We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So:
-	//theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS];
-	theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))];
-
-	// Okay, complicated math done. Let's make this object jump already.
-	A_FaceTracer(actor);
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		actor->z--;
-	else
-		actor->z++;
-
-	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
-	fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse
-	actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT));
-	actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT));
-	// Then the vertical axis. No angle-correction needed here.
-	actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT));
-	// I hope that's all that's needed, ugh
-}
-
-// Function: A_LightBeamReset
-// Description: Resets momentum and position for DSZ's projecting light beams
-//
-// var1 = unused
-// var2 = unused
-//
-void A_LightBeamReset(mobj_t *actor)
-{
-	// INT32 locvar1 = var1;
-	// INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_LightBeamReset", actor))
-		return;
-#endif
-
-	actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256;
-	P_SetScale(actor, actor->destscale);
-
-	if (!actor->spawnpoint)
-		return; // this can't work properly welp
-
-	actor->momx = -(P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128;
-	actor->momy = (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128;
-	actor->momz = (P_SignedRandom()*FRACUNIT)/128;
-
-	P_TeleportMove(actor,
-		actor->spawnpoint->x*FRACUNIT - (P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
-		actor->spawnpoint->y*FRACUNIT + (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
-		actor->spawnpoint->z*FRACUNIT + (P_SignedRandom()*FRACUNIT)/2);
-}
-
-// Function: A_MineExplode
-// Description: Handles the explosion of a DSZ mine.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_MineExplode(mobj_t *actor)
-{
-	// INT32 locvar1 = var1;
-	// INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MineExplode", actor))
-		return;
-#endif
-
-	A_Scream(actor);
-	actor->flags = MF_NOGRAVITY|MF_NOCLIP;
-
-	quake.epicenter = NULL;
-	quake.radius = 512*FRACUNIT;
-	quake.intensity = 8*FRACUNIT;
-	quake.time = TICRATE/3;
-
-	P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF);
-	P_MobjCheckWater(actor);
-
-	{
-#define dist 64
-		UINT8 i;
-		mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE);
-		S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e));
-		P_SpawnMobj(actor->x, actor->y, actor->z, type);
-		for (i = 0; i < 16; i++)
-		{
-			mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT,
-				actor->y+P_RandomRange(-dist, dist)*FRACUNIT,
-				actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT,
-				type);
-			fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z;
-			fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx));
-			b->momx = FixedDiv(dx, dm)*3;
-			b->momy = FixedDiv(dy, dm)*3;
-			b->momz = FixedDiv(dz, dm)*3;
-			if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop))
-				b->flags &= ~MF_NOGRAVITY;
-		}
-#undef dist
-
-		if (actor->watertop != INT32_MAX)
-			P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH);
-	}
-}
-
-// Function: A_MineRange
-// Description: If the target gets too close, change the state to meleestate.
-//
-// var1 = Distance to alert at
-// var2 = unused
-//
-void A_MineRange(mobj_t *actor)
-{
-	fixed_t dm;
-	INT32 locvar1 = var1;
-	// INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MineRange", actor))
-		return;
-#endif
-
-	if (!actor->target)
-		return;
-
-	dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x));
-	if ((dm>>FRACBITS) < locvar1)
-		P_SetMobjState(actor, actor->info->meleestate);
-}
-
-// Function: A_ConnectToGround
-// Description: Create a palm tree trunk/mine chain.
-//
-// var1 = Object type to connect to ground
-// var2 = Object type to place on ground
-//
-void A_ConnectToGround(mobj_t *actor)
-{
-	mobj_t *work;
-	fixed_t workz;
-	fixed_t workh;
-	SINT8 dir;
-	angle_t ang;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ConnectToGround", actor))
-		return;
-#endif
-
-	if (actor->subsector->sector->ffloors)
-		P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2);
-
-	if (actor->flags2 & MF2_OBJECTFLIP)
-	{
-		workz = actor->ceilingz - (actor->z + actor->height);
-		dir = -1;
-	}
-	else
-	{
-		workz = actor->floorz - actor->z;
-		dir = 1;
-	}
-
-	if (locvar2)
-	{
-		workh = FixedMul(mobjinfo[locvar2].height, actor->scale);
-		if (actor->flags2 & MF2_OBJECTFLIP)
-			workz -= workh;
-		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2);
-		workz += dir*workh;
-	}
-
-	if (!locvar1)
-		return;
-
-	if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale)))
-		return;
-
-	if (actor->flags2 & MF2_OBJECTFLIP)
-		workz -= workh;
-
-	ang = actor->angle + ANGLE_45;
-	while (dir*workz < 0)
-	{
-		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1);
-		if (work)
-			work->angle = ang;
-		ang += ANGLE_90;
-		workz += dir*workh;
-	}
-
-	if (workz != 0)
-		actor->z += workz;
-}
-
-// Function: A_SpawnParticleRelative
-//
-// Description: Spawns a particle effect relative to the location of the actor
-//
-// var1:
-//		var1 >> 16 = x
-//		var1 & 65535 = y
-// var2:
-//		var2 >> 16 = z
-//		var2 & 65535 = state
-//
-void A_SpawnParticleRelative(mobj_t *actor)
-{
-	INT16 x, y, z; // Want to be sure we can use negative values
-	statenum_t state;
-	mobj_t *mo;
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_SpawnParticleRelative", actor))
-		return;
-#endif
-
-	CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
-
-	x = (INT16)(locvar1>>16);
-	y = (INT16)(locvar1&65535);
-	z = (INT16)(locvar2>>16);
-	state = (statenum_t)(locvar2&65535);
-
-	// Spawn objects correctly in reverse gravity.
-	// NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame
-	mo = P_SpawnMobj(actor->x + FixedMul(x<<FRACBITS, actor->scale),
-		actor->y + FixedMul(y<<FRACBITS, actor->scale),
-		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), MT_PARTICLE);
-
-	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
-
-	if (actor->eflags & MFE_VERTICALFLIP)
-		mo->flags2 |= MF2_OBJECTFLIP;
-
-	P_SetMobjState(mo, state);
-}
-
-// Function: A_MultiShotDist
-//
-// Description: Spawns multiple shots based on player proximity
-//
-// var1 = same as A_MultiShot
-// var2 = same as A_MultiShot
-//
-void A_MultiShotDist(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_MultiShotDist", actor))
-		return;
-#endif
-
-	{
-		UINT8 i;
-		// Quick! Look through players!
-		// Don't spawn dust unless a player is relatively close by (var1).
-		for (i = 0; i < MAXPLAYERS; ++i)
-			if (playeringame[i] && players[i].mo
-			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600<<FRACBITS))
-				break; // Stop looking.
-		if (i == MAXPLAYERS)
-			return; // don't make bubble!
-	}
-
-	var1 = locvar1;
-	var2 = locvar2;
-	A_MultiShot(actor);
-}
-
-// Function: A_WhoCaresIfYourSonIsABee
-//
-// Description: Makes a child object, storing the number of created children in the parent's extravalue1.
-//
-// var1 = mobjtype of child
-//		var2 >> 16 = mobjtype of child
-//		var2 & 65535 = vertical momentum
-// var2:
-//		var2 >> 16 = forward offset
-//		var2 & 65535 = vertical offset
-//
-void A_WhoCaresIfYourSonIsABee(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-	fixed_t foffsetx;
-	fixed_t foffsety;
-	mobj_t *son;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor))
-		return;
-#endif
-
-	A_FaceTarget(actor);
-
-	if (actor->extravalue1)
-		actor->extravalue1--;
-
-	if (actor->info->attacksound)
-		S_StartSound(actor, actor->info->attacksound);
-
-	foffsetx = P_ReturnThrustX(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
-	foffsety = P_ReturnThrustY(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
-
-	if (!(son = P_SpawnMobjFromMobj(actor, foffsetx, foffsety, (locvar2&65535)*FRACUNIT, (mobjtype_t)(locvar1 >> 16))))
-		return;
-
-	P_SetObjectMomZ(son, (locvar1 & 65535)<<FRACBITS, true);
-
-	P_SetTarget(&son->tracer, actor);
-	P_SetTarget(&son->target, actor->target);
-}
-
-// Function: A_ParentTriesToSleep
-//
-// Description: If extravalue1 is less than or equal to var1, go to var2.
-//
-// var1 = state to go to when extravalue1
-// var2 = unused
-//
-void A_ParentTriesToSleep(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ParentTriesToSleep", actor))
-		return;
-#endif
-
-	if (actor->extravalue1)
-	{
-		if (actor->info->seesound)
-			S_StartSound(actor, actor->info->seesound);
-		actor->reactiontime = 0;
-		P_SetMobjState(actor, locvar1);
-	}
-	else if (!actor->reactiontime)
-	{
-		actor->reactiontime = 1;
-		if (actor->info->activesound) // more like INactivesound doy hoy hoy
-			S_StartSound(actor, actor->info->activesound);
-	}
-}
-
-
-// Function: A_CryingToMomma
-//
-// Description: If you're a child, let your parent know something's happened to you through extravalue1. Also, prepare to die.
-//
-// var1 = unused
-// var2 = unused
-//
-void A_CryingToMomma(mobj_t *actor)
-{
-	//INT32 locvar1 = var1;
-	//INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CryingToMomma", actor))
-		return;
-#endif
-
-	if (actor->tracer)
-		actor->tracer->extravalue1++;
-
-	actor->momx = actor->momy = actor->momz = 0;
-
-	P_UnsetThingPosition(actor);
-	if (sector_list)
-	{
-		P_DelSeclist(sector_list);
-		sector_list = NULL;
-	}
-	actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING;
-	P_SetThingPosition(actor);
-}
-
-// Function: A_CheckFlags2
-//
-// Description: If actor->flags2 & var1, goto var2.
-//
-// var1 = mask
-// var2 = state to go
-//
-void A_CheckFlags2(mobj_t *actor)
-{
-	INT32 locvar1 = var1;
-	INT32 locvar2 = var2;
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_CheckFlags2", actor))
-		return;
-#endif
-
-	if (actor->flags2 & locvar1)
-		P_SetMobjState(actor, (statenum_t)locvar2);
-}
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  p_enemy.c
+/// \brief Enemy thinking, AI
+///        Action Pointer Functions that are associated with states/frames
+
+#include "doomdef.h"
+#include "g_game.h"
+#include "p_local.h"
+#include "r_main.h"
+#include "r_state.h"
+#include "s_sound.h"
+#include "m_random.h"
+#include "m_misc.h"
+#include "r_things.h"
+#include "i_video.h"
+#include "lua_hook.h"
+
+#ifdef HW3SOUND
+#include "hardware/hw3sound.h"
+#endif
+
+#ifdef HAVE_BLUA
+boolean LUA_CallAction(const char *action, mobj_t *actor);
+#endif
+
+player_t *stplyr;
+INT32 var1;
+INT32 var2;
+
+//
+// P_NewChaseDir related LUT.
+//
+static dirtype_t opposite[] =
+{
+	DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
+	DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
+};
+
+static dirtype_t diags[] =
+{
+	DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
+};
+
+//Real Prototypes to A_*
+void A_Fall(mobj_t *actor);
+void A_Look(mobj_t *actor);
+void A_Chase(mobj_t *actor);
+void A_FaceStabChase(mobj_t *actor);
+void A_FaceStabRev(mobj_t *actor);
+void A_FaceStabHurl(mobj_t *actor);
+void A_FaceStabMiss(mobj_t *actor);
+void A_StatueBurst(mobj_t *actor);
+void A_JetJawRoam(mobj_t *actor);
+void A_JetJawChomp(mobj_t *actor);
+void A_PointyThink(mobj_t *actor);
+void A_CheckBuddy(mobj_t *actor);
+void A_HoodFire(mobj_t *actor);
+void A_HoodThink(mobj_t *actor);
+void A_HoodFall(mobj_t *actor);
+void A_ArrowBonks(mobj_t *actor);
+void A_SnailerThink(mobj_t *actor);
+void A_SharpChase(mobj_t *actor);
+void A_SharpSpin(mobj_t *actor);
+void A_SharpDecel(mobj_t *actor);
+void A_CrushstaceanWalk(mobj_t *actor);
+void A_CrushstaceanPunch(mobj_t *actor);
+void A_CrushclawAim(mobj_t *actor);
+void A_CrushclawLaunch(mobj_t *actor);
+void A_VultureVtol(mobj_t *actor);
+void A_VultureCheck(mobj_t *actor);
+void A_SkimChase(mobj_t *actor);
+void A_FaceTarget(mobj_t *actor);
+void A_FaceTracer(mobj_t *actor);
+void A_LobShot(mobj_t *actor);
+void A_FireShot(mobj_t *actor);
+void A_SuperFireShot(mobj_t *actor);
+void A_BossFireShot(mobj_t *actor);
+void A_Boss7FireMissiles(mobj_t *actor);
+void A_Boss1Laser(mobj_t *actor);
+void A_FocusTarget(mobj_t *actor);
+void A_Boss4Reverse(mobj_t *actor);
+void A_Boss4SpeedUp(mobj_t *actor);
+void A_Boss4Raise(mobj_t *actor);
+void A_SkullAttack(mobj_t *actor);
+void A_BossZoom(mobj_t *actor);
+void A_BossScream(mobj_t *actor);
+void A_Scream(mobj_t *actor);
+void A_Pain(mobj_t *actor);
+void A_1upThinker(mobj_t *actor);
+void A_MonitorPop(mobj_t *actor);
+void A_GoldMonitorPop(mobj_t *actor);
+void A_GoldMonitorRestore(mobj_t *actor);
+void A_GoldMonitorSparkle(mobj_t *actor);
+void A_Explode(mobj_t *actor);
+void A_BossDeath(mobj_t *actor);
+void A_CustomPower(mobj_t *actor);
+void A_GiveWeapon(mobj_t *actor);
+void A_RingBox(mobj_t *actor);
+void A_Invincibility(mobj_t *actor);
+void A_SuperSneakers(mobj_t *actor);
+void A_AwardScore(mobj_t *actor);
+void A_ExtraLife(mobj_t *actor);
+void A_GiveShield(mobj_t *actor);
+void A_GravityBox(mobj_t *actor);
+void A_ScoreRise(mobj_t *actor);
+void A_BunnyHop(mobj_t *actor);
+void A_BubbleSpawn(mobj_t *actor);
+void A_FanBubbleSpawn(mobj_t *actor);
+void A_BubbleRise(mobj_t *actor);
+void A_BubbleCheck(mobj_t *actor);
+void A_AttractChase(mobj_t *actor);
+void A_DropMine(mobj_t *actor);
+void A_FishJump(mobj_t *actor);
+void A_ThrownRing(mobj_t *actor);
+void A_SetSolidSteam(mobj_t *actor);
+void A_UnsetSolidSteam(mobj_t *actor);
+void A_SignPlayer(mobj_t *actor);
+void A_OverlayThink(mobj_t *actor);
+void A_JetChase(mobj_t *actor);
+void A_JetbThink(mobj_t *actor);
+void A_JetgShoot(mobj_t *actor);
+void A_JetgThink(mobj_t *actor);
+void A_ShootBullet(mobj_t *actor);
+void A_MinusDigging(mobj_t *actor);
+void A_MinusPopup(mobj_t *actor);
+void A_MinusCheck(mobj_t *actor);
+void A_ChickenCheck(mobj_t *actor);
+void A_MouseThink(mobj_t *actor);
+void A_DetonChase(mobj_t *actor);
+void A_CapeChase(mobj_t *actor);
+void A_RotateSpikeBall(mobj_t *actor);
+void A_SlingAppear(mobj_t *actor);
+void A_UnidusBall(mobj_t *actor);
+void A_RockSpawn(mobj_t *actor);
+void A_SetFuse(mobj_t *actor);
+void A_CrawlaCommanderThink(mobj_t *actor);
+void A_RingExplode(mobj_t *actor);
+void A_OldRingExplode(mobj_t *actor);
+void A_MixUp(mobj_t *actor);
+void A_RecyclePowers(mobj_t *actor);
+void A_Boss2TakeDamage(mobj_t *actor);
+void A_Boss7Chase(mobj_t *actor);
+void A_GoopSplat(mobj_t *actor);
+void A_Boss2PogoSFX(mobj_t *actor);
+void A_Boss2PogoTarget(mobj_t *actor);
+void A_EggmanBox(mobj_t *actor);
+void A_TurretFire(mobj_t *actor);
+void A_SuperTurretFire(mobj_t *actor);
+void A_TurretStop(mobj_t *actor);
+void A_SparkFollow(mobj_t *actor);
+void A_BuzzFly(mobj_t *actor);
+void A_GuardChase(mobj_t *actor);
+void A_EggShield(mobj_t *actor);
+void A_SetReactionTime(mobj_t *actor);
+void A_Boss1Spikeballs(mobj_t *actor);
+void A_Boss3TakeDamage(mobj_t *actor);
+void A_Boss3Path(mobj_t *actor);
+void A_LinedefExecute(mobj_t *actor);
+void A_PlaySeeSound(mobj_t *actor);
+void A_PlayAttackSound(mobj_t *actor);
+void A_PlayActiveSound(mobj_t *actor);
+void A_SmokeTrailer(mobj_t *actor);
+void A_SpawnObjectAbsolute(mobj_t *actor);
+void A_SpawnObjectRelative(mobj_t *actor);
+void A_ChangeAngleRelative(mobj_t *actor);
+void A_ChangeAngleAbsolute(mobj_t *actor);
+void A_PlaySound(mobj_t *actor);
+void A_FindTarget(mobj_t *actor);
+void A_FindTracer(mobj_t *actor);
+void A_SetTics(mobj_t *actor);
+void A_SetRandomTics(mobj_t *actor);
+void A_ChangeColorRelative(mobj_t *actor);
+void A_ChangeColorAbsolute(mobj_t *actor);
+void A_MoveRelative(mobj_t *actor);
+void A_MoveAbsolute(mobj_t *actor);
+void A_Thrust(mobj_t *actor);
+void A_ZThrust(mobj_t *actor);
+void A_SetTargetsTarget(mobj_t *actor);
+void A_SetObjectFlags(mobj_t *actor);
+void A_SetObjectFlags2(mobj_t *actor);
+void A_RandomState(mobj_t *actor);
+void A_RandomStateRange(mobj_t *actor);
+void A_DualAction(mobj_t *actor);
+void A_RemoteAction(mobj_t *actor);
+void A_ToggleFlameJet(mobj_t *actor);
+void A_OrbitNights(mobj_t *actor);
+void A_GhostMe(mobj_t *actor);
+void A_SetObjectState(mobj_t *actor);
+void A_SetObjectTypeState(mobj_t *actor);
+void A_KnockBack(mobj_t *actor);
+void A_PushAway(mobj_t *actor);
+void A_RingDrain(mobj_t *actor);
+void A_SplitShot(mobj_t *actor);
+void A_MissileSplit(mobj_t *actor);
+void A_MultiShot(mobj_t *actor);
+void A_InstaLoop(mobj_t *actor);
+void A_Custom3DRotate(mobj_t *actor);
+void A_SearchForPlayers(mobj_t *actor);
+void A_CheckRandom(mobj_t *actor);
+void A_CheckTargetRings(mobj_t *actor);
+void A_CheckRings(mobj_t *actor);
+void A_CheckTotalRings(mobj_t *actor);
+void A_CheckHealth(mobj_t *actor);
+void A_CheckRange(mobj_t *actor);
+void A_CheckHeight(mobj_t *actor);
+void A_CheckTrueRange(mobj_t *actor);
+void A_CheckThingCount(mobj_t *actor);
+void A_CheckAmbush(mobj_t *actor);
+void A_CheckCustomValue(mobj_t *actor);
+void A_CheckCusValMemo(mobj_t *actor);
+void A_SetCustomValue(mobj_t *actor);
+void A_UseCusValMemo(mobj_t *actor);
+void A_RelayCustomValue(mobj_t *actor);
+void A_CusValAction(mobj_t *actor);
+void A_ForceStop(mobj_t *actor);
+void A_ForceWin(mobj_t *actor);
+void A_SpikeRetract(mobj_t *actor);
+void A_InfoState(mobj_t *actor);
+void A_Repeat(mobj_t *actor);
+void A_SetScale(mobj_t *actor);
+void A_RemoteDamage(mobj_t *actor);
+void A_HomingChase(mobj_t *actor);
+void A_TrapShot(mobj_t *actor);
+void A_Boss1Chase(mobj_t *actor);
+void A_Boss2Chase(mobj_t *actor);
+void A_Boss2Pogo(mobj_t *actor);
+void A_BossJetFume(mobj_t *actor);
+void A_VileTarget(mobj_t *actor);
+void A_VileAttack(mobj_t *actor);
+void A_VileFire(mobj_t *actor);
+void A_BrakChase(mobj_t *actor);
+void A_BrakFireShot(mobj_t *actor);
+void A_BrakLobShot(mobj_t *actor);
+void A_NapalmScatter(mobj_t *actor);
+void A_SpawnFreshCopy(mobj_t *actor);
+void A_FlickySpawn(mobj_t *actor);
+void A_FlickyCenter(mobj_t *actor);
+void A_FlickyAim(mobj_t *actor);
+void A_FlickyFly(mobj_t *actor);
+void A_FlickySoar(mobj_t *actor);
+void A_FlickyCoast(mobj_t *actor);
+void A_FlickyHop(mobj_t *actor);
+void A_FlickyFlounder(mobj_t *actor);
+void A_FlickyCheck(mobj_t *actor);
+void A_FlickyHeightCheck(mobj_t *actor);
+void A_FlickyFlutter(mobj_t *actor);
+void A_FlameParticle(mobj_t *actor);
+void A_FadeOverlay(mobj_t *actor);
+void A_Boss5Jump(mobj_t *actor);
+void A_LightBeamReset(mobj_t *actor);
+void A_MineExplode(mobj_t *actor);
+void A_MineRange(mobj_t *actor);
+void A_ConnectToGround(mobj_t *actor);
+void A_SpawnParticleRelative(mobj_t *actor);
+void A_MultiShotDist(mobj_t *actor);
+void A_WhoCaresIfYourSonIsABee(mobj_t *actor);
+void A_ParentTriesToSleep(mobj_t *actor);
+void A_CryingToMomma(mobj_t *actor);
+void A_CheckFlags2(mobj_t *actor);
+//for p_enemy.c
+
+//
+// ENEMY THINKING
+// Enemies are always spawned with targetplayer = -1, threshold = 0
+// Most monsters are spawned unaware of all players, but some can be made preaware.
+//
+
+//
+// P_CheckMeleeRange
+//
+boolean P_CheckMeleeRange(mobj_t *actor)
+{
+	mobj_t *pl;
+	fixed_t dist;
+
+	if (!actor->target)
+		return false;
+
+	pl = actor->target;
+	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
+
+	if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius)
+		return false;
+
+	// check height now, so that damn crawlas cant attack
+	// you if you stand on a higher ledge.
+	if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))
+		return false;
+
+	if (!P_CheckSight(actor, actor->target))
+		return false;
+
+	return true;
+}
+
+// P_CheckMeleeRange for Jettysyn Bomber.
+boolean P_JetbCheckMeleeRange(mobj_t *actor)
+{
+	mobj_t *pl;
+	fixed_t dist;
+
+	if (!actor->target)
+		return false;
+
+	pl = actor->target;
+	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
+
+	if (dist >= (actor->radius + pl->radius)*2)
+		return false;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+	{
+		if (pl->z < actor->z + actor->height + FixedMul(40<<FRACBITS, actor->scale))
+			return false;
+	}
+	else
+	{
+		if (pl->z + pl->height > actor->z - FixedMul(40<<FRACBITS, actor->scale))
+			return false;
+	}
+
+	return true;
+}
+
+// P_CheckMeleeRange for CastleBot FaceStabber.
+boolean P_FaceStabCheckMeleeRange(mobj_t *actor)
+{
+	mobj_t *pl;
+	fixed_t dist;
+
+	if (!actor->target)
+		return false;
+
+	pl = actor->target;
+	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
+
+	if (dist >= (actor->radius + pl->radius)*4)
+		return false;
+
+	if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))
+		return false;
+
+	if (!P_CheckSight(actor, actor->target))
+		return false;
+
+	return true;
+}
+
+// P_CheckMeleeRange for Skim.
+boolean P_SkimCheckMeleeRange(mobj_t *actor)
+{
+	mobj_t *pl;
+	fixed_t dist;
+
+	if (!actor->target)
+		return false;
+
+	pl = actor->target;
+	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
+
+	if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius)
+		return false;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+	{
+		if (pl->z < actor->z + actor->height + FixedMul(24<<FRACBITS, actor->scale))
+			return false;
+	}
+	else
+	{
+		if (pl->z + pl->height > actor->z - FixedMul(24<<FRACBITS, actor->scale))
+			return false;
+	}
+
+	return true;
+}
+
+//
+// P_CheckMissileRange
+//
+boolean P_CheckMissileRange(mobj_t *actor)
+{
+	fixed_t dist;
+
+	if (!actor->target)
+		return false;
+
+	if (actor->reactiontime)
+		return false; // do not attack yet
+
+	if (!P_CheckSight(actor, actor->target))
+		return false;
+
+	// OPTIMIZE: get this from a global checksight
+	dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - FixedMul(64*FRACUNIT, actor->scale);
+
+	if (!actor->info->meleestate)
+		dist -= FixedMul(128*FRACUNIT, actor->scale); // no melee attack, so fire more
+
+	dist >>= FRACBITS;
+
+	if (actor->type == MT_EGGMOBILE)
+		dist >>= 1;
+
+	if (dist > 200)
+		dist = 200;
+
+	if (actor->type == MT_EGGMOBILE && dist > 160)
+		dist = 160;
+
+	if (P_RandomByte() < dist)
+		return false;
+
+	return true;
+}
+
+/** Checks for water in a sector.
+  * Used by Skim movements.
+  *
+  * \param x X coordinate on the map.
+  * \param y Y coordinate on the map.
+  * \return True if there's water at this location, false if not.
+  * \sa ::MT_SKIM
+  */
+static boolean P_WaterInSector(mobj_t *mobj, fixed_t x, fixed_t y)
+{
+	sector_t *sector;
+
+	sector = R_PointInSubsector(x, y)->sector;
+
+	if (sector->ffloors)
+	{
+		ffloor_t *rover;
+
+		for (rover = sector->ffloors; rover; rover = rover->next)
+		{
+			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE))
+				continue;
+
+			if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z)
+				return true; // we found water!!
+		}
+	}
+
+	return false;
+}
+
+static const fixed_t xspeed[NUMDIRS] = {FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS)), 0, 46341>>(16-FRACBITS)};
+static const fixed_t yspeed[NUMDIRS] = {0, 46341>>(16-FRACBITS), FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS))};
+
+/** Moves an actor in its current direction.
+  *
+  * \param actor Actor object to move.
+  * \return False if the move is blocked, otherwise true.
+  */
+boolean P_Move(mobj_t *actor, fixed_t speed)
+{
+	fixed_t tryx, tryy;
+	dirtype_t movedir = actor->movedir;
+
+	if (movedir == DI_NODIR || !actor->health)
+		return false;
+
+	I_Assert(movedir < NUMDIRS);
+
+	tryx = actor->x + FixedMul(speed*xspeed[movedir], actor->scale);
+	if (twodlevel || actor->flags2 & MF2_TWOD)
+		tryy = actor->y;
+	else
+		tryy = actor->y + FixedMul(speed*yspeed[movedir], actor->scale);
+
+	if (actor->type == MT_SKIM && !P_WaterInSector(actor, tryx, tryy)) // bail out if sector lacks water
+		return false;
+
+	if (!P_TryMove(actor, tryx, tryy, false))
+	{
+		if (actor->flags & MF_FLOAT && floatok)
+		{
+			// must adjust height
+			if (actor->z < tmfloorz)
+				actor->z += FixedMul(FLOATSPEED, actor->scale);
+			else
+				actor->z -= FixedMul(FLOATSPEED, actor->scale);
+
+			if (actor->type == MT_JETJAW && actor->z + actor->height > actor->watertop)
+				actor->z = actor->watertop - actor->height;
+
+			actor->flags2 |= MF2_INFLOAT;
+			return true;
+		}
+
+		return false;
+	}
+	else
+		actor->flags2 &= ~MF2_INFLOAT;
+
+	return true;
+}
+
+/** Attempts to move an actor on in its current direction.
+  * If the move succeeds, the actor's move count is reset
+  * randomly to a value from 0 to 15.
+  *
+  * \param actor Actor to move.
+  * \return True if the move succeeds, false if the move is blocked.
+  */
+static boolean P_TryWalk(mobj_t *actor)
+{
+	if (!P_Move(actor, actor->info->speed))
+		return false;
+	actor->movecount = P_RandomByte() & 15;
+	return true;
+}
+
+void P_NewChaseDir(mobj_t *actor)
+{
+	fixed_t deltax, deltay;
+	dirtype_t d[3];
+	dirtype_t tdir = DI_NODIR, olddir, turnaround;
+
+	I_Assert(actor->target != NULL);
+	I_Assert(!P_MobjWasRemoved(actor->target));
+
+	olddir = actor->movedir;
+
+	if (olddir >= NUMDIRS)
+		olddir = DI_NODIR;
+
+	if (olddir != DI_NODIR)
+		turnaround = opposite[olddir];
+	else
+		turnaround = olddir;
+
+	deltax = actor->target->x - actor->x;
+	deltay = actor->target->y - actor->y;
+
+	if (deltax > FixedMul(10*FRACUNIT, actor->scale))
+		d[1] = DI_EAST;
+	else if (deltax < -FixedMul(10*FRACUNIT, actor->scale))
+		d[1] = DI_WEST;
+	else
+		d[1] = DI_NODIR;
+
+	if (twodlevel || actor->flags2 & MF2_TWOD)
+		d[2] = DI_NODIR;
+	if (deltay < -FixedMul(10*FRACUNIT, actor->scale))
+		d[2] = DI_SOUTH;
+	else if (deltay > FixedMul(10*FRACUNIT, actor->scale))
+		d[2] = DI_NORTH;
+	else
+		d[2] = DI_NODIR;
+
+	// try direct route
+	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+	{
+		dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)];
+
+		actor->movedir = newdir;
+		if ((newdir != turnaround) && P_TryWalk(actor))
+			return;
+	}
+
+	// try other directions
+	if (P_RandomChance(25*FRACUNIT/32) || abs(deltay) > abs(deltax))
+	{
+		tdir = d[1];
+		d[1] = d[2];
+		d[2] = tdir;
+	}
+
+	if (d[1] == turnaround)
+		d[1] = DI_NODIR;
+	if (d[2] == turnaround)
+		d[2] = DI_NODIR;
+
+	if (d[1] != DI_NODIR)
+	{
+		actor->movedir = d[1];
+
+		if (P_TryWalk(actor))
+			return; // either moved forward or attacked
+	}
+
+	if (d[2] != DI_NODIR)
+	{
+		actor->movedir = d[2];
+
+		if (P_TryWalk(actor))
+			return;
+	}
+
+	// there is no direct path to the player, so pick another direction.
+	if (olddir != DI_NODIR)
+	{
+		actor->movedir =olddir;
+
+		if (P_TryWalk(actor))
+			return;
+	}
+
+	// randomly determine direction of search
+	if (P_RandomChance(FRACUNIT/2))
+	{
+		for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
+		{
+			if (tdir != turnaround)
+			{
+				actor->movedir = tdir;
+
+				if (P_TryWalk(actor))
+					return;
+			}
+		}
+	}
+	else
+	{
+		for (tdir = DI_SOUTHEAST; tdir >= DI_EAST; tdir--)
+		{
+			if (tdir != turnaround)
+			{
+				actor->movedir = tdir;
+
+				if (P_TryWalk(actor))
+					return;
+			}
+		}
+	}
+
+	if (turnaround != DI_NODIR)
+	{
+		actor->movedir = turnaround;
+
+		if (P_TryWalk(actor))
+			return;
+	}
+
+	actor->movedir = (angle_t)DI_NODIR; // cannot move
+}
+
+/** Looks for players to chase after, aim at, or whatever.
+  *
+  * \param actor     The object looking for flesh.
+  * \param allaround Look all around? If false, only players in a 180-degree
+  *                  range in front will be spotted.
+  * \param dist      If > 0, checks distance
+  * \return True if a player is found, otherwise false.
+  * \sa P_SupermanLook4Players
+  */
+boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist)
+{
+	INT32 c = 0, stop;
+	player_t *player;
+	angle_t an;
+
+	// BP: first time init, this allow minimum lastlook changes
+	if (actor->lastlook < 0)
+		actor->lastlook = P_RandomByte();
+
+	actor->lastlook %= MAXPLAYERS;
+
+	stop = (actor->lastlook - 1) & PLAYERSMASK;
+
+	for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK)
+	{
+		// done looking
+		if (actor->lastlook == stop)
+			return false;
+
+		if (!playeringame[actor->lastlook])
+			continue;
+
+		if (c++ == 2)
+			return false;
+
+		player = &players[actor->lastlook];
+
+		if ((netgame || multiplayer) && player->spectator)
+			continue;
+
+		if (player->pflags & PF_INVIS)
+			continue; // ignore notarget
+
+		if (!player->mo || P_MobjWasRemoved(player->mo))
+			continue;
+
+		if (player->mo->health <= 0)
+			continue; // dead
+
+		if (dist > 0
+			&& P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist)
+			continue; // Too far away
+
+		if (!allaround)
+		{
+			an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle;
+			if (an > ANGLE_90 && an < ANGLE_270)
+			{
+				dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y);
+				// if real close, react anyway
+				if (dist > FixedMul(MELEERANGE, actor->scale))
+					continue; // behind back
+			}
+		}
+
+		if (!P_CheckSight(actor, player->mo))
+			continue; // out of sight
+
+		if (tracer)
+			P_SetTarget(&actor->tracer, player->mo);
+		else
+			P_SetTarget(&actor->target, player->mo);
+		return true;
+	}
+
+	//return false;
+}
+
+/** Looks for a player with a ring shield.
+  * Used by rings.
+  *
+  * \param actor Ring looking for a shield to be attracted to.
+  * \return True if a player with ring shield is found, otherwise false.
+  * \sa A_AttractChase
+  */
+static boolean P_LookForShield(mobj_t *actor)
+{
+	INT32 c = 0, stop;
+	player_t *player;
+
+	// BP: first time init, this allow minimum lastlook changes
+	if (actor->lastlook < 0)
+		actor->lastlook = P_RandomByte();
+
+	actor->lastlook %= MAXPLAYERS;
+
+	stop = (actor->lastlook - 1) & PLAYERSMASK;
+
+	for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK))
+	{
+		// done looking
+		if (actor->lastlook == stop)
+			return false;
+
+		if (!playeringame[actor->lastlook])
+			continue;
+
+		if (c++ == 2)
+			return false;
+
+		player = &players[actor->lastlook];
+
+		if (!player->mo || player->mo->health <= 0)
+			continue; // dead
+
+		//When in CTF, don't pull rings that you cannot pick up.
+		if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) ||
+			(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
+			continue;
+
+		if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
+			&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale)))
+		{
+			P_SetTarget(&actor->tracer, player->mo);
+
+			if (actor->hnext)
+				P_SetTarget(&actor->hnext->hprev, actor->hprev);
+			if (actor->hprev)
+				P_SetTarget(&actor->hprev->hnext, actor->hnext);
+
+			return true;
+		}
+	}
+
+	//return false;
+}
+
+#ifdef WEIGHTEDRECYCLER
+// Compares players to see who currently has the "best" items, etc.
+static int P_RecycleCompare(const void *p1, const void *p2)
+{
+	player_t *player1 = &players[*(const UINT8 *)p1];
+	player_t *player2 = &players[*(const UINT8 *)p2];
+
+	// Non-shooting gametypes
+	if (!G_PlatformGametype())
+	{
+		// Invincibility.
+		if (player1->powers[pw_invulnerability] > player2->powers[pw_invulnerability]) return -1;
+		else if (player2->powers[pw_invulnerability] > player1->powers[pw_invulnerability]) return 1;
+
+		// One has a shield, the other doesn't.
+		if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1;
+		else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1;
+
+		// Sneakers.
+		if (player1->powers[pw_sneakers] > player2->powers[pw_sneakers]) return -1;
+		else if (player2->powers[pw_sneakers] > player1->powers[pw_sneakers]) return 1;
+	}
+	else // Match, Team Match, CTF, Tag, Etc.
+	{
+		UINT8 player1_em = M_CountBits((UINT32)player1->powers[pw_emeralds], 7);
+		UINT8 player2_em = M_CountBits((UINT32)player2->powers[pw_emeralds], 7);
+
+		UINT8 player1_rw = M_CountBits((UINT32)player1->ringweapons, NUM_WEAPONS-1);
+		UINT8 player2_rw = M_CountBits((UINT32)player2->ringweapons, NUM_WEAPONS-1);
+
+		UINT16 player1_am = player1->powers[pw_infinityring]          // max 800
+		                  + player1->powers[pw_automaticring]         // max 300
+		                  + (player1->powers[pw_bouncering]    * 3)   // max 100
+		                  + (player1->powers[pw_explosionring] * 6)   // max 50
+		                  + (player1->powers[pw_scatterring]   * 3)   // max 100
+		                  + (player1->powers[pw_grenadering]   * 6)   // max 50
+		                  + (player1->powers[pw_railring]      * 6);  // max 50
+		UINT16 player2_am = player2->powers[pw_infinityring]          // max 800
+		                  + player2->powers[pw_automaticring]         // max 300
+		                  + (player2->powers[pw_bouncering]    * 3)   // max 100
+		                  + (player2->powers[pw_explosionring] * 6)   // max 50
+		                  + (player2->powers[pw_scatterring]   * 3)   // max 100
+		                  + (player2->powers[pw_grenadering]   * 6)   // max 50
+		                  + (player2->powers[pw_railring]      * 6);  // max 50
+
+		// Super trumps everything.
+		if (player1->powers[pw_super] && !player2->powers[pw_super]) return -1;
+		else if (player2->powers[pw_super] && !player1->powers[pw_super]) return 1;
+
+		// Emerald count if neither player is Super.
+		if (player1_em > player2_em) return -1;
+		else if (player1_em < player2_em) return 1;
+
+		// One has a shield, the other doesn't.
+		// (the likelihood of a shielded player being worse off than one without one is low.)
+		if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1;
+		else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1;
+
+		// Ring weapons count
+		if (player1_rw > player2_rw) return -1;
+		else if (player1_rw < player2_rw) return 1;
+
+		// Ring ammo if they have the same number of weapons
+		if (player1_am > player2_am) return -1;
+		else if (player1_am < player2_am) return 1;
+	}
+
+	// Identical for our purposes
+	return 0;
+}
+#endif
+
+// Handles random monitor weights via console.
+static mobjtype_t P_DoRandomBoxChances(void)
+{
+	mobjtype_t spawnchance[256];
+	INT32 numchoices = 0, i = 0;
+
+	if (!(netgame || multiplayer))
+	{
+		switch (P_RandomKey(10))
+		{
+			case 0:
+				return MT_RING_ICON;
+			case 1:
+				return MT_SNEAKERS_ICON;
+			case 2:
+				return MT_INVULN_ICON;
+			case 3:
+				return MT_WHIRLWIND_ICON;
+			case 4:
+				return MT_ELEMENTAL_ICON;
+			case 5:
+				return MT_ATTRACT_ICON;
+			case 6:
+				return MT_FORCE_ICON;
+			case 7:
+				return MT_ARMAGEDDON_ICON;
+			case 8:
+				return MT_1UP_ICON;
+			case 9:
+				return MT_EGGMAN_ICON;
+		}
+		return MT_NULL;
+	}
+
+#define QUESTIONBOXCHANCES(type, cvar) \
+for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
+	QUESTIONBOXCHANCES(MT_RING_ICON,       cv_superring);
+	QUESTIONBOXCHANCES(MT_SNEAKERS_ICON,   cv_supersneakers);
+	QUESTIONBOXCHANCES(MT_INVULN_ICON,     cv_invincibility);
+	QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON,  cv_jumpshield);
+	QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON,  cv_watershield);
+	QUESTIONBOXCHANCES(MT_ATTRACT_ICON,    cv_ringshield);
+	QUESTIONBOXCHANCES(MT_FORCE_ICON,      cv_forceshield);
+	QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield);
+	QUESTIONBOXCHANCES(MT_1UP_ICON,        cv_1up);
+	QUESTIONBOXCHANCES(MT_EGGMAN_ICON,     cv_eggmanbox);
+	QUESTIONBOXCHANCES(MT_MIXUP_ICON,      cv_teleporters);
+	QUESTIONBOXCHANCES(MT_RECYCLER_ICON,   cv_recycler);
+#undef QUESTIONBOXCHANCES
+
+	if (numchoices == 0) return MT_NULL;
+	return spawnchance[P_RandomKey(numchoices)];
+}
+
+//
+// ACTION ROUTINES
+//
+
+// Function: A_Look
+//
+// Description: Look for a player and set your target to them.
+//
+// var1:
+//		lower 16 bits = look all around
+//		upper 16 bits = distance limit
+// var2 = If 1, only change to seestate. If 2, only play seesound. If 0, do both.
+//
+void A_Look(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Look", actor))
+		return;
+#endif
+
+	if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)))
+		return;
+
+	// go into chase state
+	if (!locvar2)
+	{
+		P_SetMobjState(actor, actor->info->seestate);
+		A_PlaySeeSound(actor);
+	}
+	else if (locvar2 == 1) // Only go into seestate
+		P_SetMobjState(actor, actor->info->seestate);
+	else if (locvar2 == 2) // Only play seesound
+		A_PlaySeeSound(actor);
+}
+
+// Function: A_Chase
+//
+// Description: Chase after your target.
+//
+// var1:
+//		1 = don't check meleestate
+//		2 = don't check missilestate
+//		3 = don't check meleestate and missilestate
+// var2 = unused
+//
+void A_Chase(mobj_t *actor)
+{
+	INT32 delta;
+	INT32 locvar1 = var1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Chase", actor))
+		return;
+#endif
+
+	I_Assert(actor != NULL);
+	I_Assert(!P_MobjWasRemoved(actor));
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// do not attack twice in a row
+	if (actor->flags2 & MF2_JUSTATTACKED)
+	{
+		actor->flags2 &= ~MF2_JUSTATTACKED;
+		P_NewChaseDir(actor);
+		return;
+	}
+
+	// check for melee attack
+	if (!(locvar1 & 1) && actor->info->meleestate && P_CheckMeleeRange(actor))
+	{
+		if (actor->info->attacksound)
+			S_StartAttackSound(actor, actor->info->attacksound);
+
+		P_SetMobjState(actor, actor->info->meleestate);
+		return;
+	}
+
+	// check for missile attack
+	if (!(locvar1 & 2) && actor->info->missilestate)
+	{
+		if (actor->movecount || !P_CheckMissileRange(actor))
+			goto nomissile;
+
+		P_SetMobjState(actor, actor->info->missilestate);
+		actor->flags2 |= MF2_JUSTATTACKED;
+		return;
+	}
+
+nomissile:
+	// possibly choose another target
+	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+		&& P_LookForPlayers(actor, true, false, 0))
+		return; // got a new target
+
+	// chase towards player
+	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		P_NewChaseDir(actor);
+}
+
+// Function: A_FaceStabChase
+//
+// Description: Unused variant of A_Chase for Castlebot Facestabber.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_FaceStabChase(mobj_t *actor)
+{
+	INT32 delta;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceStabChase", actor))
+		return;
+#endif
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// do not attack twice in a row
+	if (actor->flags2 & MF2_JUSTATTACKED)
+	{
+		actor->flags2 &= ~MF2_JUSTATTACKED;
+		P_NewChaseDir(actor);
+		return;
+	}
+
+	// check for melee attack
+	if (actor->info->meleestate && P_FaceStabCheckMeleeRange(actor))
+	{
+		if (actor->info->attacksound)
+			S_StartAttackSound(actor, actor->info->attacksound);
+
+		P_SetMobjState(actor, actor->info->meleestate);
+		return;
+	}
+
+	// check for missile attack
+	if (actor->info->missilestate)
+	{
+		if (actor->movecount || !P_CheckMissileRange(actor))
+			goto nomissile;
+
+		P_SetMobjState(actor, actor->info->missilestate);
+		actor->flags2 |= MF2_JUSTATTACKED;
+		return;
+	}
+
+nomissile:
+	// possibly choose another target
+	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+		&& P_LookForPlayers(actor, true, false, 0))
+		return; // got a new target
+
+	// chase towards player
+	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		P_NewChaseDir(actor);
+}
+
+static void P_SharpDust(mobj_t *actor, mobjtype_t type, angle_t ang)
+{
+	mobj_t *dust;
+
+	if (!type || !P_IsObjectOnGround(actor))
+		return;
+
+	dust = P_SpawnMobjFromMobj(actor,
+			-P_ReturnThrustX(actor, ang, 16<<FRACBITS),
+			-P_ReturnThrustY(actor, ang, 16<<FRACBITS),
+			0, type);
+	P_SetObjectMomZ(dust, P_RandomRange(1, 4)<<FRACBITS, false);
+}
+
+static void P_FaceStabFlume(mobj_t *actor)
+{
+	mobj_t *flume;
+	if (leveltime & 1)
+		return;
+
+	flume = P_SpawnMobjFromMobj(actor,
+		-P_ReturnThrustX(actor, actor->angle, actor->radius),
+		-P_ReturnThrustY(actor, actor->angle, actor->radius),
+		actor->height/3,
+		MT_PARTICLE);
+	flume->destscale = actor->scale*3;
+	P_SetScale(flume, flume->destscale);
+	P_SetTarget(&flume->target, actor);
+	flume->sprite = SPR_JETF;
+	flume->frame = FF_FULLBRIGHT;
+	flume->tics = 2;
+}
+
+// Function: A_FaceStabRev
+//
+// Description: Facestabber rev action
+//
+// var1 = effective duration
+// var2 = effective nextstate
+//
+void A_FaceStabRev(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceStabRev", actor))
+		return;
+#endif
+
+	if (!actor->target)
+	{
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	actor->extravalue1 = 0;
+
+	if (!actor->reactiontime)
+	{
+		actor->reactiontime = locvar1;
+		S_StartSound(actor, actor->info->activesound);
+	}
+	else
+	{
+		if ((--actor->reactiontime) == 0)
+		{
+			S_StartSound(actor, actor->info->attacksound);
+			P_SetMobjState(actor, locvar2);
+		}
+		else
+		{
+			P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<<FRACBITS), actor->y - P_ReturnThrustY(actor, actor->angle, 2<<FRACBITS), false);
+			P_FaceStabFlume(actor);
+		}
+	}
+}
+
+// Function: A_FaceStabHurl
+//
+// Description: Facestabber hurl action
+//
+// var1 = homing strength (recommended strength between 0-8)
+// var2 = effective nextstate
+//
+void A_FaceStabHurl(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceStabHurl", actor))
+		return;
+#endif
+
+	if (actor->target)
+	{
+		angle_t visang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		// Calculate new direction.
+		angle_t dirang = actor->angle;
+		angle_t diffang = visang - dirang;
+
+		if (locvar1) // Allow homing?
+		{
+			if (diffang > ANGLE_180)
+			{
+				angle_t workang = locvar1*(InvAngle(diffang)>>5);
+				diffang += InvAngle(workang);
+			}
+			else
+				diffang += (locvar1*(diffang>>5));
+		}
+		diffang += ANGLE_45;
+
+		// Check the sight cone.
+		if (diffang < ANGLE_90)
+		{
+			actor->angle = dirang;
+			if (++actor->extravalue2 < 4)
+				actor->extravalue2 = 4;
+			else if (actor->extravalue2 > 26)
+				actor->extravalue2 = 26;
+
+			if (P_TryMove(actor,
+				actor->x + P_ReturnThrustX(actor, dirang, actor->extravalue2<<FRACBITS),
+				actor->y + P_ReturnThrustY(actor, dirang, actor->extravalue2<<FRACBITS),
+				false))
+			{
+				// Do the spear damage.
+#define NUMSTEPS 3
+#define NUMGRADS 5
+#define MAXVAL (NUMSTEPS*NUMGRADS)
+				SINT8 step = (++actor->extravalue1);
+				fixed_t basesize = FRACUNIT/MAXVAL;
+				mobj_t *hwork = actor;
+				INT32 dist = 113;
+				fixed_t xo = P_ReturnThrustX(actor, actor->angle, dist*basesize);
+				fixed_t yo = P_ReturnThrustY(actor, actor->angle, dist*basesize);
+
+				while (step > 0)
+				{
+					if (!hwork->hnext)
+						P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR));
+					hwork = hwork->hnext;
+					hwork->angle = actor->angle + ANGLE_90;
+					hwork->destscale = FixedSqrt(step*basesize);
+					P_SetScale(hwork, hwork->destscale);
+					hwork->fuse = 2;
+					P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
+					step -= NUMGRADS;
+				}
+
+				if (actor->extravalue1 >= MAXVAL)
+					actor->extravalue1 -= NUMGRADS;
+
+				if ((step % 5) == 0)
+					P_SharpDust(actor, MT_SPINDUST, actor->angle);
+
+				P_FaceStabFlume(actor);
+				return;
+#undef MAXVAL
+#undef NUMGRADS
+#undef NUMSTEPS
+			}
+		}
+	}
+
+	P_SetMobjState(actor, locvar2);
+	actor->reactiontime = actor->info->reactiontime;
+}
+
+// Function: A_FaceStabMiss
+//
+// Description: Facestabber miss action
+//
+// var1 = unused
+// var2 = effective nextstate
+//
+void A_FaceStabMiss(mobj_t *actor)
+{
+	//INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceStabMiss", actor))
+		return;
+#endif
+
+	if (++actor->extravalue1 >= 3)
+	{
+		actor->extravalue2 -= 2;
+		actor->extravalue1 = 0;
+		S_StartSound(actor, sfx_s3k47);
+		P_SharpDust(actor, MT_SPINDUST, actor->angle);
+	}
+
+	if (actor->extravalue2 <= 0 || !P_TryMove(actor,
+		actor->x + P_ReturnThrustX(actor, actor->angle, actor->extravalue2<<FRACBITS),
+		actor->y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<<FRACBITS),
+		false))
+	{
+		actor->extravalue2 = 0;
+		P_SetMobjState(actor, locvar2);
+	}
+}
+
+// Function: A_StatueBurst
+//
+// Description: For suspicious statues only...
+//
+// var1 = object to create
+// var2 = effective nextstate for created object
+//
+void A_StatueBurst(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobjtype_t chunktype = (mobjtype_t)actor->info->raisestate;
+	mobj_t *new;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_StatueBurst", actor))
+		return;
+#endif
+
+	if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1)))
+		return;
+
+	new->angle = actor->angle;
+	new->target = actor->target;
+	if (locvar2)
+		P_SetMobjState(new, (statenum_t)locvar2);
+	S_StartSound(new, new->info->attacksound);
+	S_StopSound(actor);
+	S_StartSound(actor, sfx_s3k96);
+
+	{
+		fixed_t a, b;
+		fixed_t c = (actor->height>>2) - FixedMul(actor->scale, mobjinfo[chunktype].height>>1);
+		fixed_t v = 4<<FRACBITS;
+		const fixed_t r = (actor->radius>>1);
+		mobj_t *spawned;
+		UINT8 i;
+		for (i = 0; i < 8; i++)
+		{
+			a = ((i & 1) ? r : (-r));
+			b = ((i & 2) ? r : (-r));
+			if (i == 4)
+			{
+				c += (actor->height>>1);
+				v = 8<<FRACBITS;
+			}
+
+			spawned = P_SpawnMobjFromMobj(actor, a, b, c, chunktype);
+
+			P_InstaThrust(spawned, R_PointToAngle2(0, 0, a, b), 8<<FRACBITS);
+			P_SetObjectMomZ(spawned, v, false);
+
+			spawned->fuse = 3*TICRATE;
+		}
+	}
+}
+
+// Function: A_JetJawRoam
+//
+// Description: Roaming routine for JetJaw
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetJawRoam(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetJawRoam", actor))
+		return;
+#endif
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed*FRACUNIT/4, actor->scale));
+	}
+	else
+	{
+		actor->reactiontime = actor->info->reactiontime;
+		actor->angle += ANGLE_180;
+	}
+
+	if (P_LookForPlayers(actor, false, false, actor->radius * 16))
+		P_SetMobjState(actor, actor->info->seestate);
+}
+
+// Function: A_JetJawChomp
+//
+// Description: Chase and chomp at the target, as long as it is in view
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetJawChomp(mobj_t *actor)
+{
+	INT32 delta;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetJawChomp", actor))
+		return;
+#endif
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	// Stop chomping if target's dead or you can't see it
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
+		|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+	{
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// chase towards player
+	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		P_NewChaseDir(actor);
+}
+
+// Function: A_PointyThink
+//
+// Description: Thinker function for Pointy
+//
+// var1 = unused
+// var2 = unused
+//
+void A_PointyThink(mobj_t *actor)
+{
+	INT32 i;
+	player_t *player = NULL;
+	mobj_t *ball;
+	TVector v;
+	TVector *res;
+	angle_t fa;
+	fixed_t radius = FixedMul(actor->info->radius*actor->info->reactiontime, actor->scale);
+	boolean firsttime = true;
+	INT32 sign;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PointyThink", actor))
+		return;
+#endif
+	actor->momx = actor->momy = actor->momz = 0;
+
+	// Find nearest player
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i] || players[i].spectator)
+			continue;
+
+		if (!players[i].mo)
+			continue;
+
+		if (!players[i].mo->health)
+			continue;
+
+		if (!P_CheckSight(actor, players[i].mo))
+			continue;
+
+		if (firsttime)
+		{
+			firsttime = false;
+			player = &players[i];
+		}
+		else
+		{
+			if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) <
+				P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y))
+				player = &players[i];
+		}
+	}
+
+	if (!player)
+		return;
+
+	// Okay, we found the closest player. Let's move based on his movement.
+	P_SetTarget(&actor->target, player->mo);
+	A_FaceTarget(actor);
+
+	if (P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) < P_AproxDistance(player->mo->x + player->mo->momx - actor->x, player->mo->y + player->mo->momy - actor->y))
+		sign = -1; // Player is moving away
+	else
+		sign = 1; // Player is moving closer
+
+	if (player->mo->momx || player->mo->momy)
+	{
+		P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y), FixedMul(actor->info->speed*sign, actor->scale));
+
+		// Rotate our spike balls
+		actor->lastlook += actor->info->damage;
+		actor->lastlook %= FINEANGLES/4;
+	}
+
+	if (!actor->tracer) // For some reason we do not have spike balls...
+		return;
+
+	// Position spike balls relative to the value of 'lastlook'.
+	ball = actor->tracer;
+
+	i = 0;
+	while (ball)
+	{
+		fa = actor->lastlook+i;
+		v[0] = FixedMul(FINECOSINE(fa),radius);
+		v[1] = 0;
+		v[2] = FixedMul(FINESINE(fa),radius);
+		v[3] = FRACUNIT;
+
+		res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->lastlook+i)));
+		M_Memcpy(&v, res, sizeof (v));
+		res = VectorMatrixMultiply(v, *RotateZMatrix(actor->angle+ANGLE_180));
+		M_Memcpy(&v, res, sizeof (v));
+
+		P_UnsetThingPosition(ball);
+		ball->x = actor->x + v[0];
+		ball->y = actor->y + v[1];
+		ball->z = actor->z + (actor->height>>1) + v[2];
+		P_SetThingPosition(ball);
+
+		ball = ball->tracer;
+		i += ANGLE_90 >> ANGLETOFINESHIFT;
+	}
+}
+
+// Function: A_CheckBuddy
+//
+// Description: Checks if target/tracer exists/has health. If not, the object removes itself.
+//
+// var1:
+//		0 = target
+//		1 = tracer
+// var2 = unused
+//
+void A_CheckBuddy(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckBuddy", actor))
+		return;
+#endif
+	if (locvar1 && (!actor->tracer || actor->tracer->health <= 0))
+		P_RemoveMobj(actor);
+	else if (!locvar1 && (!actor->target || actor->target->health <= 0))
+		P_RemoveMobj(actor);
+}
+
+// Helper function for the Robo Hood.
+// Don't ask me how it works. Nev3r made it with dark majyks.
+static void P_ParabolicMove(mobj_t *actor, fixed_t x, fixed_t y, fixed_t z, fixed_t speed)
+{
+	fixed_t dh;
+
+	x -= actor->x;
+	y -= actor->y;
+	z -= actor->z;
+
+	dh = P_AproxDistance(x, y);
+
+	actor->momx = FixedMul(FixedDiv(x, dh), speed);
+	actor->momy = FixedMul(FixedDiv(y, dh), speed);
+
+	if (!gravity)
+		return;
+
+	dh = FixedDiv(FixedMul(dh, gravity), speed);
+	actor->momz = (dh>>1) + FixedDiv(z, dh<<1);
+}
+
+// Function: A_HoodFire
+//
+// Description: Firing Robo-Hood
+//
+// var1 = object type to fire
+// var2 = unused
+//
+void A_HoodFire(mobj_t *actor)
+{
+	mobj_t *arrow;
+	INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_HoodFire", actor))
+		return;
+#endif
+
+	// Check target first.
+	if (!actor->target)
+	{
+		actor->reactiontime = actor->info->reactiontime;
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	A_FaceTarget(actor);
+
+	if (!(arrow = P_SpawnMissile(actor, actor->target, (mobjtype_t)locvar1)))
+		return;
+
+	// Set a parabolic trajectory for the arrow.
+	P_ParabolicMove(arrow, actor->target->x, actor->target->y, actor->target->z, arrow->info->speed);
+}
+
+// Function: A_HoodThink
+//
+// Description: Thinker for Robo-Hood
+//
+// var1 = unused
+// var2 = unused
+//
+void A_HoodThink(mobj_t *actor)
+{
+	fixed_t dx, dy, dz, dm;
+	boolean checksight;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_HoodThink", actor))
+		return;
+#endif
+
+	// Check target first.
+	if (!actor->target)
+	{
+		actor->reactiontime = actor->info->reactiontime;
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	dx = (actor->target->x - actor->x), dy = (actor->target->y - actor->y), dz = (actor->target->z - actor->z);
+	dm = P_AproxDistance(dx, dy);
+	// Target dangerously close to robohood, retreat then.
+	if ((dm < 256<<FRACBITS) && (abs(dz) < 128<<FRACBITS))
+	{
+		P_SetMobjState(actor, actor->info->raisestate);
+		return;
+	}
+
+	// If target on sight, look at it.
+	if ((checksight = P_CheckSight(actor, actor->target)))
+	{
+		angle_t dang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		if (actor->angle >= ANGLE_180)
+		{
+			actor->angle = InvAngle(actor->angle)>>1;
+			actor->angle = InvAngle(actor->angle);
+		}
+		else
+			actor->angle >>= 1;
+
+		if (dang >= ANGLE_180)
+		{
+			dang = InvAngle(dang)>>1;
+			dang = InvAngle(dang);
+		}
+		else
+			dang >>= 1;
+
+		actor->angle += dang;
+	}
+
+	// Check whether to do anything.
+	if ((--actor->reactiontime) <= 0)
+	{
+		actor->reactiontime = actor->info->reactiontime;
+
+		// If way too far, don't shoot.
+		if ((dm < (3072<<FRACBITS)) && checksight)
+		{
+			P_SetMobjState(actor, actor->info->missilestate);
+			return;
+		}
+	}
+}
+
+// Function: A_HoodFall
+//
+// Description: Falling Robo-Hood
+//
+// var1 = unused
+// var2 = unused
+//
+void A_HoodFall(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_HoodFall", actor))
+		return;
+#endif
+
+	if (!P_IsObjectOnGround(actor))
+		return;
+
+	actor->momx = actor->momy = 0;
+	actor->reactiontime = actor->info->reactiontime;
+	P_SetMobjState(actor, actor->info->seestate);
+}
+
+// Function: A_ArrowBonks
+//
+// Description: Arrow momentum setting on collision
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ArrowBonks(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ArrowBonks", actor))
+		return;
+#endif
+
+	if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)
+		|| (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz))
+		actor->angle += ANGLE_180;
+
+	P_SetObjectMomZ(actor, 8*actor->scale, false);
+	P_InstaThrust(actor, actor->angle, -6*actor->scale);
+
+	actor->flags = (actor->flags|MF_NOCLIPHEIGHT) & ~MF_NOGRAVITY;
+	actor->z += P_MobjFlip(actor);
+}
+
+// Function: A_SnailerThink
+//
+// Description: Thinker function for Snailer
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SnailerThink(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SnailerThink", actor))
+		return;
+#endif
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (!P_LookForPlayers(actor, true, false, 0))
+			return;
+	}
+
+	// We now have a target. Oh bliss, rapture, and contentment!
+
+	if (actor->target->z + actor->target->height > actor->z - FixedMul(32*FRACUNIT, actor->scale)
+		&& actor->target->z < actor->z + actor->height + FixedMul(32*FRACUNIT, actor->scale)
+		&& !(leveltime % (TICRATE*2)))
+	{
+		angle_t an;
+		fixed_t z;
+
+		// Actor shouldn't face target, so we'll do things a bit differently here
+
+		an = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle;
+
+		z = actor->z + actor->height/2;
+
+		if (an > ANGLE_45 && an < ANGLE_315) // fire as close as you can to the target, even if too sharp an angle from your front
+		{
+			fixed_t dist;
+			fixed_t dx, dy;
+
+			dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y);
+
+			if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left
+			{
+				dx = actor->x + P_ReturnThrustX(actor, actor->angle + ANGLE_45, dist);
+				dy = actor->y + P_ReturnThrustY(actor, actor->angle + ANGLE_45, dist);
+			}
+			else if (an >= ANGLE_270 && an < ANGLE_315) // fire at 45 degrees to the right
+			{
+				dx = actor->x + P_ReturnThrustX(actor, actor->angle - ANGLE_45, dist);
+				dy = actor->y + P_ReturnThrustY(actor, actor->angle - ANGLE_45, dist);
+			}
+			else // fire straight ahead
+			{
+				dx = actor->x + P_ReturnThrustX(actor, actor->angle, dist);
+				dy = actor->y + P_ReturnThrustY(actor, actor->angle, dist);
+			}
+
+			P_SpawnPointMissile(actor, dx, dy, actor->target->z, MT_ROCKET, actor->x, actor->y, z);
+		}
+		else
+			P_SpawnXYZMissile(actor, actor->target, MT_ROCKET, actor->x, actor->y, z);
+	}
+
+	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z > actor->z)
+	|| (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) > (actor->z + actor->height)))
+		actor->momz += FixedMul(actor->info->speed, actor->scale);
+	else if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z < actor->z)
+	|| (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) < (actor->z + actor->height)))
+		actor->momz -= FixedMul(actor->info->speed, actor->scale);
+
+	actor->momz /= 2;
+}
+
+// Function: A_SharpChase
+//
+// Description: Thinker/Chase routine for Spincushions
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SharpChase(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SharpChase", actor))
+		return;
+#endif
+
+	if (actor->reactiontime)
+	{
+		INT32 delta;
+
+		actor->reactiontime--;
+
+		// turn towards movement direction if not there yet
+		if (actor->movedir < NUMDIRS)
+		{
+			actor->angle &= (7<<29);
+			delta = actor->angle - (actor->movedir << 29);
+
+			if (delta > 0)
+				actor->angle -= ANGLE_45;
+			else if (delta < 0)
+				actor->angle += ANGLE_45;
+		}
+
+		if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+		{
+			// look for a new target
+			if (P_LookForPlayers(actor, true, false, 0))
+				return; // got a new target
+
+			P_SetMobjState(actor, actor->info->spawnstate);
+			return;
+		}
+
+		// chase towards player
+		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+			P_NewChaseDir(actor);
+	}
+	else
+	{
+		actor->threshold = actor->info->painchance;
+		P_SetMobjState(actor, actor->info->missilestate);
+		S_StartSound(actor, actor->info->attacksound);
+	}
+}
+
+// Function: A_SharpSpin
+//
+// Description: Spin chase routine for Spincushions
+//
+// var1 = object # to spawn as dust (if not provided not done)
+// var2 = if nonzero, do the old-style spinning using this as the angle difference
+//
+void A_SharpSpin(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	angle_t oldang = actor->angle;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SharpSpin", actor))
+		return;
+#endif
+
+	if (actor->threshold && actor->target)
+	{
+		angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		P_Thrust(actor, ang, actor->info->speed*actor->scale);
+		if (locvar2)
+			actor->angle += locvar2; // ANGLE_22h;
+		else
+			actor->angle = ang;
+		actor->threshold--;
+		if (leveltime & 1)
+			S_StartSound(actor, actor->info->painsound);
+	}
+	else
+	{
+		actor->reactiontime = actor->info->reactiontime;
+		P_SetMobjState(actor, actor->info->meleestate);
+	}
+
+	P_SharpDust(actor, locvar1, oldang);
+}
+
+// Function: A_SharpDecel
+//
+// Description: Slow down the Spincushion
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SharpDecel(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SharpDecel", actor))
+		return;
+#endif
+
+	if (actor->momx > 2 || actor->momy > 2)
+	{
+		actor->momx >>= 1;
+		actor->momy >>= 1;
+	}
+	else
+		P_SetMobjState(actor, actor->info->xdeathstate);
+}
+
+// Function: A_CrushstaceanWalk
+//
+// Description: Crushstacean movement
+//
+// var1 = speed (actor info's speed if 0)
+// var2 = state to switch to when blocked (spawnstate if 0)
+//
+void A_CrushstaceanWalk(mobj_t *actor)
+{
+	INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed);
+	INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate);
+	angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CrushstaceanWalk", actor))
+		return;
+#endif
+
+	actor->reactiontime--;
+
+	if (!P_TryMove(actor,
+		actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale),
+		actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale),
+		false)
+	|| (actor->reactiontime-- <= 0))
+	{
+		actor->flags2 ^= MF2_AMBUSH;
+		P_SetMobjState(actor, locvar2);
+		actor->reactiontime = actor->info->reactiontime;
+	}
+}
+
+// Function: A_CrushstaceanPunch
+//
+// Description: Crushstacean attack
+//
+// var1 = unused
+// var2 = state to go to if unsuccessful (spawnstate if 0)
+//
+void A_CrushstaceanPunch(mobj_t *actor)
+{
+	//INT32 locvar1 = var1;
+	INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CrushstaceanPunch", actor))
+		return;
+#endif
+
+	if (!actor->tracer)
+		return;
+
+	if (!actor->target)
+	{
+		P_SetMobjState(actor, locvar2);
+		return;
+	}
+
+	actor->tracer->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+	P_SetMobjState(actor->tracer, actor->tracer->info->missilestate);
+	actor->tracer->extravalue1 = actor->tracer->extravalue2 = 0;
+	S_StartSound(actor, actor->info->attacksound);
+}
+
+// Function: A_CrushclawAim
+//
+// Description: Crushstacean claw aiming
+//
+// var1 = sideways offset
+// var2 = vertical offset
+//
+void A_CrushclawAim(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *crab = actor->tracer;
+	angle_t ang;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CrushclawAim", actor))
+		return;
+#endif
+
+	if (!crab)
+	{
+		P_RemoveMobj(actor);
+		return; // there is only one step and it is crab
+	}
+
+	if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale))
+		ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y);
+	else
+		ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);
+	ang -= actor->angle;
+
+#define anglimit ANGLE_22h
+#define angfactor 5
+	if (ang < ANGLE_180)
+	{
+		if (ang > anglimit)
+			ang = anglimit;
+		ang /= angfactor;
+	}
+	else
+	{
+		ang = InvAngle(ang);
+		if (ang > anglimit)
+			ang = anglimit;
+		ang = InvAngle(ang/angfactor);
+	}
+	actor->angle += ang;
+#undef anglimit
+#undef angfactor
+
+	P_TeleportMove(actor,
+		crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale),
+		crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale),
+		crab->z + locvar2*crab->scale);
+
+	if (!crab->target || !crab->info->missilestate || (statenum_t)(crab->state-states) == crab->info->missilestate)
+		return;
+
+	if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale)
+		P_SetMobjState(crab, crab->info->missilestate);
+}
+
+// Function: A_CrushclawLaunch
+//
+// Description: Crushstacean claw launching
+//
+// var1:
+//		0 - forwards
+//		anything else - backwards
+// var2 = state to change to when done
+//
+void A_CrushclawLaunch(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *crab = actor->tracer;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CrushclawLaunch", actor))
+		return;
+#endif
+
+	if (!crab)
+	{
+		mobj_t *chainnext;
+		while (actor)
+		{
+			chainnext = actor->target;
+			P_RemoveMobj(actor);
+			actor = chainnext;
+		}
+		return; // there is only one step and it is crab
+	}
+
+	if (!actor->extravalue1)
+	{
+		S_StartSound(actor, actor->info->activesound);
+		actor->extravalue1 = ((locvar1) ? -1 : 32);
+	}
+	else if (actor->extravalue1 != 1)
+		actor->extravalue1 -= 1;
+
+#define CSEGS 5
+	if (!actor->target)
+	{
+		mobj_t *prevchain = actor;
+		UINT8 i = 0;
+		for (i = 0; (i < CSEGS); i++)
+		{
+			mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate);
+			prevchain->target = newchain;
+			prevchain = newchain;
+		}
+		actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y);
+	}
+
+	if ((!locvar1) && crab->target)
+	{
+#define anglimit ANGLE_22h
+#define angfactor 7
+		angle_t ang = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y) - actor->target->angle;
+		if (ang < ANGLE_180)
+		{
+			if (ang > anglimit)
+				ang = anglimit;
+			ang /= angfactor;
+		}
+		else
+		{
+			ang = InvAngle(ang);
+			if (ang > anglimit)
+				ang = anglimit;
+			ang /= angfactor;
+			ang = InvAngle(ang);
+		}
+		actor->target->angle += ang;
+		actor->angle = actor->target->angle;
+	}
+
+	actor->extravalue2 += actor->extravalue1;
+
+	if (!P_TryMove(actor,
+		actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale),
+		actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale),
+		true)
+		&& !locvar1)
+	{
+		actor->extravalue1 = 0;
+		actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS;
+		P_SetMobjState(actor, locvar2);
+		S_StopSound(actor);
+		S_StartSound(actor, sfx_s3k49);
+	}
+	else
+	{
+		actor->z = actor->target->z;
+		if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16)))
+		{
+			if (locvar1) // In case of retracting, resume crab and remove the chain.
+			{
+				mobj_t *chain = actor->target, *chainnext;
+				while (chain)
+				{
+					chainnext = chain->target;
+					P_RemoveMobj(chain);
+					chain = chainnext;
+				}
+				actor->extravalue2 = 0;
+				actor->angle = R_PointToAngle2(crab->x, crab->y, actor->x, actor->y);
+				P_SetTarget(&actor->target, NULL);
+				P_SetTarget(&crab->target, NULL);
+				P_SetMobjState(crab, crab->state->nextstate);
+			}
+			actor->extravalue1 = 0;
+			P_SetMobjState(actor, locvar2);
+			S_StopSound(actor);
+			if (!locvar1)
+				S_StartSound(actor, sfx_s3k64);
+		}
+	}
+
+	if (!actor->target)
+		return;
+
+	{
+		mobj_t *chain = actor->target->target;
+		fixed_t dx = (actor->x - actor->target->x)/CSEGS, dy = (actor->y - actor->target->y)/CSEGS, dz = (actor->z - actor->target->z)/CSEGS;
+		fixed_t idx = dx, idy = dy, idz = dz;
+		while (chain)
+		{
+			P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz);
+			chain->watertop = chain->z;
+			idx += dx;
+			idy += dy;
+			idz += dz;
+			chain = chain->target;
+		}
+	}
+#undef CSEGS
+}
+
+// Function: A_VultureVtol
+//
+// Description: Vulture rising up to match target's height
+//
+// var1 = unused
+// var2 = unused
+//
+void A_VultureVtol(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_VultureVtol", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	actor->flags |= MF_NOGRAVITY;
+	actor->flags |= MF_FLOAT;
+
+	A_FaceTarget(actor);
+
+	S_StopSound(actor);
+
+	if (actor->z < actor->target->z+(actor->target->height/4) && actor->z + actor->height < actor->ceilingz)
+		actor->momz = FixedMul(2*FRACUNIT, actor->scale);
+	else if (actor->z > (actor->target->z+(actor->target->height/4)*3) && actor->z > actor->floorz)
+		actor->momz = FixedMul(-2*FRACUNIT, actor->scale);
+	else
+	{
+		// Attack!
+		actor->momz = 0;
+		P_SetMobjState(actor, actor->info->missilestate);
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+// Function: A_VultureCheck
+//
+// Description: If the vulture is stopped, look for a new target
+//
+// var1 = unused
+// var2 = unused
+//
+void A_VultureCheck(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_VultureCheck", actor))
+		return;
+#endif
+
+	if (actor->momx || actor->momy)
+		return;
+
+	actor->flags &= ~MF_NOGRAVITY; // Fall down
+
+	if (actor->z <= actor->floorz)
+	{
+		actor->angle -= ANGLE_180; // turn around
+		P_SetMobjState(actor, actor->info->spawnstate);
+	}
+}
+
+// Function: A_SkimChase
+//
+// Description: Thinker/Chase routine for Skims
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SkimChase(mobj_t *actor)
+{
+	INT32 delta;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SkimChase", actor))
+		return;
+#endif
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		P_LookForPlayers(actor, true, false, 0);
+
+		// the spawnstate for skims already calls this function so just return either way
+		// without changing state
+		return;
+	}
+
+	// do not attack twice in a row
+	if (actor->flags2 & MF2_JUSTATTACKED)
+	{
+		actor->flags2 &= ~MF2_JUSTATTACKED;
+		P_NewChaseDir(actor);
+		return;
+	}
+
+	// check for melee attack
+	if (actor->info->meleestate && P_SkimCheckMeleeRange(actor))
+	{
+		if (actor->info->attacksound)
+			S_StartAttackSound(actor, actor->info->attacksound);
+
+		P_SetMobjState(actor, actor->info->meleestate);
+		return;
+	}
+
+	// check for missile attack
+	if (actor->info->missilestate)
+	{
+		if (actor->movecount || !P_CheckMissileRange(actor))
+			goto nomissile;
+
+		P_SetMobjState(actor, actor->info->missilestate);
+		actor->flags2 |= MF2_JUSTATTACKED;
+		return;
+	}
+
+nomissile:
+	// possibly choose another target
+	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+		&& P_LookForPlayers(actor, true, false, 0))
+		return; // got a new target
+
+	// chase towards player
+	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		P_NewChaseDir(actor);
+}
+
+// Function: A_FaceTarget
+//
+// Description: Immediately turn to face towards your target.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_FaceTarget(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceTarget", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+}
+
+// Function: A_FaceTracer
+//
+// Description: Immediately turn to face towards your tracer.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_FaceTracer(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FaceTracer", actor))
+		return;
+#endif
+	if (!actor->tracer)
+		return;
+
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
+}
+
+// Function: A_LobShot
+//
+// Description: Lob an object at your target.
+//
+// var1 = object # to lob
+// var2:
+//		var2 >> 16 = height offset
+//		var2 & 65535 = airtime
+//
+void A_LobShot(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2 >> 16;
+	mobj_t *shot, *hitspot;
+	angle_t an;
+	fixed_t z;
+	fixed_t dist;
+	fixed_t vertical, horizontal;
+	fixed_t airtime = var2 & 65535;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_LobShot", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+	{
+		z = actor->z + actor->height - FixedMul(locvar2*FRACUNIT, actor->scale);
+		if (actor->type == MT_BLACKEGGMAN)
+			z -= FixedMul(mobjinfo[locvar1].height, actor->scale/2);
+		else
+			z -= FixedMul(mobjinfo[locvar1].height, actor->scale);
+	}
+	else
+		z = actor->z + FixedMul(locvar2*FRACUNIT, actor->scale);
+
+	shot = P_SpawnMobj(actor->x, actor->y, z, locvar1);
+
+	if (actor->type == MT_BLACKEGGMAN)
+	{
+		shot->destscale = actor->scale/2;
+		P_SetScale(shot, actor->scale/2);
+	}
+	else
+	{
+		shot->destscale = actor->scale;
+		P_SetScale(shot, actor->scale);
+	}
+
+	// Keep track of where it's going to land
+	hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL);
+	hitspot->tics = airtime;
+	P_SetTarget(&shot->tracer, hitspot);
+
+	P_SetTarget(&shot->target, actor); // where it came from
+
+	shot->angle = an = actor->angle;
+	an >>= ANGLETOFINESHIFT;
+
+	dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y);
+
+	horizontal = dist / airtime;
+	vertical = FixedMul((gravity*airtime)/2, shot->scale);
+
+	shot->momx = FixedMul(horizontal, FINECOSINE(an));
+	shot->momy = FixedMul(horizontal, FINESINE(an));
+	shot->momz = vertical;
+
+/* Try to adjust when destination is not the same height
+	if (actor->z != actor->target->z)
+	{
+		fixed_t launchhyp;
+		fixed_t diff;
+		fixed_t orig;
+
+		diff = actor->z - actor->target->z;
+		{
+			launchhyp = P_AproxDistance(horizontal, vertical);
+
+			orig = FixedMul(FixedDiv(vertical, horizontal), diff);
+
+			CONS_Debug(DBG_GAMELOGIC, "orig: %d\n", (orig)>>FRACBITS);
+
+			horizontal = dist / airtime;
+			vertical = (gravity*airtime)/2;
+		}
+		dist -= orig;
+		shot->momx = FixedMul(horizontal, FINECOSINE(an));
+		shot->momy = FixedMul(horizontal, FINESINE(an));
+		shot->momz = vertical;
+*/
+
+	if (shot->info->seesound)
+		S_StartSound(shot, shot->info->seesound);
+
+	if (!(actor->flags & MF_BOSS))
+	{
+		if (ultimatemode)
+			actor->reactiontime = actor->info->reactiontime*TICRATE;
+		else
+			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+	}
+}
+
+// Function: A_FireShot
+//
+// Description: Shoot an object at your target.
+//
+// var1 = object # to shoot
+// var2 = height offset
+//
+void A_FireShot(mobj_t *actor)
+{
+	fixed_t z;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FireShot", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+
+	P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z);
+
+	if (!(actor->flags & MF_BOSS))
+	{
+		if (ultimatemode)
+			actor->reactiontime = actor->info->reactiontime*TICRATE;
+		else
+			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+	}
+}
+
+// Function: A_SuperFireShot
+//
+// Description: Shoot an object at your target that will even stall Super Sonic.
+//
+// var1 = object # to shoot
+// var2 = height offset
+//
+void A_SuperFireShot(mobj_t *actor)
+{
+	fixed_t z;
+	mobj_t *mo;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SuperFireShot", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+
+	mo = P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z);
+
+	if (mo)
+		mo->flags2 |= MF2_SUPERFIRE;
+
+	if (!(actor->flags & MF_BOSS))
+	{
+		if (ultimatemode)
+			actor->reactiontime = actor->info->reactiontime*TICRATE;
+		else
+			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+	}
+}
+
+// Function: A_BossFireShot
+//
+// Description: Shoot an object at your target ala Bosses:
+//
+// var1 = object # to shoot
+// var2:
+//		0 - Boss 1 Left side
+//		1 - Boss 1 Right side
+//		2 - Boss 3 Left side upper
+//		3 - Boss 3 Left side lower
+//		4 - Boss 3 Right side upper
+//		5 - Boss 3 Right side lower
+//
+void A_BossFireShot(mobj_t *actor)
+{
+	fixed_t x, y, z;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BossFireShot", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	switch (locvar2)
+	{
+		case 0:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(48*FRACUNIT, actor->scale);
+			break;
+		case 1:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(48*FRACUNIT, actor->scale);
+			break;
+		case 2:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(42*FRACUNIT, actor->scale);
+			break;
+		case 3:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(30*FRACUNIT, actor->scale);
+			break;
+		case 4:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(42*FRACUNIT, actor->scale);
+			break;
+		case 5:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale);
+			else
+				z = actor->z + FixedMul(30*FRACUNIT, actor->scale);
+			break;
+		default:
+			x = actor->x;
+			y = actor->y;
+			z = actor->z + actor->height/2;
+			break;
+	}
+
+	P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
+}
+
+// Function: A_Boss7FireMissiles
+//
+// Description: Shoot 4 missiles of a specific object type at your target ala Black Eggman
+//
+// var1 = object # to shoot
+// var2 = firing sound
+//
+void A_Boss7FireMissiles(mobj_t *actor)
+{
+	mobj_t dummymo;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss7FireMissiles", actor))
+		return;
+#endif
+
+	if (!actor->target)
+	{
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	A_FaceTarget(actor);
+
+	S_StartSound(NULL, locvar2);
+
+	// set dummymo's coordinates
+	dummymo.x = actor->target->x;
+	dummymo.y = actor->target->y;
+	dummymo.z = actor->target->z + FixedMul(16*FRACUNIT, actor->scale); // raised height
+
+	P_SpawnXYZMissile(actor, &dummymo, locvar1,
+		actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->z + FixedDiv(actor->height, 3*FRACUNIT/2));
+
+	P_SpawnXYZMissile(actor, &dummymo, locvar1,
+		actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->z + FixedDiv(actor->height, 3*FRACUNIT/2));
+
+	P_SpawnXYZMissile(actor, &dummymo, locvar1,
+		actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->z + actor->height/2);
+
+	P_SpawnXYZMissile(actor, &dummymo, locvar1,
+		actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)),
+		actor->z + actor->height/2);
+}
+
+// Function: A_Boss1Laser
+//
+// Description: Shoot an object at your target ala Bosses:
+//
+// var1 = object # to shoot
+// var2:
+//		0 - Boss 1 Left side
+//		1 - Boss 1 Right side
+//
+void A_Boss1Laser(mobj_t *actor)
+{
+	fixed_t x, y, z, floorz, speed;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	INT32 i;
+	angle_t angle;
+	mobj_t *point;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss1Laser", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	switch (locvar2)
+	{
+		case 0:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height;
+			else
+				z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
+			break;
+		case 1:
+			x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale));
+			if (actor->eflags & MFE_VERTICALFLIP)
+				z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height;
+			else
+				z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
+			break;
+		default:
+			x = actor->x;
+			y = actor->y;
+			z = actor->z + actor->height/2;
+			break;
+	}
+
+	if (!(actor->flags2 & MF2_FIRING))
+	{
+		actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);
+		if (mobjinfo[locvar1].seesound)
+			S_StartSound(actor, mobjinfo[locvar1].seesound);
+		if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
+		{
+			point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET);
+			point->angle = actor->angle;
+			point->fuse = actor->tics+1;
+			P_SetTarget(&point->target, actor->target);
+			P_SetTarget(&actor->target, point);
+		}
+	}
+	/* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path
+	else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH))
+		actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/
+
+	if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)
+		angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT);
+	else
+		angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y));
+	point = P_SpawnMobj(x, y, z, locvar1);
+	P_SetTarget(&point->target, actor);
+	point->angle = actor->angle;
+	speed = point->radius*2;
+	point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed);
+	point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed));
+	point->momy = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINESINE(point->angle>>ANGLETOFINESHIFT), speed));
+
+	for (i = 0; i < 256; i++)
+	{
+		mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type);
+		mo->angle = point->angle;
+		P_UnsetThingPosition(mo);
+		mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY;
+		P_SetThingPosition(mo);
+
+		x = point->x, y = point->y, z = point->z;
+		if (P_RailThinker(point))
+			break;
+	}
+
+	floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height);
+	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
+	{
+		point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
+		point->target = actor;
+		point->destscale = 3*FRACUNIT;
+		point->scalespeed = FRACUNIT>>2;
+		point->fuse = TICRATE;
+	}
+
+	if (actor->tics > 1)
+		actor->flags2 |= MF2_FIRING;
+	else
+		actor->flags2 &= ~MF2_FIRING;
+}
+
+// Function: A_FocusTarget
+//
+// Description: Home in on your target.
+//
+// var1:
+//		0 - accelerative focus with friction
+//		1 - steady focus with fixed movement speed
+//      anything else - don't move
+// var2:
+//		0 - don't trace target, just move forwards
+//      & 1 - change horizontal angle
+//      & 2 - change vertical angle
+//
+void A_FocusTarget(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FocusTarget", actor))
+		return;
+#endif
+
+	if (actor->target)
+	{
+		fixed_t speed = FixedMul(actor->info->speed, actor->scale);
+		fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1);
+		angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle);
+		angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90);
+		switch(locvar1)
+		{
+		case 0:
+			{
+				actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4;
+				actor->momz += FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed);
+				actor->momx += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed));
+				actor->momy += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed));
+			}
+			break;
+		case 1:
+			if (dist > speed)
+			{
+				actor->momz = FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed);
+				actor->momx = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed));
+				actor->momy = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed));
+			}
+			else
+			{
+				actor->momx = 0, actor->momy = 0, actor->momz = 0;
+				actor->z = actor->target->z + (actor->target->height>>1);
+				P_TryMove(actor, actor->target->x, actor->target->y, true);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+// Function: A_Boss4Reverse
+//
+// Description: Reverse arms direction.
+//
+// var1 = sfx to play
+// var2 = unused
+//
+void A_Boss4Reverse(mobj_t *actor)
+{
+	sfxenum_t locvar1 = (sfxenum_t)var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss4Reverse", actor))
+		return;
+#endif
+	S_StartSound(NULL, locvar1);
+	actor->reactiontime = 0;
+	if (actor->movedir == 1)
+		actor->movedir = 2;
+	else
+		actor->movedir = 1;
+}
+
+// Function: A_Boss4SpeedUp
+//
+// Description: Speed up arms
+//
+// var1 = sfx to play
+// var2 = unused
+//
+void A_Boss4SpeedUp(mobj_t *actor)
+{
+	sfxenum_t locvar1 = (sfxenum_t)var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss4SpeedUp", actor))
+		return;
+#endif
+	S_StartSound(NULL, locvar1);
+	actor->reactiontime = 2;
+}
+
+// Function: A_Boss4Raise
+//
+// Description: Raise helmet
+//
+// var1 = sfx to play
+// var2 = unused
+//
+void A_Boss4Raise(mobj_t *actor)
+{
+	sfxenum_t locvar1 = (sfxenum_t)var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss4Raise", actor))
+		return;
+#endif
+	S_StartSound(NULL, locvar1);
+	actor->reactiontime = 1;
+}
+
+// Function: A_SkullAttack
+//
+// Description: Fly at the player like a missile.
+//
+// var1:
+//		0 - Fly at the player
+//		1 - Fly away from the player
+//		2 - Strafe in relation to the player
+// var2:
+//		0 - Fly horizontally and vertically
+//		1 - Fly horizontal-only (momz = 0)
+//
+#define SKULLSPEED (20*FRACUNIT)
+
+void A_SkullAttack(mobj_t *actor)
+{
+	mobj_t *dest;
+	angle_t an;
+	INT32 dist;
+	INT32 speed;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SkullAttack", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	speed = FixedMul(SKULLSPEED, actor->scale);
+
+	dest = actor->target;
+	actor->flags2 |= MF2_SKULLFLY;
+	if (actor->info->activesound)
+		S_StartSound(actor, actor->info->activesound);
+	A_FaceTarget(actor);
+
+	if (locvar1 == 1)
+		actor->angle += ANGLE_180;
+	else if (locvar1 == 2)
+		actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90;
+
+	an = actor->angle >> ANGLETOFINESHIFT;
+
+	actor->momx = FixedMul(speed, FINECOSINE(an));
+	actor->momy = FixedMul(speed, FINESINE(an));
+	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
+	dist = dist / speed;
+
+	if (dist < 1)
+		dist = 1;
+
+	actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist;
+
+	if (locvar1 == 1)
+		actor->momz = -actor->momz;
+	if (locvar2 == 1)
+		actor->momz = 0;
+}
+
+// Function: A_BossZoom
+//
+// Description: Like A_SkullAttack, but used by Boss 1.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_BossZoom(mobj_t *actor)
+{
+	mobj_t *dest;
+	angle_t an;
+	INT32 dist;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BossZoom", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	dest = actor->target;
+	actor->flags2 |= MF2_SKULLFLY;
+	if (actor->info->attacksound)
+		S_StartAttackSound(actor, actor->info->attacksound);
+	A_FaceTarget(actor);
+	an = actor->angle >> ANGLETOFINESHIFT;
+	actor->momx = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINECOSINE(an));
+	actor->momy = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINESINE(an));
+	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
+	dist = dist / FixedMul(actor->info->speed*5*FRACUNIT, actor->scale);
+
+	if (dist < 1)
+		dist = 1;
+	actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist;
+}
+
+// Function: A_BossScream
+//
+// Description: Spawns explosions and plays appropriate sounds around the defeated boss.
+//
+// var1:
+//		0 - Use movecount to spawn explosions evenly
+//		1 - Use P_Random to spawn explosions at complete random
+// var2 = Object to spawn. Default is MT_BOSSEXPLODE.
+//
+void A_BossScream(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t x, y, z;
+	angle_t fa;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobjtype_t explodetype;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BossScream", actor))
+		return;
+#endif
+	switch (locvar1)
+	{
+	default:
+	case 0:
+		actor->movecount += 4*16;
+		actor->movecount %= 360;
+		fa = (FixedAngle(actor->movecount*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
+		break;
+	case 1:
+		fa = (FixedAngle(P_RandomKey(360)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
+		break;
+	}
+	x = actor->x + FixedMul(FINECOSINE(fa),actor->radius);
+	y = actor->y + FixedMul(FINESINE(fa),actor->radius);
+
+	// Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default.
+	if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES)
+		explodetype = MT_BOSSEXPLODE;
+	else
+		explodetype = (mobjtype_t)locvar2;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - mobjinfo[explodetype].height - FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale);
+
+	mo = P_SpawnMobj(x, y, z, explodetype);
+	if (actor->eflags & MFE_VERTICALFLIP)
+		mo->flags2 |= MF2_OBJECTFLIP;
+	mo->destscale = actor->scale;
+	P_SetScale(mo, mo->destscale);
+	if (actor->info->deathsound)
+		S_StartSound(mo, actor->info->deathsound);
+}
+
+// Function: A_Scream
+//
+// Description: Starts the death sound of the object.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Scream(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Scream", actor))
+		return;
+#endif
+	if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL))
+		S_StartScreamSound(actor, sfx_mario2);
+	else if (actor->info->deathsound)
+		S_StartScreamSound(actor, actor->info->deathsound);
+}
+
+// Function: A_Pain
+//
+// Description: Starts the pain sound of the object.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Pain(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Pain", actor))
+		return;
+#endif
+	if (actor->info->painsound)
+		S_StartSound(actor, actor->info->painsound);
+
+	actor->flags2 &= ~MF2_FIRING;
+	actor->flags2 &= ~MF2_SUPERFIRE;
+}
+
+// Function: A_Fall
+//
+// Description: Changes a dying object's flags to reflect its having fallen to the ground.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Fall(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Fall", actor))
+		return;
+#endif
+	// actor is on ground, it can be walked over
+	actor->flags &= ~MF_SOLID;
+
+	// fall through the floor
+	actor->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY;
+
+	// So change this if corpse objects
+	// are meant to be obstacles.
+}
+
+#define LIVESBOXDISPLAYPLAYER // Use displayplayer instead of closest player
+
+// Function: A_1upThinker
+//
+// Description: Used by the 1up box to show the player's face.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_1upThinker(mobj_t *actor)
+{
+	INT32 i;
+	fixed_t dist = INT32_MAX;
+	fixed_t temp;
+	INT32 closestplayer = -1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_1upThinker", actor))
+		return;
+#endif
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i] || players[i].bot || players[i].spectator)
+			continue;
+
+		if (!players[i].mo)
+			continue;
+
+		if ((netgame || multiplayer) && players[i].playerstate != PST_LIVE)
+			continue;
+
+		temp = P_AproxDistance(players[i].mo->x-actor->x, players[i].mo->y-actor->y);
+
+		if (temp < dist)
+		{
+			closestplayer = i;
+			dist = temp;
+		}
+	}
+
+	if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0)
+	{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
+		if (actor->tracer) {
+			P_RemoveMobj(actor->tracer);
+			actor->tracer = NULL;
+		}
+		return;
+	}
+
+	// We're using the overlay, so use the overlay 1up box (no text)
+	actor->sprite = SPR_TV1P;
+
+	if (!actor->tracer)
+	{
+		P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY));
+		P_SetTarget(&actor->tracer->target, actor);
+		actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame
+		P_SetMobjState(actor->tracer, actor->info->seestate);
+
+		// The overlay is going to be one tic early turning off and on
+		// because it's going to get its thinker run the frame we spawned it.
+		// So make it take one tic longer if it just spawned.
+		++actor->tracer->tics;
+	}
+
+	actor->tracer->color = players[closestplayer].mo->color;
+	actor->tracer->skin = &skins[players[closestplayer].skin];
+}
+
+// Function: A_MonitorPop
+//
+// Description: Used by monitors when they explode.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MonitorPop(mobj_t *actor)
+{
+	mobjtype_t item = 0;
+	mobj_t *newmobj;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MonitorPop", actor))
+		return;
+#endif
+
+	// Spawn the "pop" explosion.
+	if (actor->info->deathsound)
+		S_StartSound(actor, actor->info->deathsound);
+	P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE);
+
+	// We're dead now. De-solidify.
+	actor->health = 0;
+	P_UnsetThingPosition(actor);
+	actor->flags &= ~MF_SOLID;
+	actor->flags |= MF_NOCLIP;
+	P_SetThingPosition(actor);
+
+	if (actor->info->damage == MT_UNKNOWN)
+	{
+		// MT_UNKNOWN is random. Because it's unknown to us... get it?
+		item = P_DoRandomBoxChances();
+
+		if (item == MT_NULL)
+		{
+			CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
+			return;
+		}
+	}
+	else
+		item = actor->info->damage;
+
+	if (item == 0)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n");
+		return;
+	}
+
+	newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item);
+	P_SetTarget(&newmobj->target, actor->target); // Transfer target
+
+	if (item == MT_1UP_ICON)
+	{
+		if (actor->tracer) // Remove the old lives icon.
+			P_RemoveMobj(actor->tracer);
+
+		if (!newmobj->target
+		 || !newmobj->target->player
+		 || !newmobj->target->skin
+		 || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
+			{} // No lives icon for this player, use the default.
+		else
+		{ // Spawn the lives icon.
+			mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
+			P_SetTarget(&livesico->target, newmobj);
+			P_SetTarget(&newmobj->tracer, livesico);
+
+			livesico->color = newmobj->target->player->mo->color;
+			livesico->skin = &skins[newmobj->target->player->skin];
+			P_SetMobjState(livesico, newmobj->info->seestate);
+
+			// We're using the overlay, so use the overlay 1up sprite (no text)
+			newmobj->sprite = SPR_TV1P;
+		}
+	}
+
+	// Run a linedef executor immediately upon popping
+	// You may want to delay your effects by 18 tics to sync with the reward giving
+	if (actor->spawnpoint && actor->lastlook)
+		P_LinedefExecute(actor->lastlook, actor->target, NULL);
+}
+
+// Function: A_GoldMonitorPop
+//
+// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know...
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GoldMonitorPop(mobj_t *actor)
+{
+	mobjtype_t item = 0;
+	mobj_t *newmobj;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GoldMonitorPop", actor))
+		return;
+#endif
+
+	// Don't spawn the "pop" explosion, because the monitor isn't broken.
+	if (actor->info->deathsound)
+		S_StartSound(actor, actor->info->deathsound);
+	//P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE);
+
+	// Remove our flags for a bit.
+	// Players can now stand on top of us.
+	P_UnsetThingPosition(actor);
+	actor->flags  &= ~(MF_MONITOR|MF_SHOOTABLE);
+	P_SetThingPosition(actor);
+
+	// Don't count this box in statistics. Sorry.
+	if (actor->target && actor->target->player)
+		--actor->target->player->numboxes;
+	actor->fuse = 0; // Don't let the monitor code screw us up.
+
+	if (actor->info->damage == MT_UNKNOWN)
+	{
+		// MT_UNKNOWN is random. Because it's unknown to us... get it?
+		item = P_DoRandomBoxChances();
+
+		if (item == MT_NULL)
+		{
+			CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
+			return;
+		}
+	}
+	else
+		item = actor->info->damage;
+
+	if (item == 0)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n");
+		return;
+	}
+
+	// Note: the icon spawns 1 fracunit higher
+	newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item);
+	P_SetTarget(&newmobj->target, actor->target); // Transfer target
+
+	if (item == MT_1UP_ICON)
+	{
+		if (actor->tracer) // Remove the old lives icon.
+			P_RemoveMobj(actor->tracer);
+
+		if (!newmobj->target
+		 || !newmobj->target->player
+		 || !newmobj->target->skin
+		 || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
+			{} // No lives icon for this player, use the default.
+		else
+		{ // Spawn the lives icon.
+			mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
+			P_SetTarget(&livesico->target, newmobj);
+			P_SetTarget(&newmobj->tracer, livesico);
+
+			livesico->color = newmobj->target->player->mo->color;
+			livesico->skin = &skins[newmobj->target->player->skin];
+			P_SetMobjState(livesico, newmobj->info->seestate);
+
+			// We're using the overlay, so use the overlay 1up sprite (no text)
+			newmobj->sprite = SPR_TV1P;
+		}
+	}
+
+	// Run a linedef executor immediately upon popping
+	// You may want to delay your effects by 18 tics to sync with the reward giving
+	if (actor->spawnpoint && actor->lastlook)
+		P_LinedefExecute(actor->lastlook, actor->target, NULL);
+}
+
+// Function: A_GoldMonitorRestore
+//
+// Description: A repeating monitor is coming back to life. Reset monitor flags, etc.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GoldMonitorRestore(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GoldMonitorRestore", actor))
+		return;
+#endif
+
+	actor->flags |= MF_MONITOR|MF_SHOOTABLE;
+	actor->health = 1; // Just in case.
+}
+
+// Function: A_GoldMonitorSparkle
+//
+// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it?
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GoldMonitorSparkle(mobj_t *actor)
+{
+	fixed_t i, ngangle, xofs, yofs;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GoldMonitorSparkle", actor))
+		return;
+#endif
+
+	ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS);
+	xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK)   * (actor->radius>>FRACBITS);
+	yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS);
+
+	for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2)
+		P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false);
+}
+
+// Function: A_Explode
+//
+// Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range.
+//
+// var1 = damagetype
+// var2 = unused
+//
+void A_Explode(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Explode", actor))
+		return;
+#endif
+	P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1);
+}
+
+// Function: A_BossDeath
+//
+// Description: Possibly trigger special effects when boss dies.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_BossDeath(mobj_t *mo)
+{
+	thinker_t *th;
+	mobj_t *mo2;
+	line_t junk;
+	INT32 i;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BossDeath", mo))
+		return;
+#endif
+
+	P_LinedefExecute(LE_BOSSDEAD, mo, NULL);
+	mo->health = 0;
+
+	// Boss is dead (but not necessarily fleeing...)
+	// Lua may use this to ignore bosses after they start fleeing
+	mo->flags2 |= MF2_BOSSDEAD;
+
+	// make sure there is a player alive for victory
+	for (i = 0; i < MAXPLAYERS; i++)
+		if (playeringame[i] && ((players[i].mo && players[i].mo->health)
+			|| ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
+			break;
+
+	if (i == MAXPLAYERS)
+		return; // no one left alive, so do not end game
+
+	// scan the remaining thinkers to see
+	// if all bosses are dead
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+		if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0)
+			goto bossjustdie; // other boss not dead - just go straight to dying!
+	}
+
+	// victory!
+	P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL);
+	if (mo->flags2 & MF2_BOSSNOTRAP)
+	{
+		for (i = 0; i < MAXPLAYERS; i++)
+			P_DoPlayerExit(&players[i]);
+	}
+	else
+	{
+		// Bring the egg trap up to the surface
+		junk.tag = 680;
+		EV_DoElevator(&junk, elevateHighest, false);
+		junk.tag = 681;
+		EV_DoElevator(&junk, elevateUp, false);
+		junk.tag = 682;
+		EV_DoElevator(&junk, elevateHighest, false);
+
+		if (mapheaderinfo[gamemap-1]->muspostbossname[0] &&
+			S_MusicExists(mapheaderinfo[gamemap-1]->muspostbossname, !midi_disabled, !digital_disabled))
+		{
+			// Touching the egg trap button calls P_DoPlayerExit, which calls P_RestoreMusic.
+			// So just park ourselves in the mapmus variables.
+			boolean changed = strnicmp(mapheaderinfo[gamemap-1]->musname, mapmusname, 7);
+			strncpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, 7);
+			mapmusname[6] = 0;
+			mapmusflags = (mapheaderinfo[gamemap-1]->muspostbosstrack & MUSIC_TRACKMASK) | MUSIC_RELOADRESET;
+			mapmusposition = mapheaderinfo[gamemap-1]->muspostbosspos;
+
+			// don't change if we're in another tune
+			// but in case we're in jingle, use our parked mapmus variables so the correct track restores
+			if (!changed)
+				S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, (1*MUSICRATE)+(MUSICRATE/2),
+					mapheaderinfo[gamemap-1]->muspostbossfadein);
+		}
+	}
+
+bossjustdie:
+#ifdef HAVE_BLUA
+	if (LUAh_BossDeath(mo))
+		return;
+	else if (P_MobjWasRemoved(mo))
+		return;
+#endif
+	if (mo->type == MT_BLACKEGGMAN || mo->type == MT_CYBRAKDEMON)
+	{
+		mo->flags |= MF_NOCLIP;
+		mo->flags &= ~MF_SPECIAL;
+
+		S_StartSound(NULL, sfx_befall);
+	}
+	else if (mo->type == MT_KOOPA)
+	{
+		junk.tag = 650;
+		EV_DoCeiling(&junk, raiseToHighest);
+		return;
+	}
+	else // eggmobiles
+	{
+		// Stop exploding and prepare to run.
+		P_SetMobjState(mo, mo->info->xdeathstate);
+		if (P_MobjWasRemoved(mo))
+			return;
+
+		P_SetTarget(&mo->target, NULL);
+
+		// Flee! Flee! Find a point to escape to! If none, just shoot upward!
+		// scan the thinkers to find the runaway point
+		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		{
+			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+				continue;
+
+			mo2 = (mobj_t *)th;
+
+			if (mo2->type == MT_BOSSFLYPOINT)
+			{
+				// If this one's closer then the last one, go for it.
+				if (!mo->target ||
+					P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) <
+					P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z))
+						P_SetTarget(&mo->target, mo2);
+				// Otherwise... Don't!
+			}
+		}
+
+		mo->flags |= MF_NOGRAVITY|MF_NOCLIP;
+		mo->flags |= MF_NOCLIPHEIGHT;
+
+		if (mo->target)
+		{
+			mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
+			mo->flags2 |= MF2_BOSSFLEE;
+			mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale));
+		}
+		else
+			mo->momz = FixedMul(2*FRACUNIT, mo->scale);
+	}
+
+	if (mo->type == MT_EGGMOBILE2)
+	{
+		mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
+			mo->y + P_ReturnThrustY(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
+			mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK1].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK1); // Right tank
+		mo2->angle = mo->angle;
+		mo2->destscale = mo->scale;
+		P_SetScale(mo2, mo2->destscale);
+		if (mo->eflags & MFE_VERTICALFLIP)
+		{
+			mo2->eflags |= MFE_VERTICALFLIP;
+			mo2->flags2 |= MF2_OBJECTFLIP;
+		}
+		P_InstaThrust(mo2, mo2->angle - ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale));
+		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
+
+		mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
+			mo->y + P_ReturnThrustY(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)),
+			mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK2].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK2); // Left tank
+		mo2->angle = mo->angle;
+		mo2->destscale = mo->scale;
+		P_SetScale(mo2, mo2->destscale);
+		if (mo->eflags & MFE_VERTICALFLIP)
+		{
+			mo2->eflags |= MFE_VERTICALFLIP;
+			mo2->flags2 |= MF2_OBJECTFLIP;
+		}
+		P_InstaThrust(mo2, mo2->angle + ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale));
+		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
+
+		mo2 = P_SpawnMobj(mo->x, mo->y,
+			mo->z + ((mo->eflags & MFE_VERTICALFLIP)? mobjinfo[MT_BOSSSPIGOT].height-FixedMul(32*FRACUNIT,mo->scale): mo->height + FixedMul(32*FRACUNIT, mo->scale)), MT_BOSSSPIGOT);
+		mo2->angle = mo->angle;
+		mo2->destscale = mo->scale;
+		P_SetScale(mo2, mo2->destscale);
+		if (mo->eflags & MFE_VERTICALFLIP)
+		{
+			mo2->eflags |= MFE_VERTICALFLIP;
+			mo2->flags2 |= MF2_OBJECTFLIP;
+		}
+		P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
+		return;
+	}
+}
+
+// Function: A_CustomPower
+//
+// Description: Provides a custom powerup. Target (must be a player) is awarded the powerup. Reactiontime of the object is used as an index to the powers array.
+//
+// var1 = Power index #
+// var2 = Power duration in tics
+//
+void A_CustomPower(mobj_t *actor)
+{
+	player_t *player;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	boolean spawnshield = false;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CustomPower", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	if (locvar1 >= NUMPOWERS)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Power #%d out of range!\n", locvar1);
+		return;
+	}
+
+	player = actor->target->player;
+
+	if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2)
+		spawnshield = true;
+
+	player->powers[locvar1] = (UINT16)locvar2;
+	if (actor->info->seesound)
+		S_StartSound(player->mo, actor->info->seesound);
+
+	if (spawnshield) //workaround for a bug
+		P_SpawnShieldOrb(player);
+}
+
+// Function: A_GiveWeapon
+//
+// Description: Gives the player the specified weapon panels.
+//
+// var1 = Weapon index #
+// var2 = unused
+//
+void A_GiveWeapon(mobj_t *actor)
+{
+	player_t *player;
+	INT32 locvar1 = var1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GiveWeapon", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	if (locvar1 >= 1<<(NUM_WEAPONS-1))
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Weapon #%d out of range!\n", locvar1);
+		return;
+	}
+
+	player = actor->target->player;
+
+	player->ringweapons |= locvar1;
+	if (actor->info->seesound)
+		S_StartSound(player->mo, actor->info->seesound);
+}
+
+// Function: A_RingBox
+//
+// Description: Awards the player 10 rings.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_RingBox(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RingBox", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	P_GivePlayerRings(player, actor->info->reactiontime);
+	if (actor->info->seesound)
+		S_StartSound(player->mo, actor->info->seesound);
+}
+
+// Function: A_Invincibility
+//
+// Description: Awards the player invincibility.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Invincibility(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Invincibility", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+	player->powers[pw_invulnerability] = invulntics + 1;
+
+	if (P_IsLocalPlayer(player) && !player->powers[pw_super])
+	{
+		S_StopMusic();
+		if (mariomode)
+			G_GhostAddColor(GHC_INVINCIBLE);
+		strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
+		S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
+		S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
+	}
+}
+
+// Function: A_SuperSneakers
+//
+// Description: Awards the player super sneakers.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SuperSneakers(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SuperSneakers", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	actor->target->player->powers[pw_sneakers] = sneakertics + 1;
+
+	if (P_IsLocalPlayer(player) && !player->powers[pw_super])
+	{
+		if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
+			S_SpeedMusic(1.4f);
+		else
+		{
+			S_StopMusic();
+			S_ChangeMusicInternal("_shoes", false);
+		}
+		strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
+		S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
+	}
+}
+
+// Function: A_AwardScore
+//
+// Description: Adds a set amount of points to the player's score.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_AwardScore(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_AwardScore", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	P_AddPlayerScore(player, actor->info->reactiontime);
+	if (actor->info->seesound)
+		S_StartSound(player->mo, actor->info->seesound);
+}
+
+// Function: A_ExtraLife
+//
+// Description: Awards the player an extra life.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ExtraLife(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ExtraLife", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	if (actor->type == MT_1UP_ICON && actor->tracer)
+	{
+		// We're using the overlay, so use the overlay 1up sprite (no text)
+		actor->sprite = SPR_TV1P;
+	}
+
+	if (ultimatemode) //I don't THINK so!
+	{
+		S_StartSound(player->mo, sfx_lose);
+		return;
+	}
+
+	P_GiveCoopLives(player, 1, true);
+}
+
+// Function: A_GiveShield
+//
+// Description: Awards the player a specified shield.
+//
+// var1 = Shield type (make with SH_ constants)
+// var2 = unused
+//
+void A_GiveShield(mobj_t *actor)
+{
+	player_t *player;
+	UINT16 locvar1 = var1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GiveShield", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	P_SwitchShield(player, locvar1);
+	S_StartSound(player->mo, actor->info->seesound);
+}
+
+// Function: A_GravityBox
+//
+// Description: Awards the player gravity boots.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GravityBox(mobj_t *actor)
+{
+	player_t *player;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GravityBox", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	player = actor->target->player;
+
+	S_StartSound(player, actor->info->activesound);
+
+	player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
+}
+
+// Function: A_ScoreRise
+//
+// Description: Makes the little score logos rise. Speed value sets speed.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ScoreRise(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ScoreRise", actor))
+		return;
+#endif
+	// make logo rise!
+	P_SetObjectMomZ(actor, actor->info->speed, false);
+}
+
+// Function: A_BunnyHop
+//
+// Description: Makes object hop like a bunny.
+//
+// var1 = jump strength
+// var2 = horizontal movement
+//
+void A_BunnyHop(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BunnyHop", actor))
+		return;
+#endif
+	if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)
+		|| (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz))
+	{
+		P_SetObjectMomZ(actor, locvar1*FRACUNIT, false);
+		P_InstaThrust(actor, actor->angle, FixedMul(locvar2*FRACUNIT, actor->scale)); // Launch the hopping action! PHOOM!!
+	}
+}
+
+// Function: A_BubbleSpawn
+//
+// Description: Spawns a randomly sized bubble from the object's location. Only works underwater.
+//
+// var1 = Distance to look for players.  If no player is in this distance, bubbles aren't spawned. (Ambush overrides)
+// var2 = unused
+//
+void A_BubbleSpawn(mobj_t *actor)
+{
+	INT32 i, locvar1 = var1;
+	UINT8 prandom;
+	mobj_t *bubble = NULL;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BubbleSpawn", actor))
+		return;
+#endif
+	if (!(actor->eflags & MFE_UNDERWATER))
+	{
+		// Don't draw or spawn bubbles above water
+		actor->flags2 |= MF2_DONTDRAW;
+		return;
+	}
+	actor->flags2 &= ~MF2_DONTDRAW;
+
+	if (!(actor->flags2 & MF2_AMBUSH))
+	{
+		// Quick! Look through players!
+		// Don't spawn bubbles unless a player is relatively close by (var1).
+		for (i = 0; i < MAXPLAYERS; ++i)
+			if (playeringame[i] && players[i].mo
+			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<<FRACBITS))
+				break; // Stop looking.
+		if (i == MAXPLAYERS)
+			return; // don't make bubble!
+	}
+
+	prandom = P_RandomByte();
+
+	if (leveltime % (3*TICRATE) < 8)
+		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_EXTRALARGEBUBBLE);
+	else if (prandom > 128)
+		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_SMALLBUBBLE);
+	else if (prandom < 128 && prandom > 96)
+		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE);
+
+	if (bubble)
+	{
+		bubble->destscale = actor->scale;
+		P_SetScale(bubble, actor->scale);
+	}
+}
+
+// Function: A_FanBubbleSpawn
+//
+// Description: Spawns bubbles from fans, if they're underwater.
+//
+// var1 = Distance to look for players.  If no player is in this distance, bubbles aren't spawned. (Ambush overrides)
+// var2 = unused
+//
+void A_FanBubbleSpawn(mobj_t *actor)
+{
+	INT32 i, locvar1 = var1;
+	UINT8 prandom;
+	mobj_t *bubble = NULL;
+	fixed_t hz = actor->z + (4*actor->height)/5;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FanBubbleSpawn", actor))
+		return;
+#endif
+	if (!(actor->eflags & MFE_UNDERWATER))
+		return;
+
+	if (!(actor->flags2 & MF2_AMBUSH))
+	{
+	// Quick! Look through players!
+	// Don't spawn bubbles unless a player is relatively close by (var2).
+		for (i = 0; i < MAXPLAYERS; ++i)
+			if (playeringame[i] && players[i].mo
+			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<<FRACBITS))
+				break; // Stop looking.
+		if (i == MAXPLAYERS)
+			return; // don't make bubble!
+	}
+
+	prandom = P_RandomByte();
+
+	if ((prandom & 0x7) == 0x7)
+		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_SMALLBUBBLE);
+	else if ((prandom & 0xF0) == 0xF0)
+		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE);
+
+	if (bubble)
+	{
+		bubble->destscale = actor->scale;
+		P_SetScale(bubble, actor->scale);
+	}
+}
+
+// Function: A_BubbleRise
+//
+// Description: Raises a bubble
+//
+// var1:
+//		0 = Bend around the water abit, looking more realistic
+//		1 = Rise straight up
+// var2 = rising speed
+//
+void A_BubbleRise(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BubbleRise", actor))
+		return;
+#endif
+	if (actor->type == MT_EXTRALARGEBUBBLE)
+		P_SetObjectMomZ(actor, FixedDiv(6*FRACUNIT,5*FRACUNIT), false); // make bubbles rise!
+	else
+	{
+		P_SetObjectMomZ(actor, locvar2, true); // make bubbles rise!
+
+		// Move around slightly to make it look like it's bending around the water
+		if (!locvar1)
+		{
+			UINT8 prandom = P_RandomByte();
+			if (!(prandom & 0x7)) // *****000
+			{
+				P_InstaThrust(actor, prandom & 0x70 ? actor->angle + ANGLE_90 : actor->angle,
+					FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale));
+			}
+			else if (!(prandom & 0x38)) // **000***
+			{
+				P_InstaThrust(actor, prandom & 0x70 ? actor->angle - ANGLE_90 : actor->angle - ANGLE_180,
+					FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale));
+			}
+		}
+	}
+}
+
+// Function: A_BubbleCheck
+//
+// Description: Checks if a bubble should be drawn or not. Bubbles are not drawn above water.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_BubbleCheck(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BubbleCheck", actor))
+		return;
+#endif
+	if (actor->eflags & MFE_UNDERWATER)
+		actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw
+	else
+		actor->flags2 |= MF2_DONTDRAW; // above water so don't draw
+}
+
+// Function: A_AttractChase
+//
+// Description: Makes a ring chase after a player with a ring shield and also causes spilled rings to flicker.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_AttractChase(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_AttractChase", actor))
+		return;
+#endif
+	if (actor->flags2 & MF2_NIGHTSPULL || !actor->health)
+		return;
+
+	// spilled rings flicker before disappearing
+	if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE)
+		actor->flags2 |= MF2_DONTDRAW;
+	else
+		actor->flags2 &= ~MF2_DONTDRAW;
+
+	// Turn flingrings back into regular rings if attracted.
+	if (actor->tracer && actor->tracer->player
+		&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
+	{
+		mobj_t *newring;
+		newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
+		newring->momx = actor->momx;
+		newring->momy = actor->momy;
+		newring->momz = actor->momz;
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	P_LookForShield(actor); // Go find 'em, boy!
+
+	if (!actor->tracer
+		|| !actor->tracer->player
+		|| !actor->tracer->health
+		|| !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta
+	{
+		// Lost attracted rings don't through walls anymore.
+		actor->flags &= ~MF_NOCLIP;
+		P_SetTarget(&actor->tracer, NULL);
+		return;
+	}
+
+	// If a FlingRing gets attracted by a shield, change it into a normal ring.
+	if (actor->type == (mobjtype_t)actor->info->reactiontime)
+	{
+		P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance);
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	// Keep stuff from going down inside floors and junk
+	actor->flags &= ~MF_NOCLIPHEIGHT;
+
+	// Let attracted rings move through walls and such.
+	actor->flags |= MF_NOCLIP;
+
+	P_Attract(actor, actor->tracer, false);
+}
+
+// Function: A_DropMine
+//
+// Description: Drops a mine. Raisestate specifies the object # to use for the mine.
+//
+// var1 = height offset
+// var2:
+//		lower 16 bits = proximity check distance (0 disables)
+//		upper 16 bits = 0 to check proximity with target, 1 for tracer
+//
+void A_DropMine(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t z;
+	mobj_t *mine;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_DropMine", actor))
+		return;
+#endif
+
+	if (locvar2 & 65535)
+	{
+		fixed_t dist;
+		mobj_t *target;
+
+		if (locvar2 >> 16)
+			target = actor->tracer;
+		else
+			target = actor->target;
+
+		if (!target)
+			return;
+
+		dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)>>FRACBITS;
+
+		if (dist > FixedMul((locvar2 & 65535), actor->scale))
+			return;
+	}
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - mobjinfo[actor->info->raisestate].height - FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale);
+
+	// Use raisestate instead of MT_MINE
+	mine = P_SpawnMobj(actor->x, actor->y, z, (mobjtype_t)actor->info->raisestate);
+	if (actor->eflags & MFE_VERTICALFLIP)
+		mine->eflags |= MFE_VERTICALFLIP;
+	mine->momz = actor->momz + actor->pmomz;
+
+	S_StartSound(actor, actor->info->attacksound);
+}
+
+// Function: A_FishJump
+//
+// Description: Makes the stupid harmless fish in Greenflower Zone jump.
+//
+// var1 = Jump strength (in FRACBITS), if specified. Otherwise, uses the angle value.
+// var2 = unused
+//
+void A_FishJump(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FishJump", actor))
+		return;
+#endif
+
+	if (locvar2)
+	{
+		fixed_t rad = actor->radius>>FRACBITS;
+		P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
+	}
+
+	if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale)))
+	{
+		fixed_t jumpval;
+
+		if (locvar1)
+			jumpval = var1;
+		else
+			jumpval = FixedMul(AngleFixed(actor->angle)/4, actor->scale);
+
+		if (!jumpval) jumpval = FixedMul(44*(FRACUNIT/4), actor->scale);
+		actor->momz = jumpval;
+		P_SetMobjStateNF(actor, actor->info->seestate);
+	}
+
+	if (actor->momz < 0
+		&& (actor->state < &states[actor->info->meleestate] || actor->state > &states[actor->info->xdeathstate]))
+		P_SetMobjStateNF(actor, actor->info->meleestate);
+}
+
+// Function:A_ThrownRing
+//
+// Description: Thinker for thrown rings/sparkle trail
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ThrownRing(mobj_t *actor)
+{
+	INT32 c = 0;
+	INT32 stop;
+	player_t *player;
+	fixed_t dist;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ThrownRing", actor))
+		return;
+#endif
+
+	if (leveltime % (TICRATE/7) == 0)
+	{
+		mobj_t *ring = NULL;
+
+		if (actor->flags2 & MF2_EXPLOSION)
+		{
+			if (actor->momx != 0 || actor->momy != 0)
+				ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOKE);
+			// Else spawn nothing because it's totally stationary and constantly smoking would be weird -SH
+		}
+		else if (actor->flags2 & MF2_AUTOMATIC)
+			ring = P_SpawnGhostMobj(actor);
+		else if (!(actor->flags2 & MF2_RAILRING))
+			ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPARK);
+
+		if (ring)
+		{
+			/*
+			P_SetTarget(&ring->target, actor);
+			ring->color = actor->color; //copy color
+			*/
+			ring->destscale = actor->scale;
+			P_SetScale(ring, actor->scale);
+		}
+	}
+
+	// A_GrenadeRing beeping lives once moooooore -SH
+	if (actor->type == MT_THROWNGRENADE && actor->fuse % TICRATE == 0)
+		S_StartSound(actor, actor->info->attacksound);
+
+	// decrement bounce ring time
+	if (actor->flags2 & MF2_BOUNCERING)
+	{
+		if (actor->fuse)
+			actor->fuse--;
+		else {
+			P_RemoveMobj(actor);
+			return;
+		}
+	}
+
+	// spilled rings (and thrown bounce) flicker before disappearing
+	if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE
+		&& actor->type != MT_THROWNGRENADE)
+		actor->flags2 |= MF2_DONTDRAW;
+	else
+		actor->flags2 &= ~MF2_DONTDRAW;
+
+	if (actor->tracer && actor->tracer->health <= 0)
+		P_SetTarget(&actor->tracer, NULL);
+
+	// Updated homing ring special capability
+	// If you have a ring shield, all rings thrown
+	// at you become homing (except rail)!
+	if (actor->tracer)
+	{
+		// A non-homing ring getting attracted by a
+		// magnetic player. If he gets too far away, make
+		// sure to stop the attraction!
+		if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC)
+		    && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
+		    actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
+		{
+			P_SetTarget(&actor->tracer, NULL);
+		}
+
+		if (actor->tracer && (actor->tracer->health)
+			&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
+		{
+			const INT32 temp = actor->threshold;
+			actor->threshold = 32000;
+			P_HomingAttack(actor, actor->tracer);
+			actor->threshold = temp;
+			return;
+		}
+	}
+
+	// first time init, this allow minimum lastlook changes
+	if (actor->lastlook < 0)
+		actor->lastlook = P_RandomByte();
+
+	actor->lastlook %= MAXPLAYERS;
+
+	stop = (actor->lastlook - 1) & PLAYERSMASK;
+
+	for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK)
+	{
+		// done looking
+		if (actor->lastlook == stop)
+			return;
+
+		if (!playeringame[actor->lastlook])
+			continue;
+
+		if (c++ == 2)
+			return;
+
+		player = &players[actor->lastlook];
+
+		if (!player->mo)
+			continue;
+
+		if (player->mo->health <= 0)
+			continue; // dead
+
+		if ((netgame || multiplayer) && player->spectator)
+			continue; // spectator
+
+		if (actor->target && actor->target->player)
+		{
+			if (player->mo == actor->target)
+				continue;
+
+			// Don't home in on teammates.
+			if (gametype == GT_CTF
+				&& actor->target->player->ctfteam == player->ctfteam)
+				continue;
+		}
+
+		dist = P_AproxDistance(P_AproxDistance(player->mo->x-actor->x,
+			player->mo->y-actor->y), player->mo->z-actor->z);
+
+		// check distance
+		if (actor->flags2 & MF2_RAILRING)
+		{
+			if (dist > FixedMul(RING_DIST/2, player->mo->scale))
+				continue;
+		}
+		else if (dist > FixedMul(RING_DIST, player->mo->scale))
+			continue;
+
+		// do this after distance check because it's more computationally expensive
+		if (!P_CheckSight(actor, player->mo))
+			continue; // out of sight
+
+		if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
+			&& dist < FixedMul(RING_DIST/4, player->mo->scale))
+			P_SetTarget(&actor->tracer, player->mo);
+		return;
+	}
+
+	return;
+}
+
+// Function: A_SetSolidSteam
+//
+// Description: Makes steam solid so it collides with the player to boost them.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SetSolidSteam(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetSolidSteam", actor))
+		return;
+#endif
+	actor->flags &= ~MF_NOCLIP;
+	actor->flags |= MF_SOLID;
+	if (!(actor->flags2 & MF2_AMBUSH))
+	{
+		if (P_RandomChance(FRACUNIT/8))
+		{
+			if (actor->info->deathsound)
+				S_StartSound(actor, actor->info->deathsound); // Hiss!
+		}
+		else
+		{
+			if (actor->info->painsound)
+				S_StartSound(actor, actor->info->painsound);
+		}
+	}
+
+	P_SetObjectMomZ (actor, 1, true);
+}
+
+// Function: A_UnsetSolidSteam
+//
+// Description: Makes an object non-solid and also noclip. Used by the steam.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_UnsetSolidSteam(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_UnsetSolidSteam", actor))
+		return;
+#endif
+	actor->flags &= ~MF_SOLID;
+	actor->flags |= MF_NOCLIP;
+}
+
+// Function: A_SignPlayer
+//
+// Description: Changes the state of a level end sign to reflect the player that hit it.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SignPlayer(mobj_t *actor)
+{
+	mobj_t *ov;
+	skin_t *skin;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SignPlayer", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	if (!actor->target->player)
+		return;
+
+	skin = &skins[actor->target->player->skin];
+
+	if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor?
+	{
+		actor->color = skin->prefoppositecolor;
+		/*
+		If you're here from the comment above Color_Opposite,
+		the following line is the one which is dependent on the
+		array being symmetrical. It gets the opposite of the
+		opposite of your desired colour just so it can get the
+		brightness frame for the End Sign. It's not a great
+		design choice, but it's constant time array access and
+		the idea that the colours should be OPPOSITES is kind
+		of in the name. If you have a better idea, feel free
+		to let me know. ~toast 2016/07/20
+		*/
+		actor->frame += (15 - Color_Opposite[(Color_Opposite[(skin->prefoppositecolor - 1)*2] - 1)*2 + 1]);
+	}
+	else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor.
+	{
+		actor->color = Color_Opposite[(actor->target->player->skincolor - 1)*2];
+		actor->frame += (15 - Color_Opposite[(actor->target->player->skincolor - 1)*2 + 1]);
+	}
+
+	if (skin->sprites[SPR2_SIGN].numframes)
+	{
+		// spawn an overlay of the player's face.
+		ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
+		P_SetTarget(&ov->target, actor);
+		ov->color = actor->target->player->skincolor;
+		ov->skin = skin;
+		P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
+	}
+}
+
+// Function: A_OverlayThink
+//
+// Description: Moves the overlay to the position of its target.
+//
+// var1 = unused
+// var2 = invert, z offset
+//
+void A_OverlayThink(mobj_t *actor)
+{
+	fixed_t destx, desty;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_OverlayThink", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	if (!splitscreen && rendermode != render_soft)
+	{
+		angle_t viewingangle;
+
+		if (players[displayplayer].awayviewtics)
+			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y);
+		else if (!camera.chase && players[displayplayer].mo)
+			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y);
+		else
+			viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera.x, camera.y);
+
+		destx = actor->target->x + P_ReturnThrustX(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale));
+		desty = actor->target->y + P_ReturnThrustY(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale));
+	}
+	else
+	{
+		destx = actor->target->x;
+		desty = actor->target->y;
+	}
+	P_UnsetThingPosition(actor);
+	actor->x = destx;
+	actor->y = desty;
+	P_SetThingPosition(actor);
+	if (actor->eflags & MFE_VERTICALFLIP)
+		actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height  - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
+	else
+		actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
+	actor->angle = actor->target->angle;
+	actor->eflags = actor->target->eflags;
+
+	actor->momx = actor->target->momx;
+	actor->momy = actor->target->momy;
+	actor->momz = actor->target->momz; // assume target has correct momz! Do not use P_SetObjectMomZ!
+}
+
+// Function: A_JetChase
+//
+// Description: A_Chase for Jettysyns
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetChase(mobj_t *actor)
+{
+	fixed_t thefloor;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetChase", actor))
+		return;
+#endif
+
+	if (actor->flags2 & MF2_AMBUSH)
+		return;
+
+	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
+		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
+		thefloor = actor->watertop;
+	else
+		thefloor = actor->floorz;
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	if (P_RandomChance(FRACUNIT/32))
+	{
+		actor->momx = actor->momx / 2;
+		actor->momy = actor->momy / 2;
+		actor->momz = actor->momz / 2;
+	}
+
+	// Bounce if too close to floor or ceiling -
+	// ideal for Jetty-Syns above you on 3d floors
+	if (actor->momz && ((actor->z - FixedMul((32<<FRACBITS), actor->scale)) < thefloor) && !((thefloor + FixedMul(32*FRACUNIT, actor->scale) + actor->height) > actor->ceilingz))
+		actor->momz = -actor->momz/2;
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		actor->momx = actor->momy = actor->momz = 0;
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	// turn towards movement direction if not there yet
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+
+	if ((multiplayer || netgame) && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)))
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+	// If the player is over 3072 fracunits away, then look for another player
+	if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y),
+		actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)))
+	{
+		return; // got a new target
+	}
+
+	// chase towards player
+	if (ultimatemode)
+		P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/2, actor->scale));
+	else
+		P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/4, actor->scale));
+
+	// must adjust height
+	if (ultimatemode)
+	{
+		if (actor->z < (actor->target->z + actor->target->height + FixedMul((64<<FRACBITS), actor->scale)))
+			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
+		else
+			actor->momz -= FixedMul(FRACUNIT/2, actor->scale);
+	}
+	else
+	{
+		if (actor->z < (actor->target->z + actor->target->height + FixedMul((32<<FRACBITS), actor->scale)))
+			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
+		else
+			actor->momz -= FixedMul(FRACUNIT/2, actor->scale);
+	}
+}
+
+// Function: A_JetbThink
+//
+// Description: Thinker for Jetty-Syn bombers
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetbThink(mobj_t *actor)
+{
+	sector_t *nextsector;
+	fixed_t thefloor;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetbThink", actor))
+		return;
+#endif
+
+	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
+		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
+		thefloor = actor->watertop;
+	else
+		thefloor = actor->floorz;
+
+	if (actor->target)
+	{
+		A_JetChase(actor);
+		// check for melee attack
+		if (actor->info->raisestate
+			&& (actor->z > (actor->floorz + FixedMul((32<<FRACBITS), actor->scale)))
+			&& P_JetbCheckMeleeRange(actor) && !actor->reactiontime
+			&& (actor->target->z >= actor->floorz))
+		{
+			mobj_t *bomb;
+			if (actor->info->attacksound)
+				S_StartAttackSound(actor, actor->info->attacksound);
+
+			// use raisestate instead of MT_MINE
+			bomb = P_SpawnMobj(actor->x, actor->y, actor->z - FixedMul((32<<FRACBITS), actor->scale), (mobjtype_t)actor->info->raisestate);
+
+			P_SetTarget(&bomb->target, actor);
+			bomb->destscale = actor->scale;
+			P_SetScale(bomb, actor->scale);
+			actor->reactiontime = TICRATE; // one second
+			S_StartSound(actor, actor->info->attacksound);
+		}
+	}
+	else if (((actor->z - FixedMul((32<<FRACBITS), actor->scale)) < thefloor) && !((thefloor + FixedMul((32<<FRACBITS), actor->scale) + actor->height) > actor->ceilingz))
+			actor->z = thefloor+FixedMul((32<<FRACBITS), actor->scale);
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
+
+	// Move downwards or upwards to go through a passageway.
+	if (nextsector->ceilingheight < actor->z + actor->height)
+		actor->momz -= FixedMul(5*FRACUNIT, actor->scale);
+	else if (nextsector->floorheight > actor->z)
+		actor->momz += FixedMul(5*FRACUNIT, actor->scale);
+}
+
+// Function: A_JetgShoot
+//
+// Description: Firing function for Jetty-Syn gunners.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetgShoot(mobj_t *actor)
+{
+	fixed_t dist;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetgShoot", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	if (actor->reactiontime)
+		return;
+
+	dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
+
+	if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale))
+		return;
+
+	if (dist < FixedMul(64*FRACUNIT, actor->scale))
+		return;
+
+	A_FaceTarget(actor);
+	P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate);
+
+	if (ultimatemode)
+		actor->reactiontime = actor->info->reactiontime*TICRATE;
+	else
+		actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+
+	if (actor->info->attacksound)
+		S_StartSound(actor, actor->info->attacksound);
+}
+
+// Function: A_ShootBullet
+//
+// Description: Shoots a bullet. Raisestate defines object # to use as projectile.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ShootBullet(mobj_t *actor)
+{
+	fixed_t dist;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ShootBullet", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
+
+	if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale))
+		return;
+
+	A_FaceTarget(actor);
+	P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate);
+
+	if (actor->info->attacksound)
+		S_StartSound(actor, actor->info->attacksound);
+}
+
+// Function: A_MinusDigging
+//
+// Description: Minus digging in the ground.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MinusDigging(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MinusDigging", actor))
+		return;
+#endif
+	actor->flags &= ~MF_SPECIAL;
+	actor->flags &= ~MF_SHOOTABLE;
+
+	if (!actor->target)
+	{
+		A_Look(actor);
+		return;
+	}
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+		return;
+	}
+
+	// Dirt trail
+	P_SpawnGhostMobj(actor);
+
+	actor->flags |= MF_NOCLIPTHING;
+	var1 = 3;
+	A_Chase(actor);
+	actor->flags &= ~MF_NOCLIPTHING;
+
+	// Play digging sound
+	if (!(leveltime & 15))
+		S_StartSound(actor, actor->info->activesound);
+
+	// If we're close enough to our target, pop out of the ground
+	if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius
+		&& abs(actor->target->z - actor->z) < 2*actor->height)
+		P_SetMobjState(actor, actor->info->missilestate);
+
+	// Snap to ground
+	if (actor->eflags & MFE_VERTICALFLIP)
+		actor->z = actor->ceilingz - actor->height;
+	else
+		actor->z = actor->floorz;
+}
+
+// Function: A_MinusPopup
+//
+// Description: Minus popping out of the ground.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MinusPopup(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MinusPopup", actor))
+		return;
+#endif
+	P_SetObjectMomZ(actor, 10*FRACUNIT, false);
+
+	actor->flags |= MF_SPECIAL;
+	actor->flags |= MF_SHOOTABLE;
+
+	// Sound for busting out of the ground.
+	S_StartSound(actor, actor->info->attacksound);
+}
+
+// Function: A_MinusCheck
+//
+// Description: If the minus hits the floor, dig back into the ground.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MinusCheck(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MinusCheck", actor))
+		return;
+#endif
+	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
+	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))
+	{
+		actor->flags &= ~MF_SPECIAL;
+		actor->flags &= ~MF_SHOOTABLE;
+		actor->reactiontime = TICRATE;
+		P_SetMobjState(actor, actor->info->seestate);
+		return;
+	}
+
+	// 'Falling' animation
+	if (P_MobjFlip(actor)*actor->momz < 0 && actor->state < &states[actor->info->meleestate])
+		P_SetMobjState(actor, actor->info->meleestate);
+}
+
+// Function: A_ChickenCheck
+//
+// Description: Resets the chicken once it hits the floor again.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ChickenCheck(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ChickenCheck", actor))
+		return;
+#endif
+	if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
+	|| (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz))
+	{
+		if (!(actor->momx || actor->momy || actor->momz)
+			&& actor->state > &states[actor->info->seestate])
+		{
+			A_Chase(actor);
+			P_SetMobjState(actor, actor->info->seestate);
+		}
+
+		actor->momx >>= 2;
+		actor->momy >>= 2;
+	}
+}
+
+// Function: A_JetgThink
+//
+// Description: Thinker for Jetty-Syn Gunners
+//
+// var1 = unused
+// var2 = unused
+//
+void A_JetgThink(mobj_t *actor)
+{
+	sector_t *nextsector;
+
+	fixed_t thefloor;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_JetgThink", actor))
+		return;
+#endif
+
+	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
+		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
+		thefloor = actor->watertop;
+	else
+		thefloor = actor->floorz;
+
+	if (actor->target)
+	{
+		if (P_RandomChance(FRACUNIT/8) && !actor->reactiontime)
+			P_SetMobjState(actor, actor->info->missilestate);
+		else
+			A_JetChase (actor);
+	}
+	else if (actor->z - FixedMul((32<<FRACBITS), actor->scale) < thefloor && !(thefloor + FixedMul((32<<FRACBITS), actor->scale)
+		+ actor->height > actor->ceilingz))
+	{
+		actor->z = thefloor + FixedMul((32<<FRACBITS), actor->scale);
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
+
+	// Move downwards or upwards to go through a passageway.
+	if (nextsector->ceilingheight < actor->z + actor->height)
+		actor->momz -= FixedMul(5*FRACUNIT, actor->scale);
+	else if (nextsector->floorheight > actor->z)
+		actor->momz += FixedMul(5*FRACUNIT, actor->scale);
+}
+
+// Function: A_MouseThink
+//
+// Description: Thinker for scurrying mice.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MouseThink(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MouseThink", actor))
+		return;
+#endif
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z == actor->floorz)
+		|| (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height == actor->ceilingz))
+		&& !actor->reactiontime)
+	{
+		if (twodlevel || actor->flags2 & MF2_TWOD)
+		{
+			if (P_RandomChance(FRACUNIT/2))
+				actor->angle += ANGLE_180;
+		}
+		else if (P_RandomChance(FRACUNIT/2))
+			actor->angle += ANGLE_90;
+		else
+			actor->angle -= ANGLE_90;
+
+		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale));
+		actor->reactiontime = TICRATE/5;
+	}
+}
+
+// Function: A_DetonChase
+//
+// Description: Chases a Deton after a player.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_DetonChase(mobj_t *actor)
+{
+	angle_t exact;
+	fixed_t xydist, dist;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_DetonChase", actor))
+		return;
+#endif
+
+	// modify tracer threshold
+	if (!actor->tracer || actor->tracer->health <= 0)
+		actor->threshold = 0;
+	else
+		actor->threshold = 1;
+
+	if (!actor->tracer || !(actor->tracer->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, true, 0))
+			return; // got a new target
+
+		actor->momx = actor->momy = actor->momz = 0;
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	if (multiplayer && !actor->threshold && P_LookForPlayers(actor, true, true, 0))
+		return; // got a new target
+
+	// Face movement direction if not doing so
+	exact = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
+	actor->angle = exact;
+	/*if (exact != actor->angle)
+	{
+		if (exact - actor->angle > ANGLE_180)
+		{
+			actor->angle -= actor->info->raisestate;
+			if (exact - actor->angle < ANGLE_180)
+				actor->angle = exact;
+		}
+		else
+		{
+			actor->angle += actor->info->raisestate;
+			if (exact - actor->angle > ANGLE_180)
+				actor->angle = exact;
+		}
+	}*/
+	// movedir is up/down angle: how much it has to go up as it goes over to the player
+	xydist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
+	exact = R_PointToAngle2(0, 0, xydist, actor->tracer->z - actor->z);
+	actor->movedir = exact;
+	/*if (exact != actor->movedir)
+	{
+		if (exact - actor->movedir > ANGLE_180)
+		{
+			actor->movedir -= actor->info->raisestate;
+			if (exact - actor->movedir < ANGLE_180)
+				actor->movedir = exact;
+		}
+		else
+		{
+			actor->movedir += actor->info->raisestate;
+			if (exact - actor->movedir > ANGLE_180)
+				actor->movedir = exact;
+		}
+	}*/
+
+	// check for melee attack
+	if (actor->tracer)
+	{
+		if (P_AproxDistance(actor->tracer->x-actor->x, actor->tracer->y-actor->y) < actor->radius+actor->tracer->radius)
+		{
+			if (!((actor->tracer->z > actor->z + actor->height) || (actor->z > actor->tracer->z + actor->tracer->height)))
+			{
+				P_ExplodeMissile(actor);
+				return;
+			}
+		}
+	}
+
+	// chase towards player
+	if ((dist = P_AproxDistance(xydist, actor->tracer->z-actor->z))
+		> FixedMul((actor->info->painchance << FRACBITS), actor->scale))
+	{
+		P_SetTarget(&actor->tracer, NULL); // Too far away
+		return;
+	}
+
+	if (actor->reactiontime == 0)
+	{
+		actor->reactiontime = actor->info->reactiontime;
+		return;
+	}
+
+	if (actor->reactiontime > 1)
+	{
+		actor->reactiontime--;
+		return;
+	}
+
+	if (actor->reactiontime > 0)
+	{
+		actor->reactiontime = -42;
+
+		if (actor->info->seesound)
+			S_StartScreamSound(actor, actor->info->seesound);
+	}
+
+	if (actor->reactiontime == -42)
+	{
+		fixed_t xyspeed;
+
+		actor->reactiontime = -42;
+
+		exact = actor->movedir>>ANGLETOFINESHIFT;
+		xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact));
+		actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact));
+
+		exact = actor->angle>>ANGLETOFINESHIFT;
+		actor->momx = FixedMul(xyspeed, FINECOSINE(exact));
+		actor->momy = FixedMul(xyspeed, FINESINE(exact));
+
+		// Variable re-use
+		xyspeed = (P_AproxDistance(actor->tracer->x - actor->x, P_AproxDistance(actor->tracer->y - actor->y, actor->tracer->z - actor->z))>>(FRACBITS+6));
+
+		if (xyspeed < 1)
+			xyspeed = 1;
+
+		if (leveltime % xyspeed == 0)
+			S_StartSound(actor, sfx_deton);
+	}
+}
+
+// Function: A_CapeChase
+//
+// Description: Set an object's location to its target or tracer.
+//
+// var1:
+//		0 = Use target
+//		1 = Use tracer
+//		upper 16 bits = Z offset
+// var2:
+//		upper 16 bits = forward/backward offset
+//		lower 16 bits = sideways offset
+//
+void A_CapeChase(mobj_t *actor)
+{
+	mobj_t *chaser;
+	fixed_t foffsetx, foffsety, boffsetx, boffsety;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	angle_t angle;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CapeChase", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	if (locvar1 & 65535)
+		chaser = actor->tracer;
+	else
+		chaser = actor->target;
+
+	if (!chaser || (chaser->health <= 0))
+	{
+		if (chaser)
+			CONS_Debug(DBG_GAMELOGIC, "Hmm, the guy I'm chasing (object type %d) has no health.. so I'll die too!\n", chaser->type);
+
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	angle = (chaser->player ? chaser->player->drawangle : chaser->angle);
+
+	foffsetx = P_ReturnThrustX(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
+	foffsety = P_ReturnThrustY(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
+
+	boffsetx = P_ReturnThrustX(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale));
+	boffsety = P_ReturnThrustY(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale));
+
+	P_UnsetThingPosition(actor);
+	actor->x = chaser->x + foffsetx + boffsetx;
+	actor->y = chaser->y + foffsety + boffsety;
+	if (chaser->eflags & MFE_VERTICALFLIP)
+	{
+		actor->eflags |= MFE_VERTICALFLIP;
+		actor->flags2 |= MF2_OBJECTFLIP;
+		actor->z = chaser->z + chaser->height - actor->height - FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale);
+	}
+	else
+	{
+		actor->eflags &= ~MFE_VERTICALFLIP;
+		actor->flags2 &= ~MF2_OBJECTFLIP;
+		actor->z = chaser->z + FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale);
+	}
+	actor->angle = angle;
+	P_SetThingPosition(actor);
+}
+
+// Function: A_RotateSpikeBall
+//
+// Description: Rotates a spike ball around its target/tracer.
+//
+// var1:
+//		0 = Use target
+//		1 = Use tracer
+// var2 = unused
+//
+void A_RotateSpikeBall(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RotateSpikeBall", actor))
+		return;
+#endif
+
+	if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen.
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Spikeball has no target\n");
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	if (!actor->info->speed)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Object has no speed.\n");
+		return;
+	}
+
+	actor->angle += FixedAngle(actor->info->speed);
+	P_UnsetThingPosition(actor);
+	{
+		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
+		if (!locvar1)
+		{
+			actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius);
+			actor->y = actor->target->y + FixedMul(FINESINE(fa),radius);
+			actor->z = actor->target->z + actor->target->height/2;
+		}
+		else
+		{
+			actor->x = actor->tracer->x + FixedMul(FINECOSINE(fa),radius);
+			actor->y = actor->tracer->y + FixedMul(FINESINE(fa),radius);
+			actor->z = actor->tracer->z + actor->tracer->height/2;
+		}
+		P_SetThingPosition(actor);
+	}
+}
+
+// Function: A_UnidusBall
+//
+// Description: Rotates a spike ball around its target.
+//
+// var1:
+//		0 = Don't throw
+//		1 = Throw
+//		2 = Throw when target leaves MF2_SKULLFLY.
+// var2 = unused
+//
+void A_UnidusBall(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	boolean canthrow = false;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_UnidusBall", actor))
+		return;
+#endif
+
+	actor->angle += ANGLE_11hh;
+
+	if (actor->movecount)
+	{
+		if (P_AproxDistance(actor->momx, actor->momy) < FixedMul(actor->info->damage/2, actor->scale))
+			P_ExplodeMissile(actor);
+		return;
+	}
+
+	if (!actor->target || !actor->target->health)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_UnidusBall: Removing unthrown spikeball from nonexistant Unidus\n");
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	P_UnsetThingPosition(actor);
+	{
+		const angle_t angle = actor->movedir + FixedAngle(actor->info->speed*(leveltime%360));
+		const UINT16 fa = angle>>ANGLETOFINESHIFT;
+
+		actor->x = actor->target->x + FixedMul(FINECOSINE(fa),actor->threshold);
+		actor->y = actor->target->y + FixedMul(  FINESINE(fa),actor->threshold);
+		actor->z = actor->target->z + actor->target->height/2 - actor->height/2;
+
+		if (locvar1 == 1 && actor->target->target)
+		{
+			const angle_t tang = R_PointToAngle2(actor->target->x, actor->target->y, actor->target->target->x, actor->target->target->y);
+			const angle_t mina = tang-ANGLE_11hh;
+			canthrow = (angle-mina < FixedAngle(actor->info->speed*3));
+		}
+	}
+	P_SetThingPosition(actor);
+
+	if (locvar1 == 1 && canthrow)
+	{
+		if (P_AproxDistance(actor->target->target->x - actor->target->x, actor->target->target->y - actor->target->y) > FixedMul(MISSILERANGE>>1, actor->scale)
+		|| !P_CheckSight(actor, actor->target->target))
+			return;
+
+		actor->movecount = actor->info->damage>>FRACBITS;
+		actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING);
+		P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->target->x, actor->target->target->y), FixedMul(actor->info->damage, actor->scale));
+	}
+	else if (locvar1 == 2)
+	{
+		boolean skull = (actor->target->flags2 & MF2_SKULLFLY) == MF2_SKULLFLY;
+		if (actor->target->state == &states[actor->target->info->painstate])
+		{
+			P_KillMobj(actor, NULL, NULL, 0);
+			return;
+		}
+		switch(actor->extravalue2)
+		{
+		case 0: // at least one frame where not dashing
+			if (!skull) ++actor->extravalue2;
+			else break;
+			/* FALLTHRU */
+		case 1: // at least one frame where ARE dashing
+			if (skull) ++actor->extravalue2;
+			else break;
+			/* FALLTHRU */
+		case 2: // not dashing again?
+			if (skull) break;
+			// launch.
+		{
+			mobj_t *target = actor->target;
+			if (actor->target->target)
+				target = actor->target->target;
+			actor->movecount = actor->info->damage>>FRACBITS;
+			actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING);
+			P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, target->x, target->y), FixedMul(actor->info->damage, actor->scale));
+		}
+		default: // from our compiler appeasement program (CAP).
+			break;
+		}
+	}
+}
+
+// Function: A_RockSpawn
+//
+// Spawns rocks at a specified interval
+//
+// var1 = unused
+// var2 = unused
+void A_RockSpawn(mobj_t *actor)
+{
+	mobj_t *mo;
+	mobjtype_t type;
+	INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1);
+	line_t *line;
+	fixed_t dist;
+	fixed_t randomoomph;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RockSpawn", actor))
+		return;
+#endif
+
+	if (i == -1)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Unable to find parameter line 12 (tag %d)!\n", actor->threshold);
+		return;
+	}
+
+	line = &lines[i];
+
+	if (!(sides[line->sidenum[0]].textureoffset >> FRACBITS))
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: No X-offset detected! (tag %d)!\n", actor->threshold);
+		return;
+	}
+
+	dist = P_AproxDistance(line->dx, line->dy)/16;
+
+	if (dist < 1)
+		dist = 1;
+
+	type = MT_ROCKCRUMBLE1 + (sides[line->sidenum[0]].rowoffset >> FRACBITS);
+
+	if (line->flags & ML_NOCLIMB)
+		randomoomph = P_RandomByte() * (FRACUNIT/32);
+	else
+		randomoomph = 0;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK);
+	P_SetMobjState(mo, mobjinfo[type].spawnstate);
+	mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y);
+
+	P_InstaThrust(mo, mo->angle, dist + randomoomph);
+	mo->momz = dist + randomoomph;
+
+	var1 = sides[line->sidenum[0]].textureoffset >> FRACBITS;
+	A_SetTics(actor);
+}
+
+//
+// Function: A_SlingAppear
+//
+// Appears a sling.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SlingAppear(mobj_t *actor)
+{
+	UINT8 mlength = 4;
+	mobj_t *spawnee, *hprev;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SlingAppear", actor))
+		return;
+#endif
+
+	P_UnsetThingPosition(actor);
+	actor->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT);
+	P_SetThingPosition(actor);
+	actor->lastlook = 128;
+	actor->movecount = actor->lastlook;
+	actor->threshold = 0;
+	actor->movefactor = actor->threshold;
+	actor->friction = 128;
+
+	hprev = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLGRABCHAIN);
+	P_SetTarget(&hprev->tracer, actor);
+	P_SetTarget(&hprev->hprev, actor);
+	P_SetTarget(&actor->hnext, hprev);
+	hprev->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
+	hprev->movecount = mlength;
+
+	mlength--;
+
+	while (mlength > 0)
+	{
+		spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN);
+		P_SetTarget(&spawnee->tracer, actor);
+		P_SetTarget(&spawnee->hprev, hprev);
+		P_SetTarget(&hprev->hnext, spawnee);
+		hprev = spawnee;
+
+		spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
+		spawnee->movecount = mlength;
+
+		mlength--;
+	}
+}
+
+// Function: A_SetFuse
+//
+// Description: Sets the actor's fuse timer if not set already. May also change state when fuse reaches the last tic, otherwise by default the actor will die or disappear. (Replaces A_SnowBall)
+//
+// var1 = fuse timer duration (in tics).
+// var2:
+//		lower 16 bits = if > 0, state to change to when fuse = 1
+//		upper 16 bits: 0 = (default) don't set fuse unless 0, 1 = force change, 2 = force no change
+//
+void A_SetFuse(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetFuse", actor))
+		return;
+#endif
+
+	if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value
+		actor->fuse = locvar1;
+
+	if (actor->fuse == 1 && (locvar2 & 65535)) // change state on the very last tic (fuse is handled before actions in P_MobjThinker)
+	{
+		actor->fuse = 0; // don't die/disappear the next tic!
+		P_SetMobjState(actor, locvar2 & 65535);
+	}
+}
+
+// Function: A_CrawlaCommanderThink
+//
+// Description: Thinker for Crawla Commander.
+//
+// var1 = shoot bullets?
+// var2 = "pogo mode" speed
+//
+void A_CrawlaCommanderThink(mobj_t *actor)
+{
+	fixed_t dist;
+	sector_t *nextsector;
+	fixed_t thefloor;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	boolean hovermode = (actor->health > 1 || actor->fuse);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CrawlaCommanderThink", actor))
+		return;
+#endif
+
+	if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
+		&& actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale))
+		thefloor = actor->watertop;
+	else
+		thefloor = actor->floorz;
+
+	if (!actor->fuse && actor->flags2 & MF2_FRET)
+	{
+		if (actor->info->painsound)
+			S_StartSound(actor, actor->info->painsound);
+
+		actor->fuse = TICRATE/2;
+		actor->momz = 0;
+
+		P_InstaThrust(actor, actor->angle-ANGLE_180, FixedMul(5*FRACUNIT, actor->scale));
+	}
+
+	if (actor->reactiontime > 0)
+		actor->reactiontime--;
+
+	if (actor->fuse < 2)
+	{
+		actor->fuse = 0;
+		actor->flags2 &= ~MF2_FRET;
+	}
+
+	// Hover mode
+	if (hovermode)
+	{
+		if (actor->z < thefloor + FixedMul(16*FRACUNIT, actor->scale))
+			actor->momz += FixedMul(FRACUNIT, actor->scale);
+		else if (actor->z < thefloor + FixedMul(32*FRACUNIT, actor->scale))
+			actor->momz += FixedMul(FRACUNIT/2, actor->scale);
+		else
+			actor->momz += FixedMul(16, actor->scale);
+	}
+
+	if (!actor->target)
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		if (actor->state != &states[actor->info->spawnstate])
+			P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y);
+
+	if (actor->target->player && (!hovermode || actor->reactiontime <= 2*TICRATE))
+	{
+		if (dist < FixedMul(64<<(FRACBITS+(hovermode ? 1 : 0)), actor->scale)
+			&& ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING)))
+		{
+			// Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!!
+			P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale));
+			return;
+		}
+	}
+
+	if (locvar1)
+	{
+		if (actor->health < 2 && P_RandomChance(FRACUNIT/128))
+			P_SpawnMissile(actor, actor->target, locvar1);
+	}
+
+	// Face the player
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+
+	if (actor->threshold && dist > FixedMul(256*FRACUNIT, actor->scale))
+		actor->momx = actor->momy = 0;
+
+	if (actor->reactiontime && actor->reactiontime <= 2*TICRATE && dist > actor->target->radius - FixedMul(FRACUNIT, actor->scale))
+	{
+		actor->threshold = 0;
+
+		// Roam around, somewhat in the player's direction.
+		actor->angle += (P_RandomByte()<<10);
+		actor->angle -= (P_RandomByte()<<10);
+
+		if (hovermode)
+		{
+			fixed_t mom;
+			P_Thrust(actor, actor->angle, 2*actor->scale);
+			mom = P_AproxDistance(actor->momx, actor->momy);
+			if (mom > 20*actor->scale)
+			{
+				mom += 20*actor->scale;
+				mom >>= 1;
+				P_InstaThrust(actor, R_PointToAngle2(0, 0, actor->momx, actor->momy), mom);
+			}
+		}
+	}
+	else if (!actor->reactiontime)
+	{
+		if (hovermode && !(actor->flags2 & MF2_FRET)) // Hover Mode
+		{
+			if (dist < FixedMul(512*FRACUNIT, actor->scale))
+			{
+				actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+				P_InstaThrust(actor, actor->angle, FixedMul(40*FRACUNIT, actor->scale));
+				actor->threshold = 1;
+				if (actor->info->attacksound)
+					S_StartSound(actor, actor->info->attacksound);
+			}
+		}
+		actor->reactiontime = 3*TICRATE + (P_RandomByte()>>2);
+	}
+
+	if (actor->health == 1)
+		P_Thrust(actor, actor->angle, 1);
+
+	// Pogo Mode
+	if (!hovermode && actor->z <= actor->floorz)
+	{
+		if (actor->info->activesound)
+			S_StartSound(actor, actor->info->activesound);
+
+		if (dist < FixedMul(256*FRACUNIT, actor->scale))
+		{
+			actor->momz = FixedMul(locvar2, actor->scale);
+			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+			P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale));
+			// pogo on player
+		}
+		else
+		{
+			UINT8 prandom = P_RandomByte();
+			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom);
+			P_InstaThrust(actor, actor->angle, FixedDiv(FixedMul(locvar2, actor->scale), 3*FRACUNIT/2));
+			actor->momz = FixedMul(locvar2, actor->scale); // Bounce up in air
+		}
+	}
+
+	nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector;
+
+	// Move downwards or upwards to go through a passageway.
+	if (nextsector->floorheight > actor->z && nextsector->floorheight - actor->z < FixedMul(128*FRACUNIT, actor->scale))
+		actor->momz += (nextsector->floorheight - actor->z) / 4;
+}
+
+// Function: A_RingExplode
+//
+// Description: An explosion ring exploding
+//
+// var1 = unused
+// var2 = unused
+//
+void A_RingExplode(mobj_t *actor)
+{
+	mobj_t *mo2;
+	thinker_t *th;
+	angle_t d;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RingExplode", actor))
+		return;
+#endif
+
+	for (d = 0; d < 16; d++)
+		P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true);
+
+	S_StartSound(actor, sfx_prloop);
+
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2 == actor) // Don't explode yourself! Endless loop!
+			continue;
+
+		if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > FixedMul(actor->info->painchance, actor->scale))
+			continue;
+
+		if (mo2->flags & MF_SHOOTABLE)
+		{
+			actor->flags2 |= MF2_DEBRIS;
+			P_DamageMobj(mo2, actor, actor->target, 1, 0);
+			continue;
+		}
+	}
+	return;
+}
+
+// Function: A_OldRingExplode
+//
+// Description: An explosion ring exploding, 1.09.4 style
+//
+// var1 = object # to explode as debris
+// var2 = unused
+//
+void A_OldRingExplode(mobj_t *actor) {
+	UINT8 i;
+	mobj_t *mo;
+	const fixed_t ns = FixedMul(20 * FRACUNIT, actor->scale);
+	INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+	boolean changecolor = (actor->target && actor->target->player);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_OldRingExplode", actor))
+		return;
+#endif
+
+	for (i = 0; i < 32; i++)
+	{
+		const angle_t fa = (i*FINEANGLES/16) & FINEMASK;
+
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
+		P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points
+
+		mo->momx = FixedMul(FINECOSINE(fa),ns);
+		mo->momy = FixedMul(FINESINE(fa),ns);
+
+		if (i > 15)
+		{
+			if (i & 1)
+				mo->momz = ns;
+			else
+				mo->momz = -ns;
+		}
+
+		mo->flags2 |= MF2_DEBRIS;
+		mo->fuse = TICRATE/5;
+
+		if (changecolor)
+		{
+			if (gametype != GT_CTF)
+				mo->color = actor->target->color; //copy color
+			else if (actor->target->player->ctfteam == 2)
+				mo->color = skincolor_bluering;
+		}
+	}
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
+
+	P_SetTarget(&mo->target, actor->target);
+	mo->momz = ns;
+	mo->flags2 |= MF2_DEBRIS;
+	mo->fuse = TICRATE/5;
+
+	if (changecolor)
+	{
+		if (gametype != GT_CTF)
+			mo->color = actor->target->color; //copy color
+		else if (actor->target->player->ctfteam == 2)
+			mo->color = skincolor_bluering;
+	}
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1);
+
+	P_SetTarget(&mo->target, actor->target);
+	mo->momz = -ns;
+	mo->flags2 |= MF2_DEBRIS;
+	mo->fuse = TICRATE/5;
+
+	if (changecolor)
+	{
+		if (gametype != GT_CTF)
+			mo->color = actor->target->color; //copy color
+		else if (actor->target->player->ctfteam == 2)
+			mo->color = skincolor_bluering;
+	}
+}
+
+// Function: A_MixUp
+//
+// Description: Mix up all of the player positions.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MixUp(mobj_t *actor)
+{
+	boolean teleported[MAXPLAYERS];
+	INT32 i, numplayers = 0, prandom = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MixUp", actor))
+		return;
+#else
+	(void)actor;
+#endif
+
+	if (!multiplayer)
+		return;
+
+	// No mix-up monitors in hide and seek or time only race.
+	// The random factor is okay for other game modes, but in these, it is cripplingly unfair.
+	if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE)
+	{
+		S_StartSound(actor, sfx_lose);
+		return;
+	}
+
+	numplayers = 0;
+	memset(teleported, 0, sizeof (teleported));
+
+	// Count the number of players in the game
+	// and grab their xyz coords
+	for (i = 0; i < MAXPLAYERS; i++)
+		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
+			&& !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+		{
+			if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
+				continue;
+
+			numplayers++;
+		}
+
+	if (numplayers <= 1) // Not enough players to mix up.
+	{
+		S_StartSound(actor, sfx_lose);
+		return;
+	}
+	else if (numplayers == 2) // Special case -- simple swap
+	{
+		fixed_t x, y, z;
+		angle_t angle;
+		INT32 one = -1, two = 0; // default value 0 to make the compiler shut up
+
+		// Zoom tube stuff
+		mobj_t *tempthing = NULL; //tracer
+		UINT16 carry1,carry2;     //carry
+		INT32 transspeed;         //player speed
+
+		// Starpost stuff
+		INT16 starpostx, starposty, starpostz;
+		INT32 starpostnum;
+		tic_t starposttime;
+		angle_t starpostangle;
+
+		INT32 mflags2;
+
+		for (i = 0; i < MAXPLAYERS; i++)
+			if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
+				&& !players[i].exiting && !players[i].powers[pw_super])
+			{
+				if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
+					continue;
+
+				if (one == -1)
+					one = i;
+				else
+				{
+					two = i;
+					break;
+				}
+			}
+
+		//get this done first!
+		tempthing = players[one].mo->tracer;
+		P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer);
+		P_SetTarget(&players[two].mo->tracer, tempthing);
+
+		//zoom tubes use player->speed to determine direction and speed
+		transspeed = players[one].speed;
+		players[one].speed = players[two].speed;
+		players[two].speed = transspeed;
+
+		//set flags variables now but DON'T set them.
+		carry1 = (players[one].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[one].powers[pw_carry]);
+		carry2 = (players[two].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[two].powers[pw_carry]);
+
+		x = players[one].mo->x;
+		y = players[one].mo->y;
+		z = players[one].mo->z;
+		angle = players[one].mo->angle;
+
+		starpostx = players[one].starpostx;
+		starposty = players[one].starposty;
+		starpostz = players[one].starpostz;
+		starpostangle = players[one].starpostangle;
+		starpostnum = players[one].starpostnum;
+		starposttime = players[one].starposttime;
+
+		mflags2 = players[one].mo->flags2;
+
+		P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle,
+				players[two].starpostx, players[two].starposty, players[two].starpostz,
+				players[two].starpostnum, players[two].starposttime, players[two].starpostangle,
+				players[two].mo->flags2);
+
+		P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz,
+				starpostnum, starposttime, starpostangle,
+				mflags2);
+
+		//carry set after mixup.  Stupid P_ResetPlayer() takes away some of the stuff we look for...
+		//but not all of it!  So we need to make sure they aren't set wrong or anything.
+		players[one].powers[pw_carry] = carry2;
+		players[two].powers[pw_carry] = carry1;
+
+		teleported[one] = true;
+		teleported[two] = true;
+	}
+	else
+	{
+		fixed_t position[MAXPLAYERS][3];
+		angle_t anglepos[MAXPLAYERS];
+		INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0;
+
+		// Zoom tube stuff
+		mobj_t *transtracer[MAXPLAYERS];  //tracer
+		//pflags_t transflag[MAXPLAYERS]; //cyan pink white pink cyan
+		UINT16 transcarry[MAXPLAYERS];    //player carry
+		INT32 transspeed[MAXPLAYERS];     //player speed
+
+		// Star post stuff
+		INT16 spposition[MAXPLAYERS][3];
+		INT32 starpostnum[MAXPLAYERS];
+		tic_t starposttime[MAXPLAYERS];
+		angle_t starpostangle[MAXPLAYERS];
+
+		INT32 flags2[MAXPLAYERS];
+
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			position[i][0] = position[i][1] = position[i][2] = anglepos[i] = pindex[i] = -1;
+			teleported[i] = false;
+		}
+
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i] && players[i].playerstate == PST_LIVE
+				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+			{
+				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
+					continue;
+
+				position[counter][0] = players[i].mo->x;
+				position[counter][1] = players[i].mo->y;
+				position[counter][2] = players[i].mo->z;
+				pindex[counter] = i;
+				anglepos[counter] = players[i].mo->angle;
+				players[i].mo->momx = players[i].mo->momy = players[i].mo->momz =
+					players[i].rmomx = players[i].rmomy = 1;
+				players[i].cmomx = players[i].cmomy = 0;
+
+				transcarry[counter] = (players[i].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[i].powers[pw_carry]);
+				transspeed[counter] = players[i].speed;
+				transtracer[counter] = players[i].mo->tracer;
+
+				spposition[counter][0] = players[i].starpostx;
+				spposition[counter][1] = players[i].starposty;
+				spposition[counter][2] = players[i].starpostz;
+				starpostnum[counter] = players[i].starpostnum;
+				starposttime[counter] = players[i].starposttime;
+				starpostangle[counter] = players[i].starpostangle;
+
+				flags2[counter] = players[i].mo->flags2;
+
+				counter++;
+			}
+		}
+
+		counter = 0;
+
+		// Mix them up!
+		for (;;)
+		{
+			if (counter > 255) // fail-safe to avoid endless loop
+				break;
+			prandom = P_RandomByte();
+			prandom %= numplayers; // I love modular arithmetic, don't you?
+			if (prandom) // Make sure it's not a useless mix
+				break;
+			counter++;
+		}
+
+		counter = 0;
+
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i] && players[i].playerstate == PST_LIVE
+				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+			{
+				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
+					continue;
+
+				teleportfrom = (counter + prandom) % numplayers;
+
+				//speed and tracer come before...
+				players[i].speed = transspeed[teleportfrom];
+				P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]);
+
+				P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom],
+					spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2],
+					starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom],
+					flags2[teleportfrom]);
+
+				//...carry after.  same reasoning.
+				players[i].powers[pw_carry] = transcarry[teleportfrom];
+
+				teleported[i] = true;
+				counter++;
+			}
+		}
+	}
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (teleported[i])
+		{
+			if (playeringame[i] && players[i].playerstate == PST_LIVE
+				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+			{
+				if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
+					continue;
+
+				P_SetThingPosition(players[i].mo);
+
+#ifdef ESLOPE
+				players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
+				players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
+#else
+				players[i].mo->floorz = players[i].mo->subsector->sector->floorheight;
+				players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight;
+#endif
+
+				P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y);
+			}
+		}
+	}
+
+	// Play the 'bowrwoosh!' sound
+	S_StartSound(NULL, sfx_mixup);
+}
+
+// Function: A_RecyclePowers
+//
+// Description: Take all player's powers, and swap 'em.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_RecyclePowers(mobj_t *actor)
+{
+	INT32 i, j, k, numplayers = 0;
+
+#ifdef WEIGHTEDRECYCLER
+	UINT8 beneficiary = 255;
+#endif
+	UINT8 playerslist[MAXPLAYERS];
+	UINT8 postscramble[MAXPLAYERS];
+
+	UINT16 powers[MAXPLAYERS][NUMPOWERS];
+	INT32 weapons[MAXPLAYERS];
+	INT32 weaponheld[MAXPLAYERS];
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RecyclePowers", actor))
+		return;
+#endif
+
+#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA)
+	// actor is used in all scenarios but this one, funny enough
+	(void)actor;
+#endif
+
+	if (!multiplayer)
+	{
+		S_StartSound(actor, sfx_lose);
+		return;
+	}
+
+	numplayers = 0;
+
+	// Count the number of players in the game
+	for (i = 0, j = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
+			&& !players[i].exiting && !((netgame || multiplayer) && players[i].spectator))
+		{
+#ifndef WEIGHTEDRECYCLER
+			if (players[i].powers[pw_super])
+				continue; // Ignore super players
+#endif
+
+			numplayers++;
+			postscramble[j] = playerslist[j] = (UINT8)i;
+
+#ifdef WEIGHTEDRECYCLER
+			// The guy who started the recycle gets the best result
+			if (actor && actor->target && actor->target->player && &players[i] == actor->target->player)
+				beneficiary = (UINT8)i;
+#endif
+
+			// Save powers
+			for (k = 0; k < NUMPOWERS; k++)
+				powers[i][k] = players[i].powers[k];
+			//1.1: ring weapons too
+			weapons[i] = players[i].ringweapons;
+			weaponheld[i] = players[i].currentweapon;
+
+			j++;
+		}
+	}
+
+	if (numplayers <= 1)
+	{
+		S_StartSound(actor, sfx_lose);
+		return; //nobody to touch!
+	}
+
+	//shuffle the post scramble list, whee!
+	// hardcoded 0-1 to 1-0 for two players
+	if (numplayers == 2)
+	{
+		postscramble[0] = playerslist[1];
+		postscramble[1] = playerslist[0];
+	}
+	else
+	for (j = 0; j < numplayers; j++)
+	{
+		UINT8 tempint;
+
+		i = j + ((P_RandomByte() + leveltime) % (numplayers - j));
+		tempint = postscramble[j];
+		postscramble[j] = postscramble[i];
+		postscramble[i] = tempint;
+	}
+
+#ifdef WEIGHTEDRECYCLER
+	//the joys of qsort...
+	if (beneficiary != 255) {
+		qsort(playerslist, numplayers, sizeof(UINT8), P_RecycleCompare);
+
+		// now, make sure the benificiary is in the best slot
+		// swap out whatever poor sap was going to get the best items
+		for (i = 0; i < numplayers; i++)
+		{
+			if (postscramble[i] == beneficiary)
+			{
+				postscramble[i] = postscramble[0];
+				postscramble[0] = beneficiary;
+				break;
+			}
+		}
+	}
+#endif
+
+	// now assign!
+	for (i = 0; i < numplayers; i++)
+	{
+		UINT8 send_pl = playerslist[i];
+		UINT8 recv_pl = postscramble[i];
+
+		// debugF
+		CONS_Debug(DBG_GAMELOGIC, "sending player %hu's items to %hu\n", (UINT16)send_pl, (UINT16)recv_pl);
+
+		for (j = 0; j < NUMPOWERS; j++)
+		{
+			if (j == pw_flashing || j == pw_underwater || j == pw_spacetime || j == pw_carry
+			    || j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super)
+				continue;
+			players[recv_pl].powers[j] = powers[send_pl][j];
+		}
+
+		//1.1: weapon rings too
+		players[recv_pl].ringweapons = weapons[send_pl];
+		players[recv_pl].currentweapon = weaponheld[send_pl];
+
+		P_SpawnShieldOrb(&players[recv_pl]);
+		if (P_IsLocalPlayer(&players[recv_pl]))
+			P_RestoreMusic(&players[recv_pl]);
+		P_FlashPal(&players[recv_pl], PAL_RECYCLE, 10);
+	}
+
+	S_StartSound(NULL, sfx_gravch); //heh, the sound effect I used is already in
+}
+
+// Function: A_Boss1Chase
+//
+// Description: Like A_Chase, but for Boss 1.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss1Chase(mobj_t *actor)
+{
+	INT32 delta;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss1Chase", actor))
+		return;
+#endif
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
+		return;
+	}
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	// do not attack twice in a row
+	if (actor->flags2 & MF2_JUSTATTACKED)
+	{
+		actor->flags2 &= ~MF2_JUSTATTACKED;
+		P_NewChaseDir(actor);
+		return;
+	}
+
+	if (actor->movecount)
+		goto nomissile;
+
+	if (!P_CheckMissileRange(actor))
+		goto nomissile;
+
+	if (actor->reactiontime <= 0)
+	{
+		if (actor->health > actor->info->damage)
+		{
+			if (P_RandomChance(FRACUNIT/2))
+				P_SetMobjState(actor, actor->info->missilestate);
+			else
+				P_SetMobjState(actor, actor->info->meleestate);
+		}
+		else
+		{
+			P_LinedefExecute(LE_PINCHPHASE, actor, NULL);
+			P_SetMobjState(actor, actor->info->raisestate);
+		}
+
+		actor->flags2 |= MF2_JUSTATTACKED;
+		actor->reactiontime = actor->info->reactiontime;
+		return;
+	}
+
+	// ?
+nomissile:
+	// possibly choose another target
+	if (multiplayer && P_RandomChance(FRACUNIT/128))
+	{
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+	}
+
+	if (actor->flags & MF_FLOAT && !(actor->flags2 & MF2_SKULLFLY))
+	{ // Float up/down to your target's position. Stay above them, but not out of jump range.
+		fixed_t target_min = actor->target->floorz+FixedMul(64*FRACUNIT, actor->scale);
+		if (target_min < actor->target->z - actor->height)
+			target_min = actor->target->z - actor->height;
+		if (target_min < actor->floorz+FixedMul(33*FRACUNIT, actor->scale))
+			target_min = actor->floorz+FixedMul(33*FRACUNIT, actor->scale);
+		if (actor->z > target_min+FixedMul(16*FRACUNIT, actor->scale))
+			actor->momz = FixedMul((-actor->info->speed<<(FRACBITS-1)), actor->scale);
+		else if (actor->z < target_min)
+			actor->momz = FixedMul(actor->info->speed<<(FRACBITS-1), actor->scale);
+		else
+			actor->momz = FixedMul(actor->momz,7*FRACUNIT/8);
+	}
+
+	// chase towards player
+	if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius)
+	{
+		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+			P_NewChaseDir(actor);
+	}
+	// too close, don't want to chase.
+	else if (--actor->movecount < 0)
+	{
+		// A mini-A_FaceTarget based on P_NewChaseDir.
+		// Yes, it really is this simple when you get down to it.
+		fixed_t deltax, deltay;
+
+		deltax = actor->target->x - actor->x;
+		deltay = actor->target->y - actor->y;
+
+		actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)];
+		actor->movecount = P_RandomByte() & 15;
+	}
+}
+
+// Function: A_Boss2Chase
+//
+// Description: Really doesn't 'chase', but rather goes in a circle.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss2Chase(mobj_t *actor)
+{
+	fixed_t radius;
+	boolean reverse = false;
+	INT32 speedvar;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss2Chase", actor))
+		return;
+#endif
+
+	if (actor->health <= 0)
+		return;
+
+	// Startup randomness
+	if (actor->reactiontime <= -666)
+		actor->reactiontime = 2*TICRATE + P_RandomByte();
+
+	// When reactiontime hits zero, he will go the other way
+	if (--actor->reactiontime <= 0)
+	{
+		reverse = true;
+		actor->reactiontime = 2*TICRATE + P_RandomByte();
+	}
+
+	P_SetTarget(&actor->target, P_GetClosestAxis(actor));
+
+	if (!actor->target) // This should NEVER happen.
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Boss2 has no target!\n");
+		A_BossDeath(actor);
+		return;
+	}
+
+	radius = actor->target->radius;
+
+	if (reverse)
+	{
+		actor->watertop = -actor->watertop;
+		actor->extravalue1 = 18;
+		if (actor->flags2 & MF2_AMBUSH)
+			actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2;
+		actor->extravalue2 = actor->extravalue1;
+	}
+
+	// Turnaround
+	if (actor->extravalue1 > 0)
+	{
+		--actor->extravalue1;
+
+		// Set base angle
+		{
+			const angle_t fa = (actor->target->angle + FixedAngle(actor->watertop))>>ANGLETOFINESHIFT;
+			const fixed_t fc = FixedMul(FINECOSINE(fa),radius);
+			const fixed_t fs = FixedMul(FINESINE(fa),radius);
+			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs);
+		}
+
+		// Now turn you around!
+		// Note that the start position is the final position, we move it back around
+		// to intermediary positions...
+		actor->angle -= FixedAngle(FixedMul(FixedDiv(180<<FRACBITS, actor->extravalue2<<FRACBITS), actor->extravalue1<<FRACBITS));
+	}
+	else
+	{
+		// Only speed up if you have the 'Deaf' flag.
+		if (actor->flags2 & MF2_AMBUSH)
+			speedvar = actor->health;
+		else
+			speedvar = actor->info->spawnhealth;
+
+		actor->target->angle += // Don't use FixedAngleC!
+			FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT));
+
+		P_UnsetThingPosition(actor);
+		{
+			const angle_t fa = actor->target->angle>>ANGLETOFINESHIFT;
+			const fixed_t fc = FixedMul(FINECOSINE(fa),radius);
+			const fixed_t fs = FixedMul(FINESINE(fa),radius);
+			actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs);
+			actor->x = actor->target->x + fc;
+			actor->y = actor->target->y + fs;
+		}
+		P_SetThingPosition(actor);
+
+		// Spray goo once every second
+		if (leveltime % (speedvar*15/10)-1 == 0)
+		{
+			const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale);
+			mobj_t *goop;
+			fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale);
+			angle_t fa;
+			// actor->movedir is used to determine the last
+			// direction goo was sprayed in. There are 8 possible
+			// directions to spray. (45-degree increments)
+
+			actor->movedir++;
+			actor->movedir %= NUMDIRS;
+			fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
+
+			goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
+			goop->momx = FixedMul(FINECOSINE(fa),ns);
+			goop->momy = FixedMul(FINESINE(fa),ns);
+			goop->momz = FixedMul(4*FRACUNIT, actor->scale);
+			goop->fuse = 10*TICRATE;
+
+			if (actor->info->attacksound)
+				S_StartAttackSound(actor, actor->info->attacksound);
+
+			if (P_RandomChance(FRACUNIT/2))
+			{
+				goop->momx *= 2;
+				goop->momy *= 2;
+			}
+			else if (P_RandomChance(129*FRACUNIT/256))
+			{
+				goop->momx *= 3;
+				goop->momy *= 3;
+			}
+
+			actor->flags2 |= MF2_JUSTATTACKED;
+		}
+	}
+}
+
+// Function: A_Boss2Pogo
+//
+// Description: Pogo part of Boss 2 AI.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss2Pogo(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss2Pogo", actor))
+		return;
+#endif
+	if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0)
+	{
+		if (actor->state != &states[actor->info->raisestate])
+			P_SetMobjState(actor, actor->info->raisestate);
+		// Pogo Mode
+	}
+	else if (actor->momz < 0 && actor->reactiontime)
+	{
+		const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale);
+		mobj_t *goop;
+		fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale);
+		angle_t fa;
+		INT32 i;
+		// spray in all 8 directions!
+		for (i = 0; i < 8; i++)
+		{
+			actor->movedir++;
+			actor->movedir %= NUMDIRS;
+			fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
+
+			goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
+			goop->momx = FixedMul(FINECOSINE(fa),ns);
+			goop->momy = FixedMul(FINESINE(fa),ns);
+			goop->momz = FixedMul(4*FRACUNIT, actor->scale);
+
+			goop->fuse = 10*TICRATE;
+		}
+		actor->reactiontime = 0; // we already shot goop, so don't do it again!
+		if (actor->info->attacksound)
+			S_StartAttackSound(actor, actor->info->attacksound);
+		actor->flags2 |= MF2_JUSTATTACKED;
+	}
+}
+
+// Function: A_Boss2TakeDamage
+//
+// Description: Special function for Boss 2 so you can't just sit and destroy him.
+//
+// var1 = Invincibility duration
+// var2 = unused
+//
+void A_Boss2TakeDamage(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss2TakeDamage", actor))
+		return;
+#endif
+	A_Pain(actor);
+	actor->reactiontime = 1; // turn around
+	if (locvar1 == 0) // old A_Invincibilerize behavior
+		actor->movecount = TICRATE;
+	else
+		actor->movecount = locvar1; // become flashing invulnerable for this long.
+}
+
+// Function: A_Boss7Chase
+//
+// Description: Like A_Chase, but for Black Eggman
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss7Chase(mobj_t *actor)
+{
+	INT32 delta;
+	INT32 i;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss7Chase", actor))
+		return;
+#endif
+
+	if (actor->z != actor->floorz)
+		return;
+
+	// Self-adjust if stuck on the edge
+	if (actor->tracer)
+	{
+		if (P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y) > 128*FRACUNIT - actor->radius)
+			P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), FRACUNIT);
+	}
+
+	if (actor->flags2 & MF2_FRET)
+	{
+		P_SetMobjState(actor, S_BLACKEGG_DESTROYPLAT1);
+		S_StartSound(0, sfx_s3k53);
+		actor->flags2 &= ~MF2_FRET;
+		return;
+	}
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	// Is a player on top of us?
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i] || players[i].spectator)
+			continue;
+
+		if (!players[i].mo)
+			continue;
+
+		if (players[i].mo->health <= 0)
+			continue;
+
+		if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) > actor->radius)
+			continue;
+
+		if (players[i].mo->z > actor->z + actor->height - 2*FRACUNIT
+			&& players[i].mo->z < actor->z + actor->height + 32*FRACUNIT)
+		{
+			// Punch him!
+			P_SetMobjState(actor, actor->info->meleestate);
+			S_StartSound(0, sfx_begrnd); // warning sound
+			return;
+		}
+	}
+
+	if (actor->health <= actor->info->damage
+		&& actor->target
+		&& actor->target->player
+		&& (actor->target->player->powers[pw_carry] == CR_GENERIC))
+	{
+		A_FaceTarget(actor);
+		P_SetMobjState(actor, S_BLACKEGG_SHOOT1);
+		actor->movecount = TICRATE + P_RandomByte()/2;
+		return;
+	}
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	if (actor->reactiontime <= 0 && actor->z == actor->floorz)
+	{
+		// Here, we'll call P_RandomByte() and decide what kind of attack to do
+		switch(actor->threshold)
+		{
+			case 0: // Lob cannon balls
+				if (actor->z < 1056*FRACUNIT)
+				{
+					A_FaceTarget(actor);
+					P_SetMobjState(actor, actor->info->xdeathstate);
+					actor->movecount = 7*TICRATE + P_RandomByte();
+					break;
+				}
+				actor->threshold++;
+				/* FALLTHRU */
+			case 1: // Chaingun Goop
+				A_FaceTarget(actor);
+				P_SetMobjState(actor, S_BLACKEGG_SHOOT1);
+
+				if (actor->health > actor->info->damage)
+					actor->movecount = TICRATE + P_RandomByte()/3;
+				else
+					actor->movecount = TICRATE + P_RandomByte()/2;
+				break;
+			case 2: // Homing Missile
+				A_FaceTarget(actor);
+				P_SetMobjState(actor, actor->info->missilestate);
+				S_StartSound(0, sfx_beflap);
+				break;
+		}
+
+		actor->threshold++;
+		actor->threshold %= 3;
+		return;
+	}
+
+	// possibly choose another target
+	if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+		&& P_BossTargetPlayer(actor, false))
+		return; // got a new target
+
+	if (leveltime & 1)
+	{
+		// chase towards player
+		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+			P_NewChaseDir(actor);
+	}
+}
+
+// Function: A_GoopSplat
+//
+// Description: Black Eggman goop hits a target and sticks around for awhile.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GoopSplat(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GoopSplat", actor))
+		return;
+#endif
+	P_UnsetThingPosition(actor);
+	if (sector_list)
+	{
+		P_DelSeclist(sector_list);
+		sector_list = NULL;
+	}
+	actor->flags = MF_SPECIAL; // Not a typo
+	P_SetThingPosition(actor);
+}
+
+// Function: A_Boss2PogoSFX
+//
+// Description: Pogoing for Boss 2
+//
+// var1 = pogo jump strength
+// var2 = idle pogo speed
+//
+void A_Boss2PogoSFX(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss2PogoSFX", actor))
+		return;
+#endif
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		return;
+	}
+
+	// Boing!
+	if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(256*FRACUNIT, actor->scale))
+	{
+		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale));
+		// pogo on player
+	}
+	else
+	{
+		UINT8 prandom = P_RandomByte();
+		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom);
+		P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale));
+	}
+	if (actor->info->activesound) S_StartSound(actor, actor->info->activesound);
+	actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
+	actor->reactiontime = 1;
+}
+
+// Function: A_Boss2PogoTarget
+//
+// Description: Pogoing for Boss 2, tries to actually land on the player directly.
+//
+// var1 = pogo jump strength
+// var2 = idle pogo speed
+//
+void A_Boss2PogoTarget(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss2PogoTarget", actor))
+		return;
+#endif
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing])
+	|| P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) >= FixedMul(512*FRACUNIT, actor->scale))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 512*FRACUNIT))
+			; // got a new target
+		else if (P_LookForPlayers(actor, true, false, 0))
+			; // got a new target
+		else
+			return;
+	}
+
+	// Target hit, retreat!
+	if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET)
+	{
+		UINT8 prandom = P_RandomByte();
+		actor->z++; // unstick from the floor
+		actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
+		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it.
+		P_InstaThrust(actor, actor->angle+ANGLE_180, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed
+	}
+	// Try to land on top of the player.
+	else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale))
+	{
+		fixed_t airtime, gravityadd, zoffs;
+
+		// check gravity in the sector (for later math)
+		P_CheckGravity(actor, true);
+		gravityadd = actor->momz;
+
+		actor->z++; // unstick from the floor
+		actor->momz = FixedMul(locvar1 + (locvar1>>2), actor->scale); // Bounce up in air
+
+		/*badmath = 0;
+		airtime = 0;
+		do {
+			badmath += momz;
+			momz += gravityadd;
+			airtime++;
+		} while(badmath > 0);
+		airtime = 2*airtime<<FRACBITS;
+		*/
+
+		// Remember, kids!
+		// Reduced down Calculus lets you avoid bad 'logic math' loops!
+		//airtime = FixedDiv(-actor->momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler
+		zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height,
+		airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet
+
+		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		P_InstaThrust(actor, actor->angle, FixedDiv(P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y), airtime));
+	}
+	// Wander semi-randomly towards the player to get closer.
+	else
+	{
+		UINT8 prandom = P_RandomByte();
+		actor->z++; // unstick from the floor
+		actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air
+		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it.
+		P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed
+	}
+	// Boing!
+	if (actor->info->activesound) S_StartSound(actor, actor->info->activesound);
+
+	if (actor->info->missilestate) // spawn the pogo stick collision box
+	{
+		mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
+		pogo->target = actor;
+	}
+
+	actor->reactiontime = 1;
+}
+
+// Function: A_EggmanBox
+//
+// Description: Harms the player
+//
+// var1 = unused
+// var2 = unused
+//
+void A_EggmanBox(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_EggmanBox", actor))
+		return;
+#endif
+	if (!actor->target || !actor->target->player)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
+		return;
+	}
+
+	P_DamageMobj(actor->target, actor, actor, 1, 0); // Ow!
+}
+
+// Function: A_TurretFire
+//
+// Description: Initiates turret fire.
+//
+// var1 = object # to repeatedly fire
+// var2 = distance threshold
+//
+void A_TurretFire(mobj_t *actor)
+{
+	INT32 count = 0;
+	fixed_t dist;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_TurretFire", actor))
+		return;
+#endif
+
+	if (locvar2)
+		dist = FixedMul(locvar2*FRACUNIT, actor->scale);
+	else
+		dist = FixedMul(2048*FRACUNIT, actor->scale);
+
+	if (!locvar1)
+		locvar1 = MT_TURRETLASER;
+
+	while (P_SupermanLook4Players(actor) && count < MAXPLAYERS)
+	{
+		if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist)
+		{
+			actor->flags2 |= MF2_FIRING;
+			actor->extravalue1 = locvar1;
+			break;
+		}
+
+		count++;
+	}
+}
+
+// Function: A_SuperTurretFire
+//
+// Description: Initiates turret fire that even stops Super Sonic.
+//
+// var1 = object # to repeatedly fire
+// var2 = distance threshold
+//
+void A_SuperTurretFire(mobj_t *actor)
+{
+	INT32 count = 0;
+	fixed_t dist;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SuperTurretFire", actor))
+		return;
+#endif
+
+	if (locvar2)
+		dist = FixedMul(locvar2*FRACUNIT, actor->scale);
+	else
+		dist = FixedMul(2048*FRACUNIT, actor->scale);
+
+	if (!locvar1)
+		locvar1 = MT_TURRETLASER;
+
+	while (P_SupermanLook4Players(actor) && count < MAXPLAYERS)
+	{
+		if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist)
+		{
+			actor->flags2 |= MF2_FIRING;
+			actor->flags2 |= MF2_SUPERFIRE;
+			actor->extravalue1 = locvar1;
+			break;
+		}
+
+		count++;
+	}
+}
+
+// Function: A_TurretStop
+//
+// Description: Stops the turret fire.
+//
+// var1 = Don't play activesound?
+// var2 = unused
+//
+void A_TurretStop(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_TurretStop", actor))
+		return;
+#endif
+
+	actor->flags2 &= ~MF2_FIRING;
+	actor->flags2 &= ~MF2_SUPERFIRE;
+
+	if (actor->target && actor->info->activesound && !locvar1)
+		S_StartSound(actor, actor->info->activesound);
+}
+
+// Function: A_SparkFollow
+//
+// Description: Used by the hyper sparks to rotate around their target.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SparkFollow(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SparkFollow", actor))
+		return;
+#endif
+
+	if ((!actor->target || (actor->target->health <= 0))
+		|| (actor->target->player && !actor->target->player->powers[pw_super]))
+	{
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	actor->angle += FixedAngle(actor->info->damage*FRACUNIT);
+	P_UnsetThingPosition(actor);
+	{
+		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
+		actor->x = actor->target->x + FixedMul(FINECOSINE(fa),FixedMul(actor->info->speed, actor->scale));
+		actor->y = actor->target->y + FixedMul(FINESINE(fa),FixedMul(actor->info->speed, actor->scale));
+		if (actor->target->eflags & MFE_VERTICALFLIP)
+			actor->z = actor->target->z + actor->target->height - FixedDiv(actor->target->height,3*FRACUNIT);
+		else
+			actor->z = actor->target->z + FixedDiv(actor->target->height,3*FRACUNIT) - actor->height;
+	}
+	P_SetThingPosition(actor);
+}
+
+// Function: A_BuzzFly
+//
+// Description: Makes an object slowly fly after a player, in the manner of a Buzz.
+//
+// var1 = sfx to play
+// var2 = length of sfx, set to threshold if played
+//
+void A_BuzzFly(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BuzzFly", actor))
+		return;
+#endif
+	if (actor->flags2 & MF2_AMBUSH)
+		return;
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		actor->momz = actor->momy = actor->momx = 0;
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// turn towards movement direction if not there yet
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+
+	if (actor->target->health <= 0 || (!actor->threshold && !P_CheckSight(actor, actor->target)))
+	{
+		if ((multiplayer || netgame) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)))
+			return; // got a new target
+
+		actor->momx = actor->momy = actor->momz = 0;
+		P_SetMobjState(actor, actor->info->spawnstate); // Go back to looking around
+		return;
+	}
+
+	// If the player is over 3072 fracunits away, then look for another player
+	if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y),
+		actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale))
+	{
+		if (multiplayer || netgame)
+			P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)); // maybe get a new target
+
+		return;
+	}
+
+	// chase towards player
+	{
+		INT32 dist, realspeed;
+		const fixed_t mf = 5*(FRACUNIT/4);
+
+		if (ultimatemode)
+			realspeed = FixedMul(FixedMul(actor->info->speed,mf), actor->scale);
+		else
+			realspeed = FixedMul(actor->info->speed, actor->scale);
+
+		dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x,
+			actor->target->y - actor->y), actor->target->z - actor->z);
+
+		if (dist < 1)
+			dist = 1;
+
+		actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), realspeed);
+		actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), realspeed);
+		actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), realspeed);
+
+		if (actor->z+actor->momz >= actor->waterbottom && actor->watertop > actor->floorz
+			&& actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)
+			&& actor->z+actor->momz <= actor->watertop)
+		{
+			actor->momz = 0;
+			actor->z = actor->watertop;
+		}
+	}
+
+	if (locvar1 != sfx_None && !actor->threshold)
+	{
+		S_StartSound(actor, locvar1);
+		actor->threshold = locvar2;
+	}
+}
+
+// Function: A_GuardChase
+//
+// Description: Modified A_Chase for Egg Guard
+//
+// var1 = unused
+// var2 = unused
+//
+void A_GuardChase(mobj_t *actor)
+{
+	INT32 delta;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GuardChase", actor))
+		return;
+#endif
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+
+	if (actor->threshold != 42) // In formation...
+	{
+		fixed_t speed;
+
+		if (!actor->tracer || !actor->tracer->health)
+		{
+			P_SetTarget(&actor->tracer, NULL);
+			actor->threshold = 42;
+			P_SetMobjState(actor, actor->info->painstate);
+			actor->flags |= MF_SPECIAL|MF_SHOOTABLE;
+			return;
+		}
+
+		speed = actor->extravalue1*actor->scale;
+
+		if (actor->flags2 & MF2_AMBUSH)
+			speed <<= 1;
+
+		if (speed
+		&& !P_TryMove(actor,
+			actor->x + P_ReturnThrustX(actor, actor->angle, speed),
+			actor->y + P_ReturnThrustY(actor, actor->angle, speed),
+			false)
+		&& speed > 0) // can't be the same check as previous so that P_TryMove gets to happen.
+		{
+			if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL))
+				actor->angle += ANGLE_90;
+			else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA))
+				actor->angle -= ANGLE_90;
+			else
+				actor->angle += ANGLE_180;
+		}
+
+		if (actor->extravalue1 < actor->info->speed)
+			actor->extravalue1++;
+	}
+	else // Break ranks!
+	{
+		// turn towards movement direction if not there yet
+		if (actor->movedir < NUMDIRS)
+		{
+			actor->angle &= (7<<29);
+			delta = actor->angle - (actor->movedir << 29);
+
+			if (delta > 0)
+				actor->angle -= ANGLE_45;
+			else if (delta < 0)
+				actor->angle += ANGLE_45;
+		}
+
+		if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+		{
+			// look for a new target
+			if (P_LookForPlayers(actor, true, false, 0))
+				return; // got a new target
+
+			P_SetMobjStateNF(actor, actor->info->spawnstate);
+			return;
+		}
+
+		// possibly choose another target
+		if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+			&& P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		// chase towards player
+		if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed))
+		{
+			P_NewChaseDir(actor);
+			actor->movecount += 5; // Increase tics before change in direction allowed.
+		}
+	}
+
+	// Now that we've moved, its time for our shield to move!
+	// Otherwise it'll never act as a proper overlay.
+	if (actor->tracer && actor->tracer->state
+	&& actor->tracer->state->action.acp1)
+	{
+		var1 = actor->tracer->state->var1, var2 = actor->tracer->state->var2;
+		actor->tracer->state->action.acp1(actor->tracer);
+	}
+}
+
+// Function: A_EggShield
+//
+// Description: Modified A_Chase for Egg Guard's shield
+//
+// var1 = unused
+// var2 = unused
+//
+void A_EggShield(mobj_t *actor)
+{
+	INT32 i;
+	player_t *player;
+	fixed_t blockdist;
+	fixed_t newx, newy;
+	fixed_t movex, movey;
+	angle_t angle;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_EggShield", actor))
+		return;
+#endif
+
+	if (!actor->target || !actor->target->health)
+	{
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	newx = actor->target->x + P_ReturnThrustX(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale));
+	newy = actor->target->y + P_ReturnThrustY(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale));
+
+	movex = newx - actor->x;
+	movey = newy - actor->y;
+
+	actor->angle = actor->target->angle;
+	if (actor->target->eflags & MFE_VERTICALFLIP)
+	{
+		actor->eflags |= MFE_VERTICALFLIP;
+		actor->z = actor->target->z + actor->target->height - actor->height;
+	}
+	else
+		actor->z = actor->target->z;
+
+	actor->destscale = actor->target->destscale;
+	P_SetScale(actor, actor->target->scale);
+
+	actor->floorz = actor->target->floorz;
+	actor->ceilingz = actor->target->ceilingz;
+
+	if (!movex && !movey)
+		return;
+
+	P_UnsetThingPosition(actor);
+	actor->x = newx;
+	actor->y = newy;
+	P_SetThingPosition(actor);
+
+	// Search for players to push
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i] || players[i].spectator)
+			continue;
+
+		player = &players[i];
+
+		if (!player->mo)
+			continue;
+
+		if (player->mo->z > actor->z + actor->height)
+			continue;
+
+		if (player->mo->z + player->mo->height < actor->z)
+			continue;
+
+		blockdist = actor->radius + player->mo->radius;
+
+		if (abs(actor->x - player->mo->x) >= blockdist || abs(actor->y - player->mo->y) >= blockdist)
+			continue; // didn't hit it
+
+		angle = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle;
+
+		if (angle > ANGLE_90 && angle < ANGLE_270)
+			continue;
+
+		// Blocked by the shield
+		player->mo->momx += movex;
+		player->mo->momy += movey;
+		return;
+	}
+}
+
+
+// Function: A_SetReactionTime
+//
+// Description: Sets the object's reaction time.
+//
+// var1 = 1 (use value in var2); 0 (use info table value)
+// var2 = if var1 = 1, then value to set
+//
+void A_SetReactionTime(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetReactionTime", actor))
+		return;
+#endif
+	if (var1)
+		actor->reactiontime = var2;
+	else
+		actor->reactiontime = actor->info->reactiontime;
+}
+
+// Function: A_Boss1Spikeballs
+//
+// Description: Boss 1 spikeball spawning loop.
+//
+// var1 = ball number
+// var2 = total balls
+//
+void A_Boss1Spikeballs(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *ball;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss1Spikeballs", actor))
+		return;
+#endif
+
+	ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL);
+	P_SetTarget(&ball->target, actor);
+	ball->movedir = FixedAngle(FixedMul(FixedDiv(locvar1<<FRACBITS, locvar2<<FRACBITS), 360<<FRACBITS));
+	ball->threshold = ball->radius + actor->radius + ball->info->painchance;
+
+	S_StartSound(ball, ball->info->seesound);
+	var1 = ball->state->var1, var2 = ball->state->var2;
+	ball->state->action.acp1(ball);
+}
+
+// Function: A_Boss3TakeDamage
+//
+// Description: Called when Boss 3 takes damage.
+//
+// var1 = movecount value
+// var2 = unused
+//
+void A_Boss3TakeDamage(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss3TakeDamage", actor))
+		return;
+#endif
+	actor->movecount = var1;
+
+	if (actor->target && actor->target->spawnpoint)
+		actor->threshold = actor->target->spawnpoint->extrainfo;
+}
+
+// Function: A_Boss3Path
+//
+// Description: Does pathfinding along Boss 3's nodes.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss3Path(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss3Path", actor))
+		return;
+#endif
+
+	if (actor->tracer && actor->tracer->health && actor->tracer->movecount)
+		actor->movecount |= 1;
+	else if (actor->movecount & 1)
+		actor->movecount = 0;
+
+	if (actor->movecount & 2) // We've reached a firing point?
+	{
+		// Wait here and pretend to be angry or something.
+		actor->momx = 0;
+		actor->momy = 0;
+		actor->momz = 0;
+		P_SetTarget(&actor->target, actor->tracer->target);
+		var1 = 0, var2 = 0;
+		A_FaceTarget(actor);
+		if (actor->tracer->state == &states[actor->tracer->info->missilestate])
+			P_SetMobjState(actor, actor->info->missilestate);
+		return;
+	}
+	else if (actor->threshold >= 0) // Traveling mode
+	{
+		thinker_t *th;
+		mobj_t *mo2;
+		fixed_t dist, dist2;
+		fixed_t speed;
+
+		P_SetTarget(&actor->target, NULL);
+
+		// scan the thinkers
+		// to find a point that matches
+		// the number
+		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		{
+			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+				continue;
+
+			mo2 = (mobj_t *)th;
+			if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold)
+			{
+				P_SetTarget(&actor->target, mo2);
+				break;
+			}
+		}
+
+		if (!actor->target) // Should NEVER happen
+		{
+			CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold);
+			return;
+		}
+
+		dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
+
+		if (dist < 1)
+			dist = 1;
+
+		if (actor->tracer && ((actor->tracer->movedir)
+		|| (actor->tracer->health <= actor->tracer->info->damage)))
+			speed = actor->info->speed * 2;
+		else
+			speed = actor->info->speed;
+
+		actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed);
+		actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed);
+		actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed);
+
+		if (actor->momx != 0 || actor->momy != 0)
+			actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
+
+		dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz));
+
+		if (dist2 < 1)
+			dist2 = 1;
+
+		if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
+		{
+			// If further away, set XYZ of mobj to waypoint location
+			P_UnsetThingPosition(actor);
+			actor->x = actor->target->x;
+			actor->y = actor->target->y;
+			actor->z = actor->target->z;
+			actor->momx = actor->momy = actor->momz = 0;
+			P_SetThingPosition(actor);
+
+			if (actor->threshold == 0)
+			{
+				P_RemoveMobj(actor); // Cycle completed. Dummy removed.
+				return;
+			}
+
+			// Set to next waypoint in sequence
+			if (actor->target->spawnpoint)
+			{
+				// From the center point, choose one of the five paths
+				if (actor->target->spawnpoint->angle == 0)
+				{
+					P_RemoveMobj(actor); // Cycle completed. Dummy removed.
+					return;
+				}
+				else
+					actor->threshold = actor->target->spawnpoint->extrainfo;
+
+				// If the deaf flag is set, go into firing mode
+				if (actor->target->spawnpoint->options & MTF_AMBUSH)
+					actor->movecount |= 2;
+			}
+			else // This should never happen, as well
+				CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n");
+		}
+	}
+}
+
+// Function: A_LinedefExecute
+//
+// Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well.
+//
+// var1 = tag
+// var2 = add angle to tag (optional)
+//
+void A_LinedefExecute(mobj_t *actor)
+{
+	INT32 tagnum;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_LinedefExecute", actor))
+		return;
+#endif
+
+	tagnum = locvar1;
+	// state numbers option is no more, custom states cannot be guaranteed to stay the same number anymore, now that they can be defined by names instead
+
+	if (locvar2)
+		tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS);
+
+	CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum);
+
+	// tag 32768 displayed in map editors is actually tag -32768, tag 32769 is -32767, 65535 is -1 etc.
+	P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector);
+}
+
+// Function: A_PlaySeeSound
+//
+// Description: Plays the object's seesound.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_PlaySeeSound(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PlaySeeSound", actor))
+		return;
+#endif
+	if (actor->info->seesound)
+		S_StartScreamSound(actor, actor->info->seesound);
+}
+
+// Function: A_PlayAttackSound
+//
+// Description: Plays the object's attacksound.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_PlayAttackSound(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PlayAttackSound", actor))
+		return;
+#endif
+	if (actor->info->attacksound)
+		S_StartAttackSound(actor, actor->info->attacksound);
+}
+
+// Function: A_PlayActiveSound
+//
+// Description: Plays the object's activesound.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_PlayActiveSound(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PlayActiveSound", actor))
+		return;
+#endif
+	if (actor->info->activesound)
+		S_StartSound(actor, actor->info->activesound);
+}
+
+// Function: A_SmokeTrailer
+//
+// Description: Adds smoke trails to an object.
+//
+// var1 = object # to spawn as smoke
+// var2 = unused
+//
+void A_SmokeTrailer(mobj_t *actor)
+{
+	mobj_t *th;
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SmokeTrailer", actor))
+		return;
+#endif
+
+	if (leveltime % 4)
+		return;
+
+	// add the smoke behind the rocket
+	if (actor->eflags & MFE_VERTICALFLIP)
+	{
+		th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z + actor->height - FixedMul(mobjinfo[locvar1].height, actor->scale), locvar1);
+		th->flags2 |= MF2_OBJECTFLIP;
+	}
+	else
+		th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z, locvar1);
+	P_SetObjectMomZ(th, FRACUNIT, false);
+	th->destscale = actor->scale;
+	P_SetScale(th, actor->scale);
+	th->tics -= P_RandomByte() & 3;
+	if (th->tics < 1)
+		th->tics = 1;
+}
+
+// Function: A_SpawnObjectAbsolute
+//
+// Description: Spawns an object at an absolute position
+//
+// var1:
+//		var1 >> 16 = x
+//		var1 & 65535 = y
+// var2:
+//		var2 >> 16 = z
+//		var2 & 65535 = type
+//
+void A_SpawnObjectAbsolute(mobj_t *actor)
+{
+	INT16 x, y, z; // Want to be sure we can use negative values
+	mobjtype_t type;
+	mobj_t *mo;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpawnObjectAbsolute", actor))
+		return;
+#endif
+
+	x = (INT16)(locvar1>>16);
+	y = (INT16)(locvar1&65535);
+	z = (INT16)(locvar2>>16);
+	type = (mobjtype_t)(locvar2&65535);
+
+	mo = P_SpawnMobj(x<<FRACBITS, y<<FRACBITS, z<<FRACBITS, type);
+
+	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
+	mo->angle = actor->angle;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		mo->flags2 |= MF2_OBJECTFLIP;
+}
+
+// Function: A_SpawnObjectRelative
+//
+// Description: Spawns an object relative to the location of the actor
+//
+// var1:
+//		var1 >> 16 = x
+//		var1 & 65535 = y
+// var2:
+//		var2 >> 16 = z
+//		var2 & 65535 = type
+//
+void A_SpawnObjectRelative(mobj_t *actor)
+{
+	INT16 x, y, z; // Want to be sure we can use negative values
+	mobjtype_t type;
+	mobj_t *mo;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpawnObjectRelative", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	x = (INT16)(locvar1>>16);
+	y = (INT16)(locvar1&65535);
+	z = (INT16)(locvar2>>16);
+	type = (mobjtype_t)(locvar2&65535);
+
+	// Spawn objects correctly in reverse gravity.
+	// NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame
+	mo = P_SpawnMobj(actor->x + FixedMul(x<<FRACBITS, actor->scale),
+		actor->y + FixedMul(y<<FRACBITS, actor->scale),
+		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), type);
+
+	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
+	mo->angle = actor->angle;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		mo->flags2 |= MF2_OBJECTFLIP;
+
+}
+
+// Function: A_ChangeAngleRelative
+//
+// Description: Changes the angle to a random relative value between the min and max. Set min and max to the same value to eliminate randomness
+//
+// var1 = min
+// var2 = max
+//
+void A_ChangeAngleRelative(mobj_t *actor)
+{
+	// Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of
+	//  getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result
+	//  rather than the ranges, so <0 and >360 work as possible values. -Red
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	//angle_t angle = (P_RandomByte()+1)<<24;
+	const fixed_t amin = locvar1*FRACUNIT;
+	const fixed_t amax = locvar2*FRACUNIT;
+	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
+	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ChangeAngleRelative", actor))
+		return;
+#endif
+
+#ifdef PARANOIA
+	if (amin > amax)
+		I_Error("A_ChangeAngleRelative: var1 is greater then var2");
+#endif
+/*
+	if (angle < amin)
+		angle = amin;
+	if (angle > amax)
+		angle = amax;*/
+
+	actor->angle += FixedAngle(P_RandomRange(amin, amax));
+}
+
+// Function: A_ChangeAngleAbsolute
+//
+// Description: Changes the angle to a random absolute value between the min and max. Set min and max to the same value to eliminate randomness
+//
+// var1 = min
+// var2 = max
+//
+void A_ChangeAngleAbsolute(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	//angle_t angle = (P_RandomByte()+1)<<24;
+	const fixed_t amin = locvar1*FRACUNIT;
+	const fixed_t amax = locvar2*FRACUNIT;
+	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
+	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ChangeAngleAbsolute", actor))
+		return;
+#endif
+
+#ifdef PARANOIA
+	if (amin > amax)
+		I_Error("A_ChangeAngleAbsolute: var1 is greater then var2");
+#endif
+/*
+	if (angle < amin)
+		angle = amin;
+	if (angle > amax)
+		angle = amax;*/
+
+	actor->angle = FixedAngle(P_RandomRange(amin, amax));
+}
+
+// Function: A_PlaySound
+//
+// Description: Plays a sound
+//
+// var1 = sound # to play
+// var2:
+//		0 = Play sound without an origin
+//		1 = Play sound using calling object as origin
+//
+void A_PlaySound(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PlaySound", actor))
+		return;
+#endif
+
+	S_StartSound(locvar2 ? actor : NULL, locvar1);
+}
+
+// Function: A_FindTarget
+//
+// Description: Finds the nearest/furthest mobj of the specified type and sets actor->target to it.
+//
+// var1 = mobj type
+// var2 = if (0) nearest; else furthest;
+//
+void A_FindTarget(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *targetedmobj = NULL;
+	thinker_t *th;
+	mobj_t *mo2;
+	fixed_t dist1 = 0, dist2 = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FindTarget", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	// scan the thinkers
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2->type == (mobjtype_t)locvar1)
+		{
+			if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS))
+				continue; // Ignore spectators
+			if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0)
+				continue; // Ignore dead things
+			if (targetedmobj == NULL)
+			{
+				targetedmobj = mo2;
+				dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+			}
+			else
+			{
+				dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+
+				if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2))
+				{
+					targetedmobj = mo2;
+					dist2 = dist1;
+				}
+			}
+		}
+	}
+
+	if (!targetedmobj)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Unable to find the specified object to target.\n");
+		return; // Oops, nothing found..
+	}
+
+	CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Found a target.\n");
+
+	P_SetTarget(&actor->target, targetedmobj);
+}
+
+// Function: A_FindTracer
+//
+// Description: Finds the nearest/furthest mobj of the specified type and sets actor->tracer to it.
+//
+// var1 = mobj type
+// var2 = if (0) nearest; else furthest;
+//
+void A_FindTracer(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *targetedmobj = NULL;
+	thinker_t *th;
+	mobj_t *mo2;
+	fixed_t dist1 = 0, dist2 = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FindTracer", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	// scan the thinkers
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2->type == (mobjtype_t)locvar1)
+		{
+			if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS))
+				continue; // Ignore spectators
+			if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0)
+				continue; // Ignore dead things
+			if (targetedmobj == NULL)
+			{
+				targetedmobj = mo2;
+				dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+			}
+			else
+			{
+				dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+
+				if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2))
+				{
+					targetedmobj = mo2;
+					dist2 = dist1;
+				}
+			}
+		}
+	}
+
+	if (!targetedmobj)
+	{
+		CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Unable to find the specified object to target.\n");
+		return; // Oops, nothing found..
+	}
+
+	CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Found a target.\n");
+
+	P_SetTarget(&actor->tracer, targetedmobj);
+}
+
+// Function: A_SetTics
+//
+// Description: Sets the animation tics of an object
+//
+// var1 = tics to set to
+// var2 = if this is set, and no var1 is supplied, the mobj's threshold value will be used.
+//
+void A_SetTics(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetTics", actor))
+		return;
+#endif
+
+	if (locvar1)
+		actor->tics = locvar1;
+	else if (locvar2)
+		actor->tics = actor->threshold;
+}
+
+// Function: A_SetRandomTics
+//
+// Description: Sets the animation tics of an object to a random value
+//
+// var1 = lower bound
+// var2 = upper bound
+//
+void A_SetRandomTics(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetRandomTics", actor))
+		return;
+#endif
+
+	actor->tics = P_RandomRange(locvar1, locvar2);
+}
+
+// Function: A_ChangeColorRelative
+//
+// Description: Changes the color of an object
+//
+// var1 = if (var1 > 0), find target and add its color value to yours
+// var2 = if (var1 = 0), color value to add
+//
+void A_ChangeColorRelative(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ChangeColorRelative", actor))
+		return;
+#endif
+
+	if (locvar1)
+	{
+		// Have you ever seen anything so hideous?
+		if (actor->target)
+			actor->color = (UINT8)(actor->color + actor->target->color);
+	}
+	else
+		actor->color = (UINT8)(actor->color + locvar2);
+}
+
+// Function: A_ChangeColorAbsolute
+//
+// Description: Changes the color of an object by an absolute value. Note: 0 is default colormap.
+//
+// var1 = if (var1 > 0), set your color to your target's color
+// var2 = if (var1 = 0), color value to set to
+//
+void A_ChangeColorAbsolute(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ChangeColorAbsolute", actor))
+		return;
+#endif
+
+	if (locvar1)
+	{
+		if (actor->target)
+			actor->color = actor->target->color;
+	}
+	else
+		actor->color = (UINT8)locvar2;
+}
+
+// Function: A_MoveRelative
+//
+// Description: Moves an object (wrapper for P_Thrust)
+//
+// var1 = angle
+// var2 = force
+//
+void A_MoveRelative(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MoveRelative", actor))
+		return;
+#endif
+
+	P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
+}
+
+// Function: A_MoveAbsolute
+//
+// Description: Moves an object (wrapper for P_InstaThrust)
+//
+// var1 = angle
+// var2 = force
+//
+void A_MoveAbsolute(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MoveAbsolute", actor))
+		return;
+#endif
+
+	P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
+}
+
+// Function: A_Thrust
+//
+// Description: Pushes the object horizontally at its current angle.
+//
+// var1 = amount of force
+// var2 = If 1, xy momentum is lost. If 0, xy momentum is kept
+//
+void A_Thrust(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Thrust", actor))
+		return;
+#endif
+
+	if (!locvar1)
+		CONS_Debug(DBG_GAMELOGIC, "A_Thrust: Var1 not specified!\n");
+
+	if (locvar2)
+		P_InstaThrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale));
+	else
+		P_Thrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale));
+}
+
+// Function: A_ZThrust
+//
+// Description: Pushes the object up or down.
+//
+// var1 = amount of force
+// var2:
+//		lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept
+//		upper 16 bits = If 1, z momentum is lost. If 0, z momentum is kept
+//
+void A_ZThrust(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ZThrust", actor))
+		return;
+#endif
+
+	if (!locvar1)
+		CONS_Debug(DBG_GAMELOGIC, "A_ZThrust: Var1 not specified!\n");
+
+	if (locvar2 & 65535)
+		actor->momx = actor->momy = 0;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		actor->z--;
+	else
+		actor->z++;
+
+	P_SetObjectMomZ(actor, locvar1*FRACUNIT, !(locvar2 >> 16));
+}
+
+// Function: A_SetTargetsTarget
+//
+// Description: Sets your target to the object who your target is targeting. Yikes! If it happens to be NULL, you're just out of luck.
+//
+// var1: (Your target)
+//		0 = target
+//		1 = tracer
+// var2: (Your target's target)
+//		0 = target/tracer's target
+//		1 = target/tracer's tracer
+//
+void A_SetTargetsTarget(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *oldtarg = NULL, *newtarg = NULL;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetTargetsTarget", actor))
+		return;
+#endif
+
+	// actor's target
+	if (locvar1) // or tracer
+		oldtarg = actor->tracer;
+	else
+		oldtarg = actor->target;
+
+	if (P_MobjWasRemoved(oldtarg))
+		return;
+
+	// actor's target's target!
+	if (locvar2) // or tracer
+		newtarg = oldtarg->tracer;
+	else
+		newtarg = oldtarg->target;
+
+	if (P_MobjWasRemoved(newtarg))
+		return;
+
+	// set actor's new target
+	if (locvar1) // or tracer
+		P_SetTarget(&actor->tracer, newtarg);
+	else
+		P_SetTarget(&actor->target, newtarg);
+}
+
+// Function: A_SetObjectFlags
+//
+// Description: Sets the flags of an object
+//
+// var1 = flag value to set
+// var2:
+//		if var2 == 2, add the flag to the current flags
+//		else if var2 == 1, remove the flag from the current flags
+//		else if var2 == 0, set the flags to the exact value
+//
+void A_SetObjectFlags(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	boolean unlinkthings = false;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetObjectFlags", actor))
+		return;
+#endif
+
+	if (locvar2 == 2)
+		locvar1 = actor->flags | locvar1;
+	else if (locvar2 == 1)
+		locvar1 = actor->flags & ~locvar1;
+
+	if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
+		unlinkthings = true;
+
+	if (unlinkthings) {
+		P_UnsetThingPosition(actor);
+		if (sector_list)
+		{
+			P_DelSeclist(sector_list);
+			sector_list = NULL;
+		}
+	}
+
+	actor->flags = locvar1;
+
+	if (unlinkthings)
+		P_SetThingPosition(actor);
+}
+
+// Function: A_SetObjectFlags2
+//
+// Description: Sets the flags2 of an object
+//
+// var1 = flag value to set
+// var2:
+//		if var2 == 2, add the flag to the current flags
+//		else if var2 == 1, remove the flag from the current flags
+//		else if var2 == 0, set the flags to the exact value
+//
+void A_SetObjectFlags2(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetObjectFlags2", actor))
+		return;
+#endif
+
+	if (locvar2 == 2)
+		actor->flags2 |= locvar1;
+	else if (locvar2 == 1)
+		actor->flags2 &= ~locvar1;
+	else
+		actor->flags2 = locvar1;
+}
+
+// Function: A_BossJetFume
+//
+// Description: Spawns jet fumes/other attachment miscellany for the boss. To only be used when he is spawned.
+//
+// var1:
+//		0 - Triple jet fume pattern
+//		1 - Boss 3's propeller
+//		2 - Metal Sonic jet fume
+//		3 - Boss 4 jet flame
+// var2 = unused
+//
+void A_BossJetFume(mobj_t *actor)
+{
+	mobj_t *filler;
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BossJetFume", actor))
+		return;
+#endif
+
+	if (locvar1 == 0) // Boss1 jet fumes
+	{
+		fixed_t jetx, jety, jetz;
+
+		jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale));
+		jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale));
+		if (actor->eflags & MFE_VERTICALFLIP)
+			jetz = actor->z + actor->height - FixedMul(38*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale);
+		else
+			jetz = actor->z + FixedMul(38*FRACUNIT, actor->scale);
+
+		filler = P_SpawnMobj(jetx, jety, jetz, MT_JETFUME1);
+		P_SetTarget(&filler->target, actor);
+		filler->destscale = actor->scale;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+		filler->fuse = 56;
+
+		if (actor->eflags & MFE_VERTICALFLIP)
+			jetz = actor->z + actor->height - FixedMul(12*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale);
+		else
+			jetz = actor->z + FixedMul(12*FRACUNIT, actor->scale);
+
+		filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
+				jety + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
+				jetz, MT_JETFUME1);
+		P_SetTarget(&filler->target, actor);
+		filler->destscale = actor->scale;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+		filler->fuse = 57;
+
+		filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
+				jety + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)),
+				jetz, MT_JETFUME1);
+		P_SetTarget(&filler->target, actor);
+		filler->destscale = actor->scale;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+		filler->fuse = 58;
+
+		P_SetTarget(&actor->tracer, filler);
+	}
+	else if (locvar1 == 1) // Boss 3 propeller
+	{
+		fixed_t jetx, jety, jetz;
+
+		jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
+		jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
+		if (actor->eflags & MFE_VERTICALFLIP)
+			jetz = actor->z + actor->height - FixedMul(17*FRACUNIT + mobjinfo[MT_PROPELLER].height, actor->scale);
+		else
+			jetz = actor->z + FixedMul(17*FRACUNIT, actor->scale);
+
+		filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER);
+		P_SetTarget(&filler->target, actor);
+		filler->destscale = actor->scale;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+		filler->angle = actor->angle - ANGLE_180;
+
+		P_SetTarget(&actor->tracer, filler);
+	}
+	else if (locvar1 == 2) // Metal Sonic jet fumes
+	{
+		filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1);
+		P_SetTarget(&filler->target, actor);
+		filler->fuse = 59;
+		P_SetTarget(&actor->tracer, filler);
+		filler->destscale = actor->scale/2;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+	}
+	else if (locvar1 == 3) // Boss 4 jet flame
+	{
+		fixed_t jetz;
+		if (actor->eflags & MFE_VERTICALFLIP)
+			jetz = actor->z + actor->height + FixedMul(50*FRACUNIT - mobjinfo[MT_JETFLAME].height, actor->scale);
+		else
+			jetz = actor->z - FixedMul(50*FRACUNIT, actor->scale);
+		filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME);
+		P_SetTarget(&filler->target, actor);
+		// Boss 4 already uses its tracer for other things
+		filler->destscale = actor->scale;
+		P_SetScale(filler, filler->destscale);
+		if (actor->eflags & MFE_VERTICALFLIP)
+			filler->flags2 |= MF2_OBJECTFLIP;
+	}
+}
+
+// Function: A_RandomState
+//
+// Description: Chooses one of the two state numbers supplied randomly.
+//
+// var1 = state number 1
+// var2 = state number 2
+//
+void A_RandomState(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RandomState", actor))
+		return;
+#endif
+
+	P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2);
+}
+
+// Function: A_RandomStateRange
+//
+// Description: Chooses a random state within the range supplied.
+//
+// var1 = Minimum state number to choose.
+// var2 = Maximum state number to use.
+//
+void A_RandomStateRange(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RandomStateRange", actor))
+		return;
+#endif
+
+	P_SetMobjState(actor, P_RandomRange(locvar1, locvar2));
+}
+
+// Function: A_DualAction
+//
+// Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop.
+//
+// var1 = state # to use 1st action from
+// var2 = state # to use 2nd action from
+//
+void A_DualAction(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_DualAction", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	var1 = states[locvar1].var1;
+	var2 = states[locvar1].var2;
+#ifdef HAVE_BLUA
+	astate = &states[locvar1];
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling First Action (state %d)...\n", locvar1);
+	states[locvar1].action.acp1(actor);
+
+	var1 = states[locvar2].var1;
+	var2 = states[locvar2].var2;
+#ifdef HAVE_BLUA
+	astate = &states[locvar2];
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling Second Action (state %d)...\n", locvar2);
+	states[locvar2].action.acp1(actor);
+}
+
+// Function: A_RemoteAction
+//
+// Description: var1 is the remote object. var2 is the state reference for calling the action called on var1. var1 becomes the actor's target, the action (var2) is called on var1. actor's target is restored
+//
+// var1 = remote object (-2 uses tracer, -1 uses target)
+// var2 = state reference for calling an action
+//
+void A_RemoteAction(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *originaltarget = actor->target; // Hold on to the target for later.
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RemoteAction", actor))
+		return;
+#endif
+
+	// If >=0, find the closest target.
+	if (locvar1 >= 0)
+	{
+		///* DO A_FINDTARGET STUFF *///
+		mobj_t *targetedmobj = NULL;
+		thinker_t *th;
+		mobj_t *mo2;
+		fixed_t dist1 = 0, dist2 = 0;
+
+		// scan the thinkers
+		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		{
+			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+				continue;
+
+			mo2 = (mobj_t *)th;
+
+			if (mo2->type == (mobjtype_t)locvar1)
+			{
+				if (targetedmobj == NULL)
+				{
+					targetedmobj = mo2;
+					dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+				}
+				else
+				{
+					dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y);
+
+					if ((locvar2 && dist1 < dist2) || (!locvar2 && dist1 > dist2))
+					{
+						targetedmobj = mo2;
+						dist2 = dist1;
+					}
+				}
+			}
+		}
+
+		if (!targetedmobj)
+		{
+			CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Unable to find the specified object to target.\n");
+			return; // Oops, nothing found..
+		}
+
+		CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Found a target.\n");
+
+		P_SetTarget(&actor->target, targetedmobj);
+
+		///* END A_FINDTARGET STUFF *///
+	}
+
+	// If -2, use the tracer as the target
+	else if (locvar1 == -2)
+		P_SetTarget(&actor->target, actor->tracer);
+	// if -1 or anything else, just use the target.
+
+	if (actor->target)
+	{
+		// Steal the var1 and var2 from "locvar2"
+		var1 = states[locvar2].var1;
+		var2 = states[locvar2].var2;
+#ifdef HAVE_BLUA
+		astate = &states[locvar2];
+#endif
+
+		CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Calling action on %p\n"
+				"var1 is %d\nvar2 is %d\n", actor->target, var1, var2);
+		states[locvar2].action.acp1(actor->target);
+	}
+
+	P_SetTarget(&actor->target, originaltarget); // Restore the original target.
+}
+
+// Function: A_ToggleFlameJet
+//
+// Description: Turns a flame jet on and off.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ToggleFlameJet(mobj_t* actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ToggleFlameJet", actor))
+		return;
+#endif
+	// threshold - off delay
+	// movecount - on timer
+
+	if (actor->flags2 & MF2_FIRING)
+	{
+		actor->flags2 &= ~MF2_FIRING;
+
+		if (actor->threshold)
+			actor->tics = actor->threshold;
+	}
+	else
+	{
+		actor->flags2 |= MF2_FIRING;
+
+		if (actor->movecount)
+			actor->tics = actor->movecount;
+	}
+}
+
+// Function: A_OrbitNights
+//
+// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.)
+//
+// var1 = Angle adjustment (aka orbit speed)
+// var2:
+//        Bits 1-10: height offset, max 1023
+//        Bits 11-16: X radius factor (max 63, default 20)
+//        Bit 17: set if object is Nightopian Helper
+//        Bit 18: set to define X/Y/Z rotation factor
+//        Bits 19-20: Unused
+//        Bits 21-26: Y radius factor (max 63, default 32)
+//        Bits 27-32: Z radius factor (max 63, default 32)
+//
+// If MF_GRENADEBOUNCE is flagged on mobj, use actor->threshold to define X/Y/Z radius factor, max 1023 each:
+//        Bits 1-10: X factor
+//        Bits 11-20: Y factor
+//        Bits 21-30: Z factor
+void A_OrbitNights(mobj_t* actor)
+{
+	INT32 ofs = (var2 & 0x3FF);
+	boolean ishelper = (var2 & 0x10000);
+	boolean donotrescale = (var2 & 0x40000);
+	INT32 xfactor = 32, yfactor = 32, zfactor = 20;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_OrbitNights", actor))
+		return;
+#endif
+
+	if (actor->flags & MF_GRENADEBOUNCE)
+	{
+		xfactor = (actor->threshold & 0x3FF);
+		yfactor = (actor->threshold & 0xFFC00) >> 10;
+		zfactor = (actor->threshold & 0x3FF00000) >> 20;
+	}
+	else if (var2 & 0x20000)
+	{
+		xfactor = (var2 & 0xFC00) >> 10;
+		yfactor = (var2 & 0x3F00000) >> 20;
+		zfactor = (var2 & 0xFC000000) >> 26;
+	}
+
+	if (!actor->target
+	|| (actor->target->player &&
+		// if NiGHTS special stage and not NiGHTSmode.
+	    (((maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE))
+	    // Also remove this object if they no longer have a NiGHTS helper
+		|| (ishelper && !actor->target->player->powers[pw_nights_helper]))))
+	{
+		P_RemoveMobj(actor);
+		return;
+	}
+	else
+	{
+		actor->extravalue1 += var1;
+		P_UnsetThingPosition(actor);
+		{
+			const angle_t fa  = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT;
+			const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT;
+
+			const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(xfactor*FRACUNIT, actor->scale));
+			const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(zfactor*FRACUNIT, actor->scale));
+			const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(yfactor*FRACUNIT, actor->scale));
+
+			actor->x = actor->target->x + fc;
+			actor->y = actor->target->y + fs;
+			actor->z = actor->target->z + fh + FixedMul(16*FRACUNIT, actor->scale);
+
+			// Semi-lazy hack
+			actor->angle = (angle_t)actor->extravalue1 + ANGLE_90;
+		}
+		P_SetThingPosition(actor);
+
+		if (ishelper && actor->target->player) // Flash a helper that's about to be removed.
+		{
+			if ((actor->target->player->powers[pw_nights_helper] < TICRATE)
+			&& (actor->target->player->powers[pw_nights_helper] & 1))
+				actor->flags2 |= MF2_DONTDRAW;
+			else
+				actor->flags2 &= ~MF2_DONTDRAW;
+		}
+
+		if (!donotrescale && actor->destscale != actor->target->destscale)
+			actor->destscale = actor->target->destscale;
+	}
+}
+
+// Function: A_GhostMe
+//
+// Description: Spawns a "ghost" mobj of this actor, ala spindash trails and the minus's digging "trails"
+//
+// var1 = duration in tics
+// var2 = unused
+//
+void A_GhostMe(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	mobj_t *ghost;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_GhostMe", actor))
+		return;
+#endif
+	ghost = P_SpawnGhostMobj(actor);
+	if (ghost && locvar1 > 0)
+		ghost->fuse = locvar1;
+}
+
+// Function: A_SetObjectState
+//
+// Description: Changes the state of an object's target/tracer.
+//
+// var1 = state number
+// var2:
+//		0 = target
+//		1 = tracer
+//
+void A_SetObjectState(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *target;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetObjectState", actor))
+		return;
+#endif
+
+	if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer))
+	{
+		if (cv_debug)
+			CONS_Printf("A_SetObjectState: No target to change state!\n");
+		return;
+	}
+
+	if (!locvar2) // target
+		target = actor->target;
+	else // tracer
+		target = actor->tracer;
+
+	if (target->health > 0)
+	{
+		if (!target->player)
+			P_SetMobjState(target, locvar1);
+		else
+			P_SetPlayerMobjState(target, locvar1);
+	}
+}
+
+// Function: A_SetObjectTypeState
+//
+// Description: Changes the state of all active objects of a certain type in a certain range of the actor.
+//
+// var1 = state number
+// var2:
+//		lower 16 bits = type
+//		upper 16 bits = range (if == 0, across whole map)
+//
+void A_SetObjectTypeState(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
+	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
+
+	thinker_t *th;
+	mobj_t *mo2;
+	fixed_t dist = 0;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetObjectTypeState", actor))
+		return;
+#endif
+
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2->type == (mobjtype_t)loc2lw)
+		{
+			dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y);
+
+			if (mo2->health > 0)
+			{
+				if (loc2up == 0)
+					P_SetMobjState(mo2, locvar1);
+				else
+				{
+					if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale))
+						P_SetMobjState(mo2, locvar1);
+				}
+			}
+		}
+	}
+}
+
+// Function: A_KnockBack
+//
+// Description: Knocks back the object's target at its current speed.
+//
+// var1:
+//		0 = target
+//		1 = tracer
+// var2 = unused
+//
+void A_KnockBack(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	mobj_t *target;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_KnockBack", actor))
+		return;
+#endif
+
+	if (!locvar1)
+		target = actor->target;
+	else
+		target = actor->tracer;
+
+	if (!target)
+	{
+		if(cv_debug)
+			CONS_Printf("A_KnockBack: No target!\n");
+		return;
+	}
+
+	target->momx *= -1;
+	target->momy *= -1;
+}
+
+// Function: A_PushAway
+//
+// Description: Pushes an object's target away from the calling object.
+//
+// var1 = amount of force
+// var2:
+//		lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept
+//		upper 16 bits = 0 - target, 1 - tracer
+//
+void A_PushAway(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *target; // target
+	angle_t an; // actor to target angle
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PushAway", actor))
+		return;
+#endif
+
+	if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer))
+		return;
+
+	if (!locvar1)
+		CONS_Printf("A_Thrust: Var1 not specified!\n");
+
+	if (!(locvar2 >> 16)) // target
+		target = actor->target;
+	else // tracer
+		target = actor->tracer;
+
+	an = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+
+	if (locvar2 & 65535)
+		P_InstaThrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale));
+	else
+		P_Thrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale));
+}
+
+// Function: A_RingDrain
+//
+// Description: Drain targeted player's rings.
+//
+// var1 = ammount of drained rings
+// var2 = unused
+//
+void A_RingDrain(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	player_t *player;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RingDrain", actor))
+		return;
+#endif
+
+	if (!actor->target || !actor->target->player)
+	{
+		if(cv_debug)
+			CONS_Printf("A_RingDrain: No player targeted!\n");
+		return;
+	}
+
+	player = actor->target->player;
+	P_GivePlayerRings(player, -min(locvar1, player->rings));
+}
+
+// Function: A_SplitShot
+//
+// Description: Shoots 2 missiles that hit next to the player.
+//
+// var1 = target x-y-offset
+// var2:
+//		lower 16 bits = missile type
+//		upper 16 bits = height offset
+//
+void A_SplitShot(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
+	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
+	const fixed_t offs = (fixed_t)(locvar1*FRACUNIT);
+	const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SplitShot", actor))
+		return;
+#endif
+
+	A_FaceTarget(actor);
+	{
+		const angle_t an = (actor->angle + ANGLE_90) >> ANGLETOFINESHIFT;
+		const fixed_t fasin = FINESINE(an);
+		const fixed_t facos = FINECOSINE(an);
+		fixed_t xs = FixedMul(facos,FixedMul(offs, actor->scale));
+		fixed_t ys = FixedMul(fasin,FixedMul(offs, actor->scale));
+		fixed_t z;
+
+		if (actor->eflags & MFE_VERTICALFLIP)
+			z = actor->z + actor->height - FixedMul(hoffs, actor->scale);
+		else
+			z = actor->z + FixedMul(hoffs, actor->scale);
+
+		P_SpawnPointMissile(actor, actor->target->x+xs, actor->target->y+ys, actor->target->z, loc2lw, actor->x, actor->y, z);
+		P_SpawnPointMissile(actor, actor->target->x-xs, actor->target->y-ys, actor->target->z, loc2lw, actor->x, actor->y, z);
+	}
+}
+
+// Function: A_MissileSplit
+//
+// Description: If the object is a missile it will create a new missile with an alternate flight path owned by the one who shot the former missile.
+//
+// var1 = splitting missile type
+// var2 = splitting angle
+//
+void A_MissileSplit(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MissileSplit", actor))
+		return;
+#endif
+	if (actor->eflags & MFE_VERTICALFLIP)
+		P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z+actor->height, locvar2);
+	else
+		P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z, locvar2);
+}
+
+// Function: A_MultiShot
+//
+// Description: Shoots objects horizontally that spread evenly in all directions.
+//
+// var1:
+//		lower 16 bits = number of missiles
+//		upper 16 bits = missile type #
+// var2 = height offset
+//
+void A_MultiShot(mobj_t *actor)
+{
+	fixed_t z, xr, yr;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
+	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
+	INT32 count = 0;
+	fixed_t ad;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MultiShot", actor))
+		return;
+#endif
+
+	if (actor->target)
+		A_FaceTarget(actor);
+
+	if(loc1lw > 90)
+		ad = FixedMul(90*FRACUNIT, actor->scale);
+	else
+		ad = FixedMul(loc1lw*FRACUNIT, actor->scale);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale);
+	xr = FixedMul((P_SignedRandom()/3)<<FRACBITS, actor->scale); // please note p_mobj.c's P_Rand() abuse
+	yr = FixedMul((P_SignedRandom()/3)<<FRACBITS, actor->scale); // of rand(), RAND_MAX and signness mess
+
+	while(count <= loc1lw && loc1lw >= 1)
+	{
+		const angle_t fa = FixedAngleC(count*FRACUNIT*360, ad)>>ANGLETOFINESHIFT;
+		const fixed_t rc = FINECOSINE(fa);
+		const fixed_t rs = FINESINE(fa);
+		const fixed_t xrc = FixedMul(xr, rc);
+		const fixed_t yrs = FixedMul(yr, rs);
+		const fixed_t xrs = FixedMul(xr, rs);
+		const fixed_t yrc = FixedMul(yr, rc);
+
+		P_SpawnPointMissile(actor, xrc-yrs+actor->x, xrs+yrc+actor->y, z, loc1up, actor->x, actor->y, z);
+		count++;
+	}
+
+	if (!(actor->flags & MF_BOSS))
+	{
+		if (ultimatemode)
+			actor->reactiontime = actor->info->reactiontime*TICRATE;
+		else
+			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+	}
+}
+
+// Function: A_InstaLoop
+//
+// Description: Makes the object move along a 2d (view angle, z) polygon.
+//
+// var1:
+//		lower 16 bits = current step
+//		upper 16 bits = maximum step #
+// var2 = force
+//
+void A_InstaLoop(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t force = max(locvar2, 1)*FRACUNIT; // defaults to 1 if var2 < 1
+	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
+	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
+	const angle_t fa = FixedAngleC(loc1lw*FRACUNIT*360, loc1up*FRACUNIT)>>ANGLETOFINESHIFT;
+	const fixed_t ac = FINECOSINE(fa);
+	const fixed_t as = FINESINE(fa);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_InstaLoop", actor))
+		return;
+#endif
+
+	P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale)));
+	P_SetObjectMomZ(actor, FixedMul(as, force), false);
+}
+
+// Function: A_Custom3DRotate
+//
+// Description: Rotates the actor around its target in 3 dimensions.
+//
+// var1:
+//		lower 16 bits = radius in fracunits
+//		upper 16 bits = vertical offset
+// var2:
+//		lower 16 bits = vertical rotation speed in 1/10 fracunits per tic
+//		upper 16 bits = horizontal rotation speed in 1/10 fracunits per tic
+//
+void A_Custom3DRotate(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
+	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
+	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
+	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
+
+	const fixed_t radius = FixedMul(loc1lw*FRACUNIT, actor->scale);
+	const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale);
+	const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale);
+	const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Custom3DRotate", actor))
+		return;
+#endif
+
+	if (actor->target->health == 0)
+	{
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	if (!actor->target) // This should NEVER happen.
+	{
+		if (cv_debug)
+			CONS_Printf("Error: Object has no target\n");
+		P_RemoveMobj(actor);
+		return;
+	}
+	if (hspeed==0 && vspeed==0)
+	{
+		CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n");
+		return;
+	}
+
+	actor->angle += FixedAngle(hspeed);
+	actor->movedir += FixedAngle(vspeed);
+	P_UnsetThingPosition(actor);
+	{
+		const angle_t fa = actor->angle>>ANGLETOFINESHIFT;
+
+		if (vspeed == 0 && hspeed != 0)
+		{
+			actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius);
+			actor->y = actor->target->y + FixedMul(FINESINE(fa),radius);
+			actor->z = actor->target->z + actor->target->height/2 - actor->height/2 + hOff;
+		}
+		else
+		{
+			const angle_t md = actor->movedir>>ANGLETOFINESHIFT;
+			actor->x = actor->target->x + FixedMul(FixedMul(FINESINE(md),FINECOSINE(fa)),radius);
+			actor->y = actor->target->y + FixedMul(FixedMul(FINESINE(md),FINESINE(fa)),radius);
+			actor->z = actor->target->z + FixedMul(FINECOSINE(md),radius) + actor->target->height/2 - actor->height/2 + hOff;
+		}
+	}
+	P_SetThingPosition(actor);
+}
+
+// Function: A_SearchForPlayers
+//
+// Description: Checks if the actor has targeted a vulnerable player. If not a new player will be searched all around. If no players are available the object can call a specific state. (Useful for not moving enemies)
+//
+// var1:
+//		if var1 == 0, if necessary call state with same state number as var2
+//		else, do not call a specific state if no players are available
+// var2 = state number
+//
+void A_SearchForPlayers(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SearchForPlayers", actor))
+		return;
+#endif
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		if(locvar1==0)
+		{
+			P_SetMobjStateNF(actor, locvar2);
+			return;
+		}
+	}
+}
+
+// Function: A_CheckRandom
+//
+// Description: Calls a state by chance.
+//
+// var1:
+//		lower 16 bits = denominator
+//		upper 16 bits = numerator (defaults to 1 if zero)
+// var2 = state number
+//
+void A_CheckRandom(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t chance = FRACUNIT;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckRandom", actor))
+		return;
+#endif
+	if ((locvar1 & 0xFFFF) == 0)
+		return;
+
+	// The PRNG doesn't suck anymore, OK?
+	if (locvar1 >> 16)
+		chance *= (locvar1 >> 16);
+	chance /= (locvar1 & 0xFFFF);
+
+	if (P_RandomChance(chance))
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckTargetRings
+//
+// Description: Calls a state depending on the ammount of rings currently owned by targeted players.
+//
+// var1 = if player rings >= var1 call state
+// var2 = state number
+//
+void A_CheckTargetRings(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckTargetRings", actor))
+		return;
+#endif
+
+	if (!(actor->target) || !(actor->target->player))
+	   return;
+
+	if (actor->target->player->rings >= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckRings
+//
+// Description: Calls a state depending on the ammount of rings currently owned by all players.
+//
+// var1 = if player rings >= var1 call state
+// var2 = state number
+//
+void A_CheckRings(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	INT32 i, cntr = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckRings", actor))
+		return;
+#endif
+
+	for (i = 0; i < MAXPLAYERS; i++)
+		cntr += players[i].rings;
+
+	if (cntr >= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckTotalRings
+//
+// Description: Calls a state depending on the maximum ammount of rings owned by all players during this try.
+//
+// var1 = if total player rings >= var1 call state
+// var2 = state number
+//
+void A_CheckTotalRings(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	INT32 i, cntr = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckTotalRings", actor))
+		return;
+#endif
+
+	for (i = 0; i < MAXPLAYERS; i++)
+		cntr += players[i].totalring;
+
+	if (cntr >= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckHealth
+//
+// Description: Calls a state depending on the object's current health.
+//
+// var1 = if health <= var1 call state
+// var2 = state number
+//
+void A_CheckHealth(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckHealth", actor))
+		return;
+#endif
+
+	if (actor->health <= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckRange
+//
+// Description: Calls a state if the object's target is in range.
+//
+// var1:
+//		lower 16 bits = range
+//		upper 16 bits = 0 - target, 1 - tracer
+// var2 = state number
+//
+void A_CheckRange(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t dist;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckRange", actor))
+		return;
+#endif
+
+	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
+		return;
+
+	if (!(locvar1 >> 16)) //target
+		dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
+	else //tracer
+		dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
+
+	if (dist <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckHeight
+//
+// Description: Calls a state if the object and it's target have a height offset <= var1 compared to each other.
+//
+// var1:
+//		lower 16 bits = height offset
+//		upper 16 bits = 0 - target, 1 - tracer
+// var2 = state number
+//
+void A_CheckHeight(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t height;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckHeight", actor))
+		return;
+#endif
+
+	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
+		return;
+
+	if (!(locvar1 >> 16)) // target
+		height = abs(actor->target->z - actor->z);
+	else // tracer
+		height = abs(actor->tracer->z - actor->z);
+
+	if (height <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckTrueRange
+//
+// Description: Calls a state if the object's target is in true range. (Checks height, too.)
+//
+// var1:
+//		lower 16 bits = range
+//		upper 16 bits = 0 - target, 1 - tracer
+// var2 = state number
+//
+void A_CheckTrueRange(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t height; // vertical range
+	fixed_t dist; // horizontal range
+	fixed_t l; // true range
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckTrueRange", actor))
+		return;
+#endif
+
+	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
+		return;
+
+	if (!(locvar1 >> 16)) // target
+	{
+		height = actor->target->z - actor->z;
+		dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
+
+	}
+	else // tracer
+	{
+		height = actor->tracer->z - actor->z;
+		dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
+	}
+
+	l = P_AproxDistance(dist, height);
+
+	if (l <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale))
+		P_SetMobjState(actor, locvar2);
+
+}
+
+// Function: A_CheckThingCount
+//
+// Description: Calls a state depending on the number of active things in range.
+//
+// var1:
+//		lower 16 bits = number of things
+//		upper 16 bits = thing type
+// var2:
+//		lower 16 bits = state to call
+//		upper 16 bits = range (if == 0, check whole map)
+//
+void A_CheckThingCount(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	const UINT16 loc1lw = (UINT16)(locvar1 & 65535);
+	const UINT16 loc1up = (UINT16)(locvar1 >> 16);
+	const UINT16 loc2lw = (UINT16)(locvar2 & 65535);
+	const UINT16 loc2up = (UINT16)(locvar2 >> 16);
+
+	INT32 count = 0;
+	thinker_t *th;
+	mobj_t *mo2;
+	fixed_t dist = 0;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckThingCount", actor))
+		return;
+#endif
+
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2->type == (mobjtype_t)loc1up)
+		{
+			dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y);
+
+			if (loc2up == 0)
+				count++;
+			else
+			{
+				if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale))
+					count++;
+			}
+		}
+	}
+
+	if(loc1lw <= count)
+		P_SetMobjState(actor, loc2lw);
+}
+
+// Function: A_CheckAmbush
+//
+// Description: Calls a state if the actor is behind its targeted player.
+//
+// var1:
+//		0 = target
+//		1 = tracer
+// var2 = state number
+//
+void A_CheckAmbush(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	angle_t at; // angle target is currently facing
+	angle_t atp; // actor to target angle
+	angle_t an; // angle between at and atp
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckAmbush", actor))
+		return;
+#endif
+
+	if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer))
+		return;
+
+	if (!locvar1) // target
+	{
+		at = actor->target->angle;
+		atp = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+	}
+	else // tracer
+	{
+		at = actor->tracer->angle;
+		atp = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
+	}
+
+	an = atp - at;
+
+	if (an > ANGLE_180) // flip angle if bigger than 180
+		an = InvAngle(an);
+
+	if (an < ANGLE_90+ANGLE_22h) // within an angle of 112.5 from each other?
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckCustomValue
+//
+// Description: Calls a state depending on the object's custom value.
+//
+// var1 = if custom value >= var1, call state
+// var2 = state number
+//
+void A_CheckCustomValue(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckCustomValue", actor))
+		return;
+#endif
+
+	if (actor->cusval >= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_CheckCusValMemo
+//
+// Description: Calls a state depending on the object's custom memory value.
+//
+// var1 = if memory value >= var1, call state
+// var2 = state number
+//
+void A_CheckCusValMemo(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckCusValMemo", actor))
+		return;
+#endif
+
+	if (actor->cvmem >= locvar1)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_SetCustomValue
+//
+// Description: Changes the custom value of an object.
+//
+// var1 = manipulating value
+// var2:
+//      if var2 == 5, multiply the custom value by var1
+//      else if var2 == 4, divide the custom value by var1
+//      else if var2 == 3, apply modulo var1 to the custom value
+//      else if var2 == 2, add var1 to the custom value
+//      else if var2 == 1, substract var1 from the custom value
+//      else if var2 == 0, replace the custom value with var1
+//
+void A_SetCustomValue(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetCustomValue", actor))
+		return;
+#endif
+
+	if (cv_debug)
+		CONS_Printf("Init custom value is %d\n", actor->cusval);
+
+	if (locvar1 == 0 && locvar2 == 4)
+		return; // DON'T DIVIDE BY ZERO
+
+	// no need for a "temp" value here, just modify the cusval directly
+	if (locvar2 == 5) // multiply
+		actor->cusval *= locvar1;
+	else if (locvar2 == 4) // divide
+		actor->cusval /= locvar1;
+	else if (locvar2 == 3) // modulo
+		actor->cusval %= locvar1;
+	else if (locvar2 == 2) // add
+		actor->cusval += locvar1;
+	else if (locvar2 == 1) // subtract
+		actor->cusval -= locvar1;
+	else // replace
+		actor->cusval = locvar1;
+
+	if(cv_debug)
+		CONS_Printf("New custom value is %d\n", actor->cusval);
+}
+
+// Function: A_UseCusValMemo
+//
+// Description: Memorizes or recalls a current custom value.
+//
+// var1:
+//      if var1 == 1, manipulate memory value
+//      else, recall memory value replacing the custom value
+// var2:
+//      if var2 == 5, mem = mem*cv  ||  cv = cv*mem
+//      else if var2 == 4,  mem = mem/cv  ||  cv = cv/mem
+//      else if var2 == 3, mem = mem%cv  ||  cv = cv%mem
+//      else if var2 == 2, mem += cv  ||  cv += mem
+//      else if var2 == 1,  mem -= cv  ||  cv -= mem
+//      else mem = cv  ||  cv = mem
+//
+void A_UseCusValMemo(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	INT32 temp = actor->cusval; // value being manipulated
+	INT32 tempM = actor->cvmem; // value used to manipulate temp with
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_UseCusValMemo", actor))
+		return;
+#endif
+
+	if (locvar1 == 1) // cvmem being changed using cusval
+	{
+		temp = actor->cvmem;
+		tempM = actor->cusval;
+	}
+	else // cusval being changed with cvmem
+	{
+		temp = actor->cusval;
+		tempM = actor->cvmem;
+	}
+
+	if (tempM == 0 && locvar2 == 4)
+		return; // DON'T DIVIDE BY ZERO
+
+	// now get new value for cusval/cvmem using the other
+	if (locvar2 == 5) // multiply
+		temp *= tempM;
+	else if (locvar2 == 4) // divide
+		temp /= tempM;
+	else if (locvar2 == 3) // modulo
+		temp %= tempM;
+	else if (locvar2 == 2) // add
+		temp += tempM;
+	else if (locvar2 == 1) // subtract
+		temp -= tempM;
+	else // replace
+		temp = tempM;
+
+	// finally, give cusval/cvmem the new value!
+	if (locvar1 == 1)
+		actor->cvmem = temp;
+	else
+		actor->cusval = temp;
+}
+
+// Function: A_RelayCustomValue
+//
+// Description: Manipulates the custom value of the object's target/tracer.
+//
+// var1:
+//		lower 16 bits:
+//					if var1 == 0, use own custom value
+//					else, use var1 value
+//		upper 16 bits = 0 - target, 1 - tracer
+// var2:
+//      if var2 == 5, multiply the target's custom value by var1
+//      else if var2 == 4, divide the target's custom value by var1
+//      else if var2 == 3, apply modulo var1 to the target's custom value
+//      else if var2 == 2, add var1 to the target's custom value
+//      else if var2 == 1, substract var1 from the target's custom value
+//      else if var2 == 0, replace the target's custom value with var1
+//
+void A_RelayCustomValue(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	INT32 temp; // reference value - var1 lower 16 bits changes this
+	INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RelayCustomValue", actor))
+		return;
+#endif
+
+	if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer))
+		return;
+
+	// reference custom value
+	if ((locvar1 & 65535) == 0)
+		temp = actor->cusval; // your own custom value
+	else
+		temp = (locvar1 & 65535); // var1 value
+
+	if (!(locvar1 >> 16)) // target's custom value
+		tempT = actor->target->cusval;
+	else // tracer's custom value
+		tempT = actor->tracer->cusval;
+
+	if (temp == 0 && locvar2 == 4)
+		return; // DON'T DIVIDE BY ZERO
+
+	// now get new cusval using target's and the reference
+	if (locvar2 == 5) // multiply
+		tempT *= temp;
+	else if (locvar2 == 4) // divide
+		tempT /= temp;
+	else if (locvar2 == 3) // modulo
+		tempT %= temp;
+	else if (locvar2 == 2) // add
+		tempT += temp;
+	else if (locvar2 == 1) // subtract
+		tempT -= temp;
+	else // replace
+		tempT = temp;
+
+	// finally, give target/tracer the new cusval!
+	if (!(locvar1 >> 16)) // target
+		actor->target->cusval = tempT;
+	else // tracer
+		actor->tracer->cusval = tempT;
+}
+
+// Function: A_CusValAction
+//
+// Description: Calls an action from a reference state applying custom value parameters.
+//
+// var1 = state # to use action from
+// var2:
+//      if var2 == 5, only replace new action's var2 with memory value
+//      else if var2 == 4, only replace new action's var1 with memory value
+//      else if var2 == 3, replace new action's var2 with custom value and var1 with memory value
+//      else if var2 == 2, replace new action's var1 with custom value and var2 with memory value
+//      else if var2 == 1, only replace new action's var2 with custom value
+//      else if var2 == 0, only replace new action's var1 with custom value
+//
+void A_CusValAction(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CusValAction", actor))
+		return;
+#endif
+
+	if (locvar2 == 5)
+	{
+		var1 = states[locvar1].var1;
+		var2 = (INT32)actor->cvmem;
+	}
+	else if (locvar2 == 4)
+	{
+		var1 = (INT32)actor->cvmem;
+		var2 = states[locvar1].var2;
+	}
+	else if (locvar2 == 3)
+	{
+		var1 = (INT32)actor->cvmem;
+		var2 = (INT32)actor->cusval;
+	}
+	else if (locvar2 == 2)
+	{
+		var1 = (INT32)actor->cusval;
+		var2 = (INT32)actor->cvmem;
+	}
+	else if (locvar2 == 1)
+	{
+		var1 = states[locvar1].var1;
+		var2 = (INT32)actor->cusval;
+	}
+	else
+	{
+		var1 = (INT32)actor->cusval;
+		var2 = states[locvar1].var2;
+	}
+
+#ifdef HAVE_BLUA
+	astate = &states[locvar1];
+#endif
+	states[locvar1].action.acp1(actor);
+}
+
+// Function: A_ForceStop
+//
+// Description: Actor immediately stops its current movement.
+//
+// var1:
+//      if var1 == 0, stop x-y-z-movement
+//      else, stop x-y-movement only
+// var2 = unused
+//
+void A_ForceStop(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ForceStop", actor))
+		return;
+#endif
+
+	actor->momx = actor->momy = 0;
+	if (locvar1 == 0)
+		actor->momz = 0;
+}
+
+// Function: A_ForceWin
+//
+// Description: Makes all players win the level.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ForceWin(mobj_t *actor)
+{
+	INT32 i;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ForceWin", actor))
+		return;
+#else
+	(void)actor;
+#endif
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i] && ((players[i].mo && players[i].mo->health)
+		    || ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
+			break;
+	}
+
+	if (i == MAXPLAYERS)
+		return;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+		P_DoPlayerExit(&players[i]);
+}
+
+// Function: A_SpikeRetract
+//
+// Description: Toggles actor solid flag.
+//
+// var1:
+//        if var1 == 0, actor no collide
+//        else, actor solid
+// var2 = unused
+//
+void A_SpikeRetract(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpikeRetract", actor))
+		return;
+#endif
+
+	if (actor->flags & MF_NOBLOCKMAP)
+		return;
+
+	if (locvar1 == 0)
+	{
+		actor->flags &= ~MF_SOLID;
+		actor->flags |= MF_NOCLIPTHING;
+	}
+	else
+	{
+		actor->flags |= MF_SOLID;
+		actor->flags &= ~MF_NOCLIPTHING;
+	}
+	if (actor->flags & MF_SOLID)
+		P_CheckPosition(actor, actor->x, actor->y);
+}
+
+// Function: A_InfoState
+//
+// Description: Set mobj state to one predefined in mobjinfo.
+//
+// var1:
+//        if var1 == 0, set actor to spawnstate
+//        else if var1 == 1, set actor to seestate
+//        else if var1 == 2, set actor to meleestate
+//        else if var1 == 3, set actor to missilestate
+//        else if var1 == 4, set actor to deathstate
+//        else if var1 == 5, set actor to xdeathstate
+//        else if var1 == 6, set actor to raisestate
+// var2 = unused
+//
+void A_InfoState(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	switch (locvar1)
+	{
+	case 0:
+		if (actor->state != &states[actor->info->spawnstate])
+			P_SetMobjState(actor, actor->info->spawnstate);
+		break;
+	case 1:
+		if (actor->state != &states[actor->info->seestate])
+			P_SetMobjState(actor, actor->info->seestate);
+		break;
+	case 2:
+		if (actor->state != &states[actor->info->meleestate])
+			P_SetMobjState(actor, actor->info->meleestate);
+		break;
+	case 3:
+		if (actor->state != &states[actor->info->missilestate])
+			P_SetMobjState(actor, actor->info->missilestate);
+		break;
+	case 4:
+		if (actor->state != &states[actor->info->deathstate])
+			P_SetMobjState(actor, actor->info->deathstate);
+		break;
+	case 5:
+		if (actor->state != &states[actor->info->xdeathstate])
+			P_SetMobjState(actor, actor->info->xdeathstate);
+		break;
+	case 6:
+		if (actor->state != &states[actor->info->raisestate])
+			P_SetMobjState(actor, actor->info->raisestate);
+		break;
+	default:
+		break;
+	}
+}
+
+// Function: A_Repeat
+//
+// Description: Returns to state var2 until animation has been used var1 times, then continues to nextstate.
+//
+// var1 = repeat count
+// var2 = state to return to if extravalue2 > 0
+//
+void A_Repeat(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Repeat", actor))
+		return;
+#endif
+
+	if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1))
+		actor->extravalue2 = locvar1;
+
+	if (--actor->extravalue2 > 0)
+		P_SetMobjState(actor, locvar2);
+}
+
+// Function: A_SetScale
+//
+// Description: Changes the scale of the actor or its target/tracer
+//
+// var1 = new scale (1*FRACUNIT = 100%)
+// var2:
+//        upper 16 bits: 0 = actor, 1 = target, 2 = tracer
+//        lower 16 bits: 0 = instant change, 1 = smooth change
+//
+void A_SetScale(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *target;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SetScale", actor))
+		return;
+#endif
+
+	if (locvar1 <= 0)
+	{
+		if(cv_debug)
+			CONS_Printf("A_SetScale: Valid scale not specified!\n");
+		return;
+	}
+
+	if ((locvar2>>16) == 1)
+		target = actor->target;
+	else if ((locvar2>>16) == 2)
+		target = actor->tracer;
+	else // default to yourself!
+		target = actor;
+
+	if (!target)
+	{
+		if(cv_debug)
+			CONS_Printf("A_SetScale: No target!\n");
+		return;
+	}
+
+	target->destscale = locvar1; // destination scale
+	if (!(locvar2 & 65535))
+		P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway
+}
+
+// Function: A_RemoteDamage
+//
+// Description: Damages, kills or even removes either the actor or its target/tracer. Actor acts as the inflictor/source unless harming itself
+//
+// var1 = Mobj affected: 0 - actor, 1 - target, 2 - tracer
+// var2 = Action: 0 - Damage, 1 - Kill, 2 - Remove
+//
+void A_RemoteDamage(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *target; // we MUST have a target
+	mobj_t *source = NULL; // on the other hand we don't necessarily need a source
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RemoteDamage", actor))
+		return;
+#endif
+	if (locvar1 == 1)
+		target = actor->target;
+	else if (locvar1 == 2)
+		target = actor->tracer;
+	else // default to yourself!
+		target = actor;
+
+	if (locvar1 == 1 || locvar1 == 2)
+		source = actor;
+
+	if (!target)
+	{
+		if(cv_debug)
+			CONS_Printf("A_RemoteDamage: No target!\n");
+		return;
+	}
+
+	if (locvar2 == 1) // Kill mobj!
+	{
+		if (target->player) // players die using P_DamageMobj instead for some reason
+			P_DamageMobj(target, source, source, 1, DMG_INSTAKILL);
+		else
+			P_KillMobj(target, source, source, 0);
+	}
+	else if (locvar2 == 2) // Remove mobj!
+	{
+		if (target->player) //don't remove players!
+			return;
+
+		P_RemoveMobj(target);
+	}
+	else // default: Damage mobj!
+		P_DamageMobj(target, source, source, 1, 0);
+}
+
+// Function: A_HomingChase
+//
+// Description: Actor chases directly towards its destination object
+//
+// var1 = speed multiple
+// var2 = destination: 0 = target, 1 = tracer
+//
+void A_HomingChase(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *dest;
+	fixed_t dist;
+	fixed_t speedmul;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_HomingChase", actor))
+		return;
+#endif
+
+	if (locvar2 == 1)
+		dest = actor->tracer;
+	else //default
+		dest = actor->target;
+
+	if (!dest || !dest->health)
+		return;
+
+	actor->angle = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
+
+	dist = P_AproxDistance(P_AproxDistance(dest->x - actor->x, dest->y - actor->y), dest->z - actor->z);
+
+	if (dist < 1)
+		dist = 1;
+
+	speedmul = FixedMul(locvar1, actor->scale);
+
+	actor->momx = FixedMul(FixedDiv(dest->x - actor->x, dist), speedmul);
+	actor->momy = FixedMul(FixedDiv(dest->y - actor->y, dist), speedmul);
+	actor->momz = FixedMul(FixedDiv(dest->z - actor->z, dist), speedmul);
+}
+
+// Function: A_TrapShot
+//
+// Description: Fires a missile in a particular direction and angle rather than AT something, Trapgoyle-style!
+//
+// var1:
+//        lower 16 bits = object # to fire
+//        upper 16 bits = front offset
+// var2:
+//        lower 15 bits = vertical angle variable
+//        16th bit:
+//			- 0: use vertical angle variable as vertical angle in degrees
+//			- 1: mimic P_SpawnXYZMissile
+//				use z of actor minus z of missile as vertical distance to cover during momz calculation
+//				use vertical angle variable as horizontal distance to cover during momz calculation
+//        upper 16 bits = height offset
+//
+void A_TrapShot(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	boolean oldstyle = (locvar2 & 32768) ? true : false;
+	mobjtype_t type = (mobjtype_t)(locvar1 & 65535);
+	mobj_t *missile;
+	INT16 frontoff = (INT16)(locvar1 >> 16);
+	INT16 vertoff = (INT16)(locvar2 >> 16);
+	fixed_t x, y, z;
+	fixed_t speed;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_TrapShot", actor))
+		return;
+#endif
+
+	x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
+	y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale));
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale);
+	else
+		z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale);
+
+	CONS_Debug(DBG_GAMELOGIC, "A_TrapShot: missile no. = %d, front offset = %d, vertical angle = %d, z offset = %d\n",
+		type, frontoff, (INT16)(locvar2 & 65535), vertoff);
+
+	missile = P_SpawnMobj(x, y, z, type);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		missile->flags2 |= MF2_OBJECTFLIP;
+
+	missile->destscale = actor->scale;
+	P_SetScale(missile, actor->scale);
+
+	if (missile->info->seesound)
+		S_StartSound(missile, missile->info->seesound);
+
+	P_SetTarget(&missile->target, actor);
+	missile->angle = actor->angle;
+
+	speed = FixedMul(missile->info->speed, missile->scale);
+
+	if (oldstyle)
+	{
+		missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed);
+		missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed);
+		// The below line basically mimics P_SpawnXYZMissile's momz calculation.
+		missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed);
+		P_CheckMissileSpawn(missile);
+	}
+	else
+	{
+		angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT);
+		if (actor->eflags & MFE_VERTICALFLIP)
+				vertang = InvAngle(vertang); // flip firing angle
+		missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed));
+		missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed));
+		missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed);
+	}
+}
+
+// Function: A_VileTarget
+//
+// Description: Spawns an object directly on the target, and sets this object as the actor's tracer.
+//              Originally used by Archviles to summon a pillar of hellfire, hence the name.
+//
+// var1 = mobj to spawn
+// var2 = If 0, target only the actor's target. Else, target every player, period.
+//
+void A_VileTarget(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *fog;
+	mobjtype_t fogtype;
+	INT32 i;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_VileTarget", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	// Determine object to spawn
+	if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES)
+		fogtype = MT_CYBRAKDEMON_TARGET_RETICULE;
+	else
+		fogtype = (mobjtype_t)locvar1;
+
+	if (!locvar2)
+	{
+		fog = P_SpawnMobj(actor->target->x,
+							actor->target->y,
+							actor->target->z + ((actor->target->eflags & MFE_VERTICALFLIP) ? actor->target->height - mobjinfo[fogtype].height : 0),
+							fogtype);
+		if (actor->target->eflags & MFE_VERTICALFLIP)
+		{
+			fog->eflags |= MFE_VERTICALFLIP;
+			fog->flags2 |= MF2_OBJECTFLIP;
+		}
+		fog->destscale = actor->target->scale;
+		P_SetScale(fog, fog->destscale);
+
+		P_SetTarget(&actor->tracer, fog);
+		P_SetTarget(&fog->target, actor);
+		P_SetTarget(&fog->tracer, actor->target);
+		A_VileFire(fog);
+	}
+	else
+	{
+		// Our "Archvile" here is actually Oprah. "YOU GET A TARGET! YOU GET A TARGET! YOU ALL GET A TARGET!"
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (!playeringame[i] || players[i].spectator)
+				continue;
+
+			if (!players[i].mo)
+				continue;
+
+			if (!players[i].mo->health)
+				continue;
+
+			fog = P_SpawnMobj(players[i].mo->x,
+							players[i].mo->y,
+							players[i].mo->z + ((players[i].mo->eflags & MFE_VERTICALFLIP) ? players[i].mo->height - mobjinfo[fogtype].height : 0),
+							fogtype);
+			if (players[i].mo->eflags & MFE_VERTICALFLIP)
+			{
+				fog->eflags |= MFE_VERTICALFLIP;
+				fog->flags2 |= MF2_OBJECTFLIP;
+			}
+			fog->destscale = players[i].mo->scale;
+			P_SetScale(fog, fog->destscale);
+
+			if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now
+				P_SetTarget(&actor->tracer, fog);
+			P_SetTarget(&fog->target, actor);
+			P_SetTarget(&fog->tracer, players[i].mo);
+			A_VileFire(fog);
+		}
+	}
+}
+
+// Function: A_VileAttack
+//
+// Description: Instantly hurts the actor's target, if it's in the actor's line of sight.
+//              Originally used by Archviles to cause explosions where their hellfire pillars were, hence the name.
+//
+// var1 = sound to play
+// var2:
+//		Lower 16 bits = optional explosion object
+//		Upper 16 bits = If 0, attack only the actor's target. Else, attack all the players. All of them.
+//
+void A_VileAttack(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	sfxenum_t soundtoplay;
+	mobjtype_t explosionType = MT_NULL;
+	mobj_t *fire;
+	INT32 i;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_VileAttack", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	if (locvar1 <= 0 || locvar1 >= NUMSFX)
+		soundtoplay = sfx_brakrx;
+	else
+		soundtoplay = (sfxenum_t)locvar1;
+
+	if ((locvar2 & 0xFFFF) > 0 && (locvar2 & 0xFFFF) <= NUMMOBJTYPES)
+	{
+		explosionType = (mobjtype_t)(locvar2 & 0xFFFF);
+	}
+
+	if (!(locvar2 & 0xFFFF0000)) {
+		if (!P_CheckSight(actor, actor->target))
+			return;
+
+		S_StartSound(actor, soundtoplay);
+		P_DamageMobj(actor->target, actor, actor, 1, 0);
+		//actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it
+		actor->target->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(actor->target); // How we're doing it
+		if (explosionType != MT_NULL)
+		{
+			P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, explosionType);
+		}
+
+		// Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway.
+		fire = actor->tracer;
+
+		if (!fire)
+			return;
+
+		// move the fire between the vile and the player
+		//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
+		//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
+		P_TeleportMove(fire,
+						actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
+						actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
+						fire->z);
+		P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
+	}
+	else
+	{
+		// Oprahvile strikes again, but this time, she brings HOT PAIN
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (!playeringame[i] || players[i].spectator)
+				continue;
+
+			if (!players[i].mo)
+				continue;
+
+			if (!players[i].mo->health)
+				continue;
+
+			if (!P_CheckSight(actor, players[i].mo))
+				continue;
+
+			S_StartSound(actor, soundtoplay);
+			P_DamageMobj(players[i].mo, actor, actor, 1, 0);
+			//actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it
+			players[i].mo->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(players[i].mo); // How we're doing it
+			if (explosionType != MT_NULL)
+			{
+				P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z, explosionType);
+			}
+
+			// Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway.
+			// However, it ONLY applies to the actor's target. Nobody else matters!
+			if (actor->target != players[i].mo)
+				continue;
+
+			fire = actor->tracer;
+
+			if (!fire)
+				continue;
+
+			// move the fire between the vile and the player
+			//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
+			//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
+			P_TeleportMove(fire,
+							actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
+							actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
+							fire->z);
+			P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
+		}
+	}
+
+}
+
+// Function: A_VileFire
+//
+// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it.
+//				Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific).
+//				Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit.
+//
+// var1 = sound to play
+// var2:
+//		Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all)
+//		Upper 16 bits = # to spawn (default is 8)
+//
+void A_VileFire(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	mobj_t *dest;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_VileFire", actor))
+		return;
+#endif
+
+	dest = actor->tracer;
+	if (!dest)
+		return;
+
+	// don't move it if the vile lost sight
+	if (!P_CheckSight(actor->target, dest))
+		return;
+
+	// keep to same scale and gravity as tracer ALWAYS
+	actor->destscale = dest->scale;
+	P_SetScale(actor, actor->destscale);
+	if (dest->eflags & MFE_VERTICALFLIP)
+	{
+		actor->eflags |= MFE_VERTICALFLIP;
+		actor->flags2 |= MF2_OBJECTFLIP;
+	}
+	else
+	{
+		actor->eflags &= ~MFE_VERTICALFLIP;
+		actor->flags2 &= ~MF2_OBJECTFLIP;
+	}
+
+	P_UnsetThingPosition(actor);
+	actor->x = dest->x + P_ReturnThrustX(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale));
+	actor->y = dest->y + P_ReturnThrustY(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale));
+	actor->z = dest->z + ((actor->eflags & MFE_VERTICALFLIP) ? dest->height-actor->height : 0);
+	P_SetThingPosition(actor);
+
+	// Play sound, if one's specified
+	if (locvar1 > 0 && locvar1 < NUMSFX)
+		S_StartSound(actor, (sfxenum_t)locvar1);
+
+	// Now draw the line to the actor's target
+	if (locvar2 & 0xFFFF)
+	{
+		mobjtype_t lineMobj;
+		UINT16 numLineMobjs;
+		fixed_t distX;
+		fixed_t distY;
+		fixed_t distZ;
+		UINT16 i;
+
+		lineMobj = (mobjtype_t)(locvar2 & 0xFFFF);
+		numLineMobjs = (UINT16)(locvar2 >> 16);
+		if (numLineMobjs == 0) {
+			numLineMobjs = 8;
+		}
+
+		// Get distance for each step
+		distX = (actor->target->x - actor->x) / numLineMobjs;
+		distY = (actor->target->y - actor->y) / numLineMobjs;
+		distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs;
+
+		for (i = 1; i <= numLineMobjs; i++)
+		{
+			P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj);
+		}
+	}
+}
+
+// Function: A_BrakChase
+//
+// Description: Chase after your target, but speed and attack are tied to health.
+//
+// Every time this is called, generate a random number from a 1/4 to 3/4 of mobj's spawn health.
+// If health is above that value, use missilestate to attack.
+// If health is at or below that value, use meleestate to attack (default to missile state if not available).
+//
+// Likewise, state will linearly speed up as health goes down.
+// Upper bound will be the frame's normal length.
+// Lower bound defaults to 1 tic (technically 0, but we round up), unless a lower bound is specified in var1.
+//
+// var1 = lower-bound of frame length, in tics
+// var2 = optional sound to play
+//
+void A_BrakChase(mobj_t *actor)
+{
+	INT32 delta;
+	INT32 lowerbound;
+	INT32 newtics;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BrakChase", actor))
+		return;
+#endif
+
+	// Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly
+	if (actor->tics > 1 && locvar1 < actor->tics) // Not much point, otherwise
+	{
+		if (locvar1 < 0)
+			lowerbound = 0;
+		else
+			lowerbound = locvar1;
+
+		newtics = (((actor->tics - lowerbound) * actor->health) / actor->info->spawnhealth) + lowerbound;
+		if (newtics < 1)
+			newtics = 1;
+
+		actor->tics = newtics;
+	}
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+		if (actor->reactiontime == 0 && actor->type == MT_CYBRAKDEMON)
+			S_StartSound(0, sfx_bewar1 + P_RandomKey(4));
+	}
+
+	// modify target threshold
+	if (actor->threshold)
+	{
+		if (!actor->target || actor->target->health <= 0)
+			actor->threshold = 0;
+		else
+			actor->threshold--;
+	}
+
+	// turn towards movement direction if not there yet
+	if (actor->movedir < NUMDIRS)
+	{
+		actor->angle &= (7<<29);
+		delta = actor->angle - (actor->movedir << 29);
+
+		if (delta > 0)
+			actor->angle -= ANGLE_45;
+		else if (delta < 0)
+			actor->angle += ANGLE_45;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{
+		// look for a new target
+		if (P_LookForPlayers(actor, true, false, 0))
+			return; // got a new target
+
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
+		return;
+	}
+
+	// do not attack twice in a row
+	if (actor->flags2 & MF2_JUSTATTACKED)
+	{
+		actor->flags2 &= ~MF2_JUSTATTACKED;
+		P_NewChaseDir(actor);
+		return;
+	}
+
+	// Check if we can attack
+	if (P_CheckMissileRange(actor) && !actor->movecount)
+	{
+		// Check if we should use "melee" attack first. (Yes, this still runs outside of melee range. Quiet, you.)
+		if (actor->info->meleestate
+			&& actor->health <= P_RandomRange(actor->info->spawnhealth/4, (actor->info->spawnhealth * 3)/4)) // Guaranteed true if <= 1/4 health, guaranteed false if > 3/4 health
+		{
+			if (actor->info->attacksound)
+				S_StartAttackSound(actor, actor->info->attacksound);
+
+			P_SetMobjState(actor, actor->info->meleestate);
+			actor->flags2 |= MF2_JUSTATTACKED;
+			return;
+		}
+		// Else, check for missile attack.
+		else if (actor->info->missilestate)
+		{
+			P_SetMobjState(actor, actor->info->missilestate);
+			actor->flags2 |= MF2_JUSTATTACKED;
+			return;
+		}
+	}
+
+	// possibly choose another target
+	if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
+		&& P_LookForPlayers(actor, true, false, 0))
+		return; // got a new target
+
+	// chase towards player
+	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		P_NewChaseDir(actor);
+
+	// Optionally play a sound effect
+	if (locvar2 > 0 && locvar2 < NUMSFX)
+		S_StartSound(actor, (sfxenum_t)locvar2);
+
+	// make active sound
+	if (actor->type != MT_CYBRAKDEMON && actor->info->activesound && P_RandomChance(3*FRACUNIT/256))
+	{
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+// Function: A_BrakFireShot
+//
+// Description: Shoot an object at your target, offset to match where Brak's gun is.
+// Also, sets Brak's reaction time; behaves normally otherwise.
+//
+// var1 = object # to shoot
+// var2 = unused
+//
+void A_BrakFireShot(mobj_t *actor)
+{
+	fixed_t x, y, z;
+	INT32 locvar1 = var1;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BrakFireShot", actor))
+		return;
+#endif
+	if (!actor->target)
+		return;
+
+	A_FaceTarget(actor);
+
+	x = actor->x
+		+ P_ReturnThrustX(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale))
+		+ P_ReturnThrustX(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale));
+	y = actor->y
+		+ P_ReturnThrustY(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale))
+		+ P_ReturnThrustY(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale));
+	if (actor->eflags & MFE_VERTICALFLIP)
+		z = actor->z + actor->height - FixedMul(144*FRACUNIT, actor->scale);
+	else
+		z = actor->z + FixedMul(144*FRACUNIT, actor->scale);
+
+	P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
+
+	if (!(actor->flags & MF_BOSS))
+	{
+		if (ultimatemode)
+			actor->reactiontime = actor->info->reactiontime*TICRATE;
+		else
+			actor->reactiontime = actor->info->reactiontime*TICRATE*2;
+	}
+}
+
+// Function: A_BrakLobShot
+//
+// Description: Lobs an object at the floor about a third of the way toward your target.
+//				Implication is it'll bounce the rest of the way.
+//				(You can also just aim straight at the target, but whatever)
+//				Formula grabbed from http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_required_to_hit_coordinate_.28x.2Cy.29
+//
+// var1 = object # to lob
+// var2:
+//		Lower 16 bits: height offset to shoot from, from the actor's bottom (none that "airtime" malarky)
+//		Upper 16 bits: if 0, aim 1/3 of the way. Else, aim directly at target.
+//
+
+void A_BrakLobShot(mobj_t *actor)
+{
+	fixed_t v; // Velocity to shoot object
+	fixed_t a1, a2, aToUse; // Velocity squared
+	fixed_t g; // Gravity
+	fixed_t x; // Horizontal difference
+	INT32 x_int; // x! But in integer form!
+	fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up)
+	INT32 y_int; // y! But in integer form!
+	INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper.
+	fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number.
+	angle_t theta; // Angle of attack
+	mobjtype_t typeOfShot;
+	mobj_t *shot; // Object to shoot
+	fixed_t newTargetX; // If not aiming directly
+	fixed_t newTargetY; // If not aiming directly
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2 & 0x0000FFFF;
+	INT32 aimDirect = var2 & 0xFFFF0000;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_BrakLobShot", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return; // Don't even bother if we've got nothing to aim at.
+
+	// Look up actor's current gravity situation
+	if (actor->subsector->sector->gravity)
+		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
+	else
+		g = gravity;
+
+	// Look up distance between actor and its target
+	x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
+	if (!aimDirect)
+	{
+		// Distance should actually be a third of the way over
+		x = FixedDiv(x, 3<<FRACBITS);
+		newTargetX = actor->x + P_ReturnThrustX(actor, actor->angle, x);
+		newTargetY = actor->y + P_ReturnThrustY(actor, actor->angle, x);
+		x = P_AproxDistance(newTargetX - actor->x, newTargetY - actor->y);
+		// Look up height difference between actor and the ground 1/3 of the way to its target
+		y = P_FloorzAtPos(newTargetX, newTargetY, actor->target->z, actor->target->height) - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale));
+	}
+	else
+	{
+		// Look up height difference between actor and its target
+		y = actor->target->z - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale));
+	}
+
+	// Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise.
+	x_int = x>>FRACBITS;
+	y_int = y>>FRACBITS;
+	intHypotenuse = (x_int*x_int) + (y_int*y_int);
+	fixedHypotenuse = FixedSqrt(intHypotenuse) *256;
+
+	// a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -.
+	a1 = FixedMul(g,y+fixedHypotenuse);
+	a2 = FixedMul(g,y-fixedHypotenuse);
+
+	// Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v.
+	if (a1 < 0 || a2 < 0)
+	{
+		if (a1 < 0 && a2 < 0)
+		{
+			//Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort!
+			return;
+		}
+		// Just find which one's NOT negative, and use that
+		aToUse = max(a1,a2);
+	}
+	else
+	{
+		// Both are positive; use whichever's smaller so it can decay faster
+		aToUse = min(a1,a2);
+	}
+	v = FixedSqrt(aToUse);
+	// Okay, so we know the velocity. Let's actually find theta.
+	// We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So:
+	//theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS];
+	theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))];
+
+	// Okay, complicated math done. Let's fire our object already, sheesh.
+	A_FaceTarget(actor);
+	if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES)
+		typeOfShot = MT_CANNONBALL;
+	else typeOfShot = (mobjtype_t)locvar1;
+	shot = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(locvar2*FRACUNIT, actor->scale), typeOfShot);
+	if (shot->info->seesound)
+		S_StartSound(shot, shot->info->seesound);
+	P_SetTarget(&shot->target, actor); // where it came from
+
+	shot->angle = actor->angle;
+
+	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
+	shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT));
+	shot->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(shot->angle >> ANGLETOFINESHIFT));
+	// Then the vertical axis. No angle-correction needed here.
+	shot->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT));
+	// I hope that's all that's needed, ugh
+}
+
+// Function: A_NapalmScatter
+//
+// Description: Scatters a specific number of projectiles around in a circle.
+//				Intended for use with objects that are affected by gravity; would be kind of silly otherwise.
+//
+// var1:
+//		Lower 16 bits: object # to lob (TODO: come up with a default)
+//		Upper 16 bits: Number to lob (default 8)
+// var2:
+//		Lower 16 bits: distance to toss them (No default - 0 does just that - but negatives will revert to 128)
+//		Upper 16 bits: airtime in tics (default 16)
+//
+void A_NapalmScatter(mobj_t *actor)
+{
+	mobjtype_t typeOfShot = var1 & 0x0000FFFF; // Type
+	INT32 numToShoot = (var1 & 0xFFFF0000) >> 16; // How many
+	fixed_t distance = (var2 & 0x0000FFFF) << FRACBITS; // How far
+	fixed_t airtime = var2 & 0xFFFF0000; // How long until impact (assuming no obstacles)
+	fixed_t vx; // Horizontal momentum
+	fixed_t vy; // Vertical momentum
+	fixed_t g; // Gravity
+	INT32 i; // for-loop cursor
+	mobj_t *mo; // each and every spawned napalm burst
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_NapalmScatter", actor))
+		return;
+#endif
+
+	// Some quick sanity-checking
+	if (typeOfShot >= NUMMOBJTYPES) // I'd add a <0 check, too, but 0x0000FFFF isn't negative in this case
+		typeOfShot = MT_NULL;
+	if (numToShoot <= 0) // Presumably you forgot to set var1 up; else, why are you calling this to shoot nothing?
+		numToShoot = 8;
+	else if (numToShoot > 8192) // If you seriously need this many objects spawned, stop and ask yourself "Why am I doing this?"
+		numToShoot = 8192;
+	if (distance < 0) // Presumably you thought this was an unsigned integer, you naive fool
+		distance = 32767<<FRACBITS;
+	if (airtime <= 0) // Same deal as distance I guess
+		airtime = 16<<FRACBITS;
+
+	// Look up actor's current gravity situation
+	if (actor->subsector->sector->gravity)
+		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
+	else
+		g = gravity;
+
+	// vy = (g*(airtime-1))/2
+	vy = FixedMul(g,(airtime-(1<<FRACBITS)))>>1;
+	// vx = distance/airtime
+	vx = FixedDiv(distance, airtime);
+
+	for (i = 0; i<numToShoot; i++)
+	{
+		const angle_t fa = (i*FINEANGLES/numToShoot) & FINEMASK;
+
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot);
+		P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot
+
+		mo->angle = fa << ANGLETOFINESHIFT;
+		mo->momx = FixedMul(FINECOSINE(fa),vx);
+		mo->momy = FixedMul(FINESINE(fa),vx);
+		mo->momz = vy;
+	}
+}
+
+// Function: A_SpawnFreshCopy
+//
+// Description: Spawns a copy of the mobj. x, y, z, angle, scale, target and tracer carry over; everything else starts anew.
+//				Mostly writing this because I want to do multiple actions to pass these along in a single frame instead of several.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SpawnFreshCopy(mobj_t *actor)
+{
+	mobj_t *newObject;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpawnFreshCopy", actor))
+		return;
+#endif
+
+	newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type);
+	newObject->flags2 = actor->flags2 & MF2_AMBUSH;
+	newObject->angle = actor->angle;
+	newObject->color = actor->color;
+	P_SetTarget(&newObject->target, actor->target);
+	P_SetTarget(&newObject->tracer, actor->tracer);
+
+	if (newObject->info->seesound)
+		S_StartSound(newObject, newObject->info->seesound);
+}
+
+// Internal Flicky spawning function.
+mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers)
+{
+	mobj_t *flicky;
+
+	if (!flickytype)
+	{
+		if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service.
+			return NULL;
+		else
+		{
+			INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies);
+			flickytype = mapheaderinfo[gamemap-1]->flickies[prandom];
+		}
+	}
+
+	flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype);
+	flicky->angle = actor->angle;
+
+	if (flickytype == MT_SEED)
+		flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2;
+
+	if (actor->eflags & MFE_UNDERWATER)
+		momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
+
+	P_SetObjectMomZ(flicky, momz, false);
+	flicky->movedir = (P_RandomChance(FRACUNIT/2) ?  -1 : 1);
+	flicky->fuse = P_RandomRange(595, 700);	// originally 300, 350
+	flicky->threshold = 0;
+
+	if (lookforplayers)
+		P_LookForPlayers(flicky, true, false, 0);
+
+	return flicky;
+}
+
+// Function: A_FlickySpawn
+//
+// Description: Flicky spawning function.
+//
+// var1:
+//		lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
+//		upper 16 bits: if 0, no sound is played. Else, A_Scream is called.
+// var2 = upwards thrust for spawned flicky. If zero, default value is provided.
+//
+void A_FlickySpawn(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickySpawn", actor))
+		return;
+#endif
+
+	if (locvar1 >> 16) {
+		A_Scream(actor); // A shortcut for the truly lazy.
+		locvar1 &= 65535;
+	}
+
+	P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true);
+}
+
+// Internal Flicky color setting
+void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo)
+{
+	UINT8 flickycolors[] = {
+		SKINCOLOR_RED,
+		SKINCOLOR_CYAN,
+		SKINCOLOR_BLUE,
+		SKINCOLOR_VAPOR,
+		SKINCOLOR_PURPLE,
+		SKINCOLOR_BUBBLEGUM,
+		SKINCOLOR_NEON,
+		SKINCOLOR_BLACK,
+		SKINCOLOR_BEIGE,
+		SKINCOLOR_LAVENDER,
+		SKINCOLOR_RUBY,
+		SKINCOLOR_SALMON,
+		SKINCOLOR_SUNSET,
+		SKINCOLOR_ORANGE,
+		SKINCOLOR_YELLOW,
+	};
+
+	if (extrainfo == 0)
+		// until we can customize flicky colors by level header, just stick to SRB2's defaults
+		actor->color = flickycolors[P_RandomKey(2)]; //flickycolors[P_RandomKey(sizeof(flickycolors))];
+	else
+		actor->color = flickycolors[min(extrainfo-1, 14)]; // sizeof(flickycolors)-1
+}
+
+// Function: A_FlickyCenter
+//
+// Description: Place flickies in-level.
+//
+// var1:
+//        Lower 16 bits = if 0, spawns random flicky based on level header. Else, spawns the designated thing type.
+//        Bits 17-20 = Flicky color, up to 15. Applies to fish.
+//        Bit 21 = Flag MF_SLIDEME (see below)
+//        Bit 22 = Flag MF_GRENADEBOUNCE (see below)
+//        Bit 23 = Flag MF_NOCLIPTHING (see below)
+//
+//        If actor is placed from a spawnpoint (map Thing), the Thing's properties take precedence.
+//
+// var2 = maximum default distance away from spawn the flickies are allowed to travel. If angle != 0, then that's the radius.
+//
+// If MTF_EXTRA (MF_SLIDEME): is flagged, Flickies move aimlessly. Else, orbit around the target.
+// If MTF_OBJECTSPECIAL (MF_GRENADEBOUNCE): Flickies stand in-place without gravity (unless they hop, then gravity is applied.)
+// If MTF_AMBUSH (MF_NOCLIPTHING): is flagged, Flickies hop.
+//
+void A_FlickyCenter(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	UINT16 flickytype = (locvar1 & 0xFFFF);
+	UINT8 flickycolor = ((locvar1 >> 16) & 0xFF);
+	UINT8 flickyflags = ((locvar1 >> 20) & 0xF);
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyCenter", actor))
+		return;
+#endif
+
+	if (!actor->tracer)
+	{
+		mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false);
+		P_SetTarget(&flicky->target, actor);
+		P_SetTarget(&actor->tracer, flicky);
+
+		if (actor->spawnpoint)
+		{
+			actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING);
+			actor->flags |= (
+				((actor->spawnpoint->options & MTF_EXTRA) ? MF_SLIDEME : 0)
+				| ((actor->spawnpoint->options & MTF_OBJECTSPECIAL) ? MF_GRENADEBOUNCE : 0)
+				| ((actor->spawnpoint->options & MTF_AMBUSH) ? MF_NOCLIPTHING : 0)
+			);
+			actor->extravalue1 = actor->spawnpoint->angle ? abs(actor->spawnpoint->angle) * FRACUNIT
+				: locvar2 ? abs(locvar2) : 384 * FRACUNIT;
+			actor->extravalue2 = actor->spawnpoint->extrainfo;
+			actor->friction = actor->spawnpoint->x*FRACUNIT;
+			actor->movefactor = actor->spawnpoint->y*FRACUNIT;
+			actor->watertop = actor->spawnpoint->z*FRACUNIT;
+		}
+		else
+		{
+			actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING);
+			actor->flags |= (
+				((flickyflags & 1) ? MF_SLIDEME : 0)
+				| ((flickyflags & 2) ? MF_GRENADEBOUNCE : 0)
+				| ((flickyflags & 4) ? MF_NOCLIPTHING : 0)
+			);
+			actor->extravalue1 = abs(locvar2);
+			actor->extravalue2 = flickycolor;
+			actor->friction = actor->x;
+			actor->movefactor = actor->y;
+			actor->watertop = actor->z;
+			locvar1 = flickytype;
+		}
+
+		if (actor->flags & MF_GRENADEBOUNCE) // in-place
+			actor->tracer->fuse = 0;
+		else if (actor->flags & MF_SLIDEME) // aimless
+		{
+			actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly.
+			actor->tracer->angle = P_RandomKey(180)*ANG2;
+		}
+		else //orbit
+			actor->tracer->fuse = FRACUNIT;
+
+		if (locvar1 == MT_FLICKY_08)
+			P_InternalFlickySetColor(actor->tracer, actor->extravalue2);
+
+		actor->extravalue2 = 0;
+	}
+
+	if (!(actor->flags & MF_SLIDEME) && !(actor->flags & MF_GRENADEBOUNCE))
+	{
+		fixed_t originx = actor->friction;
+		fixed_t originy = actor->movefactor;
+		fixed_t originz = actor->watertop;
+
+		actor->tracer->fuse = FRACUNIT;
+
+		// Impose default home radius if flicky orbits around player
+		if (!actor->extravalue1)
+			actor->extravalue1 = locvar2 ? abs(locvar2) : 384 * FRACUNIT;
+
+		P_LookForPlayers(actor, true, false, actor->extravalue1);
+
+		if (actor->target && P_AproxDistance(actor->target->x - originx, actor->target->y - originy) < actor->extravalue1)
+		{
+			actor->extravalue2 = 1;
+		 	P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z);
+		}
+		else if(actor->extravalue2)
+		{
+			actor->extravalue2 = 0;
+			P_TeleportMove(actor, originx, originy, originz);
+		}
+	}
+}
+
+// Internal Flicky bubbling function.
+void P_InternalFlickyBubble(mobj_t *actor)
+{
+	if (actor->eflags & MFE_UNDERWATER)
+	{
+		mobj_t *overlay;
+
+		if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer)
+			return;
+
+		overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
+		P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate);
+		P_SetTarget(&actor->tracer, overlay);
+		P_SetTarget(&overlay->target, actor);
+		return;
+	}
+
+	if (!actor->tracer || P_MobjWasRemoved(actor->tracer))
+		return;
+
+	P_RemoveMobj(actor->tracer);
+	P_SetTarget(&actor->tracer, NULL);
+}
+
+// Function: A_FlickyAim
+//
+// Description: Flicky aiming function.
+//
+// var1 = how far around the target (in angle constants) the flicky should look
+// var2 = distance from target to aim for
+//
+void A_FlickyAim(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	boolean flickyhitwall = false;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyAim", actor))
+		return;
+#endif
+
+	if ((actor->momx == actor->momy && actor->momy == 0)
+		|| (actor->target && P_IsFlickyCenter(actor->target->type)
+			&& actor->target->extravalue1 && (actor->target->flags & MF_SLIDEME)
+			&& P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) >= actor->target->extravalue1))
+		flickyhitwall = true;
+
+	P_InternalFlickyBubble(actor);
+	P_InstaThrust(actor, 0, 0);
+
+	if (!actor->target)
+	{
+		P_LookForPlayers(actor, true, false, 0);
+		actor->angle = P_RandomKey(36)*ANG10;
+		return;
+	}
+
+	if (actor->fuse > 2*TICRATE)
+	{
+		angle_t posvar;
+		fixed_t chasevar, chasex, chasey;
+
+		if (flickyhitwall)
+			actor->movedir *= -1;
+
+		posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK;
+		chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2;
+
+		chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar);
+		chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar);
+
+		if (P_AproxDistance(chasex - actor->x, chasey - actor->y))
+			actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey);
+	}
+	else if (flickyhitwall)
+	{
+		if (actor->target && P_IsFlickyCenter(actor->target->type))
+			actor->angle = R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + P_RandomRange(112, 248) * ANG1;
+		else
+			actor->angle += P_RandomRange(112, 248)*ANG1;
+		actor->threshold = 0;
+	}
+}
+
+//Internal Flicky flying function. Also usuable as an underwater swim thrust.
+void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez)
+{
+	angle_t vertangle;
+
+	flyspeed = FixedMul(flyspeed, actor->scale);
+	actor->flags |= MF_NOGRAVITY;
+
+	var1 = ANG30;
+	var2 = 32*FRACUNIT;
+	A_FlickyAim(actor);
+
+	chasez *= 8;
+	if (!actor->target || !(actor->fuse > 2*TICRATE))
+		chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT);
+	else
+	{
+		fixed_t add = actor->target->z + (actor->target->height - actor->height)/2;
+		if (add > (actor->ceilingz - 24*actor->scale - actor->height))
+			add = actor->ceilingz - 24*actor->scale - actor->height;
+		else if (add < (actor->floorz + 24*actor->scale))
+			add = actor->floorz + 24*actor->scale;
+		chasez += add;
+	}
+
+	if (!targetdist)
+		targetdist = 16*FRACUNIT; //Default!
+
+	if (actor->target && abs(chasez - actor->z) > targetdist)
+		targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
+
+	if (actor->target
+		&& P_IsFlickyCenter(actor->target->type)
+		&& (actor->target->flags & MF_SLIDEME))
+		vertangle = 0;
+	else
+		vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK;
+
+	P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed));
+	actor->momz = FixedMul(FINESINE(vertangle), flyspeed);
+}
+
+// Function: A_FlickyFly
+//
+// Description: Flicky flying function.
+//
+// var1 = how fast to fly
+// var2 = how far ahead the target should be considered
+//
+void A_FlickyFly(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyFly", actor))
+		return;
+#endif
+	P_InternalFlickyFly(actor, locvar1, locvar2,
+	FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK)
+	);
+}
+
+// Function: A_FlickySoar
+//
+// Description: Flicky soaring function - specific to puffin.
+//
+// var1 = how fast to fly
+// var2 = how far ahead the target should be considered
+//
+void A_FlickySoar(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickySoar", actor))
+		return;
+#endif
+	P_InternalFlickyFly(actor, locvar1, locvar2,
+	2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK)))
+	);
+
+	if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10)
+		actor->frame = 3;
+}
+
+//Function: A_FlickyCoast
+//
+// Description: Flicky swim-coasting function.
+//
+// var1 = speed to change state upon reaching
+// var2 = state to change to upon slowing down
+// the spawnstate of the mobj = state to change to when above water
+//
+void A_FlickyCoast(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyCoast", actor))
+		return;
+#endif
+	if (actor->eflags & MFE_UNDERWATER)
+	{
+		actor->momx = (11*actor->momx)/12;
+		actor->momy = (11*actor->momy)/12;
+		actor->momz = (11*actor->momz)/12;
+
+		if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1)
+			P_SetMobjState(actor, locvar2);
+
+		return;
+	}
+
+	actor->flags &= ~MF_NOGRAVITY;
+	P_SetMobjState(actor, mobjinfo[actor->type].spawnstate);
+}
+
+// Internal Flicky hopping function.
+void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle)
+{
+	if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
+	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
+	{
+		if (momz)
+		{
+			if (actor->eflags & MFE_UNDERWATER)
+				momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT));
+			P_SetObjectMomZ(actor, momz, false);
+		}
+		P_InstaThrust(actor, angle, FixedMul(momh, actor->scale));
+	}
+}
+
+// Function: A_FlickyHop
+//
+// Description: Flicky hopping function.
+//
+// var1 = vertical thrust
+// var2 = horizontal thrust
+//
+void A_FlickyHop(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyHop", actor))
+		return;
+#endif
+	P_InternalFlickyHop(actor, locvar1, locvar2, actor->angle);
+}
+
+// Function: A_FlickyFlounder
+//
+// Description: Flicky floundering function.
+//
+// var1 = intended vertical thrust
+// var2 = intended horizontal thrust
+//
+void A_FlickyFlounder(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	angle_t hopangle;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyFlounder", actor))
+		return;
+#endif
+	locvar1 *= (P_RandomKey(2) + 1);
+	locvar2 *= (P_RandomKey(2) + 1);
+	hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2);
+	P_InternalFlickyHop(actor, locvar1, locvar2, hopangle);
+}
+
+// Function: A_FlickyCheck
+//
+// Description: Flicky airtime check function.
+//
+// var1 = state to change to upon touching the floor
+// var2 = state to change to upon falling
+// the meleestate of the mobj = state to change to when underwater
+//
+void A_FlickyCheck(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyCheck", actor))
+		return;
+#endif
+	if (actor->target
+		&& P_IsFlickyCenter(actor->target->type)
+		&& (actor->target->flags & MF_GRENADEBOUNCE))
+	{
+		if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping
+		{
+			actor->momz = 0;
+			actor->flags |= MF_NOGRAVITY;
+		}
+		actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY;
+		P_SetMobjState(actor, mobjinfo[actor->type].seestate);
+	}
+	else if (locvar2 && P_MobjFlip(actor)*actor->momz < 1)
+		P_SetMobjState(actor, locvar2);
+	else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
+	|| ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)))
+		P_SetMobjState(actor, locvar1);
+	else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER))
+		P_SetMobjState(actor, mobjinfo[actor->type].meleestate);
+	P_InternalFlickyBubble(actor);
+}
+
+// Function: A_FlickyHeightCheck
+//
+// Description: Flicky height check function.
+//
+// var1 = state to change to when falling below height relative to target
+// var2 = height relative to target to change state at
+//
+void A_FlickyHeightCheck(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyHeightCheck", actor))
+		return;
+#endif
+	if (actor->target
+		&& P_IsFlickyCenter(actor->target->type)
+		&& (actor->target->flags & MF_GRENADEBOUNCE))
+	{
+		if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping
+		{
+			actor->momz = 0;
+			actor->flags |= MF_NOGRAVITY;
+		}
+		actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY;
+		P_SetMobjState(actor, mobjinfo[actor->type].seestate);
+	}
+	else if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1
+	&& ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2)
+	|| (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz)))
+		P_SetMobjState(actor, locvar1);
+	P_InternalFlickyBubble(actor);
+}
+
+// Function: A_FlickyFlutter
+//
+// Description: Flicky fluttering function - specific to chicken.
+//
+// var1 = state to change to upon touching the floor
+// var2 = state to change to upon falling
+// the meleestate of the mobj = state to change to when underwater
+//
+void A_FlickyFlutter(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlickyFlutter", actor))
+		return;
+#endif
+	var1 = locvar1;
+	var2 = locvar2;
+	A_FlickyCheck(actor);
+
+	var1 = ANG30;
+	var2 = 32*FRACUNIT;
+	A_FlickyAim(actor);
+
+	P_InstaThrust(actor, actor->angle, 2*actor->scale);
+	if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2)
+		actor->momz = -P_MobjFlip(actor)*actor->scale/2;
+}
+
+#undef FLICKYHITWALL
+
+// Function: A_FlameParticle
+//
+// Description: Creates the mobj's painchance at a random position around the object's radius.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_FlameParticle(mobj_t *actor)
+{
+	mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance);
+	fixed_t rad, hei;
+	mobj_t *particle;
+	//INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FlameParticle", actor))
+		return;
+#endif
+
+	if (!type)
+		return;
+
+	rad = actor->radius>>FRACBITS;
+	hei = actor->height>>FRACBITS;
+	particle = P_SpawnMobjFromMobj(actor,
+		P_RandomRange(rad, -rad)<<FRACBITS,
+		P_RandomRange(rad, -rad)<<FRACBITS,
+		P_RandomRange(hei/2, hei)<<FRACBITS,
+		type);
+	P_SetObjectMomZ(particle, 2<<FRACBITS, false);
+}
+
+// Function: A_FadeOverlay
+//
+// Description: Makes a pretty overlay (primarily for super/NiGHTS transformation).
+//
+// var1 = bit 1 = bit 1 = don't make fast, bit 2 = don't set tracer
+// var2 = unused
+//
+void A_FadeOverlay(mobj_t *actor)
+{
+	mobj_t *fade;
+	INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FadeOverlay", actor))
+		return;
+#endif
+
+	fade = P_SpawnGhostMobj(actor);
+	fade->frame = actor->frame;
+
+	if (!(locvar1 & 1))
+	{
+		fade->fuse = 15;
+		fade->flags2 |= MF2_BOSSNOTRAP;
+	}
+	else
+		fade->fuse = 20;
+
+	if (!(locvar1 & 2))
+		P_SetTarget(&actor->tracer, fade);
+}
+
+// Function: A_Boss5Jump
+//
+// Description: Makes an object jump in an arc to land on their tracer precicely.
+//				Adapted from A_BrakLobShot, see there for explanation.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_Boss5Jump(mobj_t *actor)
+{
+	fixed_t v; // Velocity to jump at
+	fixed_t a1, a2, aToUse; // Velocity squared
+	fixed_t g; // Gravity
+	fixed_t x; // Horizontal difference
+	INT32 x_int; // x! But in integer form!
+	fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up)
+	INT32 y_int; // y! But in integer form!
+	INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper.
+	fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number.
+	angle_t theta; // Angle of attack
+	// INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_Boss5Jump", actor))
+		return;
+#endif
+
+	if (!actor->tracer)
+		return; // Don't even bother if we've got nothing to aim at.
+
+	// Look up actor's current gravity situation
+	if (actor->subsector->sector->gravity)
+		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
+	else
+		g = gravity;
+
+	// Look up distance between actor and its tracer
+	x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
+	// Look up height difference between actor and its tracer
+	y = actor->tracer->z - actor->z;
+
+	// Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise.
+	x_int = x>>FRACBITS;
+	y_int = y>>FRACBITS;
+	intHypotenuse = (x_int*x_int) + (y_int*y_int);
+	fixedHypotenuse = FixedSqrt(intHypotenuse) *256;
+
+	// a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -.
+	a1 = FixedMul(g,y+fixedHypotenuse);
+	a2 = FixedMul(g,y-fixedHypotenuse);
+
+	// Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v.
+	if (a1 < 0 || a2 < 0)
+	{
+		if (a1 < 0 && a2 < 0)
+		{
+			//Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort!
+			return;
+		}
+		// Just find which one's NOT negative, and use that
+		aToUse = max(a1,a2);
+	}
+	else
+	{
+		// Both are positive; use whichever's smaller so it can decay faster
+		aToUse = min(a1,a2);
+	}
+	v = FixedSqrt(aToUse);
+	// Okay, so we know the velocity. Let's actually find theta.
+	// We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So:
+	//theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS];
+	theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))];
+
+	// Okay, complicated math done. Let's make this object jump already.
+	A_FaceTracer(actor);
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		actor->z--;
+	else
+		actor->z++;
+
+	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
+	fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse
+	actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT));
+	actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT));
+	// Then the vertical axis. No angle-correction needed here.
+	actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT));
+	// I hope that's all that's needed, ugh
+}
+
+// Function: A_LightBeamReset
+// Description: Resets momentum and position for DSZ's projecting light beams
+//
+// var1 = unused
+// var2 = unused
+//
+void A_LightBeamReset(mobj_t *actor)
+{
+	// INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_LightBeamReset", actor))
+		return;
+#endif
+
+	actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256;
+	P_SetScale(actor, actor->destscale);
+
+	if (!actor->spawnpoint)
+		return; // this can't work properly welp
+
+	actor->momx = -(P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128;
+	actor->momy = (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128;
+	actor->momz = (P_SignedRandom()*FRACUNIT)/128;
+
+	P_TeleportMove(actor,
+		actor->spawnpoint->x*FRACUNIT - (P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
+		actor->spawnpoint->y*FRACUNIT + (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
+		actor->spawnpoint->z*FRACUNIT + (P_SignedRandom()*FRACUNIT)/2);
+}
+
+// Function: A_MineExplode
+// Description: Handles the explosion of a DSZ mine.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MineExplode(mobj_t *actor)
+{
+	// INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MineExplode", actor))
+		return;
+#endif
+
+	A_Scream(actor);
+	actor->flags = MF_NOGRAVITY|MF_NOCLIP;
+
+	quake.epicenter = NULL;
+	quake.radius = 512*FRACUNIT;
+	quake.intensity = 8*FRACUNIT;
+	quake.time = TICRATE/3;
+
+	P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF);
+	P_MobjCheckWater(actor);
+
+	{
+#define dist 64
+		UINT8 i;
+		mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE);
+		S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e));
+		P_SpawnMobj(actor->x, actor->y, actor->z, type);
+		for (i = 0; i < 16; i++)
+		{
+			mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT,
+				actor->y+P_RandomRange(-dist, dist)*FRACUNIT,
+				actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT,
+				type);
+			fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z;
+			fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx));
+			b->momx = FixedDiv(dx, dm)*3;
+			b->momy = FixedDiv(dy, dm)*3;
+			b->momz = FixedDiv(dz, dm)*3;
+			if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop))
+				b->flags &= ~MF_NOGRAVITY;
+		}
+#undef dist
+
+		if (actor->watertop != INT32_MAX)
+			P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH);
+	}
+}
+
+// Function: A_MineRange
+// Description: If the target gets too close, change the state to meleestate.
+//
+// var1 = Distance to alert at
+// var2 = unused
+//
+void A_MineRange(mobj_t *actor)
+{
+	fixed_t dm;
+	INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MineRange", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x));
+	if ((dm>>FRACBITS) < locvar1)
+		P_SetMobjState(actor, actor->info->meleestate);
+}
+
+// Function: A_ConnectToGround
+// Description: Create a palm tree trunk/mine chain.
+//
+// var1 = Object type to connect to ground
+// var2 = Object type to place on ground
+//
+void A_ConnectToGround(mobj_t *actor)
+{
+	mobj_t *work;
+	fixed_t workz;
+	fixed_t workh;
+	SINT8 dir;
+	angle_t ang;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ConnectToGround", actor))
+		return;
+#endif
+
+	if (actor->subsector->sector->ffloors)
+		P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2);
+
+	if (actor->flags2 & MF2_OBJECTFLIP)
+	{
+		workz = actor->ceilingz - (actor->z + actor->height);
+		dir = -1;
+	}
+	else
+	{
+		workz = actor->floorz - actor->z;
+		dir = 1;
+	}
+
+	if (locvar2)
+	{
+		workh = FixedMul(mobjinfo[locvar2].height, actor->scale);
+		if (actor->flags2 & MF2_OBJECTFLIP)
+			workz -= workh;
+		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2);
+		workz += dir*workh;
+	}
+
+	if (!locvar1)
+		return;
+
+	if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale)))
+		return;
+
+	if (actor->flags2 & MF2_OBJECTFLIP)
+		workz -= workh;
+
+	ang = actor->angle + ANGLE_45;
+	while (dir*workz < 0)
+	{
+		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1);
+		if (work)
+			work->angle = ang;
+		ang += ANGLE_90;
+		workz += dir*workh;
+	}
+
+	if (workz != 0)
+		actor->z += workz;
+}
+
+// Function: A_SpawnParticleRelative
+//
+// Description: Spawns a particle effect relative to the location of the actor
+//
+// var1:
+//		var1 >> 16 = x
+//		var1 & 65535 = y
+// var2:
+//		var2 >> 16 = z
+//		var2 & 65535 = state
+//
+void A_SpawnParticleRelative(mobj_t *actor)
+{
+	INT16 x, y, z; // Want to be sure we can use negative values
+	statenum_t state;
+	mobj_t *mo;
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpawnParticleRelative", actor))
+		return;
+#endif
+
+	CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
+
+	x = (INT16)(locvar1>>16);
+	y = (INT16)(locvar1&65535);
+	z = (INT16)(locvar2>>16);
+	state = (statenum_t)(locvar2&65535);
+
+	// Spawn objects correctly in reverse gravity.
+	// NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame
+	mo = P_SpawnMobj(actor->x + FixedMul(x<<FRACBITS, actor->scale),
+		actor->y + FixedMul(y<<FRACBITS, actor->scale),
+		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), MT_PARTICLE);
+
+	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
+	mo->angle = actor->angle;
+
+	if (actor->eflags & MFE_VERTICALFLIP)
+		mo->flags2 |= MF2_OBJECTFLIP;
+
+	P_SetMobjState(mo, state);
+}
+
+// Function: A_MultiShotDist
+//
+// Description: Spawns multiple shots based on player proximity
+//
+// var1 = same as A_MultiShot
+// var2 = same as A_MultiShot
+//
+void A_MultiShotDist(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MultiShotDist", actor))
+		return;
+#endif
+
+	{
+		UINT8 i;
+		// Quick! Look through players!
+		// Don't spawn dust unless a player is relatively close by (var1).
+		for (i = 0; i < MAXPLAYERS; ++i)
+			if (playeringame[i] && players[i].mo
+			 && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600<<FRACBITS))
+				break; // Stop looking.
+		if (i == MAXPLAYERS)
+			return; // don't make bubble!
+	}
+
+	var1 = locvar1;
+	var2 = locvar2;
+	A_MultiShot(actor);
+}
+
+// Function: A_WhoCaresIfYourSonIsABee
+//
+// Description: Makes a child object, storing the number of created children in the parent's extravalue1.
+//
+// var1 = mobjtype of child
+//		var2 >> 16 = mobjtype of child
+//		var2 & 65535 = vertical momentum
+// var2:
+//		var2 >> 16 = forward offset
+//		var2 & 65535 = vertical offset
+//
+void A_WhoCaresIfYourSonIsABee(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t foffsetx;
+	fixed_t foffsety;
+	mobj_t *son;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor))
+		return;
+#endif
+
+	A_FaceTarget(actor);
+
+	if (actor->extravalue1)
+		actor->extravalue1--;
+
+	if (actor->info->attacksound)
+		S_StartSound(actor, actor->info->attacksound);
+
+	foffsetx = P_ReturnThrustX(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
+	foffsety = P_ReturnThrustY(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale));
+
+	if (!(son = P_SpawnMobjFromMobj(actor, foffsetx, foffsety, (locvar2&65535)*FRACUNIT, (mobjtype_t)(locvar1 >> 16))))
+		return;
+
+	P_SetObjectMomZ(son, (locvar1 & 65535)<<FRACBITS, true);
+
+	P_SetTarget(&son->tracer, actor);
+	P_SetTarget(&son->target, actor->target);
+}
+
+// Function: A_ParentTriesToSleep
+//
+// Description: If extravalue1 is less than or equal to var1, go to var2.
+//
+// var1 = state to go to when extravalue1
+// var2 = unused
+//
+void A_ParentTriesToSleep(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_ParentTriesToSleep", actor))
+		return;
+#endif
+
+	if (actor->extravalue1)
+	{
+		if (actor->info->seesound)
+			S_StartSound(actor, actor->info->seesound);
+		actor->reactiontime = 0;
+		P_SetMobjState(actor, locvar1);
+	}
+	else if (!actor->reactiontime)
+	{
+		actor->reactiontime = 1;
+		if (actor->info->activesound) // more like INactivesound doy hoy hoy
+			S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+
+// Function: A_CryingToMomma
+//
+// Description: If you're a child, let your parent know something's happened to you through extravalue1. Also, prepare to die.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_CryingToMomma(mobj_t *actor)
+{
+	//INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CryingToMomma", actor))
+		return;
+#endif
+
+	if (actor->tracer)
+		actor->tracer->extravalue1++;
+
+	actor->momx = actor->momy = actor->momz = 0;
+
+	P_UnsetThingPosition(actor);
+	if (sector_list)
+	{
+		P_DelSeclist(sector_list);
+		sector_list = NULL;
+	}
+	actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING;
+	P_SetThingPosition(actor);
+}
+
+// Function: A_CheckFlags2
+//
+// Description: If actor->flags2 & var1, goto var2.
+//
+// var1 = mask
+// var2 = state to go
+//
+void A_CheckFlags2(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_CheckFlags2", actor))
+		return;
+#endif
+
+	if (actor->flags2 & locvar1)
+		P_SetMobjState(actor, (statenum_t)locvar2);
+}
diff --git a/src/p_floor.c b/src/p_floor.c
index 8f1afaeba1712b93b7f91c82a5839857744c8172..65e4b9537d831f243a38fe40db3ee76425ac46f7 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -815,6 +815,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
 		{
 			bouncer->sector->ceilingheight = actionsector->ceilingheight;
 			bouncer->sector->floorheight = bouncer->sector->ceilingheight - (halfheight*2);
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
 			P_RecalcPrecipInSector(actionsector);
 			bouncer->sector->ceilingdata = NULL;
 			bouncer->sector->floordata = NULL;
@@ -829,6 +831,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
 		{
 			bouncer->sector->ceilingheight = floorheight + (halfheight << 1);
 			bouncer->sector->floorheight = floorheight;
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
 			P_RecalcPrecipInSector(actionsector);
 			bouncer->sector->ceilingdata = NULL;
 			bouncer->sector->floordata = NULL;
@@ -845,9 +849,9 @@ void T_BounceCheese(levelspecthink_t *bouncer)
 		}
 
 		T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->ceilingheight -
-			70*FRACUNIT, 0, 1, -1); // move floor
+			70*FRACUNIT, 0, 1, -1); // move ceiling
 		T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->floorheight - 70*FRACUNIT,
-			0, 0, -1); // move ceiling
+			0, 0, -1); // move floor
 
 		bouncer->sector->floorspeed = -bouncer->speed/2;
 		bouncer->sector->ceilspeed = 42;
@@ -897,6 +901,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
 		{
 			bouncer->sector->floorheight = bouncer->floorwasheight;
 			bouncer->sector->ceilingheight = bouncer->ceilingwasheight;
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
+			T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
 			bouncer->sector->ceilingdata = NULL;
 			bouncer->sector->floordata = NULL;
 			bouncer->sector->floorspeed = 0;
@@ -1981,7 +1987,7 @@ void T_ThwompSector(levelspecthink_t *thwomp)
 					continue;
 
 				mo = (mobj_t *)th;
-				if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator 
+				if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator
 				    && mo->z <= thwomp->sector->ceilingheight
 					&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
 				{
diff --git a/src/p_inter.c b/src/p_inter.c
index 63abf4c0ed1601934ffa97bfd5e86b6bd31a072f..5f2875252e0314e10d0c4a358a236ce959c22c46 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -793,28 +793,76 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_SwitchSpheresBonusMode(false);
 				if (!(netgame || multiplayer) && !(player->powers[pw_carry] == CR_NIGHTSMODE))
 					P_SetTarget(&special->tracer, toucher);
+				P_SetTarget(&player->drone, special); // Mark the player as 'center into the drone'
 				P_NightserizePlayer(player, special->health); // Transform!
 				if (!spec)
 				{
-					if (toucher->tracer) // Move the ideya over to the drone!
+					if (toucher->tracer) // Move the Ideya to an anchor!
 					{
-						mobj_t *hnext = special->hnext;
-						P_SetTarget(&special->hnext, toucher->tracer);
-						P_SetTarget(&special->hnext->hnext, hnext); // Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo.
-						P_SetTarget(&special->hnext->target, special);
+						mobj_t *orbittarget = special->target ? special->target : special;
+						mobj_t *hnext = orbittarget->hnext, *anchorpoint = NULL, *anchorpoint2 = NULL;
+						mobj_t *mo2;
+						thinker_t *th;
+
+						// The player might have two Ideyas: toucher->tracer and toucher->tracer->hnext
+						// so handle their anchorpoints accordingly.
+						// scan the thinkers to find the corresponding anchorpoint
+						for (th = thinkercap.next; th != &thinkercap; th = th->next)
+						{
+							if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+								continue;
+
+							mo2 = (mobj_t *)th;
+
+							if (mo2->type == MT_IDEYAANCHOR)
+							{
+								if (mo2->health == toucher->tracer->health) // do ideya numberes match?
+									anchorpoint = mo2;
+								else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health)
+									anchorpoint2 = mo2;
+
+								if ((!toucher->tracer->hnext && anchorpoint)
+									|| (toucher->tracer->hnext && anchorpoint && anchorpoint2))
+									break;
+							}
+						}
+
+						if (anchorpoint)
+						{
+							toucher->tracer->flags |= MF_GRENADEBOUNCE; // custom radius factors
+							toucher->tracer->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8
+						}
+
+						if (anchorpoint2)
+						{
+							toucher->tracer->hnext->flags |= MF_GRENADEBOUNCE; // custom radius factors
+							toucher->tracer->hnext->threshold = 8 << 20; // X factor 0, Y factor 0, Z factor 8
+						}
+
+						P_SetTarget(&orbittarget->hnext, toucher->tracer);
+						if (!orbittarget->hnext->hnext)
+							P_SetTarget(&orbittarget->hnext->hnext, hnext); // Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo.
+						else
+							P_SetTarget(&orbittarget->hnext->hnext->target, anchorpoint2 ? anchorpoint2 : orbittarget);
+						P_SetTarget(&orbittarget->hnext->target, anchorpoint ? anchorpoint : orbittarget);
 						P_SetTarget(&toucher->tracer, NULL);
+
 						if (hnext)
 						{
-							special->hnext->extravalue1 = (angle_t)(hnext->extravalue1 - 72*ANG1);
-							if (special->hnext->extravalue1 > hnext->extravalue1)
-								special->hnext->extravalue1 -= (72*ANG1)/special->hnext->extravalue1;
+							orbittarget->hnext->extravalue1 = (angle_t)(hnext->extravalue1 - 72*ANG1);
+							if (orbittarget->hnext->extravalue1 > hnext->extravalue1)
+								orbittarget->hnext->extravalue1 -= (72*ANG1)/orbittarget->hnext->extravalue1;
 						}
 					}
 					if (player->exiting) // ...then move it back?
 					{
-						mobj_t *hnext = special;
+						mobj_t *hnext = special->target ? special->target : special; // goalpost
 						while ((hnext = hnext->hnext))
+						{
+							hnext->flags &= ~MF_GRENADEBOUNCE;
+							hnext->threshold = 0;
 							P_SetTarget(&hnext->target, toucher);
+						}
 					}
 					return;
 				}
@@ -961,8 +1009,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if (player->powers[pw_carry] == CR_NIGHTSMODE && !toucher->target)
 				return;
 
-			if (toucher->tracer)
-				return; // Don't have multiple ideya
+			if (toucher->tracer && toucher->tracer->health > 0)
+				return; // Don't have multiple ideya, unless it's the first one given (health = 0)
 
 			if (player->mare != special->threshold) // wrong mare
 				return;
diff --git a/src/p_map.c b/src/p_map.c
index 648bb2bccc164d1fde2b3903e42870ca58361f2c..b4ace61c79adc4f07952c7f5d7a9165ba69113fe 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -134,7 +134,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 {
 	fixed_t vertispeed = spring->info->mass;
 	fixed_t horizspeed = spring->info->damage;
-	boolean final;
+	boolean final = false;
 
 	// Object was already sprung this tic
 	if (object->eflags & MFE_SPRUNG)
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 3c1418252839601810150fc782f5763c92021c02..2a00660a3e6861cd138931009c29b03a39ec4b6d 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -7454,7 +7454,7 @@ void P_MobjThinker(mobj_t *mobj)
 
 			// failure state: mobj is not facing tracer
 			// Reasaonable defaults: ANGLE_67h, ANGLE_292h
-			if (ang >= (UINT32)mobj->extravalue1 && ang <= ANGLE_MAX - (UINT32)mobj->extravalue1)
+			if (ang >= (angle_t)mobj->extravalue1 && ang <= ANGLE_MAX - (angle_t)mobj->extravalue1)
 			{
 				if (mobj->cvmem)
 					mobj->cvmem--;
@@ -7924,78 +7924,247 @@ void P_MobjThinker(mobj_t *mobj)
 				}
 				break;
 			case MT_NIGHTSDRONE:
-				// GOAL mode?
-				if (mobj->state >= &states[S_NIGHTSDRONE_SPARKLING1] && mobj->state <= &states[S_NIGHTSDRONE_SPARKLING16])
 				{
-					INT32 i;
-					boolean bonustime = false;
+					// variable setup
+					mobj_t *goalpost = NULL;
+					mobj_t *sparkle = NULL;
+					mobj_t *droneman = NULL;
 
-					for (i = 0; i < MAXPLAYERS; i++)
-						if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE)
-						{
-							bonustime = true;
-							break;
-						}
+					boolean flip = mobj->flags2 & MF2_OBJECTFLIP;
+					boolean topaligned = (mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE);
+					boolean middlealigned = (mobj->flags & MF_GRENADEBOUNCE) && !(mobj->flags & MF_SLIDEME);
+					boolean bottomoffsetted = !(mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE);
+					boolean flipchanged = false;
+
+					fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff;
 
-					if (!bonustime)
+					if (mobj->target && mobj->target->type == MT_NIGHTSDRONE_GOAL)
 					{
-						CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n");
-						P_RemoveMobj(mobj->target);
-						P_SetTarget(&mobj->target, NULL);
+						goalpost = mobj->target;
+						if (goalpost->target && goalpost->target->type == MT_NIGHTSDRONE_SPARKLING)
+							sparkle = goalpost->target;
+						if (goalpost->tracer && goalpost->tracer->type == MT_NIGHTSDRONE_MAN)
+							droneman = goalpost->tracer;
+					}
 
-						mobj->flags &= ~MF_NOGRAVITY;
-						mobj->flags2 |= MF2_DONTDRAW;
-						P_SetMobjState(mobj, S_NIGHTSDRONE1);
+					if (!goalpost || !sparkle || !droneman)
+						break;
+
+					// did NIGHTSDRONE position, scale, flip, or flags change? all elements need to be synced
+					droneboxmandiff = max(mobj->height - droneman->height, 0);
+					dronemangoaldiff = max(droneman->height - goalpost->height, 0);
+
+					if (!(goalpost->flags2 & MF2_OBJECTFLIP) && (mobj->flags2 & MF2_OBJECTFLIP))
+					{
+						goalpost->eflags |= MFE_VERTICALFLIP;
+						goalpost->flags2 |= MF2_OBJECTFLIP;
+						sparkle->eflags |= MFE_VERTICALFLIP;
+						sparkle->flags2 |= MF2_OBJECTFLIP;
+						droneman->eflags |= MFE_VERTICALFLIP;
+						droneman->flags2 |= MF2_OBJECTFLIP;
+						flipchanged = true;
+					}
+					else if ((goalpost->flags2 & MF2_OBJECTFLIP) && !(mobj->flags2 & MF2_OBJECTFLIP))
+					{
+						goalpost->eflags &= ~MFE_VERTICALFLIP;
+						goalpost->flags2 &= ~MF2_OBJECTFLIP;
+						sparkle->eflags &= ~MFE_VERTICALFLIP;
+						sparkle->flags2 &= ~MF2_OBJECTFLIP;
+						droneman->eflags &= ~MFE_VERTICALFLIP;
+						droneman->flags2 &= ~MF2_OBJECTFLIP;
+						flipchanged = true;
 					}
-				}
-				// Invisible/bouncing mode.
-				else
-				{
-					INT32 i;
-					boolean bonustime = false;
 
-					// Bouncy bouncy!
-					mobj->angle += ANG10;
-					if (mobj->flags2 & MF2_DONTDRAW)
-						mobj->momz = 0;
-					else if (mobj->z <= mobj->floorz)
-						mobj->momz = 5*FRACUNIT;
+					if (goalpost->destscale != mobj->destscale
+					    || goalpost->movefactor != mobj->z
+						|| goalpost->friction != mobj->height
+						|| flipchanged
+						|| goalpost->threshold != (INT32)(mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE)))
+					{
+						goalpost->destscale = sparkle->destscale = droneman->destscale = mobj->destscale;
 
-					for (i = 0; i < MAXPLAYERS; i++)
-						if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE)
+						// straight copy-pasta from P_SpawnMapThing, case MT_NIGHTSDRONE
+						if (!flip)
 						{
-							bonustime = true;
-							break;
+							if (topaligned) // Align droneman to top of hitbox
+							{
+								dronemanoffset = droneboxmandiff;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+							else if (middlealigned) // Align droneman to center of hitbox
+							{
+								dronemanoffset = droneboxmandiff / 2;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+							else if (bottomoffsetted)
+							{
+								dronemanoffset = 24*FRACUNIT;
+								goaloffset = dronemangoaldiff + dronemanoffset;
+							}
+							else
+							{
+								dronemanoffset = 0;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+
+							sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale);
+						}
+						else
+						{
+							if (topaligned) // Align droneman to top of hitbox
+							{
+								dronemanoffset = 0;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+							else if (middlealigned) // Align droneman to center of hitbox
+							{
+								dronemanoffset = droneboxmandiff / 2;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+							else if (bottomoffsetted)
+							{
+								dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale);
+								goaloffset = dronemangoaldiff + dronemanoffset;
+							}
+							else
+							{
+								dronemanoffset = droneboxmandiff;
+								goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+							}
+
+							sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale);
 						}
 
-					if (bonustime)
+						P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset);
+						P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset);
+						if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height)
+						{
+							P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset);
+							goalpost->movefactor = mobj->z;
+							goalpost->friction = mobj->height;
+						}
+						goalpost->threshold = mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE);
+					}
+					else
 					{
-						mobj->z = mobj->floorz + mobj->height;
-						mobj->angle = mobj->momz = 0;
+						if (goalpost->x != mobj->x || goalpost->y != mobj->y)
+						{
+							P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z);
+							P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z);
+						}
+
+						if (droneman->x != mobj->x || droneman->y != mobj->y)
+							P_TeleportMove(droneman, mobj->x, mobj->y,
+							               droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z);
+					}
 
-						if (mobj->spawnpoint)
-							mobj->z += (mobj->spawnpoint->options >> ZSHIFT)<<FRACBITS;
+					// now toggle states!
+					// GOAL mode?
+					if (sparkle->state >= &states[S_NIGHTSDRONE_SPARKLING1] && sparkle->state <= &states[S_NIGHTSDRONE_SPARKLING16])
+					{
+						INT32 i;
+						boolean bonustime = false;
 
-						CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n");
-						P_SetTarget(&mobj->target, P_SpawnMobjFromMobj(mobj, 0, 0, FRACUNIT, MT_NIGHTSGOAL));
+						for (i = 0; i < MAXPLAYERS; i++)
+							if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE)
+							{
+								bonustime = true;
+								break;
+							}
 
-						mobj->flags2 &= ~MF2_DONTDRAW;
-						mobj->flags |= MF_NOGRAVITY;
-						P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1);
+						if (!bonustime)
+						{
+							CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n");
+							if (goalpost && goalpost->state != &states[S_INVISIBLE])
+								P_SetMobjState(goalpost, S_INVISIBLE);
+							if (sparkle && sparkle->state != &states[S_INVISIBLE])
+								P_SetMobjState(sparkle, S_INVISIBLE);
+						}
 					}
-					else if (!G_IsSpecialStage(gamemap))
+					// Invisible/bouncing mode.
+					else
 					{
+						fixed_t droneboxmandiff = max(mobj->height - droneman->height, 0);
+						INT32 i;
+						boolean bonustime = false;
+						fixed_t zcomp;
+
+						// Bouncy bouncy!
+						if (!flip)
+						{
+							if (topaligned)
+								zcomp = droneboxmandiff + mobj->z;
+							else if (middlealigned)
+								zcomp = (droneboxmandiff / 2) + mobj->z;
+							else if (bottomoffsetted)
+								zcomp = mobj->z + FixedMul(24*FRACUNIT, mobj->scale);
+							else
+								zcomp = mobj->z;
+						}
+						else
+						{
+							if (topaligned)
+								zcomp = mobj->z;
+							else if (middlealigned)
+								zcomp = (droneboxmandiff / 2) + mobj->z;
+							else if (bottomoffsetted)
+								zcomp = mobj->z + droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale);
+							else
+								zcomp = mobj->z + droneboxmandiff;
+						}
+
+						droneman->angle += ANG10;
+						if (!flip && droneman->z <= zcomp)
+							droneman->momz = FixedMul(5*FRACUNIT, droneman->scale);
+						else if (flip && droneman->z >= zcomp)
+							droneman->momz = FixedMul(-5*FRACUNIT, droneman->scale);
+
+						// state switching logic
 						for (i = 0; i < MAXPLAYERS; i++)
-							if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+							if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE)
 							{
-								bonustime = true; // variable reuse
+								bonustime = true;
 								break;
 							}
 
 						if (bonustime)
-							mobj->flags2 &= ~MF2_DONTDRAW;
-						else
-							mobj->flags2 |= MF2_DONTDRAW;
+						{
+							CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n");
+							if (!(droneman->flags2 & MF2_DONTDRAW))
+								droneman->flags2 |= MF2_DONTDRAW;
+							if (goalpost->state == &states[S_INVISIBLE])
+								P_SetMobjState(goalpost, mobjinfo[goalpost->type].meleestate);
+							if (sparkle->state == &states[S_INVISIBLE])
+								P_SetMobjState(sparkle, mobjinfo[sparkle->type].meleestate);
+						}
+						else if (!G_IsSpecialStage(gamemap))
+						{
+							for (i = 0; i < MAXPLAYERS; i++)
+								if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
+								{
+									bonustime = true; // variable reuse
+									break;
+								}
+
+							if (bonustime)
+							{
+								// show droneman if at least one player is non-nights
+								if (goalpost->state != &states[S_INVISIBLE])
+									P_SetMobjState(goalpost, S_INVISIBLE);
+								if (sparkle->state != &states[S_INVISIBLE])
+									P_SetMobjState(sparkle, S_INVISIBLE);
+								if (droneman->state != &states[mobjinfo[droneman->type].meleestate])
+									P_SetMobjState(droneman, mobjinfo[droneman->type].meleestate);
+								if (droneman->flags2 & MF2_DONTDRAW)
+									droneman->flags2 &= ~MF2_DONTDRAW;
+							}
+							else
+							{
+								// else, hide it
+								if (!(droneman->flags2 & MF2_DONTDRAW))
+									droneman->flags2 |= MF2_DONTDRAW;
+							}
+						}
 					}
 				}
 				break;
@@ -8850,13 +9019,13 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			mobj->fuse += 30 * TICRATE;
 			break;
 		case MT_NIGHTSDRONE:
-			if (G_IsSpecialStage(gamemap))
-				mobj->flags2 |= MF2_DONTDRAW;
 			nummaprings = -1; // no perfect bonus, rings are free
 			break;
 		case MT_EGGCAPSULE:
-			mobj->extravalue1 = -1; // sphere timer for how long a player has been at the capsule
-			mobj->extravalue2 = -1; // tic timer for how long a player has been at the capsule
+			mobj->reactiontime = 0;
+			mobj->extravalue1 = mobj->cvmem =\
+			 mobj->cusval = mobj->movecount =\
+			 mobj->lastlook = mobj->extravalue2 = -1;
 			break;
 		case MT_REDTEAMRING:
 			mobj->color = skincolor_redteam;
@@ -9554,6 +9723,7 @@ void P_SpawnPlayer(INT32 playernum)
 			if (p == players) // this is totally the wrong place to do this aaargh.
 			{
 				mobj_t *idya = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_GOTEMERALD);
+				idya->health = 0; // for identification
 				P_SetTarget(&idya->target, mobj);
 				P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate);
 				P_SetTarget(&mobj->tracer, idya);
@@ -9825,7 +9995,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	 || mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum
 	 || mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum
 	 || (mthing->type >= 600 && mthing->type <= 609) // circles and diagonals
-	 || mthing->type == 1705 || mthing->type == 1713 || mthing->type == 1800) // hoops
+	 || mthing->type == 1705 || mthing->type == 1713) // hoops
 	{
 		// Don't spawn hoops, wings, or rings yet!
 		return;
@@ -10622,9 +10792,124 @@ ML_EFFECT4 : Don't clip inside the ground
 		mobj->health = mthing->angle & 255;
 		mobj->threshold = mthing->angle >> 8;
 		break;
+	case MT_IDEYAANCHOR:
+		mobj->health = mthing->extrainfo;
+		break;
 	case MT_NIGHTSDRONE:
-		if (mthing->angle > 0)
-			mobj->health = mthing->angle;
+		{
+			boolean flip = mthing->options & MTF_OBJECTFLIP;
+			boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
+			boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL);
+			boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
+
+			INT16 timelimit = mthing->angle & 0xFFF;
+			fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12) * 32 * FRACUNIT;
+			fixed_t hitboxheight = mthing->extrainfo * 32 * FRACUNIT;
+			fixed_t oldheight = mobj->height;
+			fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff;
+
+			if (timelimit > 0)
+				mobj->health = timelimit;
+
+			if (hitboxradius > 0)
+				mobj->radius = hitboxradius;
+
+			if (hitboxheight > 0)
+				mobj->height = hitboxheight;
+			else
+				mobj->height = mobjinfo[MT_NIGHTSDRONE].height;
+
+			droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0);
+			dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0);
+
+			if (flip && mobj->height != oldheight)
+				P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight));
+
+			if (!flip)
+			{
+				if (topaligned) // Align droneman to top of hitbox
+				{
+					dronemanoffset = droneboxmandiff;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+				else if (middlealigned) // Align droneman to center of hitbox
+				{
+					dronemanoffset = droneboxmandiff / 2;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+				else if (bottomoffsetted)
+				{
+					dronemanoffset = 24*FRACUNIT;
+					goaloffset = dronemangoaldiff + dronemanoffset;
+				}
+				else
+				{
+					dronemanoffset = 0;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+
+				sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale);
+			}
+			else
+			{
+				mobj->eflags |= MFE_VERTICALFLIP;
+				mobj->flags2 |= MF2_OBJECTFLIP;
+
+				if (topaligned) // Align droneman to top of hitbox
+				{
+					dronemanoffset = 0;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+				else if (middlealigned) // Align droneman to center of hitbox
+				{
+					dronemanoffset = droneboxmandiff / 2;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+				else if (bottomoffsetted)
+				{
+					dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale);
+					goaloffset = dronemangoaldiff + dronemanoffset;
+				}
+				else
+				{
+					dronemanoffset = droneboxmandiff;
+					goaloffset = dronemangoaldiff / 2 + dronemanoffset;
+				}
+
+				sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale);
+			}
+
+			// spawn visual elements
+			mobj_t *goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL);
+			mobj_t *sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING);
+			mobj_t *droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN);
+
+			P_SetTarget(&mobj->target, goalpost);
+			P_SetTarget(&goalpost->target, sparkle);
+			P_SetTarget(&goalpost->tracer, droneman);
+
+			// correct Z position
+			if (flip)
+			{
+				P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset);
+				P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset);
+				P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset);
+			}
+
+			// Remember position preference for later
+			mobj->flags &= ~(MF_SLIDEME | MF_GRENADEBOUNCE);
+			if (topaligned)
+				mobj->flags |= MF_SLIDEME;
+			else if (middlealigned)
+				mobj->flags |= MF_GRENADEBOUNCE;
+			else if (!bottomoffsetted)
+				mobj->flags |= MF_SLIDEME | MF_GRENADEBOUNCE;
+
+			// Remember old Z position and flags for correction detection
+			goalpost->movefactor = mobj->z;
+			goalpost->friction = mobj->height;
+			goalpost->threshold = mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE);
+		}
 		break;
 	case MT_HIVEELEMENTAL:
 		if (mthing->extrainfo)
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 6a07e513f20d2f20407d6ad24cd0063d7de65b31..10ed68ddf59a85ee6621263805b535cbb3fc27e6 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -58,6 +58,7 @@ typedef enum
 	FIRSTAXIS  = 0x10,
 	SECONDAXIS = 0x20,
 	FOLLOW     = 0x40,
+	DRONE      = 0x80,
 } player_saveflags;
 
 //
@@ -198,10 +199,10 @@ static void P_NetArchivePlayers(void)
 		WRITEINT32(save_p, players[i].drillmeter);
 		WRITEUINT8(save_p, players[i].drilldelay);
 		WRITEUINT8(save_p, players[i].bonustime);
+		WRITEFIXED(save_p, players[i].oldscale);
 		WRITEUINT8(save_p, players[i].mare);
 		WRITEUINT8(save_p, players[i].marelap);
 		WRITEUINT8(save_p, players[i].marebonuslap);
-
 		WRITEUINT32(save_p, players[i].marebegunat);
 		WRITEUINT32(save_p, players[i].startedtime);
 		WRITEUINT32(save_p, players[i].finishedtime);
@@ -236,6 +237,9 @@ static void P_NetArchivePlayers(void)
 		if (players[i].followmobj)
 			flags |= FOLLOW;
 
+		if (players[i].drone)
+			flags |= DRONE;
+
 		WRITEINT16(save_p, players[i].lastsidehit);
 		WRITEINT16(save_p, players[i].lastlinehit);
 
@@ -264,6 +268,9 @@ static void P_NetArchivePlayers(void)
 		if (flags & FOLLOW)
 			WRITEUINT32(save_p, players[i].followmobj->mobjnum);
 
+		if (flags & DRONE)
+			WRITEUINT32(save_p, players[i].drone->mobjnum);
+
 		WRITEFIXED(save_p, players[i].camerascale);
 		WRITEFIXED(save_p, players[i].shieldscale);
 
@@ -396,10 +403,10 @@ static void P_NetUnArchivePlayers(void)
 		players[i].drillmeter = READINT32(save_p);
 		players[i].drilldelay = READUINT8(save_p);
 		players[i].bonustime = (boolean)READUINT8(save_p);
+		players[i].oldscale = READFIXED(save_p);
 		players[i].mare = READUINT8(save_p);
 		players[i].marelap = READUINT8(save_p);
 		players[i].marebonuslap = READUINT8(save_p);
-
 		players[i].marebegunat = READUINT32(save_p);
 		players[i].startedtime = READUINT32(save_p);
 		players[i].finishedtime = READUINT32(save_p);
@@ -447,6 +454,9 @@ static void P_NetUnArchivePlayers(void)
 		if (flags & FOLLOW)
 			players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p);
 
+		if (flags & DRONE)
+			players[i].drone = (mobj_t *)(size_t)READUINT32(save_p);
+
 		players[i].camerascale = READFIXED(save_p);
 		players[i].shieldscale = READFIXED(save_p);
 
@@ -486,7 +496,7 @@ static UINT32 num_ffloors = 0; // for loading
 // But also check for equality and return the matching index
 static UINT32 CheckAddNetColormapToList(extracolormap_t *extra_colormap)
 {
-	extracolormap_t *exc, *exc_prev;
+	extracolormap_t *exc, *exc_prev = NULL;
 	UINT32 i = 0;
 
 	if (!net_colormaps)
@@ -3670,6 +3680,13 @@ static void P_RelinkPointers(void)
 				if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp)))
 					CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type);
 			}
+			if (mobj->player && mobj->player->drone)
+			{
+				temp = (UINT32)(size_t)mobj->player->drone;
+				mobj->player->drone = NULL;
+				if (!P_SetTarget(&mobj->player->drone, P_FindNewPosition(temp)))
+					CONS_Debug(DBG_GAMELOGIC, "drone not found on %d\n", mobj->type);
+			}
 		}
 	}
 }
diff --git a/src/p_setup.c b/src/p_setup.c
index 2e86dffa133c54edc0c147192e36d4c8e841f91e..86f4c77624bcf8bd2fe57f869b2f93c51bf71fc9 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -56,8 +56,11 @@
 
 #include "filesrch.h" // refreshdirmenu
 
-// wipes
-#include "f_finale.h"
+#ifdef HAVE_BLUA
+#include "lua_hud.h" // level title
+#endif
+
+#include "f_finale.h" // wipes
 
 #include "md5.h" // map MD5
 
@@ -100,6 +103,7 @@ side_t *sides;
 mapthing_t *mapthings;
 INT32 numstarposts;
 boolean levelloading;
+UINT8 levelfadecol;
 
 // BLOCKMAP
 // Created from axis aligned bounding box
@@ -1098,7 +1102,7 @@ static void P_LoadThings(void)
 		 || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum
 		 || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum
 		 || (mt->type >= 600 && mt->type <= 609) // circles and diagonals
-		 || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) // hoops
+		 || mt->type == 1705 || mt->type == 1713) // hoops
 		{
 			mt->mobj = NULL;
 
@@ -2301,7 +2305,7 @@ static void P_LevelInitStuff(void)
 		 players[i].texttimer = players[i].linkcount =\
 		 players[i].linktimer = players[i].flyangle =\
 		 players[i].anotherflyangle = players[i].nightstime =\
-		 players[i].mare = players[i].marelap =\
+		 players[i].oldscale = players[i].mare = players[i].marelap =\
 		 players[i].marebonuslap = players[i].lapbegunat =\
 		 players[i].lapstartedtime = players[i].totalmarescore =\
 		 players[i].realtime = players[i].exiting = 0;
@@ -2319,7 +2323,7 @@ static void P_LevelInitStuff(void)
 		// unset ALL the pointers. P_SetTarget isn't needed here because if this
 		// function is being called we're just going to clobber the data anyways
 		players[i].mo = players[i].followmobj = players[i].awayviewmobj =\
-		players[i].capsule = players[i].axis1 = players[i].axis2 = NULL;
+		players[i].capsule = players[i].axis1 = players[i].axis2 = players[i].drone = NULL;
 	}
 }
 
@@ -2600,6 +2604,43 @@ static void P_LoadNightsGhosts(void)
 	free(gpath);
 }
 
+static void P_SetupCamera(void)
+{
+	if (players[displayplayer].mo && (server || addedtogame))
+	{
+		camera.x = players[displayplayer].mo->x;
+		camera.y = players[displayplayer].mo->y;
+		camera.z = players[displayplayer].mo->z;
+		camera.angle = players[displayplayer].mo->angle;
+		camera.subsector = R_PointInSubsector(camera.x, camera.y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18)
+	}
+	else
+	{
+		mapthing_t *thing;
+
+		switch (gametype)
+		{
+		case GT_MATCH:
+		case GT_TAG:
+			thing = deathmatchstarts[0];
+			break;
+
+		default:
+			thing = playerstarts[0];
+			break;
+		}
+
+		if (thing)
+		{
+			camera.x = thing->x;
+			camera.y = thing->y;
+			camera.z = thing->z;
+			camera.angle = FixedAngle((fixed_t)thing->angle << FRACBITS);
+			camera.subsector = R_PointInSubsector(camera.x, camera.y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18)
+		}
+	}
+}
+
 static boolean CanSaveLevel(INT32 mapnum)
 {
 	if (ultimatemode) // never save in ultimate (probably redundant with cursaveslot also being checked)
@@ -2640,7 +2681,6 @@ boolean P_SetupLevel(boolean skipprecip)
 	CON_Drawer(); // let the user know what we are going to do
 	I_FinishUpdate(); // page flip or blit buffer
 
-
 	// Reset the palette
 	if (rendermode != render_none)
 		V_SetPaletteLump("PLAYPAL");
@@ -2693,9 +2733,14 @@ boolean P_SetupLevel(boolean skipprecip)
 	// will be set by player think.
 	players[consoleplayer].viewz = 1;
 
+	// Cancel all d_main.c fadeouts (keep fade in though).
+	wipegamestate = -2;
+
 	// Special stage fade to white
 	// This is handled BEFORE sounds are stopped.
-	if (rendermode != render_none && G_IsSpecialStage(gamemap))
+	if (modeattacking && !demoplayback && (pausedelay == INT32_MIN))
+		ranspecialwipe = 2;
+	else if (rendermode != render_none && G_IsSpecialStage(gamemap))
 	{
 		tic_t starttime = I_GetTime();
 		tic_t endtime = starttime + (3*TICRATE)/2;
@@ -2728,37 +2773,46 @@ boolean P_SetupLevel(boolean skipprecip)
 	S_StopSounds();
 	S_ClearSfx();
 
-	// As oddly named as this is, this handles music only.
-	// We should be fine starting it here.
-	/// ... as long as this isn't a titlemap transition, that is
 	if (!titlemapinaction)
+	{
+		// As oddly named as this is, this handles music only.
+		// We should be fine starting it here.
 		S_Start();
 
-	// Let's fade to black here
-	// But only if we didn't do the special stage wipe
-	if (rendermode != render_none && !ranspecialwipe)
-	{
-		F_WipeStartScreen();
-		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
+		// Let's fade to black here
+		// But only if we didn't do the special stage wipe
+		if (rendermode != render_none && !ranspecialwipe)
+		{
+			F_WipeStartScreen();
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
 
-		F_WipeEndScreen();
-		F_RunWipe(wipedefs[wipe_level_toblack], false);
-	}
+			F_WipeEndScreen();
+			F_RunWipe(wipedefs[wipe_level_toblack], false);
+		}
 
-	// Print "SPEEDING OFF TO [ZONE] [ACT 1]..."
-	if (!titlemapinaction && rendermode != render_none)
-	{
-		// Don't include these in the fade!
-		char tx[64];
-		V_DrawSmallString(1, 191, V_ALLOWLOWERCASE, M_GetText("Speeding off to..."));
-		snprintf(tx, 63, "%s%s%s",
-			mapheaderinfo[gamemap-1]->lvlttl,
-			(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE",
-			(mapheaderinfo[gamemap-1]->actnum > 0) ? va(", Act %d",mapheaderinfo[gamemap-1]->actnum) : "");
-		V_DrawSmallString(1, 195, V_ALLOWLOWERCASE, tx);
-		I_UpdateNoVsync();
+		if (ranspecialwipe == 2)
+		{
+			pausedelay = -3; // preticker plus one
+			S_StartSound(NULL, sfx_s3k73);
+		}
+
+		// Print "SPEEDING OFF TO [ZONE] [ACT 1]..."
+		if (rendermode != render_none)
+		{
+			// Don't include these in the fade!
+			char tx[64];
+			V_DrawSmallString(1, 191, V_ALLOWLOWERCASE, M_GetText("Speeding off to..."));
+			snprintf(tx, 63, "%s%s%s",
+				mapheaderinfo[gamemap-1]->lvlttl,
+				(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE",
+				(mapheaderinfo[gamemap-1]->actnum > 0) ? va(", Act %d",mapheaderinfo[gamemap-1]->actnum) : "");
+			V_DrawSmallString(1, 195, V_ALLOWLOWERCASE, tx);
+			I_UpdateNoVsync();
+		}
 	}
 
+	levelfadecol = (ranspecialwipe) ? 0 : 31;
+
 	// Close text prompt before freeing the old level
 	F_EndTextPrompt(false, true);
 
@@ -3043,37 +3097,7 @@ boolean P_SetupLevel(boolean skipprecip)
 
 	if (!dedicated)
 	{
-		if (players[displayplayer].mo && (server || addedtogame))
-		{
-			camera.x = players[displayplayer].mo->x;
-			camera.y = players[displayplayer].mo->y;
-			camera.z = players[displayplayer].mo->z;
-			camera.angle = players[displayplayer].mo->angle;
-		}
-		else
-		{
-			mapthing_t *thing;
-
-			switch (gametype)
-			{
-			case GT_MATCH:
-			case GT_TAG:
-				thing = deathmatchstarts[0];
-				break;
-
-			default:
-				thing = playerstarts[0];
-				break;
-			}
-
-			if (thing)
-			{
-				camera.x = thing->x;
-				camera.y = thing->y;
-				camera.z = thing->z;
-				camera.angle = FixedAngle((fixed_t)thing->angle << FRACBITS);
-			}
-		}
+		P_SetupCamera();
 
 		// Salt: CV_ClearChangedFlags() messes with your settings :(
 		/*if (!cv_cam_height.changed)
@@ -3136,8 +3160,8 @@ boolean P_SetupLevel(boolean skipprecip)
 	P_MapEnd();
 
 	// Remove the loading shit from the screen
-	if (rendermode != render_none)
-		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (ranspecialwipe) ? 0 : 31);
+	if (rendermode != render_none && !titlemapinaction)
+		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
 
 	if (precache || dedicated)
 		R_PrecacheLevel();
@@ -3187,6 +3211,45 @@ boolean P_SetupLevel(boolean skipprecip)
 #endif
 	}
 
+	// Stage title!
+	if (rendermode != render_none
+		&& (!titlemapinaction)
+		&& ranspecialwipe != 2
+		&& *mapheaderinfo[gamemap-1]->lvlttl != '\0'
+#ifdef HAVE_BLUA
+		&& LUA_HudEnabled(hud_stagetitle)
+#endif
+	)
+	{
+		tic_t starttime = I_GetTime();
+		tic_t endtime = starttime + (10*NEWTICRATERATIO);
+		tic_t nowtime = starttime;
+		tic_t lasttime = starttime;
+		while (nowtime < endtime)
+		{
+			// draw loop
+			while (!((nowtime = I_GetTime()) - lasttime))
+				I_Sleep();
+			lasttime = nowtime;
+
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
+			stplyr = &players[consoleplayer];
+			ST_drawLevelTitle(nowtime - starttime);
+			if (splitscreen)
+			{
+				stplyr = &players[secondarydisplayplayer];
+				ST_drawLevelTitle(nowtime - starttime);
+			}
+
+			I_OsPolling();
+			I_UpdateNoBlit();
+			I_FinishUpdate(); // page flip or blit buffer
+
+			if (moviemode) // make sure we save frames for the white hold too
+				M_SaveFrame();
+		}
+	}
+
 	return true;
 }
 
diff --git a/src/p_setup.h b/src/p_setup.h
index 569501531e06e009f711a7076837dc26bca5d30c..158e0110b44f334487ed7826c9b40e1b40ffeed2 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -27,6 +27,7 @@ extern mapthing_t *deathmatchstarts[MAX_DM_STARTS];
 extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
 
 extern boolean levelloading;
+extern UINT8 levelfadecol;
 
 extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame
 //
diff --git a/src/p_spec.c b/src/p_spec.c
index e5aa1a76f6d180b8ed1cc2ba9b517494c54443b5..64a6dad64eb33358945664ed472d27d77161b1d4 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3763,7 +3763,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 		case 457: // Track mobj angle to point
 			if (mo)
 			{
-				INT32 failureangle = min(max(abs(sides[line->sidenum[0]].textureoffset>>FRACBITS), 0), 360) * ANG1;
+				INT32 failureangle = FixedAngle((min(max(abs(sides[line->sidenum[0]].textureoffset>>FRACBITS), 0), 360))*FRACUNIT);
 				INT32 failuredelay = abs(sides[line->sidenum[0]].rowoffset>>FRACBITS);
 				INT32 failureexectag = line->sidenum[1] != 0xffff ?
 					(INT32)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0;
diff --git a/src/p_user.c b/src/p_user.c
index 2639ab148503f3c586a2214a42584e01e6542ee9..02650f11eb418d776981335b60e206004e51153b 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -634,6 +634,10 @@ static void P_DeNightserizePlayer(player_t *player)
 		break;
 	}
 
+	if (player->mo->scale != player->oldscale)
+		player->mo->destscale = player->oldscale;
+	player->oldscale = 0;
+
 	// Restore from drowning music
 	P_RestoreMusic(player);
 
@@ -653,7 +657,10 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		return;
 
 	if (player->powers[pw_carry] != CR_NIGHTSMODE)
+	{
 		player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
+		player->oldscale = player->mo->scale;
+	}
 
 	player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
 	player->homing = 0;
@@ -786,10 +793,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 
 		// Don't show before title card
 		// Not consistency safe, but this only affects drawing
-		if (timeinmap + 40 < 110)
-			player->texttimer = (UINT8)(110 - timeinmap);
+		if (timeinmap + 40 < (110 - 70))
+			player->texttimer = (UINT8)((110 - 70) - timeinmap);
 	}
 
+	if (player->drone && player->drone->scale != player->mo->scale)
+		player->mo->destscale = player->drone->scale;
+
 	// force NiGHTS to face forward or backward
 	if (player->mo->target)
 		player->mo->angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y) // player->angle_pos, won't be set on first instance
@@ -3955,7 +3965,7 @@ void P_DoJump(player_t *player, boolean soundandstate)
 			}
 		}
 		else if (maptol & TOL_NIGHTS)
-			player->mo->momz = 24*FRACUNIT;
+			player->mo->momz = 18*FRACUNIT;
 		else if (player->powers[pw_super])
 		{
 			player->mo->momz = 13*FRACUNIT;
@@ -3996,6 +4006,9 @@ void P_DoJump(player_t *player, boolean soundandstate)
 	if (player->charflags & SF_MULTIABILITY && player->charability == CA_DOUBLEJUMP)
 		factor -= max(0, player->secondjump * player->jumpfactor / ((player->actionspd >> FRACBITS) + 1)); // Reduce the jump height each time
 
+	//if (maptol & TOL_NIGHTS)
+	//	factor = player->jumpfactor; // all skins jump the same. if you nerf jumping abilities, you may want this.
+
 	P_SetObjectMomZ(player->mo, FixedMul(factor, player->mo->momz), false); // Custom height
 
 	// set just an eensy above the ground
@@ -5960,11 +5973,10 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 //
 static void P_DoNiGHTSCapsule(player_t *player)
 {
-	INT32 i;
+	INT32 i, spherecount, totalduration, popduration, deductinterval, deductquantity, sphereresult, firstpoptic, startingspheres;
+	INT32 tictimer = ++player->capsule->extravalue2;
 
-	player->capsule->extravalue2++; // tic counter
-
-	if (abs(player->mo->x-player->capsule->x) <= 2*FRACUNIT)
+	if (abs(player->mo->x-player->capsule->x) <= 3*FRACUNIT)
 	{
 		P_UnsetThingPosition(player->mo);
 		player->mo->x = player->capsule->x;
@@ -5972,7 +5984,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
 		player->mo->momx = 0;
 	}
 
-	if (abs(player->mo->y-player->capsule->y) <= 2*FRACUNIT)
+	if (abs(player->mo->y-player->capsule->y) <= 3*FRACUNIT)
 	{
 		P_UnsetThingPosition(player->mo);
 		player->mo->y = player->capsule->y;
@@ -5980,26 +5992,26 @@ static void P_DoNiGHTSCapsule(player_t *player)
 		player->mo->momy = 0;
 	}
 
-	if (abs(player->mo->z - (player->capsule->z+(player->capsule->height/3))) <= 2*FRACUNIT)
+	if (abs(player->mo->z - (player->capsule->z+(player->capsule->height/3))) <= 3*FRACUNIT)
 	{
 		player->mo->z = player->capsule->z+(player->capsule->height/3);
 		player->mo->momz = 0;
 	}
 
 	if (player->mo->x > player->capsule->x)
-		player->mo->momx = -2*FRACUNIT;
+		player->mo->momx = -3*FRACUNIT;
 	else if (player->mo->x < player->capsule->x)
-		player->mo->momx = 2*FRACUNIT;
+		player->mo->momx = 3*FRACUNIT;
 
 	if (player->mo->y > player->capsule->y)
-		player->mo->momy = -2*FRACUNIT;
+		player->mo->momy = -3*FRACUNIT;
 	else if (player->mo->y < player->capsule->y)
-		player->mo->momy = 2*FRACUNIT;
+		player->mo->momy = 3*FRACUNIT;
 
 	if (player->mo->z > player->capsule->z+(player->capsule->height/3))
-		player->mo->momz = -2*FRACUNIT;
+		player->mo->momz = -3*FRACUNIT;
 	else if (player->mo->z < player->capsule->z+(player->capsule->height/3))
-		player->mo->momz = 2*FRACUNIT;
+		player->mo->momz = 3*FRACUNIT;
 
 	if (player->powers[pw_carry] == CR_NIGHTSMODE)
 	{
@@ -6014,6 +6026,13 @@ static void P_DoNiGHTSCapsule(player_t *player)
 			P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_ATTACK);
 		}
 	}
+	else
+	{
+		if (!(player->pflags & PF_JUMPED) && !(player->pflags & PF_SPINNING))
+			player->pflags |= PF_JUMPED;
+		if (player->panim != PA_ROLL)
+			P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
+	}
 
 	if (G_IsSpecialStage(gamemap))
 	{ // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here!
@@ -6033,25 +6052,82 @@ static void P_DoNiGHTSCapsule(player_t *player)
 		&& player->mo->y == player->capsule->y
 		&& player->mo->z == player->capsule->z+(player->capsule->height/3))
 	{
-		if (player->spheres > 0)
+		if (player->capsule->lastlook < 0)
+		{
+			// Stretch the sphere deduction across the capsule time!
+			// 1. Force the remaining capsule time to `popduration`
+			// 2. Given `popduration` and `spherecount`, at what tic interval do we deduct spheres? `deductinterval`
+			// 3. And on each deduction, how many spheres do we deduct? `deductquantity`
+			// 4. Store the expected capsule health upon completion: `sphereresult`
+			spherecount = min(player->spheres, player->capsule->health);
+			totalduration = min(40 + spherecount, 60);
+
+			popduration = player->capsule->extravalue1 = max(totalduration - tictimer, 1);
+			deductinterval = player->capsule->cvmem = max(FixedFloor(FixedDiv(popduration, spherecount))/FRACUNIT, 1);
+			deductquantity = player->capsule->cusval = max(FixedRound(FixedDiv(spherecount, popduration))/FRACUNIT, 1);
+			sphereresult = player->capsule->movecount = player->capsule->health - spherecount;
+			firstpoptic = player->capsule->lastlook = tictimer;
+		}
+		else
 		{
-			player->spheres--;
-			player->capsule->health--;
-			player->capsule->extravalue1++;
+			popduration = player->capsule->extravalue1;
+			deductinterval = player->capsule->cvmem;
+			deductquantity = player->capsule->cusval;
+			sphereresult = player->capsule->movecount;
+			firstpoptic = player->capsule->lastlook;
+		}
+
+		if (tictimer - firstpoptic < popduration)
+		{
+			if (!((tictimer - firstpoptic) % deductinterval))
+			{
+				// Did you somehow get more spheres during destruct?
+				if (player->capsule->health <= sphereresult && player->spheres > 0 && player->capsule->health > 0)
+					sphereresult = max(sphereresult - player->spheres, 0);
+
+				if (player->capsule->health > sphereresult && player->spheres > 0)
+				{
+					player->spheres -= deductquantity;
+					player->capsule->health -= deductquantity;
+				}
+
+				if (player->spheres < 0)
+					player->spheres = 0;
 
-			// Spawn a 'pop' for every 5 rings you deposit
-			if (!(player->capsule->extravalue1 % 5))
+				if (player->capsule->health < sphereresult)
+					player->capsule->health = sphereresult;
+			}
+
+			// Spawn a 'pop' for every 5 tics
+			if (!((tictimer - firstpoptic) % 5))
 				S_StartSound(P_SpawnMobj(player->capsule->x + ((P_SignedRandom()/2)<<FRACBITS),
 				player->capsule->y + ((P_SignedRandom()/2)<<FRACBITS),
 				player->capsule->z + (player->capsule->height/2) + ((P_SignedRandom()/2)<<FRACBITS),
 				MT_BOSSEXPLODE),sfx_cybdth);
+		}
+		else
+		{
+			if (player->spheres != 0 && player->capsule->health > 0)
+			{
+				if (player->spheres < player->capsule->health)
+				{
+					player->capsule->health -= player->spheres;
+					player->spheres = 0;
+				}
+				else
+				{
+					startingspheres = player->spheres - player->capsule->health;
+					player->capsule->health = 0;
+					player->spheres = startingspheres;
+				}
+			}
 
 			if (player->capsule->health <= 0)
 			{
 				player->capsule->flags &= ~MF_NOGRAVITY;
 				player->capsule->momz = 5*FRACUNIT;
 				player->capsule->reactiontime = 0;
-				player->capsule->extravalue1 = player->capsule->extravalue2 = -1;
+				tictimer = -1;
 
 				for (i = 0; i < MAXPLAYERS; i++)
 					if (playeringame[i] && !player->exiting && players[i].mare == player->mare)
@@ -6085,6 +6161,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
 						UINT8 em = P_GetNextEmerald();
 						// Only give it to ONE person, and THAT player has to get to the goal!
 						mobj_t *emmo = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD);
+						emmo->health = em; // for identification
 						P_SetTarget(&emmo->target, player->mo);
 						P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
 						P_SetTarget(&player->mo->tracer, emmo);
@@ -6111,8 +6188,17 @@ static void P_DoNiGHTSCapsule(player_t *player)
 					}*/
 					mobj_t *idya = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD);
 					idya->extravalue2 = player->mare/5;
+					idya->health = player->mare + 1; // for identification
 					P_SetTarget(&idya->target, player->mo);
 					P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate + ((player->mare + 1) % 5));
+
+					if (player->mo->tracer)
+					{
+						P_SetTarget(&idya->hnext, player->mo->tracer);
+						idya->extravalue1 = (angle_t)(player->mo->tracer->extravalue1 - 72*ANG1);
+						if (idya->extravalue1 > player->mo->tracer->extravalue1)
+							idya->extravalue1 -= (72*ANG1)/idya->extravalue1;
+					}
 					P_SetTarget(&player->mo->tracer, idya);
 				}
 				for (i = 0; i < MAXPLAYERS; i++)
@@ -6122,19 +6208,68 @@ static void P_DoNiGHTSCapsule(player_t *player)
 				P_SwitchSpheresBonusMode(true);
 				P_RunNightsCapsuleTouchExecutors(player->mo, false, true); // run capsule exit executors, and we destroyed it
 			}
+			else
+			{
+				S_StartScreamSound(player->mo, sfx_lose);
+				player->texttimer = 4*TICRATE;
+				player->textvar = 3; // Get more rings!
+				player->capsule->reactiontime = 0;
+				player->capsule->extravalue1 = player->capsule->cvmem =\
+				 player->capsule->cusval = player->capsule->movecount =\
+				 player->capsule->lastlook = player->capsule->extravalue2 = -1;
+				P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked rings
+			}
 		}
+	}
+	else if (player->capsule->lastlook > -1)
+		// We somehow moved out of the capsule (OBJECTPLACE?)
+		// So recalculate all the timings
+		player->capsule->lastlook = player->capsule->extravalue2 = -1;
+}
+
+//
+// P_MoveNiGHTSToDrone
+//
+// Pull NiGHTS to the drone during Nightserizing
+//
+static void P_MoveNiGHTSToDrone(player_t *player)
+{
+	if (!player->drone)
+		return;
+
+	boolean flip = player->drone->flags2 & MF2_OBJECTFLIP;
+	boolean topaligned = (player->drone->flags & MF_SLIDEME) && !(player->drone->flags & MF_GRENADEBOUNCE);
+	boolean middlealigned = (player->drone->flags & MF_GRENADEBOUNCE) && !(player->drone->flags & MF_SLIDEME);
+	boolean bottomoffsetted = !(player->drone->flags & MF_SLIDEME) && !(player->drone->flags & MF_GRENADEBOUNCE);
+	fixed_t droneboxmandiff = max(player->drone->height - player->mo->height, 0);
+	fixed_t zofs;
+
+	if (!flip)
+	{
+		if (topaligned)
+			zofs = droneboxmandiff;
+		else if (middlealigned)
+			zofs = droneboxmandiff / 2;
+		else if (bottomoffsetted)
+			zofs = FixedMul(24*FRACUNIT, player->drone->scale);
 		else
-		{
-			S_StartScreamSound(player->mo, sfx_lose);
-			player->texttimer = 4*TICRATE;
-			player->textvar = 3; // Get more rings!
-			player->capsule->reactiontime = 0;
-			player->capsule->extravalue1 = player->capsule->extravalue2 = -1;
-			P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked rings
-		}
+			zofs = 0;
 	}
 	else
-		player->capsule->extravalue1 = -1;
+	{
+		if (topaligned)
+			zofs = 0;
+		else if (middlealigned)
+			zofs = droneboxmandiff / 2;
+		else if (bottomoffsetted)
+			zofs = droneboxmandiff - FixedMul(24*FRACUNIT, player->drone->scale);
+		else
+			zofs = droneboxmandiff;
+	}
+
+	player->mo->momx = player->mo->momy = player->mo->momz = 0;
+	P_TeleportMove(player->mo, player->drone->x, player->drone->y, player->drone->z + zofs);
+	P_SetTarget(&player->drone, NULL);
 }
 
 //
@@ -7059,6 +7194,13 @@ static void P_MovePlayer(player_t *player)
 			return;
 		}
 
+		// Suck player into their drone
+		if (player->drone)
+		{
+			P_MoveNiGHTSToDrone(player);
+			return;
+		}
+
 		// Test revamped NiGHTS movement.
 		if (player->powers[pw_carry] == CR_NIGHTSMODE)
 		{
@@ -8955,7 +9097,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 	// sets ideal cam pos
 	if (twodlevel || (mo->flags2 & MF2_TWOD))
 		dist = 480<<FRACBITS;
-	else if (player->powers[pw_carry] == CR_NIGHTSMODE)
+	else if (player->powers[pw_carry] == CR_NIGHTSMODE
+		|| ((maptol & TOL_NIGHTS) && player->capsule && player->capsule->reactiontime > 0 && player == &players[player->capsule->reactiontime-1]))
 		dist = 320<<FRACBITS;
 	else
 	{
diff --git a/src/r_main.c b/src/r_main.c
index 98ce978a693b73acb894b46cfb9fe682990f7fe5..ab5993c5bd4c3a4c9030f8d58133d34de85d92ed 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -219,21 +219,11 @@ static void ChaseCam2_OnChange(void)
 
 static void FlipCam_OnChange(void)
 {
-	if (cv_flipcam.value)
-		players[consoleplayer].pflags |= PF_FLIPCAM;
-	else
-		players[consoleplayer].pflags &= ~PF_FLIPCAM;
-
 	SendWeaponPref();
 }
 
 static void FlipCam2_OnChange(void)
 {
-	if (cv_flipcam2.value)
-		players[secondarydisplayplayer].pflags |= PF_FLIPCAM;
-	else
-		players[secondarydisplayplayer].pflags &= ~PF_FLIPCAM;
-
 	SendWeaponPref2();
 }
 
diff --git a/src/r_segs.c b/src/r_segs.c
index cde019f66de508f2f4031e720e2d705a3801816a..d3369672902a6df23d57526c54a984981105498b 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -607,8 +607,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 						else
 							rlight->rcolormap = xwalllights[pindex];
 
-						rlight->height += rlight->heightstep;
 						height = rlight->height;
+						rlight->height += rlight->heightstep;
 
 						if (height <= windowtop)
 						{
@@ -858,26 +858,21 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			light = &frontsector->lightlist[i];
 			rlight = &dc_lightlist[p];
 #ifdef ESLOPE
-			if (light->slope) {
-				leftheight = P_GetZAt(light->slope, ds->leftpos.x, ds->leftpos.y);
-				rightheight = P_GetZAt(light->slope, ds->rightpos.x, ds->rightpos.y);
-			} else
-				leftheight = rightheight = light->height;
 
-			if (*pfloor->b_slope) {
-				pfloorleft = P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y);
-				pfloorright = P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y);
-			} else
-				pfloorleft = pfloorright = *pfloor->bottomheight;
+#define SLOPEPARAMS(slope, end1, end2, normalheight) \
+	if (slope) { \
+		end1 = P_GetZAt(slope, ds->leftpos.x, ds->leftpos.y); \
+		end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y); \
+	} else \
+		end1 = end2 = normalheight;
+
+			SLOPEPARAMS(light->slope,     leftheight, rightheight, light->height)
+			SLOPEPARAMS(*pfloor->b_slope, pfloorleft, pfloorright, *pfloor->bottomheight)
 
 			if (leftheight < pfloorleft && rightheight < pfloorright)
 				continue;
 
-			if (*pfloor->t_slope) {
-				pfloorleft = P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y);
-				pfloorright = P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y);
-			} else
-				pfloorleft = pfloorright = *pfloor->topheight;
+			SLOPEPARAMS(*pfloor->t_slope, pfloorleft, pfloorright, *pfloor->topheight)
 
 			if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights)
 			{
@@ -890,17 +885,17 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			leftheight -= viewz;
 			rightheight -= viewz;
 
-			overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
-			if (overflow_test < 0) overflow_test = -overflow_test;
-			if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
-			overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
-			if (overflow_test < 0) overflow_test = -overflow_test;
-			if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
+#define OVERFLOWTEST(height, scale) \
+	overflow_test = (INT64)centeryfrac - (((INT64)height*scale)>>FRACBITS); \
+	if (overflow_test < 0) overflow_test = -overflow_test; \
+	if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
+
+			OVERFLOWTEST(leftheight, ds->scale1)
+			OVERFLOWTEST(rightheight, ds->scale2)
 
 			rlight->height = (centeryfrac) - FixedMul(leftheight, ds->scale1);
 			rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
 			rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
-			rlight->height -= rlight->heightstep;
 #else
 			if (light->height < *pfloor->bottomheight)
 				continue;
@@ -910,36 +905,28 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 			lheight = light->height;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : light->height;
 			rlight->heightstep = -FixedMul (rw_scalestep, (lheight - viewz));
-			rlight->height = (centeryfrac) - FixedMul((lheight - viewz), spryscale) - rlight->heightstep;
+			rlight->height = (centeryfrac) - FixedMul((lheight - viewz), spryscale);
 #endif
 			rlight->flags = light->flags;
 			if (light->flags & FF_CUTLEVEL)
 			{
 #ifdef ESLOPE
-				if (*light->caster->b_slope) {
-					leftheight = P_GetZAt(*light->caster->b_slope, ds->leftpos.x, ds->leftpos.y);
-					rightheight = P_GetZAt(*light->caster->b_slope, ds->rightpos.x, ds->rightpos.y);
-				} else
-					leftheight = rightheight = *light->caster->bottomheight;
-
+				SLOPEPARAMS(*light->caster->b_slope, leftheight, rightheight, *light->caster->bottomheight)
+#undef SLOPEPARAMS
 				leftheight -= viewz;
 				rightheight -= viewz;
 
-				overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
-				if (overflow_test < 0) overflow_test = -overflow_test;
-				if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
-				overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
-				if (overflow_test < 0) overflow_test = -overflow_test;
-				if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
+				OVERFLOWTEST(leftheight, ds->scale1)
+				OVERFLOWTEST(rightheight, ds->scale2)
+#undef OVERFLOWTEST
 
 				rlight->botheight = (centeryfrac) - FixedMul(leftheight, ds->scale1);
 				rlight->botheightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
 				rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range);
-				rlight->botheight -= rlight->botheightstep;
 #else
 				lheight = *light->caster->bottomheight;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : *light->caster->bottomheight;
 				rlight->botheightstep = -FixedMul (rw_scalestep, (lheight - viewz));
-				rlight->botheight = (centeryfrac) - FixedMul((lheight - viewz), spryscale) - rlight->botheightstep;
+				rlight->botheight = (centeryfrac) - FixedMul((lheight - viewz), spryscale);
 #endif
 			}
 
@@ -1130,33 +1117,28 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 				oldx = dc_x;
 			}
 #endif
-			// SoM: New code does not rely on R_DrawColumnShadowed_8 which
-			// will (hopefully) put less strain on the stack.
-			if (dc_numlights)
-			{
-				lighttable_t **xwalllights;
-				fixed_t height;
-				fixed_t bheight = 0;
-				INT32 solid = 0;
-				INT32 lighteffect = 0;
+			// Calculate bounds
+			// clamp the values if necessary to avoid overflows and rendering glitches caused by them
 
 #ifdef ESLOPE
-				if      (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX;
-				else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac;
-				else                                 sprtopscreen = windowtop = CLAMPMIN;
-				if      (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX;
-				else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac;
-				else                                    sprbotscreen = windowbottom = CLAMPMIN;
+			if      (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX;
+			else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac;
+			else                                 sprtopscreen = windowtop = CLAMPMIN;
+			if      (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX;
+			else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac;
+			else                                    sprbotscreen = windowbottom = CLAMPMIN;
 
-				top_frac += top_step;
-				bottom_frac += bottom_step;
+			top_frac += top_step;
+			bottom_frac += bottom_step;
 #else
-				sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
-				sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
+			sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
+			sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
 #endif
 
-				// SoM: If column is out of range, why bother with it??
-				if (windowbottom < topbounds || windowtop > bottombounds)
+			// SoM: If column is out of range, why bother with it??
+			if (windowbottom < topbounds || windowtop > bottombounds)
+			{
+				if (dc_numlights)
 				{
 					for (i = 0; i < dc_numlights; i++)
 					{
@@ -1165,14 +1147,25 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						if (rlight->flags & FF_CUTLEVEL)
 							rlight->botheight += rlight->botheightstep;
 					}
-					spryscale += rw_scalestep;
-					continue;
 				}
+				spryscale += rw_scalestep;
+				continue;
+			}
 
-				dc_iscale = 0xffffffffu / (unsigned)spryscale;
+			dc_iscale = 0xffffffffu / (unsigned)spryscale;
 
-				// draw the texture
-				col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);
+			// Get data for the column
+			col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);
+
+			// SoM: New code does not rely on R_DrawColumnShadowed_8 which
+			// will (hopefully) put less strain on the stack.
+			if (dc_numlights)
+			{
+				lighttable_t **xwalllights;
+				fixed_t height;
+				fixed_t bheight = 0;
+				INT32 solid = 0;
+				INT32 lighteffect = 0;
 
 				for (i = 0; i < dc_numlights; i++)
 				{
@@ -1192,7 +1185,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 						pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
 
-						if (pindex >=  MAXLIGHTSCALE)
+						if (pindex >= MAXLIGHTSCALE)
 							pindex = MAXLIGHTSCALE-1;
 
 						if (pfloor->flags & FF_FOG)
@@ -1231,13 +1224,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 					else
 						solid = 0;
 
-					rlight->height += rlight->heightstep;
 					height = rlight->height;
+					rlight->height += rlight->heightstep;
 
 					if (solid)
 					{
-						rlight->botheight += rlight->botheightstep;
 						bheight = rlight->botheight - (FRACUNIT >> 1);
+						rlight->botheight += rlight->botheightstep;
 					}
 
 					if (height <= windowtop)
@@ -1253,6 +1246,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 					if (windowbottom >= sprbotscreen)
 					{
 						windowbottom = sprbotscreen;
+						// draw the texture
 						colfunc_2s (col);
 						for (i++; i < dc_numlights; i++)
 						{
@@ -1263,6 +1257,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						}
 						continue;
 					}
+					// draw the texture
 					colfunc_2s (col);
 					if (solid)
 						windowtop = bheight;
@@ -1272,6 +1267,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						dc_colormap = rlight->rcolormap;
 				}
 				windowbottom = sprbotscreen;
+				// draw the texture, if there is any space left
 				if (windowtop < windowbottom)
 					colfunc_2s (col);
 
@@ -1286,31 +1282,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 				pindex = MAXLIGHTSCALE - 1;
 
 			dc_colormap = walllights[pindex];
-			if (frontsector->extra_colormap)
-				dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
+
 			if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap)
 				dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
-
-#ifdef ESLOPE
-			if      (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX;
-			else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac;
-			else                                 sprtopscreen = windowtop = CLAMPMIN;
-			if      (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX;
-			else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac;
-			else                                    sprbotscreen = windowbottom = CLAMPMIN;
-
-			top_frac += top_step;
-			bottom_frac += bottom_step;
-#else
-			sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
-			sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
-#endif
-
-			dc_iscale = 0xffffffffu / (unsigned)spryscale;
+			else if (frontsector->extra_colormap)
+				dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
 
 			// draw the texture
-			col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);
-
 			colfunc_2s (col);
 			spryscale += rw_scalestep;
 		}
diff --git a/src/r_things.c b/src/r_things.c
index a6a7d9877c977b60eb2008126f9d87080fd96cf6..e2f1a896b15e26977a85a31d91e7a2dad937ab23 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -2514,7 +2514,7 @@ static void Sk_SetDefaultValue(skin_t *skin)
 
 	strcpy(skin->realname, "Someone");
 	strcpy(skin->hudname, "???");
-	strncpy(skin->charsel, "CHRSONIC", 8);
+	strncpy(skin->charsel, "CHRSONIC", 9);
 	strncpy(skin->face, "MISSING", 8);
 	strncpy(skin->superface, "MISSING", 8);
 
diff --git a/src/r_things.h b/src/r_things.h
index 9a9761d5bf288b095b1262cb54393bb3b546f68b..508da6a547e9865de0cee8e73a8545c6140dc7b7 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -75,7 +75,7 @@ typedef struct
 
 	char realname[SKINNAMESIZE+1]; // Display name for level completion.
 	char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long)
-	char charsel[8], face[8], superface[8]; // Arbitrarily named patch lumps
+	char charsel[9], face[9], superface[9]; // Arbitrarily named patch lumps
 
 	UINT8 ability; // ability definition
 	UINT8 ability2; // secondary ability definition
diff --git a/src/screen.c b/src/screen.c
index b3e94091fea11c820983ac2f96ac6bd366104d3b..9ea996bf98ed2de32205e961e4f48e37157213cf 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -281,7 +281,10 @@ void SCR_Recalc(void)
 	vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT);
 
 #ifdef HWRENDER
-	if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl
+	//if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl
+	// 13/11/18:
+	// The above is no longer necessary, since we want OpenGL to be just like software now
+	// -- Monster Iestyn
 #endif
 		vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
 
@@ -438,15 +441,17 @@ void SCR_ClosedCaptions(void)
 	boolean gamestopped = (paused || P_AutoPause());
 	INT32 basey = BASEVIDHEIGHT;
 
+	if (gamestate != wipegamestate)
+		return;
+
 	if (gamestate == GS_LEVEL)
 	{
 		if (splitscreen)
 			basey -= 8;
 		else if ((modeattacking == ATTACKING_NIGHTS)
 		|| (!(maptol & TOL_NIGHTS)
-		&& ((cv_powerupdisplay.value == 2)
-		|| (cv_powerupdisplay.value == 1 && ((stplyr == &players[displayplayer] && !camera.chase)
-		|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))))))
+		&& ((cv_powerupdisplay.value == 2) // "Always"
+		 || (cv_powerupdisplay.value == 1 && !camera.chase)))) // "First-person only"
 			basey -= 16;
 	}
 
diff --git a/src/sdl/IMG_xpm.c b/src/sdl/IMG_xpm.c
index 8adfd3434f1fa72a2afc59ee3a5059483c5c417c..af76ec1ddd1d2dfe8ee0b02f22293c7db7696cdd 100644
--- a/src/sdl/IMG_xpm.c
+++ b/src/sdl/IMG_xpm.c
@@ -45,9 +45,10 @@
 #if 0
 #include "SDL_image.h"
 #else
-extern SDLCALL int SDLCALL IMG_isXPM(SDL_RWops *src);
-extern SDLCALL SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src);
-extern SDLCALL SDL_Surface * SDLCALL IMG_ReadXPMFromArray(const char **xpm);
+// SDLCALL terms removed from original SDL_image declarations
+int IMG_isXPM(SDL_RWops *src);
+SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src);
+SDL_Surface *IMG_ReadXPMFromArray(const char **xpm);
 #define IMG_SetError    SDL_SetError
 #define IMG_GetError    SDL_GetError
 #endif
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 1d132faf0e9624e29157ae13a72527e9e98f7627..bf9e4ac13eb290ad3360c435e246f0e4fab2a994 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -216,6 +216,9 @@
     <ClInclude Include="..\hardware\hws_data.h">
       <Filter>Hw_Hardware</Filter>
     </ClInclude>
+    <ClInclude Include="..\hardware\hw_clip.h">
+      <Filter>Hw_Hardware</Filter>
+    </ClInclude>
     <ClInclude Include="..\hardware\hw_data.h">
       <Filter>Hw_Hardware</Filter>
     </ClInclude>
@@ -606,6 +609,9 @@
     <ClCompile Include="..\hardware\hw_cache.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
+    <ClCompile Include="..\hardware\hw_clip.c">
+      <Filter>Hw_Hardware</Filter>
+    </ClCompile>
     <ClCompile Include="..\hardware\hw_draw.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 128faaab8703b5680b941f1dd6989657b148e95c..2d99acbbe4c6df1921a055872e369479a19ea6c1 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -666,7 +666,7 @@ boolean I_SongPlaying(void)
 #ifdef HAVE_LIBGME
 		(I_SongType() == MU_GME && gme) ||
 #endif
-		(boolean)music
+		music != NULL
 	);
 }
 
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 26d9678a3cd6aab92724ff1f1507ac28d4bf7a64..5728419f122cf467f1656a10f59583b4235640c1 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -460,7 +460,8 @@ static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fix
 // Devmode information
 static void ST_drawDebugInfo(void)
 {
-	INT32 height = 0;
+	INT32 height = 0, h = 8, w = 18, lowh;
+	void (*textfunc)(INT32, INT32, INT32, const char *);
 
 	if (!(stplyr->mo && cv_debug))
 		return;
@@ -469,135 +470,135 @@ static void ST_drawDebugInfo(void)
 
 	if ((moviemode == MM_GIF && cv_gif_downscale.value) || vid.dupx == 1)
 	{
-		if (cv_debug & DBG_BASIC)
-		{
-			const fixed_t d = AngleFixed(stplyr->mo->angle);
-			V_DrawRightAlignedString(320,  0, VFLAGS, va("X: %6d", stplyr->mo->x>>FRACBITS));
-			V_DrawRightAlignedString(320,  8, VFLAGS, va("Y: %6d", stplyr->mo->y>>FRACBITS));
-			V_DrawRightAlignedString(320, 16, VFLAGS, va("Z: %6d", stplyr->mo->z>>FRACBITS));
-			V_DrawRightAlignedString(320, 24, VFLAGS, va("A: %6d", FixedInt(d)));
+		textfunc = V_DrawRightAlignedString;
+		lowh = ((vid.height/vid.dupy) - 16);
+	}
+	else
+	{
+		textfunc = V_DrawRightAlignedSmallString;
+		h /= 2;
+		w /= 2;
+		lowh = 0;
+	}
 
-			height += 4*9;
-		}
+#define V_DrawDebugLine(str) if (lowh && (height > lowh))\
+							{\
+								V_DrawRightAlignedThinString(320,  8+lowh, VFLAGS|V_REDMAP, "SOME INFO NOT VISIBLE");\
+								return;\
+							}\
+							textfunc(320, height, VFLAGS, str);\
+							height += h;
 
-		if (cv_debug & (DBG_MEMORY|DBG_RANDOMIZER|DBG_DETAILED))
-		{
-			V_DrawRightAlignedThinString(320,   height, VFLAGS|V_REDMAP, "INFO NOT AVAILABLE");
-			V_DrawRightAlignedThinString(320, 8+height, VFLAGS|V_REDMAP, "AT THIS RESOLUTION");
-		}
+#define V_DrawDebugFlag(f, str) textfunc(width, height, VFLAGS|f, str);\
+								width -= w
+
+	if (cv_debug & DBG_MEMORY)
+	{
+		V_DrawDebugLine(va("Heap: %8sKB", sizeu1(Z_TotalUsage()>>10)));
+
+		height += h/2;
 	}
-	else
+
+	if (cv_debug & DBG_RANDOMIZER) // randomizer testing
 	{
-#define h 4
-#define dist 2
-#define V_DrawDebugLine(str) V_DrawRightAlignedSmallString(320, height, VFLAGS, str);\
-								height += h
+		fixed_t peekres = P_RandomPeek();
+		peekres *= 10000;     // Change from fixed point
+		peekres >>= FRACBITS; // to displayable decimal
 
-		if (cv_debug & DBG_MEMORY)
-		{
-			V_DrawDebugLine(va("Heap: %8sKB", sizeu1(Z_TotalUsage()>>10)));
+		V_DrawDebugLine(va("Init: %08x", P_GetInitSeed()));
+		V_DrawDebugLine(va("Seed: %08x", P_GetRandSeed()));
+		V_DrawDebugLine(va("==  :    .%04d", peekres));
 
-			height += dist;
-		}
+		height += h/2;
+	}
 
-		if (cv_debug & DBG_RANDOMIZER) // randomizer testing
-		{
-			fixed_t peekres = P_RandomPeek();
-			peekres *= 10000;     // Change from fixed point
-			peekres >>= FRACBITS; // to displayable decimal
+	if (cv_debug & DBG_PLAYER)
+	{
+		INT32 width = 320;
+		const fixed_t d = AngleFixed(stplyr->drawangle);
 
-			V_DrawDebugLine(va("Init: %08x", P_GetInitSeed()));
-			V_DrawDebugLine(va("Seed: %08x", P_GetRandSeed()));
-			V_DrawDebugLine(va("==  :    .%04d", peekres));
+		V_DrawDebugLine(va("SHIELD: %5x", stplyr->powers[pw_shield]));
+		V_DrawDebugLine(va("SCALE: %5d%%", (stplyr->mo->scale*100)>>FRACBITS));
+		V_DrawDebugLine(va("CARRY: %5x", stplyr->powers[pw_carry]));
+		V_DrawDebugLine(va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime]));
+		V_DrawDebugLine(va("ABILITY: %3d, %3d", stplyr->charability, stplyr->charability2));
+		V_DrawDebugLine(va("ACTIONSPD: %5d", stplyr->actionspd>>FRACBITS));
+		V_DrawDebugLine(va("PEEL: %3d", stplyr->dashmode));
+		V_DrawDebugLine(va("SCOREADD: %3d", stplyr->scoreadd));
 
-			height += dist;
-		}
+		// Flags
+		V_DrawDebugFlag(((stplyr->pflags & PF_SHIELDABILITY)  ? V_GREENMAP : V_REDMAP), "SH");
+		V_DrawDebugFlag(((stplyr->pflags & PF_THOKKED)        ? V_GREENMAP : V_REDMAP), "TH");
+		V_DrawDebugFlag(((stplyr->pflags & PF_STARTDASH)      ? V_GREENMAP : V_REDMAP), "ST");
+		V_DrawDebugFlag(((stplyr->pflags & PF_SPINNING)       ? V_GREENMAP : V_REDMAP), "SP");
+		V_DrawDebugFlag(((stplyr->pflags & PF_NOJUMPDAMAGE)   ? V_GREENMAP : V_REDMAP), "ND");
+		V_DrawDebugFlag(((stplyr->pflags & PF_JUMPED)         ? V_GREENMAP : V_REDMAP), "JD");
+		V_DrawDebugFlag(((stplyr->pflags & PF_STARTJUMP)      ? V_GREENMAP : V_REDMAP), "SJ");
+		V_DrawDebugFlag(0, "PF/SF:");
+		height += h;
+		width = 320;
+		V_DrawDebugFlag(((stplyr->pflags & PF_INVIS)          ? V_GREENMAP : V_REDMAP), "*I");
+		V_DrawDebugFlag(((stplyr->pflags & PF_NOCLIP)         ? V_GREENMAP : V_REDMAP), "*C");
+		V_DrawDebugFlag(((stplyr->pflags & PF_GODMODE)        ? V_GREENMAP : V_REDMAP), "*G");
+		V_DrawDebugFlag(((stplyr->charflags & SF_SUPER)       ? V_GREENMAP : V_REDMAP), "SU");
+		V_DrawDebugFlag(((stplyr->pflags & PF_APPLYAUTOBRAKE) ? V_GREENMAP : V_REDMAP), "AA");
+		V_DrawDebugFlag(((stplyr->pflags & PF_SLIDING)        ? V_GREENMAP : V_REDMAP), "SL");
+		V_DrawDebugFlag(((stplyr->pflags & PF_BOUNCING)       ? V_GREENMAP : V_REDMAP), "BO");
+		V_DrawDebugFlag(((stplyr->pflags & PF_GLIDING)        ? V_GREENMAP : V_REDMAP), "GL");
+		height += h;
 
-		if (cv_debug & DBG_DETAILED)
-		{
-#define V_DrawDebugFlag(f, str) V_DrawRightAlignedSmallString(w, height, VFLAGS|f, str);\
-								w -= 9
-			const fixed_t d = AngleFixed(stplyr->drawangle);
-			INT32 w = 320;
-
-			V_DrawDebugLine(va("SHIELD: %5x", stplyr->powers[pw_shield]));
-			V_DrawDebugLine(va("SCALE: %5d%%", (stplyr->mo->scale*100)>>FRACBITS));
-			V_DrawDebugLine(va("CARRY: %5x", stplyr->powers[pw_carry]));
-			V_DrawDebugLine(va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime]));
-			V_DrawDebugLine(va("ABILITY: %3d, %3d", stplyr->charability, stplyr->charability2));
-			V_DrawDebugLine(va("ACTIONSPD: %5d", stplyr->actionspd>>FRACBITS));
-			V_DrawDebugLine(va("PEEL: %3d", stplyr->dashmode));
-			V_DrawDebugLine(va("SCOREADD: %3d", stplyr->scoreadd));
-
-			// Flags
-			V_DrawDebugFlag(((stplyr->pflags & PF_SHIELDABILITY)  ? V_GREENMAP : V_REDMAP), "SH");
-			V_DrawDebugFlag(((stplyr->pflags & PF_THOKKED)        ? V_GREENMAP : V_REDMAP), "TH");
-			V_DrawDebugFlag(((stplyr->pflags & PF_STARTDASH)      ? V_GREENMAP : V_REDMAP), "ST");
-			V_DrawDebugFlag(((stplyr->pflags & PF_SPINNING)       ? V_GREENMAP : V_REDMAP), "SP");
-			V_DrawDebugFlag(((stplyr->pflags & PF_NOJUMPDAMAGE)   ? V_GREENMAP : V_REDMAP), "ND");
-			V_DrawDebugFlag(((stplyr->pflags & PF_JUMPED)         ? V_GREENMAP : V_REDMAP), "JD");
-			V_DrawDebugFlag(((stplyr->pflags & PF_STARTJUMP)      ? V_GREENMAP : V_REDMAP), "SJ");
-			V_DrawDebugFlag(0, "PF/SF:");
-			height += h;
-			w = 320;
-			V_DrawDebugFlag(((stplyr->pflags & PF_INVIS)          ? V_GREENMAP : V_REDMAP), "*I");
-			V_DrawDebugFlag(((stplyr->pflags & PF_NOCLIP)         ? V_GREENMAP : V_REDMAP), "*C");
-			V_DrawDebugFlag(((stplyr->pflags & PF_GODMODE)        ? V_GREENMAP : V_REDMAP), "*G");
-			V_DrawDebugFlag(((stplyr->charflags & SF_SUPER)       ? V_GREENMAP : V_REDMAP), "SU");
-			V_DrawDebugFlag(((stplyr->pflags & PF_APPLYAUTOBRAKE) ? V_GREENMAP : V_REDMAP), "AA");
-			V_DrawDebugFlag(((stplyr->pflags & PF_SLIDING)        ? V_GREENMAP : V_REDMAP), "SL");
-			V_DrawDebugFlag(((stplyr->pflags & PF_BOUNCING)       ? V_GREENMAP : V_REDMAP), "BO");
-			V_DrawDebugFlag(((stplyr->pflags & PF_GLIDING)        ? V_GREENMAP : V_REDMAP), "GL");
-			height += h;
-
-			V_DrawDebugLine(va("CEILINGZ: %6d", stplyr->mo->ceilingz>>FRACBITS));
-			V_DrawDebugLine(va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS));
-
-			V_DrawDebugLine(va("CMOMX: %6d", stplyr->cmomx>>FRACBITS));
-			V_DrawDebugLine(va("CMOMY: %6d", stplyr->cmomy>>FRACBITS));
-			V_DrawDebugLine(va("PMOMZ: %6d", stplyr->mo->pmomz>>FRACBITS));
-
-			w = 320;
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_APPLYPMOMZ)      ? V_GREENMAP : V_REDMAP), "AP");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_SPRUNG)          ? V_GREENMAP : V_REDMAP), "SP");
-			//V_DrawDebugFlag(((stplyr->mo->eflags & MFE_PUSHED)          ? V_GREENMAP : V_REDMAP), "PU"); -- not relevant to players
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_GOOWATER)        ? V_GREENMAP : V_REDMAP), "GW");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_VERTICALFLIP)    ? V_GREENMAP : V_REDMAP), "VF");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTSTEPPEDDOWN) ? V_GREENMAP : V_REDMAP), "JS");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_UNDERWATER)      ? V_GREENMAP : V_REDMAP), "UW");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_TOUCHWATER)      ? V_GREENMAP : V_REDMAP), "TW");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTHITFLOOR)    ? V_GREENMAP : V_REDMAP), "JH");
-			V_DrawDebugFlag(((stplyr->mo->eflags & MFE_ONGROUND)        ? V_GREENMAP : V_REDMAP), "OG");
-			V_DrawDebugFlag(0, "MFE:");
-			height += h;
-
-			V_DrawDebugLine(va("MOMX: %6d", stplyr->rmomx>>FRACBITS));
-			V_DrawDebugLine(va("MOMY: %6d", stplyr->rmomy>>FRACBITS));
-			V_DrawDebugLine(va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS));
-
-			V_DrawDebugLine(va("SPEED: %6d", stplyr->speed>>FRACBITS));
-
-			V_DrawDebugLine(va("DRAWANGLE: %6d", FixedInt(d)));
-
-			height += dist;
-#undef V_DrawDebugFlag
-		}
+		V_DrawDebugLine(va("DRAWANGLE: %6d", FixedInt(d)));
 
-		if (cv_debug & DBG_BASIC)
-		{
-			const fixed_t d = AngleFixed(stplyr->mo->angle);
-			V_DrawDebugLine(va("X: %6d", stplyr->mo->x>>FRACBITS));
-			V_DrawDebugLine(va("Y: %6d", stplyr->mo->y>>FRACBITS));
-			V_DrawDebugLine(va("Z: %6d", stplyr->mo->z>>FRACBITS));
-			V_DrawDebugLine(va("A: %6d", FixedInt(d)));
+		height += h/2;
+	}
 
-			//height += dist;
-		}
+	if (cv_debug & DBG_DETAILED)
+	{
+		INT32 width = 320;
+
+		V_DrawDebugLine(va("CEILINGZ: %6d", stplyr->mo->ceilingz>>FRACBITS));
+		V_DrawDebugLine(va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS));
+
+		V_DrawDebugLine(va("CMOMX: %6d", stplyr->cmomx>>FRACBITS));
+		V_DrawDebugLine(va("CMOMY: %6d", stplyr->cmomy>>FRACBITS));
+		V_DrawDebugLine(va("PMOMZ: %6d", stplyr->mo->pmomz>>FRACBITS));
+
+		width = 320;
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_APPLYPMOMZ)      ? V_GREENMAP : V_REDMAP), "AP");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_SPRUNG)          ? V_GREENMAP : V_REDMAP), "SP");
+		//V_DrawDebugFlag(((stplyr->mo->eflags & MFE_PUSHED)          ? V_GREENMAP : V_REDMAP), "PU"); -- not relevant to players
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_GOOWATER)        ? V_GREENMAP : V_REDMAP), "GW");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_VERTICALFLIP)    ? V_GREENMAP : V_REDMAP), "VF");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTSTEPPEDDOWN) ? V_GREENMAP : V_REDMAP), "JS");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_UNDERWATER)      ? V_GREENMAP : V_REDMAP), "UW");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_TOUCHWATER)      ? V_GREENMAP : V_REDMAP), "TW");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTHITFLOOR)    ? V_GREENMAP : V_REDMAP), "JH");
+		V_DrawDebugFlag(((stplyr->mo->eflags & MFE_ONGROUND)        ? V_GREENMAP : V_REDMAP), "OG");
+		V_DrawDebugFlag(0, "MFE:");
+		height += h;
+
+		V_DrawDebugLine(va("MOMX: %6d", stplyr->rmomx>>FRACBITS));
+		V_DrawDebugLine(va("MOMY: %6d", stplyr->rmomy>>FRACBITS));
+		V_DrawDebugLine(va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS));
+
+		V_DrawDebugLine(va("SPEED: %6d", stplyr->speed>>FRACBITS));
+
+		height += h/2;
+	}
+
+	if (cv_debug & DBG_BASIC)
+	{
+		const fixed_t d = AngleFixed(stplyr->mo->angle);
+		V_DrawDebugLine(va("X: %6d", stplyr->mo->x>>FRACBITS));
+		V_DrawDebugLine(va("Y: %6d", stplyr->mo->y>>FRACBITS));
+		V_DrawDebugLine(va("Z: %6d", stplyr->mo->z>>FRACBITS));
+		V_DrawDebugLine(va("A: %6d", FixedInt(d)));
+
+		//height += h/2;
 	}
 
+#undef V_DrawDebugFlag
 #undef V_DrawDebugLine
-#undef dist
-#undef h
 #undef VFLAGS
 }
 
@@ -1123,7 +1124,7 @@ static void ST_drawInput(void)
 		V_DrawThinString(x, y, hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!");
 }
 
-static void ST_drawLevelTitle(void)
+void ST_drawLevelTitle(tic_t titletime)
 {
 	char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
 	char *subttl = mapheaderinfo[gamemap-1]->subttl;
@@ -1131,7 +1132,7 @@ static void ST_drawLevelTitle(void)
 	INT32 lvlttly, zoney, lvlttlxpos, ttlnumxpos, zonexpos;
 	INT32 subttlxpos = BASEVIDWIDTH/2;
 
-	if (!(timeinmap > 2 && timeinmap-3 < 110))
+	if (!(titletime > 2 && titletime-3 < 110))
 		return;
 
 	lvlttlxpos = ((BASEVIDWIDTH/2) - (V_LevelNameWidth(lvlttl)/2));
@@ -1151,22 +1152,22 @@ static void ST_drawLevelTitle(void)
 #define MIDZONEY 105
 #define MIDDIFF 4
 
-	if (timeinmap < 10)
+	if (titletime < 10)
 	{
-		fixed_t z = ((timeinmap - 3)<<FRACBITS)/7;
+		fixed_t z = ((titletime - 3)<<FRACBITS)/7;
 		INT32 ttlh = V_LevelNameHeight(lvlttl);
 		zoney = (200<<FRACBITS) - ((200 - (MIDZONEY + MIDDIFF))*z);
 		lvlttly = ((MIDTTLY + ttlh - MIDDIFF)*z) - (ttlh<<FRACBITS);
 	}
-	else if (timeinmap < 105)
+	else if (titletime < 105)
 	{
-		fixed_t z = (((timeinmap - 10)*MIDDIFF)<<(FRACBITS+1))/95;
+		fixed_t z = (((titletime - 10)*MIDDIFF)<<(FRACBITS+1))/95;
 		zoney = ((MIDZONEY + MIDDIFF)<<FRACBITS) - z;
 		lvlttly = ((MIDTTLY - MIDDIFF)<<FRACBITS) + z;
 	}
 	else
 	{
-		fixed_t z = ((timeinmap - 105)<<FRACBITS)/7;
+		fixed_t z = ((titletime - 105)<<FRACBITS)/7;
 		INT32 zoneh = V_LevelNameHeight(M_GetText("ZONE"));
 		zoney = (MIDZONEY + zoneh - MIDDIFF)*(FRACUNIT - z) - (zoneh<<FRACBITS);
 		lvlttly = ((MIDTTLY + MIDDIFF)<<FRACBITS) + ((200 - (MIDTTLY + MIDDIFF))*z);
@@ -1177,8 +1178,8 @@ static void ST_drawLevelTitle(void)
 #undef MIDDIFF
 #else
 	// There's no consistent algorithm that can accurately define the old positions
-	// so I just ended up resorting to a single switct statement to define them
-	switch (timeinmap-3)
+	// so I just ended up resorting to a single switch statement to define them
+	switch (titletime-3)
 	{
 		case 0:   zoney = 200; lvlttly =   0; break;
 		case 1:   zoney = 188; lvlttly =  12; break;
@@ -1509,7 +1510,7 @@ static void ST_drawNiGHTSLink(void)
 	else
 		colornum = linkColor[mag][sel];
 
-	aflag |= ((stplyr->linktimer < nightslinktics/3)
+	aflag |= ((stplyr->linktimer < (UINT32)nightslinktics/3)
 	? (9 - 9*stplyr->linktimer/(nightslinktics/3)) << V_ALPHASHIFT
 	: 0);
 
@@ -1613,11 +1614,12 @@ static void ST_drawNiGHTSHUD(void)
 #endif
 	ST_DrawTopLeftOverlayPatch(16, 8, nbracket);
 	if (G_IsSpecialStage(gamemap))
-		ST_DrawTopLeftOverlayPatch(24, 16, (
 #ifdef MANIASPHERES
-			(stplyr->bonustime && (leveltime & 4)) ? nssbon :
+		ST_DrawTopLeftOverlayPatch(24, 16, (
+			(stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud));
+#else
+		ST_DrawTopLeftOverlayPatch(24, 16, (nsshud));
 #endif
-			nsshud));
 	else
 		ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12)));
 
@@ -1871,7 +1873,7 @@ static void ST_drawNiGHTSHUD(void)
 	}
 }
 
-static inline void ST_drawWeaponSelect(INT32 xoffs, INT32 y)
+static void ST_drawWeaponSelect(INT32 xoffs, INT32 y)
 {
 	INT32 q = stplyr->weapondelay, del = 0, p = 16;
 	while (q)
@@ -2461,12 +2463,14 @@ static void ST_overlayDrawer(void)
 			{
 				ST_drawFirstPersonHUD();
 				if (cv_powerupdisplay.value)
-					ST_drawPowerupHUD();
+					ST_drawPowerupHUD();  // same as it ever was...
 			}
 			else if (cv_powerupdisplay.value == 2)
-				ST_drawPowerupHUD();
+				ST_drawPowerupHUD();  // same as it ever was...
 		}
 	}
+	else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2)
+		ST_drawPowerupHUD(); // same as it ever was...
 
 #ifdef HAVE_BLUA
 	if (!(netgame || multiplayer) || !hu_showscores)
@@ -2479,7 +2483,7 @@ static void ST_overlayDrawer(void)
 	&& LUA_HudEnabled(hud_stagetitle)
 #endif
 	)
-		ST_drawLevelTitle();
+		ST_drawLevelTitle(timeinmap+70);
 
 	if (!hu_showscores && (netgame || multiplayer)
 #ifdef HAVE_BLUA
@@ -2488,7 +2492,7 @@ static void ST_overlayDrawer(void)
 	)
 		ST_drawTextHUD();
 
-	if (modeattacking)
+	if (modeattacking && !(demoplayback && hu_showscores))
 		ST_drawInput();
 
 	ST_drawDebugInfo();
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 3886d737cdf41c8166540b43b1ba47fb19ea0f4d..9c48a38af532d64e2f455008b254a5e89d54fef5 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -47,6 +47,9 @@ void ST_ReloadSkinFaceGraphics(void);
 
 void ST_doPaletteStuff(void);
 
+// level title draw
+void ST_drawLevelTitle(tic_t titletime);
+
 // return if player a is in the same team as player b
 boolean ST_SameTeam(player_t *a, player_t *b);
 
diff --git a/src/w_wad.c b/src/w_wad.c
index 9056165422d044b706adeceeb31d5a77d2541e59..258552950b02f4a2d99c0317f30b170556316d93 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -340,6 +340,16 @@ UINT16 W_InitFile(const char *filename)
 	if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
 		refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
 
+	if (refreshdirname)
+		Z_Free(refreshdirname);
+	if (dirmenu)
+	{
+		refreshdirname = Z_StrDup(filename);
+		nameonly(refreshdirname);
+	}
+	else
+		refreshdirname = NULL;
+
 	//CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
 	//
 	// check if limit of active wadfiles
@@ -360,9 +370,7 @@ UINT16 W_InitFile(const char *filename)
 	// see PutFileNeeded in d_netfil.c
 	if ((important = !W_VerifyNMUSlumps(filename)))
 	{
-		packetsize = packetsizetally;
-
-		packetsize += nameonlylength(filename) + 22;
+		packetsize = packetsizetally + nameonlylength(filename) + 22;
 
 		if (packetsize > MAXFILENEEDED*sizeof(UINT8))
 		{
diff --git a/src/w_wad.h b/src/w_wad.h
index ef4213579faf2120bda9b9459e79a9746b29f41c..16d97dd4cc40791a5b9318e69fe8eceecf1ba5d6 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -67,7 +67,7 @@ typedef struct
 //                         DYNAMIC WAD LOADING
 // =========================================================================
 
-#define MAX_WADPATH 128
+#define MAX_WADPATH 512
 #define MAX_WADFILES 48 // maximum of wad files used at the same time
 // (there is a max of simultaneous open files anyway, and this should be plenty)
 
diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg
index 749734a727512fe87d3856d74e94a2902b31cb3a..a73858bd46c41a1abac7da190aee236423f1fbe8 100644
--- a/src/win32/Makefile.cfg
+++ b/src/win32/Makefile.cfg
@@ -9,6 +9,9 @@
 ifdef MINGW64
 	NOASM=1
 	NONX86=1
+	HAVE_LIBGME=1
+	LIBGME_CFLAGS=-I../libs/gme/include
+	LIBGME_LDFLAGS=-L../libs/gme/win64 -lgme
 	SDL_CFLAGS?=-I../libs/SDL2/x86_64-w64-mingw32/include/SDL2 -I../libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2 -Dmain=SDL_main
 	SDL_LDFLAGS?=-L../libs/SDL2/x86_64-w64-mingw32/lib -L../libs/SDL2_mixer/x86_64-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows
 else
@@ -23,7 +26,9 @@ ifndef NOASM
 	USEASM=1
 endif
 
+ifndef MINGW64 #miniupnc is broken with MINGW64
 	HAVE_MINIUPNPC=1
+endif
 
 	OPTS=-DSTDC_HEADERS
 
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 6319749a9e8cfdb7d61f0899c9e63db60e098dc5..c21cedb8a4bf258af6efa2d9a2faba1de00da325 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -93,6 +93,9 @@
     <ClCompile Include="..\hardware\hw_cache.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
+    <ClCompile Include="..\hardware\hw_clip.c">
+      <Filter>Hw_Hardware</Filter>
+    </ClCompile>
     <ClCompile Include="..\hardware\hw_draw.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
@@ -476,6 +479,9 @@
     <ClInclude Include="win_main.h">
       <Filter>Win32app</Filter>
     </ClInclude>
+    <ClInclude Include="..\hardware\hw_clip.h">
+      <Filter>Hw_Hardware</Filter>
+    </ClInclude>
     <ClInclude Include="..\hardware\hw_data.h">
       <Filter>Hw_Hardware</Filter>
     </ClInclude>
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index c9b3fba4eea522aec31a6e956387939cdc7665b0..71eda04371d4223dedcd5e193d8c27ed8cf0f70d 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -148,7 +148,7 @@ static loadfunc_t hwdFuncTable[] = {
 #ifdef SHUFFLE
 	{"PostImgRedraw",       &hwdriver.pfnPostImgRedraw},
 #endif
-	{"FlushScreenTextures"},&hwdriver.pfnFlushScreenTextures},
+	{"FlushScreenTextures", &hwdriver.pfnFlushScreenTextures},
 	{"StartScreenWipe",     &hwdriver.pfnStartScreenWipe},
 	{"EndScreenWipe",       &hwdriver.pfnEndScreenWipe},
 	{"DoScreenWipe",        &hwdriver.pfnDoScreenWipe},
diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c
index 371384328f793133022ae53bd0cf2caf3ebcb9bd..4507c27ff3dad2dd6ed04a0060e1993252cfed3b 100644
--- a/src/win32/win_snd.c
+++ b/src/win32/win_snd.c
@@ -457,6 +457,8 @@ void I_ShutdownMusic(void)
 
 musictype_t I_SongType(void)
 {
+	FMOD_SOUND_TYPE type;
+
 #ifdef HAVE_LIBGME
 	if (gme)
 		return MU_GME;
@@ -465,7 +467,6 @@ musictype_t I_SongType(void)
 	if (!music_stream)
 		return MU_NONE;
 
-	FMOD_SOUND_TYPE type;
 	if (FMOD_Sound_GetFormat(music_stream, &type, NULL, NULL, NULL) == FMOD_OK)
 	{
 		switch(type)
@@ -492,15 +493,15 @@ musictype_t I_SongType(void)
 
 boolean I_SongPlaying(void)
 {
-	return (boolean)music_stream;
+	return (music_stream != NULL);
 }
 
 boolean I_SongPaused(void)
 {
-	boolean fmpaused = false;
+	FMOD_BOOL fmpaused = false;
 	if (music_stream)
 		FMOD_Channel_GetPaused(music_channel, &fmpaused);
-	return fmpaused;
+	return (boolean)fmpaused;
 }
 
 /// ------------------------
@@ -551,7 +552,12 @@ boolean I_LoadSong(char *data, size_t len)
 	FMOD_TAG tag;
 	unsigned int loopstart, loopend;
 
-	if (gme || music_stream)
+	if (
+#ifdef HAVE_LIBGME
+		gme ||
+#endif
+		music_stream
+	)
 		I_UnloadSong();
 
 	memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO));
diff --git a/src/y_inter.c b/src/y_inter.c
index ec7aa30ca66659b13c6346087ebad31cd0fc99b1..1a1675fdd000faf5ea38a08bf4a7dfea46c6deea 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -1595,6 +1595,7 @@ static void Y_CalculateCompetitionWinners(void)
 	UINT32 maxrings[MAXPLAYERS];
 	UINT32 monitors[MAXPLAYERS];
 	UINT32 scores[MAXPLAYERS];
+	char tempname[9];
 
 	memset(data.competition.points, 0, sizeof (data.competition.points));
 	memset(points, 0, sizeof (points));
@@ -1686,8 +1687,9 @@ static void Y_CalculateCompetitionWinners(void)
 		data.competition.monitors[data.competition.numplayers] = monitors[winner];
 		data.competition.scores[data.competition.numplayers] = scores[winner];
 
-		snprintf(data.competition.name[data.competition.numplayers], 9, "%s", player_names[winner]);
-		data.competition.name[data.competition.numplayers][8] = '\0';
+		strncpy(tempname, player_names[winner], 8);
+		tempname[8] = '\0';
+		strncpy(data.competition.name[data.competition.numplayers], tempname, 9);
 
 		data.competition.color[data.competition.numplayers] = &players[winner].skincolor;
 		data.competition.character[data.competition.numplayers] = &players[winner].skin;
@@ -1907,8 +1909,8 @@ static void Y_AwardCoopBonuses(void)
 		}
 
 		ptlives = min(
-			((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0),
-			(mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives));
+			(INT32)((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((INT32)((players[i].score/50000) - (oldscore/50000)), (INT32)0) : 0),
+			(INT32)(mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives));
 		if (ptlives)
 			P_GivePlayerLives(&players[i], ptlives);
 
@@ -1953,10 +1955,9 @@ static void Y_AwardSpecialStageBonus(void)
 
 		// grant extra lives right away since tally is faked
 		ptlives = min(
-			((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0),
-			(mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives));
-		if (ptlives)
-			P_GivePlayerLives(&players[i], ptlives);
+			(INT32)((!ultimatemode && !modeattacking && players[i].lives != INFLIVES) ? max((INT32)((players[i].score/50000) - (oldscore/50000)), (INT32)0) : 0),
+			(INT32)(mapheaderinfo[prevmap]->maxbonuslives < 0 ? INT32_MAX : mapheaderinfo[prevmap]->maxbonuslives));
+		P_GivePlayerLives(&players[i], ptlives);
 
 		if (i == consoleplayer)
 		{
@@ -2054,4 +2055,5 @@ static void Y_UnloadData(void)
 			//are not handled
 			break;
 	}
+
 }