diff --git a/app_info_setup.bat b/app_info_setup.bat new file mode 100644 index 0000000..eab1e8d --- /dev/null +++ b/app_info_setup.bat @@ -0,0 +1,5 @@ +REM ** Make sure american code page is used, otherwise the %DATE environmental var might be wrong +CHCP 437 + +#just a batch file so any other batch files in windows can snag the name of this project. Used by batch files in /android and /html5 +set APP_NAME=RTDink diff --git a/bin/zlib1.dll b/bin/zlib1.dll new file mode 100644 index 0000000..1cf8a47 Binary files /dev/null and b/bin/zlib1.dll differ diff --git a/bin/zlibwapi.dll b/bin/zlibwapi.dll new file mode 100644 index 0000000..e267cc9 Binary files /dev/null and b/bin/zlibwapi.dll differ diff --git a/dinkhd_license.txt b/dinkhd_license.txt new file mode 100644 index 0000000..158e048 --- /dev/null +++ b/dinkhd_license.txt @@ -0,0 +1,17 @@ +The Dink HD source code license + +Copyright (C) 1997-2017 Seth A. Robinson All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. + +2. Any software using source code from this distribution must contain the text "This product includes software developed by Seth A. Robinson ( www.rtsoft.com )" inside the app in an easily accessible position and sufficiently legible font. + +3. Except as contained in this notice, the name of Seth A. Robinson shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior authorization from Seth A. Robinson. + +4. The name "Dink Smallwood" and "Dink Smallwood HD" are copyrighted by Robinson Technologies Corporation and shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior authorization from Seth A. Robinson. + +5. Media such as graphics/audio are not included in this license. Please ask Seth if you'd like to distribute Dink HD specific media in a port. + +THIS SOFTWARE IS PROVIDED 'AS IS' AND ANY EXPRESSED 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 SETH A. ROBINSON 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. \ No newline at end of file diff --git a/dxsdk/Lib/x64/Unused/DxErr.lib b/dxsdk/Lib/x64/Unused/DxErr.lib new file mode 100644 index 0000000..bfd2cd5 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/DxErr.lib differ diff --git a/dxsdk/Lib/x64/Unused/DxErr8.lib b/dxsdk/Lib/x64/Unused/DxErr8.lib new file mode 100644 index 0000000..08def18 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/DxErr8.lib differ diff --git a/dxsdk/Lib/x64/Unused/X3DAudio.lib b/dxsdk/Lib/x64/Unused/X3DAudio.lib new file mode 100644 index 0000000..3e8115f Binary files /dev/null and b/dxsdk/Lib/x64/Unused/X3DAudio.lib differ diff --git a/dxsdk/Lib/x64/Unused/XInput.lib b/dxsdk/Lib/x64/Unused/XInput.lib new file mode 100644 index 0000000..c881eae Binary files /dev/null and b/dxsdk/Lib/x64/Unused/XInput.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3d10.lib b/dxsdk/Lib/x64/Unused/d3d10.lib new file mode 100644 index 0000000..f442d7b Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3d10.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3d9.lib b/dxsdk/Lib/x64/Unused/d3d9.lib new file mode 100644 index 0000000..ade1872 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3d9.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3dx10.lib b/dxsdk/Lib/x64/Unused/d3dx10.lib new file mode 100644 index 0000000..1004408 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3dx10.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3dx10d.lib b/dxsdk/Lib/x64/Unused/d3dx10d.lib new file mode 100644 index 0000000..0c14419 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3dx10d.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3dx9.lib b/dxsdk/Lib/x64/Unused/d3dx9.lib new file mode 100644 index 0000000..872cae3 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3dx9.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3dx9d.lib b/dxsdk/Lib/x64/Unused/d3dx9d.lib new file mode 100644 index 0000000..63fcbeb Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3dx9d.lib differ diff --git a/dxsdk/Lib/x64/Unused/d3dxof.lib b/dxsdk/Lib/x64/Unused/d3dxof.lib new file mode 100644 index 0000000..66dbd30 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/d3dxof.lib differ diff --git a/dxsdk/Lib/x64/Unused/ddraw.lib b/dxsdk/Lib/x64/Unused/ddraw.lib new file mode 100644 index 0000000..c7d77b3 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/ddraw.lib differ diff --git a/dxsdk/Lib/x64/Unused/dinput.lib b/dxsdk/Lib/x64/Unused/dinput.lib new file mode 100644 index 0000000..5f89b95 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dinput.lib differ diff --git a/dxsdk/Lib/x64/Unused/dinput8.lib b/dxsdk/Lib/x64/Unused/dinput8.lib new file mode 100644 index 0000000..38aa632 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dinput8.lib differ diff --git a/dxsdk/Lib/x64/Unused/dplayx.lib b/dxsdk/Lib/x64/Unused/dplayx.lib new file mode 100644 index 0000000..07fdf94 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dplayx.lib differ diff --git a/dxsdk/Lib/x64/Unused/dsound.lib b/dxsdk/Lib/x64/Unused/dsound.lib new file mode 100644 index 0000000..12c580d Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dsound.lib differ diff --git a/dxsdk/Lib/x64/Unused/dxgi.lib b/dxsdk/Lib/x64/Unused/dxgi.lib new file mode 100644 index 0000000..56e590e Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dxgi.lib differ diff --git a/dxsdk/Lib/x64/Unused/dxtrans.lib b/dxsdk/Lib/x64/Unused/dxtrans.lib new file mode 100644 index 0000000..d69fb30 Binary files /dev/null and b/dxsdk/Lib/x64/Unused/dxtrans.lib differ diff --git a/dxsdk/Lib/x64/dxguid.lib b/dxsdk/Lib/x64/dxguid.lib new file mode 100644 index 0000000..234312f Binary files /dev/null and b/dxsdk/Lib/x64/dxguid.lib differ diff --git a/dxsdk/Lib/x86/Unused/DxErr.lib b/dxsdk/Lib/x86/Unused/DxErr.lib new file mode 100644 index 0000000..b47687f Binary files /dev/null and b/dxsdk/Lib/x86/Unused/DxErr.lib differ diff --git a/dxsdk/Lib/x86/Unused/DxErr8.lib b/dxsdk/Lib/x86/Unused/DxErr8.lib new file mode 100644 index 0000000..cbf3aff Binary files /dev/null and b/dxsdk/Lib/x86/Unused/DxErr8.lib differ diff --git a/dxsdk/Lib/x86/Unused/X3DAudio.lib b/dxsdk/Lib/x86/Unused/X3DAudio.lib new file mode 100644 index 0000000..7d1ad2d Binary files /dev/null and b/dxsdk/Lib/x86/Unused/X3DAudio.lib differ diff --git a/dxsdk/Lib/x86/Unused/XInput.lib b/dxsdk/Lib/x86/Unused/XInput.lib new file mode 100644 index 0000000..bd55e6a Binary files /dev/null and b/dxsdk/Lib/x86/Unused/XInput.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3d10.lib b/dxsdk/Lib/x86/Unused/d3d10.lib new file mode 100644 index 0000000..5524954 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3d10.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3d8.lib b/dxsdk/Lib/x86/Unused/d3d8.lib new file mode 100644 index 0000000..252aac4 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3d8.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3d9.lib b/dxsdk/Lib/x86/Unused/d3d9.lib new file mode 100644 index 0000000..7f236c6 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3d9.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3dx10.lib b/dxsdk/Lib/x86/Unused/d3dx10.lib new file mode 100644 index 0000000..98ab37a Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3dx10.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3dx10d.lib b/dxsdk/Lib/x86/Unused/d3dx10d.lib new file mode 100644 index 0000000..fa6b96d Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3dx10d.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3dx9d.lib b/dxsdk/Lib/x86/Unused/d3dx9d.lib new file mode 100644 index 0000000..52db37d Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3dx9d.lib differ diff --git a/dxsdk/Lib/x86/Unused/d3dxof.lib b/dxsdk/Lib/x86/Unused/d3dxof.lib new file mode 100644 index 0000000..bf3cde4 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/d3dxof.lib differ diff --git a/dxsdk/Lib/x86/Unused/ddraw.lib b/dxsdk/Lib/x86/Unused/ddraw.lib new file mode 100644 index 0000000..57f83d6 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/ddraw.lib differ diff --git a/dxsdk/Lib/x86/Unused/dinput.lib b/dxsdk/Lib/x86/Unused/dinput.lib new file mode 100644 index 0000000..7c93a65 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dinput.lib differ diff --git a/dxsdk/Lib/x86/Unused/dinput8.lib b/dxsdk/Lib/x86/Unused/dinput8.lib new file mode 100644 index 0000000..a639c4e Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dinput8.lib differ diff --git a/dxsdk/Lib/x86/Unused/dplayx.lib b/dxsdk/Lib/x86/Unused/dplayx.lib new file mode 100644 index 0000000..a8ada84 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dplayx.lib differ diff --git a/dxsdk/Lib/x86/Unused/dsetup.lib b/dxsdk/Lib/x86/Unused/dsetup.lib new file mode 100644 index 0000000..b1030af Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dsetup.lib differ diff --git a/dxsdk/Lib/x86/Unused/dsound.lib b/dxsdk/Lib/x86/Unused/dsound.lib new file mode 100644 index 0000000..37bf188 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dsound.lib differ diff --git a/dxsdk/Lib/x86/Unused/dxgi.lib b/dxsdk/Lib/x86/Unused/dxgi.lib new file mode 100644 index 0000000..9570db4 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dxgi.lib differ diff --git a/dxsdk/Lib/x86/Unused/dxtrans.lib b/dxsdk/Lib/x86/Unused/dxtrans.lib new file mode 100644 index 0000000..c222133 Binary files /dev/null and b/dxsdk/Lib/x86/Unused/dxtrans.lib differ diff --git a/dxsdk/Lib/x86/dxguid.lib b/dxsdk/Lib/x86/dxguid.lib new file mode 100644 index 0000000..c29117d Binary files /dev/null and b/dxsdk/Lib/x86/dxguid.lib differ diff --git a/programmer_readme.txt b/programmer_readme.txt new file mode 100644 index 0000000..7c86253 --- /dev/null +++ b/programmer_readme.txt @@ -0,0 +1,16 @@ +Dink Smallwood HD + +-- How to compile and run: + +* First, be able to compile and run the proton example RTSimpleApp. More info at www.protonsdk.com on installing and setting up proton +* Move the RTDink directory checkout to a sub directory of your proton dir. (it works exactly like a proton example - you can still svn update/commit like normal, svn allows you to move around dirs like that) +* Sign up at fmod.com and download FMod Studio for Windows. Unzip to \shared\win\fmodstudio, so you should have a proton\shared\win\fmodstudio\api dir, etc. +* Install Visual Studio 2017 (Community version works fine and is free) and open RTDink\windows_vs2017\iPhoneRTDink.sln +* Set the profile to "Release GL" and "Win32". (or "Debug GL" is ok too) Compile. If it worked, you should have a dink.exe created in DinkHD/bin. +* Install DinkHD from rtsoft.com. (media is not svn, so this is a way to get it..) Overwrite its dink.exe with your new one. It should run! + +Use the "Debug GL" or "Release GL" solution configuations. + +--- Have a bugfix or patch?! Please send it over to Seth! Please note that any submission (code, media, translations, ect) must be 100% compatible with the license as listed in dinkhd_license.txt + +See script/installer/readme.txt for what's new info. diff --git a/script/BuildAndPackageWindows.bat b/script/BuildAndPackageWindows.bat new file mode 100644 index 0000000..99802a6 --- /dev/null +++ b/script/BuildAndPackageWindows.bat @@ -0,0 +1,72 @@ +REM ** Make sure american code page is used, otherwise the %DATE environmental var might be wrong +CHCP 437 + +REM first clean out any bogus files +cd ..\ +cd media +set NO_PAUSE=1 +:call update_media.bat +cd .. +cd script + +:setup for VS 2017 +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\"vcvars32.bat + +set C_TARGET_EXE=..\bin\dink.exe + +REM erase it so we know it got built right +del %C_TARGET_EXE% > NUL + +set CL=/DRT_SCRIPT_BUILD +:This would need to be "Release GL|x64" for the 64 bit build. But I don't think we really need to do one yet + +:for full rebuild +devenv ..\windows_vs2017\iphoneRTDink.sln /rebuild "Release GL|Win32" + +:for no rebuild +:devenv ..\windows_vs2017\iphoneRTDink.sln /build "Release GL|Win32" + +REM Make sure the file compiled ok +if not exist %C_TARGET_EXE% beeper.exe /p + +:Sign it with the RTsoft cert (optional) + +call sign.bat %C_TARGET_EXE% + +REM Do a little cleanup in the dink bin dir as well +del ..\bin\dink\continue_state.dat +del ..\bin\dink\save*.dat +del ..\bin\dink\quicksave.dat + +//make the windows installer part +SET C_FILENAME=DinkSmallwoodHDInstaller.exe +del %C_FILENAME% > NUL + +REM get version information from the source code +echo Grabbing version # information from source code. + +ctoenv.exe ..\source\App.cpp "m_version = " C_VERSION /r +if errorlevel 1 beeper.exe /p +call setenv.bat +del setenv.bat + +ctoenv.exe ..\source\App.cpp "m_versionString = \"" C_TEXT_VERSION_TEMP +if errorlevel 1 beeper.exe /p +call setenv.bat +del setenv.bat +SET C_TEXT_VERSION=%C_TEXT_VERSION_TEMP% +REM done with temp var, kill it +SET C_TEXT_VERSION_TEMP= +echo Building installer: %C_FILENAME% %C_TEXT_VERSION% + +cd win_installer +..\..\..\..\util\NSIS\makensis.exe dink.nsi + +cd .. +set d_fname=%C_FILENAME% + +call sign.bat %C_FILENAME% + +:call FTPToSiteWin.bat +cd script +pause \ No newline at end of file diff --git a/script/BuildAndroidAndUploadBeta.bat b/script/BuildAndroidAndUploadBeta.bat new file mode 100644 index 0000000..f8e6de1 --- /dev/null +++ b/script/BuildAndroidAndUploadBeta.bat @@ -0,0 +1,11 @@ +cd ..\android +call build.bat +@ECHO ON +set D_FILE_NAME=%APP_NAME%-unprotected.apk +del ..\%D_FILE_NAME% +copy bin\%APP_NAME%-debug.apk ..\%D_FILE_NAME% +cd .. +set d_fname=%D_FILE_NAME% +call script\FTPToSite.bat +cd script +pause \ No newline at end of file diff --git a/script/win_installer/readme.txt b/script/win_installer/readme.txt new file mode 100644 index 0000000..55ad8dd --- /dev/null +++ b/script/win_installer/readme.txt @@ -0,0 +1,48 @@ +Dink Smallwood HD for Windows 7, 8, 10. + +Requires OpenGL, if you have any problems running this, try installing the latest video drivers for your video card/chip. + +To change screen size, drag the window borders around. (Hold shift while dragging to toggle aspect-ratio lock) +To toggle a psuedo full screen mode, click Full Screen Toggle in the options. (Or hit Alt-Enter) + +------------- BETA VERSION ----------------- + +This is a beta version which means it probably has bugs and isn't ready for general consumption. However, it means you've been recruited to help us make it better! + +To report a bug, find or post a thread about Dink HD on dinknetwork.com and and please include the following information if you can: + +- Dink files are installed to C:\Users\\AppData\Local\DinkSmallwoodHD by default. + +- Description of the bug and how to recreate it +- If the bug takes work to get to, it would be great if you could "Quick save" in the game and add a URL to download the quicksave.dat file. + +quicksave.dat should be located in C:\Users\\AppData\Local\DinkSmallwoodHD for the main game and C:\Users\\AppData\Local\DinkSmallwoodHD\dmods\ for DMODs. + +- The DMOD name (and URL to download it if possible) +- Windows version you're playing on +- Screen mode/resolution +- If the game crashes, please include the log.txt file as it may contain information about the crash. + +-Seth (seth@rtsoft.com) +www.rtsoft.com + +------ Change log for 1.7.0 ---------- + +* Upgraded source projects to Visual Studio 2017 (free community edition works fine) +* (bugfix) No longer forces reload of all graphics when saving the state +* (bugfix) No longer forces reload of all graphics and audio when losing focus/going into the background +* (bugfix) Fixed issue where screen scrolling could bug out if window was resized on windows +* Latest state data to "Continue" persists even if the game crashes now +* Added support for 64 bit builds (still fully compatible with existing save states/games) +* Added support for aspect ratio correction (can be disabled by enabling "Fullscreen stretch" in the options) +* Added IPV6 support +* (DinkC) Goto statements no longer require a ; at the end to work +* (iOS) Now compatible with iOS 11 +* (Windows) Installer no longer requires admin privileges, now installs to local user's appdata dir (C:\UserName\AppData\Local\DinkSmallwoodHD) +* (Windows) .exe and installer are now signed with RTsoft's distribution certificate +* (Windows) Now checks for new versions on startup +* (Windows) Now writes the stack trace to log.txt if the game crashes (helps debug problems) + +------ Change log for 1.7.1 ---------- + +* (Windows) Fixed app icon \ No newline at end of file diff --git a/source/App.cpp b/source/App.cpp new file mode 100644 index 0000000..fd1017c --- /dev/null +++ b/source/App.cpp @@ -0,0 +1,877 @@ +/* + * App.cpp + * Created by Seth Robinson on 3/6/09. + * For license info, check the license.txt file that should have come with this. + * + */ +#include "PlatformPrecomp.h" +#include "App.h" +#include "GUI/MainMenu.h" +#include "Entity/EntityUtils.h"//create the classes that our globally library expects to exist somewhere. +#include "dink/dink.h" +#include "GUI/GameMenu.h" +#include "util/archive/TarHandler.h" +#include "Renderer/SoftSurface.h" +#include "GUI/BrowseMenu.h" +#include "Entity/SliderComponent.h" +#include "GUI/OptionsMenu.h" +#include "FileSystem/FileSystemZip.h" +#include "Entity/ArcadeInputComponent.h" +#include "GUI/ExpiredMenu.h" +#include +#include "Gamepad/GamepadManager.h" +#include "Gamepad/GamepadProvideriCade.h" + +#ifdef WINAPI + +#include "StackWalker/StackUtils.h" + +#endif + + +extern Surface g_transitionSurf; + +#ifdef RT_MOGA_ENABLED +#include "Gamepad/GamepadProviderMoga.h" +#endif + +#ifdef RT_CHARTBOOST_ENABLED +#include "Ad/AdProviderChartBoost.h" +#endif + +#ifdef RT_IOS_60BEAT_GAMEPAD_SUPPORT +#include "Gamepad/GamepadProvider60Beat.h" +#endif + +//#define FORCE_DMOD_SUPPORT + +MessageManager g_messageManager; +MessageManager * GetMessageManager() {return &g_messageManager;} + +FileManager g_fileManager; +FileManager * GetFileManager() {return &g_fileManager;} + +GamepadManager g_gamepadManager; +GamepadManager * GetGamepadManager() {return &g_gamepadManager;} + +#ifdef __APPLE__ + +#if TARGET_OS_IPHONE == 1 + //it's an iPhone or iPad + //#include "Audio/AudioManagerOS.h" + //AudioManagerOS g_audioManager; + //#include "Audio/AudioManagerDenshion.h" + + //AudioManagerDenshion g_audioManager; + + #include "Audio/AudioManagerFMODStudio.h" + AudioManagerFMOD g_audioManager; +#else + //it's being compiled as a native OSX app +#include "Audio/AudioManagerFMODStudio.h" + AudioManagerFMOD g_audioManager; //dummy with no sound + + //in theory, CocosDenshion should work for the Mac builds, but right now it seems to want a big chunk of + //Cocos2d included so I'm not fiddling with it for now + + //#include "Audio/AudioManagerDenshion.h" + //AudioManagerDenshion g_audioManager; +#endif + +#else + +#if defined RT_WEBOS || defined RTLINUX +#include "Audio/AudioManagerSDL.h" + AudioManagerSDL g_audioManager; //sound in windows and WebOS + //AudioManager g_audioManager; //to disable sound +#elif defined ANDROID_NDK +#include "Audio/AudioManagerAndroid.h" + AudioManagerAndroid g_audioManager; //sound for android +#elif defined PLATFORM_BBX +#include "Audio/AudioManagerBBX.h" + //AudioManager g_audioManager; //to disable sound + AudioManagerBBX g_audioManager; +#elif defined PLATFORM_HTML5 +#include "Audio/AudioManagerSDL.h" +//AudioManager g_audioManager; //to disable sound +AudioManagerSDL g_audioManager; + +#elif defined PLATFORM_FLASH + //AudioManager g_audioManager; //to disable sound +#include "Audio/AudioManagerFlash.h" + AudioManagerFlash g_audioManager; +#else + + //in windows + //AudioManager g_audioManager; //to disable sound + +#ifdef RT_FLASH_TEST + #include "Audio/AudioManagerFlash.h" + AudioManagerFlash g_audioManager; +#else + // #include "Audio/AudioManagerAudiere.h" + // AudioManagerAudiere g_audioManager; //Use Audiere for audio + + #include "Gamepad/GamepadProviderDirectX.h" + #include "Audio/AudioManagerFMODStudio.h" + AudioManagerFMOD g_audioManager; //if we wanted FMOD sound in windows +#endif + +#endif +#endif + + + +#ifdef ANDROID_NDK +void SetPreferSDCardForStorage(bool bNew); +#endif + +AudioManager * GetAudioManager(){return &g_audioManager;} + +App *g_pApp = NULL; +BaseApp * GetBaseApp() +{ + if (!g_pApp) + { + g_pApp = new App; + } + + return g_pApp; +} + +App * GetApp() +{ + return g_pApp; +} + +const char * GetAppName() {return "Dink Smallwood HD";}; + + +App::App() +{ + http://www.rtsoft.com + + +#ifdef ANDROID_NDK + SetPreferSDCardForStorage(true); +#endif + + m_bDidPostInit = false; + m_bHasDMODSupport = true; + //for mobiles + m_version = 1.71f; + m_versionString = "V1.7.1"; + m_build = 1; + m_bCheatsEnabled = false; + + //for Win/mac + m_desktopVersion = m_version; + m_desktopVersionString = m_versionString; + m_desktopBuild = 1; + m_bForceAspectRatio = true; +} + +App::~App() +{ + + //L_ParticleSystem::deinit(); +} + + +void App::AddIcadeProvider() +{ + GamepadProvider * pProv = GetGamepadManager()->AddProvider(new GamepadProvideriCade); //use iCade, this actually should work with any platform... + GetBaseApp()->SetAllowScreenDimming(false); + if (pProv) + { + pProv->m_sig_failed_to_connect.connect(1, boost::bind(&App::OniCadeDisconnected, this, _1)); + } +} + +bool App::GetForceAspectRatio() +{ + return m_bForceAspectRatio; +} + +void App::OniCadeDisconnected(GamepadProvider *pProvider) +{ + LogMsg("Dealing with icade disconnect"); + GetGamepadManager()->RemoveProviderByName("iCade"); + GetApp()->RemoveAndroidKeyboardKeys(); + + GetApp()->GetVar("check_icade")->Set(uint32(0)); + + Entity *pOptions = GetEntityRoot()->GetEntityByName("OptionsMenu"); + if (pOptions) + { + LogMsg("Found options"); + Entity *pCheckBox = pOptions->GetEntityByName("check_icade"); + if (pCheckBox) + { + LogMsg("Found checkbox"); + SetCheckBoxChecked(pCheckBox, false, true); + } + } +} + +bool App::Init() +{ + +#ifdef WINAPI + InitUnhandledExceptionFilter(); +#endif + + SetDefaultButtonStyle(Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_RELEASE); + SetManualRotationMode(false); + + bool bScaleScreenActive = true; //if true, we'll stretch every screen to the coords below + int scaleToX = 480; + int scaleToY = 320; + + if (IsTabletSize()) + { + scaleToX = 1024; + scaleToY = 768; + } + + + /* + if (IsIphoneSize || IsIphone4Size || IsIPADSize) + { + bScaleScreenActive = false; + } + */ + + switch (GetEmulatedPlatformID()) + { + //special handling for certain platforms to tweak the video settings + + case PLATFORM_ID_WEBOS: + //if we do this, everything will be stretched/zoomed to fit the screen + if (IsIPADSize) + { + //doesn't need rotation + SetLockedLandscape(false); //because it's set in the app manifest, we don't have to rotate ourselves + SetupScreenInfo(GetPrimaryGLX(), GetPrimaryGLY(), ORIENTATION_PORTRAIT); + if (bScaleScreenActive) + SetupFakePrimaryScreenSize(scaleToX,scaleToY); //game will think it's this size, and will be scaled up + } + else + { + //but the phones do + SetLockedLandscape(true); //we don't allow portrait mode for this game + if (bScaleScreenActive) + SetupFakePrimaryScreenSize(scaleToX,scaleToY); //game will think it's this size, and will be scaled up + } + + break; + + case PLATFORM_ID_IOS: + SetLockedLandscape(true); //we stay in portrait but manually rotate, gives better fps on older devices + if (bScaleScreenActive) + SetupFakePrimaryScreenSize(scaleToX,scaleToY); //game will think it's this size, and will be scaled up + break; + + default: + + //Default settings for other platforms + + SetLockedLandscape(false); //we don't allow portrait mode for this game + SetupScreenInfo(GetPrimaryGLX(), GetPrimaryGLY(), ORIENTATION_PORTRAIT); + if (bScaleScreenActive) + SetupFakePrimaryScreenSize(scaleToX,scaleToY); //game will think it's this size, and will be scaled up + } + + + //L_ParticleSystem::init(2000); + SetInputMode(INPUT_MODE_SEPARATE_MOVE_TOUCHES); //this game has so much move touching, I handle them separately for performance reasons + + if (m_bInitted) + { + return true; + } + + if (!BaseApp::Init()) + { + return false; + } + + m_adManager.Init(); + +#ifdef RT_CHARTBOOST_ENABLED + AdProviderChartBoost *pProvider = new AdProviderChartBoost; + +#ifdef PLATFORM_ANDROID + assert(!"No longer using chartboost!"); + + pProvider->SetupInfo("", ""); //Dink HD Android + +#else + + pProvider->SetupInfo("", ""); //Dink HD iOS + +#endif + + + + m_adManager.AddProvider(pProvider); + pProvider->CacheShowInterstitial(); +// pProvider->CacheShowMoreApps(); + + m_adManager.GetProviderByType(AD_PROVIDER_CHARTBOOST)->ShowInterstitial(); + //m_adManager.GetProviderByType(AD_PROVIDER_CHARTBOOST)->ShowMoreApps(); +#endif + + LogMsg("Save path is %s", GetSavePath().c_str()); + + if (GetEmulatedPlatformID() == PLATFORM_ID_HTML5) + { + g_dglo.m_bUsingDinkPak = true; + } + + + + if (g_dglo.m_bUsingDinkPak) + { + FileSystemZip *pFileSystem = new FileSystemZip(); + if (!pFileSystem->Init(GetBaseAppPath()+ "dink/dink.pak")) + { + LogMsg("Error finding APK file to load resources"); + } + + //pFileSystem->SetRootDirectory("dink"); + + GetFileManager()->MountFileSystem(pFileSystem); + + } + + if (GetPlatformID() != PLATFORM_ID_ANDROID) + { + /* + FileSystemZip *pFileSystem = new FileSystemZip(); + if (!pFileSystem->Init(GetBaseAppPath()+ "dink/dink.pak")) + { + LogMsg("Error finding APK file to load resources"); + } + + GetFileManager()->MountFileSystem(pFileSystem); + */ + /* + vector contents = pFileSystem->GetContents(); + LogMsg("Listing all %d files.", contents.size()); + + for (int i=0; i < contents.size(); i++) + { + LogMsg("%s", contents[i].c_str()); + } + */ + + RemoveFile(GetDMODRootPath()+"temp.dmod"); + RemoveFile("temp.dmod"); + } + + switch (GetPlatformID()) + { + case PLATFORM_ID_WINDOWS: + case PLATFORM_ID_BBX: + case PLATFORM_ID_WEBOS: + case PLATFORM_ID_HTML5: + CreateDirectoryRecursively("", GetDMODRootPath()); + break; + + + default: + + CreateAppCacheDirIfNeeded(); + break; + } + + + if (IsLargeScreen()) + { + if (!GetFont(FONT_SMALL)->Load("interface/font_normalx2.rtfont")) return false; + if (!GetFont(FONT_LARGE)->Load("interface/font_bigx2.rtfont")) return false; + } else + { + if (!GetFont(FONT_SMALL)->Load("interface/font_normal.rtfont")) return false; + if (!GetFont(FONT_LARGE)->Load("interface/font_big.rtfont")) return false; + } + + //GetFont(FONT_SMALL)->SetSmoothing(false); + #ifndef FORCE_DMOD_SUPPORT + + if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) + { + //m_bHasDMODSupport = false; + } + #endif + + #ifdef _DEBUG + GetBaseApp()->SetFPSVisible(true); + #endif + + bool bFileExisted; + m_varDB.Load("save.dat", &bFileExisted); + + GetApp()->GetVarWithDefault("smoothing",uint32(1))->GetUINT32(); + + GetApp()->GetVarWithDefault("buttons",uint32(0)); + + GetApp()->GetVarWithDefault("music_vol",1.0f)->GetFloat(); + GetApp()->GetVarWithDefault("gui_transparency",0.35f)->GetFloat(); + + + #ifdef PLATFORM_WINDOWS + //If you don't have directx, just comment out this and remove the dx lib dependency, directx is only used for the + //gamepad input on windows + GetGamepadManager()->AddProvider(new GamepadProviderDirectX); //use directx joysticks + #endif + +#ifdef RT_MOGA_ENABLED + GetGamepadManager()->AddProvider( new GamepadProviderMoga); + GetBaseApp()->SetAllowScreenDimming(false); +#endif + + if (GetVar("check_icade")->GetUINT32() != 0) + { + AddIcadeProvider(); + } + +#if defined(PLATFORM_IOS) && defined(RT_IOS_60BEAT_GAMEPAD_SUPPORT) + //startup the 60beat gamepad stuff.. really, we should only do this if they've checked to use it in options + //or such because their driver may slow us down.. unsure + if (GetVar("check_60beat")->GetUINT32() != 0) + { + //startup the 60beat gamepad stuff + GetGamepadManager()->AddProvider(new GamepadProvider60Beat); + GetBaseApp()->SetAllowScreenDimming(false); + } +#endif + + + + if (GetEmulatedPlatformID() == PLATFORM_ID_WINDOWS || GetEmulatedPlatformID() == PLATFORM_ID_OSX || GetEmulatedPlatformID() == PLATFORM_ID_HTML5) + { + //should we draw that onscreen GUI stuff for Dink? + m_bUsingTouchScreen = false; + } else + { + m_bUsingTouchScreen = true; + } + + if (IsIPADSize && GetEmulatedPlatformID() != PLATFORM_ID_WEBOS) + { + GetApp()->GetVarWithDefault("fpsLimit", Variant(uint32(VIDEO_FPS_LIMIT_OFF)))->GetUINT32(); + } + + UpdateVideoSettings(); + //preload audio + + +if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) +{ + //use our own DLS, as iPhone/iPad don't have any midi system + g_audioManager.SetDLS("dink/midi/TimGM6mbTiny.dls"); +} + +#ifdef _DEBUG + GetApp()->SetCheatsEnabled(true); + +#endif +#ifdef _WIN32 + + //temporary while I make movies + //GetApp()->SetCheatsEnabled(true); +#endif + + bool bSound = m_varDB.GetVarWithDefault("sound", uint32(1))->GetUINT32() != 0; + GetAudioManager()->SetSoundEnabled(bSound); + + //GetAudioManager()->SetMusicEnabled(!GetApp()->GetVar("musicDisabled")->GetUINT32()); + GetAudioManager()->SetMusicVol(GetApp()->GetVar("music_vol")->GetFloat()); + GetAudioManager()->Preload("audio/click.wav"); + InitDinkPaths(GetBaseAppPath(), "dink", ""); + + GetBaseApp()->m_sig_pre_enterbackground.connect(1, boost::bind(&App::OnPreEnterBackground, this, _1)); + + + GetBaseApp()->m_sig_loadSurfaces.connect(1, boost::bind(&App::OnLoadSurfaces, this)); + + //when screen size changes we'll unload surfaces + GetBaseApp()->m_sig_unloadSurfaces.connect(1, boost::bind(&App::OnUnloadSurfaces, this)); + + + + + return true; +} + +void App::OnPreEnterBackground(VariantList *pVList) +{ + SaveAllData(); +} + +void App::OnExitApp(VariantList *pVarList) +{ + LogMsg("Exiting the app"); + + OSMessage o; + o.m_type = OSMessage::MESSAGE_FINISH_APP; + GetBaseApp()->AddOSMessage(o); +} + +void App::Kill() +{ + + if (!IsInBackground()) + { + SaveAllData(); + } + + finiObjects(); + + BaseApp::Kill(); + g_pApp = NULL; //make sure nobody elses access this +} + + +void App::RemoveAndAttachAllAvailableGamepads() +{ + ArcadeInputComponent *pComp = (ArcadeInputComponent*) GetEntityRoot()->GetComponentByName("ArcadeInput"); + assert(pComp); + + for (int i=0; i < GetGamepadManager()->GetGamepadCount(); i++) + { + Gamepad *pPad = GetGamepadManager()->GetGamepad((eGamepadID)i); + pPad->ConnectToArcadeComponent(pComp, true, true); + + //if we cared about the analog sticks too, we'd do this: + //pPad->m_sig_left_stick.connect(1, boost::bind(&OnGamepadStickUpdate, this, _1)); + //pPad->m_sig_right_stick.connect(1, boost::bind(&OnGamepadStickUpdate, this, _1)); + } +} + +void App::RemoveAndroidKeyboardKeys() +{ + ArcadeInputComponent *pComp = (ArcadeInputComponent*) GetEntityRoot()->GetComponentByName("ArcadeInput"); + //first clear out all old ones to be safe + VariantList vList((string)"Keyboard"); + pComp->GetFunction("RemoveKeyBindingsStartingWith")->sig_function(&vList); +} + +void App::AddDroidKeyboardKeys() +{ + if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) + { + + + ArcadeInputComponent *pComp = (ArcadeInputComponent*) GetEntityRoot()->GetComponentByName("ArcadeInput"); + + RemoveAndroidKeyboardKeys(); + + //I think the ASWZ binding thing is for the control pad on the xperia play?? + + AddKeyBinding(pComp, "KeyboardLeft",'A', VIRTUAL_KEY_DIR_LEFT); + AddKeyBinding(pComp, "KeyboardRight",'S', VIRTUAL_KEY_DIR_RIGHT); + AddKeyBinding(pComp, "KeyboardUp", 'W', VIRTUAL_KEY_DIR_UP); + AddKeyBinding(pComp, "KeyboardDown", 'Z', VIRTUAL_KEY_DIR_DOWN); + AddKeyBinding(pComp, "KeyboardAltMagic", 8, VIRTUAL_KEY_GAME_MAGIC); + + AddKeyBinding(pComp, "KeyboardInventory", 'I', VIRTUAL_KEY_GAME_INVENTORY); + AddKeyBinding(pComp, "KeyboardAltTalk", 13, VIRTUAL_KEY_GAME_TALK); + AddKeyBinding(pComp, "KeyboardFire", VIRTUAL_KEY_DIR_CENTER, VIRTUAL_KEY_GAME_FIRE); + AddKeyBinding(pComp, "KeyboardFire2", 'X', VIRTUAL_KEY_GAME_FIRE); +// AddKeyBinding(pComp, "KeyboardAltFire", VIRTUAL_KEY_SHIFT, VIRTUAL_KEY_GAME_FIRE); + } +} + +void App::Update() +{ + BaseApp::Update(); + m_adManager.Update(); + g_gamepadManager.Update(); + + if (!m_bDidPostInit) + { + m_bDidPostInit = true; + m_special = GetSystemData() != C_PIRATED_NO; + + //build a GUI node + Entity *pGUIEnt = GetEntityRoot()->AddEntity(new Entity("GUI")); + +#ifdef RT_EXPIRING + time_t rawtime, expiretime; + time(&rawtime); + + expiretime = 1290050035 + ((3600)*24)*8; //expire in 8 days from Nov 18 + bool bExpired = expiretime < rawtime; + + if (bExpired) + { + ExpiredMenuCreate(pGUIEnt); + return; + } + +#endif + + ArcadeInputComponent *pComp = (ArcadeInputComponent*) GetEntityRoot()->AddComponent(new ArcadeInputComponent); + + RemoveAndAttachAllAvailableGamepads(); + + //add key bindings, I may want to move these later if I add a custom key config... + + AddKeyBinding(pComp, "Left", VIRTUAL_KEY_DIR_LEFT, VIRTUAL_KEY_DIR_LEFT); + AddKeyBinding(pComp, "Right", VIRTUAL_KEY_DIR_RIGHT, VIRTUAL_KEY_DIR_RIGHT); + AddKeyBinding(pComp, "Up", VIRTUAL_KEY_DIR_UP, VIRTUAL_KEY_DIR_UP); + AddKeyBinding(pComp, "Down", VIRTUAL_KEY_DIR_DOWN, VIRTUAL_KEY_DIR_DOWN); + AddKeyBinding(pComp, "Talk", ' ', VIRTUAL_KEY_GAME_TALK); + + AddKeyBinding(pComp, "GamePadInventory", VIRTUAL_DPAD_SELECT, VIRTUAL_KEY_GAME_INVENTORY); + AddKeyBinding(pComp, "GamePadInventory2", VIRTUAL_DPAD_BUTTON_UP, VIRTUAL_KEY_GAME_INVENTORY); + AddKeyBinding(pComp, "GamePadEscape", VIRTUAL_DPAD_START, VIRTUAL_KEY_BACK, true); + AddKeyBinding(pComp, "GamePadFire", VIRTUAL_DPAD_BUTTON_DOWN, VIRTUAL_KEY_GAME_FIRE); + AddKeyBinding(pComp, "GamePadTalk", VIRTUAL_DPAD_BUTTON_RIGHT, VIRTUAL_KEY_GAME_TALK); + AddKeyBinding(pComp, "GamePadMagic", VIRTUAL_DPAD_BUTTON_LEFT, VIRTUAL_KEY_GAME_MAGIC); + + AddKeyBinding(pComp, "GamePadSpeedup", VIRTUAL_DPAD_LBUTTON, 'M', true); + AddKeyBinding(pComp, "GamePadSpeedup2", VIRTUAL_DPAD_RBUTTON, 9); + + AddKeyBinding(pComp, "GamePadInventory3", VIRTUAL_DPAD_LTRIGGER, VIRTUAL_KEY_GAME_INVENTORY); + AddKeyBinding(pComp, "GamePadPause", VIRTUAL_DPAD_RTRIGGER, VIRTUAL_KEY_BACK, true); + + +//if (IsDesktop()) +{ + AddKeyBinding(pComp, "Inventory", 13, VIRTUAL_KEY_GAME_INVENTORY); + AddKeyBinding(pComp, "Magic", VIRTUAL_KEY_SHIFT, VIRTUAL_KEY_GAME_MAGIC); + AddKeyBinding(pComp, "Fire", VIRTUAL_KEY_CONTROL, VIRTUAL_KEY_GAME_FIRE); + AddKeyBinding(pComp, "Speedup", 9, 9); //handle tab + AddKeyBinding(pComp, "Quicksave", VIRTUAL_KEY_F1, VIRTUAL_KEY_F1); + AddKeyBinding(pComp, "Quickload", VIRTUAL_KEY_F8, VIRTUAL_KEY_F8); +} + + + +if (GetVar("check_icade")->GetUINT32() == 0) + { + + AddDroidKeyboardKeys(); + } + + MainMenuCreate(pGUIEnt); + } +} + +void App::Draw() +{ + BaseApp::Draw(); +} + +void App::OnScreenSizeChange() +{ +#ifdef _DEBUG + LogMsg("Got OnScreenSizeChange"); +#endif + + BaseApp::OnScreenSizeChange(); + if (GetPrimaryGLX() != 0) + { + SetupOrtho(); + DinkOnForeground(); //rebuild lost surfaces + + if (GetDinkGameState() != DINK_GAME_STATE_PLAYING) + { + PrepareForGL(); + } + + } +} + +void App::GetServerInfo( string &server, uint32 &port ) +{ +#if defined (_DEBUG) && defined(WIN32) +// server = "localhost"; +// port = 8080; + + server = "rtsoft.com"; + port = 80; + +#else + + server = "rtsoft.com"; + port = 80; +#endif +} + +int App::GetSpecial() +{ + return m_special; //1 means pirated copy +} + +Variant * App::GetVar( const string &keyName ) +{ + return GetShared()->GetVar(keyName); +} + +std::string App::GetVersionString() +{ + if (IsDesktop()) return m_desktopVersionString; + return m_versionString; +} + +float App::GetVersion() +{ + if (IsDesktop()) return m_desktopVersion; + return m_version; +} + +int App::GetBuild() +{ + if (IsDesktop()) return m_desktopBuild; + return m_build; +} + +void App::OnMemoryWarning() +{ + BaseApp::OnMemoryWarning(); + + GetAudioManager()->KillCachedSounds(false, true, 0, 1, false); + DinkUnloadUnusedGraphicsByUsageTime(100); //unload anything not used in the last second +} + +void App::UpdateVideoSettings() +{ + eVideoFPS v = (eVideoFPS)GetApp()->GetVarWithDefault("fpsLimit", Variant(uint32(VIDEO_FPS_LIMIT_OFF)))->GetUINT32(); + OSMessage o; + o.m_type = OSMessage::MESSAGE_SET_FPS_LIMIT; + + switch (v) + { + case VIDEO_FPS_LIMIT_ON: + o.m_x = 30; + break; + + case VIDEO_FPS_LIMIT_OFF: + o.m_x = 2000; + break; + } + + GetBaseApp()->AddOSMessage(o); +}; + +void App::SaveAllData() +{ + + if (GetDinkGameState() == DINK_GAME_STATE_PLAYING) + { + // SaveState(GetSavePath()+"state.dat"); + SaveState(g_dglo.m_savePath+"continue_state.dat"); + WriteLastPathSaved(g_dglo.m_savePath); //so we know what to reload + } + + //GetAudioManager()->StopMusic(); + m_varDB.Save("save.dat"); +} + +void App::OnEnterBackground() +{ + //SaveAllData(); +// DinkUnloadGraphicsCache(); + + +/* +//I don't think we really need to uncache everything. If low memory is a problem we could though.. + + GetAudioManager()->KillCachedSounds(false, true, 0, 1, false); + LogMsg("Unloading some graphics"); + DinkUnloadUnusedGraphicsByUsageTime(0); //unload anything not used in the last second +*/ + + BaseApp::OnEnterBackground(); +} + +void App::OnEnterForeground() +{ + if (GetPrimaryGLX() == 0) return; //not ready, probably minimized on Windows + + BaseApp::OnEnterForeground(); + +} + +bool App::GetIconsOnLeft() +{ + return GetShared()->GetVar("buttons")->GetUINT32() != 0; +} + +//below is a sort of hack that allows "release" builds on windows to override the settings of whatever the shared main.cpp is telling +//us for window sizes +#ifdef _WINDOWS_ +#include "win/app/main.h" +#endif + +extern int g_winVideoScreenX; +extern int g_winVideoScreenY; + +bool App::OnPreInitVideo() +{ + if (!BaseApp::OnPreInitVideo()) return false; + +#ifdef PLATFORM_HTML5 + g_winVideoScreenX = 1024; + g_winVideoScreenY = 768; +#endif + +//#if !defined(_DEBUG) && defined(WINAPI) +#ifdef WINAPI + +#ifdef RT_SCRIPT_BUILD + + SetEmulatedPlatformID(PLATFORM_ID_WINDOWS); + g_winVideoScreenX = 1024; + g_winVideoScreenY = 768; +#endif + +// g_winVideoScreenX = 800; +// g_winVideoScreenY = 1280; + + +#endif + return true; +} + +//for palm webos and android +const char * GetBundlePrefix() +{ + + char * bundlePrefix = "com.rtsoft."; + return bundlePrefix; +} + +//applicable to Palm WebOS builds only +const char * GetBundleName() +{ + char * bundleName = "rtdink"; + return bundleName; +} + +void App::OnMessage( Message &m ) +{ + m_adManager.OnMessage(m); //gives the AdManager a way to handle messages + BaseApp::OnMessage(m); +} + + +void App::OnLoadSurfaces() +{ + LogMsg("Reloading dink engine surfaces"); + DinkOnForeground(); + +} + +void App::OnUnloadSurfaces() +{ + LogMsg("Unloading dink engine surfaces"); + DinkUnloadUnusedGraphicsByUsageTime(0); + + //g_transitionSurf.Kill(); +} diff --git a/source/App.h b/source/App.h new file mode 100644 index 0000000..ad494c2 --- /dev/null +++ b/source/App.h @@ -0,0 +1,116 @@ +/* + * App.h + * Created by Seth Robinson on 3/6/09. + * For license info, check the license.txt file that should have come with this. + * + */ + +#pragma once +#include "BaseApp.h" +#include "Manager/AdManager.h" + +#define RT_IS_BETA 1 + +#ifdef RT_SCRIPT_BUILD + + //this is being build from the command line, enable special flags here +#endif + +class GamepadProvider; + +enum eControlStyle +{ + CONTROLS_JOYPAD, + CONTROLS_DRAG_ANYWHERE, + CONTROLS_FLING +}; + +enum eVideoFPS +{ + VIDEO_FPS_LIMIT_ON, + VIDEO_FPS_LIMIT_OFF +}; + + + +#ifndef __APPLE__ +//#define RT_EXPIRING +#endif + +//#define RT_CHARTBOOST_ENABLED + + +class App: public BaseApp +{ +public: + + App(); + virtual ~App(); + + virtual bool Init(); + virtual void Kill(); + virtual bool OnPreInitVideo(); + virtual void Draw(); + virtual void OnScreenSizeChange(); + virtual void Update(); + virtual void OnMemoryWarning(); + virtual void OnEnterBackground(); + virtual void OnEnterForeground(); + + string GetVersionString(); + float GetVersion(); + int GetBuild(); + void GetServerInfo(string &server, uint32 &port); + VariantDB * GetShared() {return &m_varDB;} + Variant * GetVar(const string &keyName ); + Variant * GetVarWithDefault(const string &varName, const Variant &var) {return m_varDB.GetVarWithDefault(varName, var);} + int GetSpecial(); + void UpdateVideoSettings(); + bool GetUsingTouchScreen() {return m_bUsingTouchScreen;} + bool CanDownloadDMODS() {return m_bHasDMODSupport;} + void SetCheatsEnabled(bool bCheatsEnabled) {m_bCheatsEnabled = bCheatsEnabled;} + bool GetCheatsEnabled() {return m_bCheatsEnabled;} + void OnExitApp(VariantList *pVarList); + bool GetIconsOnLeft(); + void RemoveAndAttachAllAvailableGamepads(); + + AdManager * GetAdManager() {return &m_adManager;} + + void OnMessage( Message &m ); + void OnLoadSurfaces(); + void OnUnloadSurfaces(); + void AddDroidKeyboardKeys(); + void RemoveAndroidKeyboardKeys(); + void AddIcadeProvider(); + bool GetForceAspectRatio(); + +private: + + AdManager m_adManager; + + bool m_bDidPostInit; + VariantDB m_varDB; //holds all data we want to save/load + int m_special; + bool m_bUsingTouchScreen; + bool m_bForceAspectRatio; + + void SaveAllData(); + void OnPreEnterBackground(VariantList *pVList); + void OniCadeDisconnected(GamepadProvider *pProvider); + float m_version; + string m_versionString; + int m_build; + + float m_desktopVersion; + string m_desktopVersionString; + int m_desktopBuild; + bool m_bHasDMODSupport; + bool m_bCheatsEnabled; + +}; + + +App * GetApp(); +const char * GetAppName(); +const char * GetBundleName(); +const char * GetBundlePrefix(); \ No newline at end of file diff --git a/source/Component/ActionButtonComponent.cpp b/source/Component/ActionButtonComponent.cpp new file mode 100644 index 0000000..43bcabb --- /dev/null +++ b/source/Component/ActionButtonComponent.cpp @@ -0,0 +1,169 @@ +#include "PlatformPrecomp.h" +#include "ActionButtonComponent.h" +#include "util/GLESUtils.h" +#include "Entity/EntityUtils.h" +#include "BaseApp.h" +#include "../dink/dink.h" + +ActionButtonComponent::ActionButtonComponent() +{ + SetName("ActionButton"); + m_mode = MODE_MAGIC; +} + +ActionButtonComponent::~ActionButtonComponent() +{ + +} + + +void ActionButtonComponent::OnAdd(Entity *pEnt) +{ + EntityComponent::OnAdd(pEnt); + + m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2(); + + if (GetParent()->GetName() != "magic") + { + m_mode = MODE_WEAPON; + } + /* + m_pSize2d = &GetParent()->GetVar("size2d")->GetVector2(); + m_pScale = &GetParent()->GetShared()->GetVarWithDefault("scale", Variant(1.0f))->GetFloat(); + m_pRotation = &GetParent()->GetVar("rotation")->GetFloat(); //in degrees + + m_pColor = &GetParent()->GetShared()->GetVarWithDefault("color", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32(); + m_pColorMod = &GetParent()->GetShared()->GetVarWithDefault("colorMod", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32(); + m_pAlignment = &GetParent()->GetVar("alignment")->GetUINT32(); + */ + + m_pAlpha = &GetParent()->GetShared()->GetVarWithDefault("alpha", Variant(1.0f))->GetFloat(); + + //register ourselves to render if the parent does + GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&ActionButtonComponent::OnRender, this, _1)); + GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&ActionButtonComponent::OnUpdate, this, _1)); + + UpdateIcon(); +} + +void ActionButtonComponent::OnRemove() +{ + EntityComponent::OnRemove(); +} + +void ActionButtonComponent::OnRender(VariantList *pVList) +{ + CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d; + + Surface *pSurf; + + switch (m_mode) + { + case MODE_MAGIC: + pSurf = DinkGetMagicIconImage(); + break; + + case MODE_WEAPON: + pSurf = DinkGetWeaponIconImage(); + break; + } + + if (pSurf) + { + rtRectf srcRect = pSurf->GetRectf(); + rtRectf dstRect = srcRect; + + if (IsLargeScreen()) + { + + dstRect = rtRectf(0,0, 90,90); + + } else + { + + dstRect = rtRectf(0,0, 44,39); + + } + + dstRect.AdjustPosition(vFinalPos.x, vFinalPos.y); + if (IsLargeScreen()) + { + dstRect.AdjustPosition(19, 25); + } else + { + dstRect.AdjustPosition(9, 12); + + } + + + pSurf->BlitEx(dstRect, srcRect, MAKE_RGBA(255* *m_pAlpha,255* *m_pAlpha,255* *m_pAlpha,255* *m_pAlpha)); + + if (g_dglo.GetActiveView() == DinkGlobals::VIEW_ZOOMED) + { + + int alpha = int(255.0f * *m_pAlpha); + + if (alpha > 2) + { + + + if (m_mode ==MODE_MAGIC) + { + float percent = DinkGetMagicChargePercent(); + + if (percent > 0) + { + + + //LogMsg("Magic: %.2f", DinkGetMagicChargePercent()); + rtRectf rBar(0,0, iPhoneMapX2X(54)*percent, iPhoneMapY2X(3)); + rBar.AdjustPosition(vFinalPos.x, vFinalPos.y); + rBar.AdjustPosition(iPhoneMapX2X(6), iPhoneMapY2X(-4)); + + if (percent == 1) + { + DrawFilledRect(rBar, MAKE_RGBA(0, 180, 0, 255* *m_pAlpha)); + DrawRect(rBar, MAKE_RGBA(0, 255, 0, 255* *m_pAlpha)); + + } else + { + + DrawFilledRect(rBar, MAKE_RGBA(0, 100, 0, 255* *m_pAlpha)); + DrawRect(rBar, MAKE_RGBA(0, 255, 0, 170* *m_pAlpha)); + } + } + + } else + { + float percent = DinkGetHealthPercent(); + //LogMsg("Magic: %.2f", DinkGetMagicChargePercent()); + rtRectf rBar(0,0, iPhoneMapX2X(54)*percent, iPhoneMapY2X(3)); + rBar.AdjustPosition(vFinalPos.x, vFinalPos.y); + rBar.AdjustPosition(iPhoneMapX2X(6), iPhoneMapY2X(-4)); + + DrawFilledRect(rBar, MAKE_RGBA(180, 0, 0, 255* *m_pAlpha)); + DrawRect(rBar, MAKE_RGBA(255, 0, 0, 255* *m_pAlpha)); + + } + + } + + } + } +} + +void ActionButtonComponent::OnUpdate(VariantList *pVList) +{ +} + +void ActionButtonComponent::UpdateIcon() +{ +} + +Entity * CreateActionButtonEntity(Entity *pParentEnt, string name, string fileName, float x, float y) +{ + + Entity *pButtonEnt = CreateOverlayButtonEntity(pParentEnt, name, fileName, x, y); + pButtonEnt->AddComponent(new ActionButtonComponent); + return pButtonEnt; +} \ No newline at end of file diff --git a/source/Component/ActionButtonComponent.h b/source/Component/ActionButtonComponent.h new file mode 100644 index 0000000..74958e8 --- /dev/null +++ b/source/Component/ActionButtonComponent.h @@ -0,0 +1,56 @@ +// *************************************************************** +// ActionButtonComponent - Creation date: 3/15/2010 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2010 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef ActionButtonComponent_h__ +#define ActionButtonComponent_h__ + +#include "Entity/Component.h" +#include "Entity/Entity.h" +#include "Renderer/SurfaceAnim.h" + +class ActionButtonComponent: public EntityComponent +{ +public: + ActionButtonComponent(); + virtual ~ActionButtonComponent(); + + virtual void OnAdd(Entity *pEnt); + virtual void OnRemove(); + + + enum eMode + { + MODE_MAGIC, + MODE_WEAPON + }; + +private: + + void OnRender(VariantList *pVList); + void OnUpdate(VariantList *pVList); + bool IsMagic() {return m_mode == MODE_MAGIC;} + void UpdateIcon(); + CL_Vec2f *m_pPos2d; + + /* + CL_Vec2f *m_pSize2d; + float *m_pScale; + uint32 *m_pColor; + uint32 *m_pColorMod; + uint32 *m_pAlignment; + float *m_pRotation; //in degrees + */ + float *m_pAlpha; + + eMode m_mode; +}; + +Entity * CreateActionButtonEntity(Entity *pParentEnt, string name, string fileName, float x, float y); + +#endif // ActionButtonComponent_h__ \ No newline at end of file diff --git a/source/Component/CursorComponent.cpp b/source/Component/CursorComponent.cpp new file mode 100644 index 0000000..f368d9d --- /dev/null +++ b/source/Component/CursorComponent.cpp @@ -0,0 +1,87 @@ +#include "PlatformPrecomp.h" +#include "CursorComponent.h" +#include "util/GLESUtils.h" +#include "Entity/EntityUtils.h" +#include "BaseApp.h" + +CursorComponent::CursorComponent() +{ + SetName("Cursor"); +} + +CursorComponent::~CursorComponent() +{ +} + +void CursorComponent::OnAdd(Entity *pEnt) +{ + EntityComponent::OnAdd(pEnt); + m_pArrowEnt = NULL; + m_bDisable = false; + m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2(); + + + //register ourselves to render if the parent does + GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&CursorComponent::OnRender, this, _1)); + GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&CursorComponent::OnUpdate, this, _1)); + AddInputMovementFocusIfNeeded(GetParent()); + GetParent()->GetFunction("OnInput")->sig_function.connect(1, boost::bind(&CursorComponent::OnInput, this, _1)); + GetParent()->GetParent()->GetFunction("OnKillingControls")->sig_function.connect(1, boost::bind(&CursorComponent::OnKillingControls, this, _1)); + +} + +void CursorComponent::OnRemove() +{ + EntityComponent::OnRemove(); +} +void CursorComponent::OnKillingControls(VariantList *pVList) +{ + RemoveFocusIfNeeded(this->GetParent()); + m_bDisable = true; +} + +void CursorComponent::OnUpdatePos(CL_Vec2f vPos) +{ + //LogMsg("Got %s", PrintVector2(vPos).c_str()); + DinkSetCursorPosition(NativeToDinkCoords(vPos)); +} + +void CursorComponent::OnRender(VariantList *pVList) +{ + //CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d; +} + +void CursorComponent::OnUpdate(VariantList *pVList) +{ +} + + +void CursorComponent::OnInput( VariantList *pVList ) +{ + //0 = message type, 1 = parent coordinate offset + CL_Vec2f pt = pVList->Get(1).GetVector2(); + //pt += GetAlignmentOffset(*m_pSize2d, eAlignment(*m_pAlignment)); + + switch (eMessageType( int(pVList->Get(0).GetFloat()))) + { + case MESSAGE_TYPE_GUI_CLICK_START: + //HandleClickStart(pt); + OnUpdatePos(pt); + break; + case MESSAGE_TYPE_GUI_CLICK_END: + if (!m_bDisable) + { + OnUpdatePos(pt); + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + } + + //HandleClickEnd(pt); + break; + case MESSAGE_TYPE_GUI_CLICK_MOVE: + case MESSAGE_TYPE_GUI_CLICK_MOVE_RAW: + OnUpdatePos(pt); + break; + } + +} diff --git a/source/Component/CursorComponent.h b/source/Component/CursorComponent.h new file mode 100644 index 0000000..f26e172 --- /dev/null +++ b/source/Component/CursorComponent.h @@ -0,0 +1,51 @@ +// *************************************************************** +// CursorComponent - Creation date: ?/?/2009 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2009 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef CursorComponent_h__ +#define CursorComponent_h__ + +#include "Entity/Component.h" +#include "Entity/Entity.h" +#include "../dink/dink.h" + +class CursorComponent: public EntityComponent +{ +public: + CursorComponent(); + virtual ~CursorComponent(); + + virtual void OnAdd(Entity *pEnt); + virtual void OnRemove(); + +private: + + void OnRender(VariantList *pVList); + void OnUpdate(VariantList *pVList); + + void OnInput( VariantList *pVList ); + void OnUpdatePos(CL_Vec2f vPos); + void OnKillingControls(VariantList *pVList); + CL_Vec2f *m_pPos2d; + + /* + CL_Vec2f *m_pSize2d; + float *m_pScale; + uint32 *m_pColor; + uint32 *m_pColorMod; + float *m_pAlpha; + uint32 *m_pAlignment; + float *m_pRotation; //in degrees + */ + Entity *m_pArrowEnt; + bool m_bDisable; + + +}; + +#endif // CursorComponent_h__ \ No newline at end of file diff --git a/source/Component/DragControlComponent.cpp b/source/Component/DragControlComponent.cpp new file mode 100644 index 0000000..f27dda8 --- /dev/null +++ b/source/Component/DragControlComponent.cpp @@ -0,0 +1,332 @@ +#include "PlatformPrecomp.h" +#include "DragControlComponent.h" +#include "util/GLESUtils.h" +#include "Entity/EntityUtils.h" +#include "BaseApp.h" +#include "Entity/ArcadeInputComponent.h" +#include "GUI/GameMenu.h" + + +DragControlComponent::DragControlComponent() +{ + SetName("DragControl"); + + +SAMPLE_COUNT = 8; //unused + +LENGTH_REQUIRED_FOR_MOVE = 16; + +if (IsIphoneSize || IsIphone4Size) LENGTH_REQUIRED_FOR_MOVE = 32; //the screen is tiny, need a few more pixels + + if (IsIphone4Size) + { + LENGTH_REQUIRED_FOR_MOVE *= 2; + } + + +} + +DragControlComponent::~DragControlComponent() +{ +} + +void DragControlComponent::OnAdd(Entity *pEnt) +{ + EntityComponent::OnAdd(pEnt); + m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2(); + m_pSize2d = &GetParent()->GetVar("size2d")->GetVector2(); + if (IsIPAD()) + { + *m_pPos2d =(CL_Vec2f(0,29)); + } else + { + *m_pPos2d = (iPhoneMap(0,29)); + } + + + + //fit the active area to match the active dink screen layout + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar()) + { + if (IsIPAD()) + { + *m_pSize2d = CL_Vec2f(865, 584); + } else + { + *m_pSize2d = iPhoneMap(380, 237); + } + + } else + { + if (IsIPAD()) + { + *m_pSize2d = CL_Vec2f(866, 715); + + } else + { + *m_pSize2d = iPhoneMap(380, 286); + } + } + + if (GetApp()->GetIconsOnLeft()) + { + m_pPos2d->x += GetScreenSizeXf()-m_pSize2d->x; + } + + m_lastTouch = CL_Vec2f(0,0); + + /* + m_pScale = &GetParent()->GetShared()->GetVarWithDefault("scale", Variant(1.0f))->GetFloat(); + m_pRotation = &GetParent()->GetVar("rotation")->GetFloat(); //in degrees + + m_pColor = &GetParent()->GetShared()->GetVarWithDefault("color", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32(); + m_pColorMod = &GetParent()->GetShared()->GetVarWithDefault("colorMod", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32(); + m_pAlpha = &GetParent()->GetShared()->GetVarWithDefault("alpha", Variant(1.0f))->GetFloat(); + m_pAlignment = &GetParent()->GetVar("alignment")->GetUINT32(); + */ + + //register ourselves to render if the parent does + //GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&DragControlComponent::OnRender, this, _1)); + GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&DragControlComponent::OnUpdate, this, _1)); + GetBaseApp()->m_sig_arcade_input.connect(1, boost::bind(&DragControlComponent::OnArcadeInput, this, _1)); + + GetParent()->GetVar("ignoreTouchesOutsideRect")->Set(uint32(1)); + EntityComponent *pTouch = GetParent()->AddComponent(new TouchHandlerComponent); + + //movement arrows + + //for speed, we've disabled movement message handling in App.cpp, but we actually want them just here, so we'll hardwire it + AddInputMovementFocusIfNeeded(GetParent()); + + GetParent()->GetFunction("OnOverStart")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverStart, this, _1)); + GetParent()->GetFunction("OnOverEnd")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverEnd, this, _1)); + GetParent()->GetFunction("OnOverMove")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverMove, this, _1)); + + GetParent()->GetParent()->GetFunction("OnKillingControls")->sig_function.connect(1, boost::bind(&DragControlComponent::OnKillingControls, this, _1)); + + /* + + EntityComponent *pFilter = m_pArrowEnt->AddComponent(new FilterInputComponent); + pFilter->GetVar("mode")->Set(uint32(FilterInputComponent::MODE_CLIP_INPUT_TO_ABSOLUTE_CLIP_RECT_AND_DISABLE_INPUT_CHILDREN)); + pFilter->GetVar("clipRect")->Set(CL_Rectf(0,43,397, GetScreenSizeY())); + + m_timeOfLastTouch = GetTick(TIMER_SYSTEM); + SetAlignmentEntity(m_pArrowEnt, ALIGNMENT_CENTER); + m_pArrowEnt->GetVar("pos2d")->Set(CL_Vec2f(80, 240)); + + m_vArrowImageSizeOver2 = m_pArrowEnt->GetVar("size2d")->GetVector2()/2; + */ + VariantList vTemp; + OnOverEnd(&vTemp); +} + +void DragControlComponent::OnRemove() +{ + EntityComponent::OnRemove(); +} + +void DragControlComponent::SendKey(eDinkInput key, bool bIsDown) +{ + if (bIsDown) + { + g_dglo.m_dirInput[key] = true; + g_dglo.m_dirInputFinished[key] = false; //make sure it wasn't scheduled to stop pressing + } else + { + g_dglo.m_dirInputFinished[key] = true; + } +} + +void DragControlComponent::OnKillingControls(VariantList *pVList) +{ + RemoveFocusIfNeeded(GetParent()); +} + +void DragControlComponent::AddSample(DragUnit v) +{ + if (DinkIsDoingScreenTransition()) return; + m_samples.push_back(v); + + /* + if (m_samples.size() > SAMPLE_COUNT) + { + m_samples.pop_front(); + } + */ + +} + +void DragControlComponent::OnOverStart(VariantList *pVList) +{ + m_samples.clear(); + m_lastTouch = pVList->Get(0).GetVector2(); +} + +void DragControlComponent::OnOverEnd(VariantList *pVList) +{ +// CL_Vec2f vPos = pVList->Get(0).GetVector2(); +// LogMsg("Got over end: %s", PrintVector2(vPos).c_str()); + m_samples.clear(); + m_lastTouch = CL_Vec2f(0,0); + ClearKeyInput(); +} + +void DragControlComponent::OnOverMove(VariantList *pVList) +{ + AddSample( DragUnit(pVList->Get(0).GetVector2() - m_lastTouch, GetTick(TIMER_GAME))); + //SetPosition(pVList->Get(0).GetVector2()); + m_lastTouch = pVList->Get(0).GetVector2(); +} + +void DragControlComponent::ClearKeyInput() +{ + SendKey(DINK_INPUT_UP, false); + SendKey(DINK_INPUT_DOWN, false); + SendKey(DINK_INPUT_LEFT, false); + SendKey(DINK_INPUT_RIGHT, false); +} + +void DragControlComponent::OnRender(VariantList *pVList) +{ + CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d; +} + +void DragControlComponent::ProcessLastJoystickReading() +{ + + if (m_samples.size() == 0) return; + //first, lets figure out what direction we want + CL_Vec2f vDir = CL_Vec2f(0,0); + + std::deque< DragUnit> sampleTemp; + + for (int i=m_samples.size()-1; i >= 0;) + { + //if (m_samples.size() < SAMPLE_COUNT) break; + + /* + if (1) + //if (m_samples.at(i).m_timeMade+100 < GetTick(TIMER_GAME)) + { + vDir = CL_Vec2f(0,0); + //would removing this stop us from moving? + for (int h=1; h < m_samples.size();h++) + { + vDir += m_samples[h].m_vPos; + } + + if (vDir.length() < LENGTH_REQUIRED_FOR_MOVE) + { + //yes it would. Just let it be, for now. + //break; + } else + { + //it's not needed + } + + m_samples.erase(m_samples.begin()+i); + continue; + } else + { + break; + } + + */ + vDir += m_samples[i].m_vPos; + sampleTemp.push_front( m_samples[i]); + + if (vDir.length() >= LENGTH_REQUIRED_FOR_MOVE) + { + //all done + break; + } + + i--; + } + + m_samples = sampleTemp; + + //vDir = CL_Vec2f(0,0); + + /* + for (unsigned int i=0; i < m_samples.size();i++) + { + vDir += m_samples[i].m_vPos; + } + */ + ClearKeyInput(); + + //LogMsg("vDir length is %.2f", vDir.length()); + if (vDir.length() < LENGTH_REQUIRED_FOR_MOVE) return; + + vDir.normalize(); + + //recalculate the points + sampleTemp.clear(); + + //sampleTemp.push_front(m_samples[m_samples.size()-1]); + + sampleTemp.push_front(DragUnit( (vDir*LENGTH_REQUIRED_FOR_MOVE)*1.1, 0)); + m_samples = sampleTemp; + +#ifdef _DEBUG + //LogMsg("Dir is %s (%d samples)", PrintVector2(vDir).c_str(), m_samples.size()); +#endif + //convert to 360 degrees + int dir = (int(RAD2DEG(atan2(vDir.y, vDir.x))+(90))); + + const int maxDirections = 8; + int finaldir = mod(dir+ (360/ (maxDirections*2)), 360)/ (360/maxDirections); + + //nah, let's do 8 actually + + //LogMsg("Pressing %s, which is dir %d (final: %d)", PrintVector2(m_lastTouchDir).c_str(), dir, finaldir); + + switch (finaldir) + { + case 0: SendKey(DINK_INPUT_UP, true); break; + case 1: SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_UP, true); break; + + case 2: SendKey(DINK_INPUT_RIGHT, true); break; + case 3: SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_DOWN, true); break; + case 4: SendKey(DINK_INPUT_DOWN, true); break; + + case 5: SendKey(DINK_INPUT_DOWN, true); SendKey(DINK_INPUT_LEFT, true); break; + case 6: SendKey(DINK_INPUT_LEFT, true); break; + case 7: SendKey(DINK_INPUT_LEFT, true); SendKey(DINK_INPUT_UP, true); break; + } +} + + + +void DragControlComponent::OnArcadeInput(VariantList *pVList) +{ + int vKey = pVList->Get(0).GetUINT32(); + bool bIsDown = pVList->Get(1).GetUINT32() != 0; + + //LogMsg("Key %d, down is %d", vKey, int(bIsDown)); + switch (vKey) + { + case VIRTUAL_KEY_DIR_LEFT: + SendKey(DINK_INPUT_LEFT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_RIGHT: + SendKey(DINK_INPUT_RIGHT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_UP: + SendKey(DINK_INPUT_UP, bIsDown); + break; + + case VIRTUAL_KEY_DIR_DOWN: + SendKey(DINK_INPUT_DOWN, bIsDown); + break; + } +} + + +void DragControlComponent::OnUpdate(VariantList *pVList) +{ + ProcessLastJoystickReading(); +} \ No newline at end of file diff --git a/source/Component/DragControlComponent.h b/source/Component/DragControlComponent.h new file mode 100644 index 0000000..3aa35fa --- /dev/null +++ b/source/Component/DragControlComponent.h @@ -0,0 +1,77 @@ +// *************************************************************** +// DragControlComponent - Creation date: 4/27/2010 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2009 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef DragControlComponent_h__ +#define DragControlComponent_h__ + +#include "Entity/Component.h" +#include "Entity/Entity.h" +#include "../dink/dink.h" + +class DragUnit +{ +public: + DragUnit(CL_Vec2f vPos, unsigned int time) + { + m_vPos = vPos; + m_timeMade = time; + } + CL_Vec2f m_vPos; + unsigned int m_timeMade; //in game ticks + +}; + +class DragControlComponent: public EntityComponent +{ + + +public: + DragControlComponent(); + virtual ~DragControlComponent(); + + virtual void OnAdd(Entity *pEnt); + virtual void OnRemove(); + +private: + + void OnRender(VariantList *pVList); + void OnUpdate(VariantList *pVList); + void OnStripUpdate(VariantList *pVList); + void SendKey(eDinkInput key, bool bIsDown); + void OnOverStart(VariantList *pVList); + void OnOverEnd(VariantList *pVList); + void OnOverMove(VariantList *pVList); + void ClearKeyInput(); + void ProcessLastJoystickReading(); + void ProcessArrowInput(CL_Vec2f vDir); + void OnKillingControls(VariantList *pVList); + void AddSample(DragUnit v); + void OnArcadeInput(VariantList *pVList); + CL_Vec2f *m_pPos2d; + CL_Vec2f *m_pSize2d; + + /* + float *m_pScale; + uint32 *m_pColor; + uint32 *m_pColorMod; + float *m_pAlpha; + uint32 *m_pAlignment; + float *m_pRotation; //in degrees + */ + CL_Vec2f m_lastTouch; + + unsigned int m_timeOfLastTouch; + + std::deque< DragUnit> m_samples; + + float SAMPLE_COUNT; + float LENGTH_REQUIRED_FOR_MOVE; +}; + +#endif // DragControlComponent_h__ \ No newline at end of file diff --git a/source/Component/FPSControlComponent.cpp b/source/Component/FPSControlComponent.cpp new file mode 100644 index 0000000..04bed9b --- /dev/null +++ b/source/Component/FPSControlComponent.cpp @@ -0,0 +1,271 @@ +#include "PlatformPrecomp.h" +#include "FPSControlComponent.h" +#include "util/GLESUtils.h" +#include "Entity/EntityUtils.h" +#include "BaseApp.h" +#include "GUI/GameMenu.h" + +#define C_GUI_FADE_OUT_TIMER 400 +#define C_GUI_FADE_IN_TIMER 150 + + +FPSControlComponent::FPSControlComponent() +{ + SetName("FPSControl"); +} + +FPSControlComponent::~FPSControlComponent() +{ +} + +void FPSControlComponent::OnAdd(Entity *pEnt) +{ + EntityComponent::OnAdd(pEnt); + m_pArrowEnt = NULL; + m_pCenterBall = NULL; + m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2(); + m_lastTouchDir = CL_Vec2f(0, 0); //the middle + + m_bTouchingArrows = false; + + + //register ourselves to render if the parent does + GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnRender, this, _1)); + GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnUpdate, this, _1)); + + float guiTrans = GetApp()->GetVar("gui_transparency")->GetFloat(); + GetApp()->GetVar("gui_transparency")->Set(guiTrans); + + GetBaseApp()->m_sig_arcade_input.connect(1, boost::bind(&FPSControlComponent::OnArcadeInput, this, _1)); + + m_arrowMinTransparency = guiTrans; + m_arrowMaxTransparency = rt_max(0.5f, guiTrans); + + //movement arrows? + + if (GetApp()->GetUsingTouchScreen()) + { + + m_pArrowEnt = CreateOverlayEntity(GetParent(), "arrow_gui", ReplaceWithDeviceNameInFileName("interface/iphone/arrows.rttex"), 0, 0); + + EntityComponent *pStripComp = m_pArrowEnt->AddComponent(new TouchStripComponent); + m_pArrowEnt->GetVarWithDefault(string("touchPadding"), Variant(CL_Rectf(100, 100, 100, 100)))->GetRect(); + //m_pArrowEnt->AddComponent(new TouchHandlerComponent); + + //for speed, we've disabled movement message handling in App.cpp, but we actually want them just here, so we'll hardwire it + AddInputMovementFocusIfNeeded(m_pArrowEnt); + + m_pArrowEnt->GetFunction("OnTouchStripUpdate")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnStripUpdate, this, _1)); + m_pArrowEnt->GetFunction("OnOverStart")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnOverStart, this, _1)); + m_pArrowEnt->GetFunction("OnOverEnd")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnOverEnd, this, _1)); + + GetParent()->GetParent()->GetFunction("OnKillingControls")->sig_function.connect(1, boost::bind(&FPSControlComponent::OnKillingControls, this, _1)); + SetAlphaEntity(m_pArrowEnt, 0); + FadeEntity(m_pArrowEnt, true, m_arrowMinTransparency, 300, 0); + + //limit it to touches only on the left side of the screen + + //m_pCenterBall = CreateOverlayEntity(m_pArrowEnt, "center_ball", "interface/center_ball.rttex",0,0); + + if (m_pCenterBall) + { + m_pCenterBall->GetVar("color")->Set(MAKE_RGBA(255,255,255,0)); + //SetAlphaEntity(m_pCenterBall, 0); + SetAlignmentEntity(m_pCenterBall, ALIGNMENT_CENTER); + } + + m_timeOfLastTouch = GetTick(TIMER_SYSTEM); + SetAlignmentEntity(m_pArrowEnt, ALIGNMENT_CENTER); + + CL_Vec2f vArrowPos = FlipXIfNeeded(iPhoneMap(CL_Vec2f(80, 240))); + if (IsIPAD()) + { + if (IsInFlingMode()) + { + vArrowPos = CL_Vec2f( FlipXIfNeeded(149-30), C_FLING_JOYSTICK_Y); + } else + { + vArrowPos = FlipXIfNeeded(CL_Vec2f(137-20, 651-80)); + } + } + + m_pArrowEnt->GetVar("pos2d")->Set(vArrowPos); + m_vArrowImageSizeOver2 = m_pArrowEnt->GetVar("size2d")->GetVector2()/2; + + VariantList vList; + OnOverEnd(&vList); + } + +} + +void FPSControlComponent::OnRemove() +{ + EntityComponent::OnRemove(); +} + +void SendKey(eDinkInput key, bool bIsDown) +{ + if (bIsDown) + { + g_dglo.m_dirInput[key] = true; + g_dglo.m_dirInputFinished[key] = false; //make sure it wasn't scheduled to stop pressing + } else + { + g_dglo.m_dirInputFinished[key] = true; + } +} + +void FPSControlComponent::ProcessLastJoystickReading() +{ + CL_Vec2f vDir = m_lastTouchDir; + vDir.normalize(); + + if (m_pCenterBall) + m_pCenterBall->GetVar("pos2d")->Set(m_vArrowImageSizeOver2+vDir* (rt_min(m_lastTouchDir.length(), 1) * 58)); + + float deadSpace = 0.25f/2; + + if (IsInFlingMode()) + { + deadSpace *= 1.4f; + } else + { + if (IsIPADSize) deadSpace *= 2; + + } + + if (m_lastTouchDir.length() < deadSpace) + { + //dead space + if (m_pCenterBall) + { + m_pCenterBall->GetVar("pos2d")->Set(m_vArrowImageSizeOver2); + } + return; + } + + //convert to 360 degrees + int dir = (int(RAD2DEG(atan2(m_lastTouchDir.y, m_lastTouchDir.x))+(90))); + + const int maxDirections = 8; + int finaldir = mod(dir+ (360/ (maxDirections*2)), 360)/ (360/maxDirections); + + //nah, let's do 8 actually + + //LogMsg("Pressing %s, which is dir %d (final: %d)", PrintVector2(m_lastTouchDir).c_str(), dir, finaldir); + + switch (finaldir) + { + case 0: SendKey(DINK_INPUT_UP, true); break; + case 1: SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_UP, true); break; + + case 2: SendKey(DINK_INPUT_RIGHT, true); break; + case 3: SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_DOWN, true); break; + case 4: SendKey(DINK_INPUT_DOWN, true); break; + + case 5: SendKey(DINK_INPUT_DOWN, true); SendKey(DINK_INPUT_LEFT, true); break; + case 6: SendKey(DINK_INPUT_LEFT, true); break; + case 7: SendKey(DINK_INPUT_LEFT, true); SendKey(DINK_INPUT_UP, true); break; + } +} +void FPSControlComponent::OnKillingControls(VariantList *pVList) +{ + RemoveFocusIfNeeded(m_pArrowEnt); + +} + +void FPSControlComponent::OnArcadeInput(VariantList *pVList) +{ + int vKey = pVList->Get(0).GetUINT32(); + bool bIsDown = pVList->Get(1).GetUINT32() != 0; + + //LogMsg("Key %d, down is %d", vKey, int(bIsDown)); + switch (vKey) + { + case VIRTUAL_KEY_DIR_LEFT: + SendKey(DINK_INPUT_LEFT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_RIGHT: + SendKey(DINK_INPUT_RIGHT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_UP: + SendKey(DINK_INPUT_UP, bIsDown); + break; + + case VIRTUAL_KEY_DIR_DOWN: + SendKey(DINK_INPUT_DOWN, bIsDown); + break; + } +} + + +void FPSControlComponent::OnOverStart(VariantList *pVList) +{ +} + +void FPSControlComponent::OnOverEnd(VariantList *pVList) +{ + m_bTouchingArrows = false; + ClearKeyInput(); + if (m_pCenterBall) + m_pCenterBall->GetVar("color")->Set(MAKE_RGBA(255,255,255,0)); + + //m_pArrowEnt->GetVar("alpha")->Set(1.0f); + FadeEntity(m_pArrowEnt, false, m_arrowMinTransparency, C_GUI_FADE_OUT_TIMER); + if (m_pCenterBall) + FadeEntity(m_pCenterBall, false, 0.0, C_GUI_FADE_OUT_TIMER/3); +} + +void FPSControlComponent::ClearKeyInput() +{ + SendKey(DINK_INPUT_UP, false); + SendKey(DINK_INPUT_DOWN, false); + SendKey(DINK_INPUT_LEFT, false); + SendKey(DINK_INPUT_RIGHT, false); +} + +void FPSControlComponent::ProcessArrowInput(CL_Vec2f vDir) +{ + if (m_bTouchingArrows || 1) + { + m_lastTouchDir = vDir*2 - CL_Vec2f(1, 1); + + //update current position + ClearKeyInput(); + ProcessLastJoystickReading(); + } else + { + // m_lastTouchDir = CL_Vec2f(0,0); + if (m_pCenterBall) + m_pCenterBall->GetVar("pos2d")->Set(m_lastTouchDir); + } +} + +void FPSControlComponent::OnStripUpdate(VariantList *pVList) +{ + if (!m_bTouchingArrows) + { + m_bTouchingArrows = true; + //m_pArrowEnt->GetVar("pos2d")->Set( ConvertEntityClickToScreenCoords(pVList->Get(0).GetVector2(), pVList->Get(1).GetEntity())); + //ProcessArrowInput(pVList->Get(1).GetVector2()); + if (m_pCenterBall) + m_pCenterBall->GetVar("color")->Set(MAKE_RGBA(255,255,255,255)); + + FadeEntity(m_pArrowEnt, false, m_arrowMaxTransparency, C_GUI_FADE_IN_TIMER); + if (m_pCenterBall) + FadeEntity(m_pCenterBall, false, m_arrowMaxTransparency, C_GUI_FADE_OUT_TIMER/3); + + } + ProcessArrowInput(pVList->Get(1).GetVector2()); +} + +void FPSControlComponent::OnRender(VariantList *pVList) +{ + CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d; +} + +void FPSControlComponent::OnUpdate(VariantList *pVList) +{ +} \ No newline at end of file diff --git a/source/Component/FPSControlComponent.h b/source/Component/FPSControlComponent.h new file mode 100644 index 0000000..685816d --- /dev/null +++ b/source/Component/FPSControlComponent.h @@ -0,0 +1,65 @@ +// *************************************************************** +// FPSControlComponent - Creation date: ?/?/2009 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2009 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef FPSControlComponent_h__ +#define FPSControlComponent_h__ + +#include "Entity/Component.h" +#include "Entity/Entity.h" +#include "../dink/dink.h" + +#define C_FLING_JOYSTICK_Y (520+50) +class FPSControlComponent: public EntityComponent +{ +public: + FPSControlComponent(); + virtual ~FPSControlComponent(); + + virtual void OnAdd(Entity *pEnt); + virtual void OnRemove(); + +private: + + void OnRender(VariantList *pVList); + void OnUpdate(VariantList *pVList); + void OnStripUpdate(VariantList *pVList); + void OnOverStart(VariantList *pVList); + void OnOverEnd(VariantList *pVList); + void ClearKeyInput(); + void ProcessLastJoystickReading(); + void ProcessArrowInput(CL_Vec2f vDir); + void OnKillingControls(VariantList *pVList); + void OnArcadeInput(VariantList *pVList); + CL_Vec2f *m_pPos2d; + + /* + CL_Vec2f *m_pSize2d; + float *m_pScale; + uint32 *m_pColor; + uint32 *m_pColorMod; + float *m_pAlpha; + uint32 *m_pAlignment; + float *m_pRotation; //in degrees + */ + Entity *m_pArrowEnt; + Entity *m_pCenterBall; //will be a child of the arrowEnt + + CL_Vec2f m_lastTouchDir; + + unsigned int m_timeOfLastTouch; + bool m_bTouchingArrows; + CL_Vec2f m_vArrowImageSizeOver2; + float m_arrowMinTransparency; + float m_arrowMaxTransparency; + +}; + +void SendKey(eDinkInput key, bool bIsDown); + +#endif // FPSControlComponent_h__ \ No newline at end of file diff --git a/source/Component/InventoryComponent.cpp b/source/Component/InventoryComponent.cpp new file mode 100644 index 0000000..ada4cfe --- /dev/null +++ b/source/Component/InventoryComponent.cpp @@ -0,0 +1,112 @@ +#include "PlatformPrecomp.h" +#include "InventoryComponent.h" +#include "util/GLESUtils.h" +#include "Entity/EntityUtils.h" +#include "BaseApp.h" + +InventoryComponent::InventoryComponent() +{ + m_activeFinger = -1; + + SetName("Inventory"); +} + +InventoryComponent::~InventoryComponent() +{ +} + +void InventoryComponent::OnAdd(Entity *pEnt) +{ + EntityComponent::OnAdd(pEnt); + m_pArrowEnt = NULL; + m_bGotFirstClick = false; + m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2(); + + + //register ourselves to render if the parent does + GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&InventoryComponent::OnRender, this, _1)); + GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&InventoryComponent::OnUpdate, this, _1)); + + AddInputMovementFocusIfNeeded(GetParent()); + + GetParent()->GetFunction("OnInput")->sig_function.connect(1, boost::bind(&InventoryComponent::OnInput, this, _1)); + +} + +void InventoryComponent::OnRemove() +{ + EntityComponent::OnRemove(); +} + +void InventoryComponent::OnUpdatePos(CL_Vec2f vPos) +{ + //LogMsg("Got %s", PrintVector2(vPos).c_str()); + DinkSetInventoryPosition(NativeToDinkCoords(vPos)); +} + +void InventoryComponent::OnRender(VariantList *pVList) +{ + //CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d; +} + +void InventoryComponent::OnUpdate(VariantList *pVList) +{ +} + + +void InventoryComponent::OnInput( VariantList *pVList ) +{ + //0 = message type, 1 = parent coordinate offset + CL_Vec2f pt = pVList->Get(1).GetVector2(); + //pt += GetAlignmentOffset(*m_pSize2d, eAlignment(*m_pAlignment)); + + switch (eMessageType( int(pVList->Get(0).GetFloat()))) + { + case MESSAGE_TYPE_GUI_CLICK_START: + { + + uint32 fingerID = pVList->Get(2).GetUINT32(); + TouchTrackInfo *pTouch = GetBaseApp()->GetTouch(fingerID); + if (pTouch->WasHandled()) return; + pTouch->SetWasHandled(true); + m_activeFinger = fingerID; + } + + OnUpdatePos(pt); + break; + + case MESSAGE_TYPE_GUI_CLICK_END: + { + + uint32 fingerID = pVList->Get(2).GetUINT32(); + if (fingerID == m_activeFinger) + { + + OnUpdatePos(pt); + /* + if (!m_bGotFirstClick) + { + //ignore this, they are just releasing from the previous menu's button + m_bGotFirstClick = true; + } else + { + */ + if (DinkSetInventoryPosition(NativeToDinkCoords(pt))) + { + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + } + + } + } + //HandleClickEnd(pt); + break; + case MESSAGE_TYPE_GUI_CLICK_MOVE: + { + uint32 fingerID = pVList->Get(2).GetUINT32(); + if (fingerID == m_activeFinger) OnUpdatePos(pt); + } + break; + } + +} diff --git a/source/Component/InventoryComponent.h b/source/Component/InventoryComponent.h new file mode 100644 index 0000000..d7ef48f --- /dev/null +++ b/source/Component/InventoryComponent.h @@ -0,0 +1,42 @@ +// *************************************************************** +// InventoryComponent - Creation date: ?/?/2009 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2009 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef InventoryComponent_h__ +#define InventoryComponent_h__ + +#include "Entity/Component.h" +#include "Entity/Entity.h" +#include "../dink/dink.h" + +class InventoryComponent: public EntityComponent +{ +public: + InventoryComponent(); + virtual ~InventoryComponent(); + + virtual void OnAdd(Entity *pEnt); + virtual void OnRemove(); + +private: + + void OnRender(VariantList *pVList); + void OnUpdate(VariantList *pVList); + + void OnInput( VariantList *pVList ); + void OnUpdatePos(CL_Vec2f vPos); + CL_Vec2f *m_pPos2d; + int m_activeFinger; + + Entity *m_pArrowEnt; + + bool m_bGotFirstClick; + +}; + +#endif // InventoryComponent_h__ \ No newline at end of file diff --git a/source/GUI/AboutMenu.cpp b/source/GUI/AboutMenu.cpp new file mode 100644 index 0000000..2492852 --- /dev/null +++ b/source/GUI/AboutMenu.cpp @@ -0,0 +1,553 @@ +#include "PlatformPrecomp.h" +#include "AboutMenu.h" +#include "MainMenu.h" +#include "Entity/EntityUtils.h" +#include "PopUpMenu.h" + +void AboutMenuAddScrollContent(Entity *pParent); + +void AboutMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + Entity *pMenu = GetEntityRoot()->GetEntityByName("AboutMenu"); + + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[0].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + MainMenuCreate(pEntClicked->GetParent()->GetParent()); + return; + } + + if (pEntClicked->GetName() == "mindwall_ad") + { + string url = "http://www.codedojo.com/?p=138"; + + if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) + { + url = "market://details?id=com.rtsoft.rtmindwall"; + } else if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) + { + url = "http://www.rtsoft.com/mindwall/purchase.php"; + } + + + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to check out `wMind Wall?``", url, + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + + if (pEntClicked->GetName() == "dink_ad") + { + + string url = "http://www.rtsoft.com/pages/dink.php"; + + switch (GetEmulatedPlatformID()) + { + + case PLATFORM_ID_WEBOS: + // url = "http://www.rtsoft.com/mindwall/purchase_webos.php"; + break; + case PLATFORM_ID_IOS: + break; + + case PLATFORM_ID_OSX: + url = "http://itunes.apple.com/us/app/dink-smallwood-hd/id391690243?mt=8"; + break; + + case PLATFORM_ID_ANDROID: + url = "market://details?id=com.rtsoft.rtdink"; + break; + } + + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Leave the game and check out Dink Smallwood HD?", url, + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + if (pEntClicked->GetName() == "fling_ad") + { + string url = "http://tenonedesign.com/fling"; + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to visit Ten One Design's webpage and learn more about the `wFling``?", url, + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + if (pEntClicked->GetName() == "ds_ad") + { + + string url = "http://www.rtsoft.com/pages/dscroll.php"; + + if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) + { + url = "market://details?id=com.rtsoft.rtdscroll"; + } else if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) + + { + url = "http://www.rtsoft.com/dscroll_iphone/purchase.php"; + } + + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to check out `wDungeon Scroll``?", url, + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + if (pEntClicked->GetName() == "dinknetwork") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to check out `wThe Dink Network``?", "http://www.dinknetwork.com?device="+toString(GetEmulatedPlatformID()), + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + if (pEntClicked->GetName() == "email") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to email `wsupport@rtsoft.com now``?", "mailto:support@rtsoft.com", + "cancel", "`wCancel", "url", "`wEmail", true); + return; + } + if (pEntClicked->GetName() == "twitter") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "View the `wRTsoft twitter page``?", "http://twitter.com/rtsoft", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + if (pEntClicked->GetName() == "list") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to enter your email to subscribe to the `wRTsoft Newsletter``?", "http://www.rtsoft.com/lists/?p=subscribe", + "cancel", "`wCancel", "url", "`wOh yeah!", true); + return; + } + + if (pEntClicked->GetName() == "forums") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to visit the `wRTsoft Dink Forums``?", "http://www.rtsoft.com/forums/forumdisplay.php?6-Dink-Smallwood", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + + /* + if (pEntClicked->GetName() == "rtsoft") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Leave the game and visit `wrtsoft.com``?", "http://www.rtsoft.com/iphone", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + */ + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + +void AddBlurb(Entity* pParent, float x, float y, string fileName, string msg) +{ + + Entity * pLogo = CreateOverlayButtonEntity(pParent, fileName, string("interface/")+fileName+".rttex", x, y); + EntityRetinaRemapIfNeeded(pLogo, false, false, true); + pLogo->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + + + CL_Vec2f imageSize = pLogo->GetVar("size2d")->GetVector2(); + + float imagePaddingX = iPhoneMapX(20); + + CL_Vec2f vTextBoxPos(iPhoneMapX(x)+imageSize.x+imagePaddingX,y); + CL_Vec2f vTextBounds(iPhoneMapX(400)-imageSize.x+imagePaddingX , iPhoneMapY(200)); + + + Entity *pEnt = CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg); + + +} + +void AboutMenuAddScrollContent(Entity *pParent) +{ + pParent = pParent->GetEntityByName("scroll_child"); + + pParent->RemoveAllEntities(); + float x = 5; + float y = 0; + float ySpacer = iPhoneMapY(27); + + + Entity *pTitle = CreateTextLabelEntity(pParent, "Title", x, 0, "About & Help"); + SetupTextEntity(pTitle, FONT_LARGE); + y += iPhoneMapY(30); + + float blurbSpacingY = iPhoneMapX(27); + + if (IsIPAD()) + { + AddBlurb(pParent, x, y, "fling_ad", "`6This game is compatible with the `wFling analog joystick``. Tap the Fling logo to visit Ten One Design to learn more."); + y += iPhoneMapY(blurbSpacingY); + //y += ySpacer; + + } + CL_Vec2f vTextBoxPos(iPhoneMapX(x),y); + CL_Vec2f vTextBounds(iPhoneMapX(434), iPhoneMapY(200)); + + + string msg = + GetAppName()+string("`$ ")+GetApp()->GetVersionString()+" Build "+toString(GetApp()->GetBuild())+"``\nCopyright (c) 2012 Robinson Technologies\n"\ + "\nDink Script Version: `$1.10``\n\n"\ + ; + + + + +if (IsDesktop()) +{ + + + + msg += \ + "Keyboard controls:\n\n"\ + "Esc ``-`8 Bring up the game menu/pause``\n"\ + "Arrow keys ``-`8 Movement/menu selections``\n"\ + "Ctrl ``- `8Attack\n``"\ + "Shift ``- `8Magic\n``"\ + "Enter ``- `8Inventory screen/Inventory select\n``"\ + "M ``- `8Show map\n\n``"\ + "TAB ``- `8Speed up game (hold it down)\n``"\ + "F1 ``- `8Quick state save\n``"\ + "F8 ``- `8Quick state load\n``"\ + "Alt-Enter ``- `8Toggle fullscreen\n``"\ + "Drag window corners ``- `8Changes screensize. Hold Shift to allow any aspect ratio\n``"\ + "\n`6Stuck? Try visiting `wdinknetwork.com`` or use google to find a walkthrough.\n"\ + "\n`wFPS Lock``: If enabled, the game is limited to 30 frames per second. This should be enabled on most devices for more consistent gameplay.\n"\ + "\n`wPushing:`` If you make Dink walk against an object for one second, he will begin to push it. Useful when you see rocks blocking cave entrances.\n"\ + "\n`wTrees:`` Some trees can be burned down with magic to reveal secrets.\n"\ + "\n`wSave Machines:`` Use Save Machines frequently and don't only rely on quick saves as they may sometimes put you in a difficult spot.\n"\ + "\n`wAuto Save:`` Your game is automatically saved every five minutes to save slot 10 as long as you have more than 30% health.\n"\ + + "\n`wQuick save/load:`` In addition to the full auto state save whenever you exit the game, and the normal save system, you can use `wQuick Save/Load`` from the pause menu. It's very useful to beat a tough boss. Each add-on you install will also remember its own unique save states as well.\n"\ + "\n`wTo use an existing DMOD directory:`` Start the game with a command line parm of `w-dmodpath `` to use it instead of the default dmod directory.\n"\ +""; + +} else if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) +{ + + //android + msg += \ + "`6Thanks for buying `wDink Smallwood HD`` for Android. Here are some tips and info to get started.\n"\ + "\n`wControl mode - Virtual Joypad:`` This is the default control method, simple to use.\n"\ + "\n`wControl mode - Drag Anywhere:`` This control scheme allows you to draw an angle with your finger and dink will walk in that angle. It doesn't matter where you draw it on the screen. As long as you don't let your finger up, he'll keep moving.\n"\ + "\n`wTrackball:`` You can also use the trackball to move. You may wish to reverse the action icon positions from the Option menu.\n"\ + "\n`wiCade:`` Pair the iCade with your device, then start the game. Choose `$Use iCade Controller Mode`` from the options menu.\n"\ + "\n`wXperia Play:`` Explode the pay and play, no special setup required. Note that the shoulder buttons map to the map and speed-up.\n"\ + "\n`wHW Keyboard:`` If your device has a hardware keyboard, you can use WASZ to move, I for inventory, shift for punch, enter/menu for magic, space to talk.\n"\ + + "\n`wPushing:`` If you make Dink walk against an object for one second, he will begin to push it. Useful when you see rocks blocking cave entrances.\n"\ + "\n`wTrees:`` Some trees can be burned down with magic to reveal secrets.\n"\ + "\n`wQuick save/load:`` In addition to the full auto state save whenever you exit the game, and the normal save system, you can use `wQuick Save/Load`` from the pause menu. It's very useful to beat a tough boss.\n"\ + "\n`wSave Machines:`` Use Save Machines frequently and don't only rely on quick saves as they may sometimes put you in a difficult spot.\n"\ + "\n`wAuto Save:`` Your game is automatically saved every five minutes to save slot 10 as long as you have more than 30% health.\n"\ + "\n`wFPS Lock:`` If enabled, the game is limited to 30 frames per second. This should be enabled on slower devices for smoother gameplay.\n"\ + "\n`wInstalling DMODS by Browse:`` Click Browse from the Add-On menu to see a selection of recommended DMODs to install.\n"\ + "\n`wInstalling DMODS from URL:`` Click Install from URL from the Add-On menu.\n"\ + "\n`wInstalling DMODS from SD card:`` Place a .dmod file on your SD card in `w/Android/data/com.rtsoft.dink/files`` and it will be installed the next time you play.\n"\ + "\n`wIf the game is slow:`` Try turning Pic Smoothing to off in the options menu.\n"\ + "\n`wMulti-touch:`` Multi touch is supported when possible. Please note that many HTC phones such as the Nexus One only partially support multi-touch resulting in strange behavior when two fingers are on the screen.\n"\ + ; +} else if ( GetEmulatedPlatformID() == PLATFORM_ID_WEBOS || GetEmulatedPlatformID() == PLATFORM_ID_BBX) +{ + + //android + msg += \ + "`6Thanks for buying `wDink Smallwood HD``. Here are some tips and info to get started.\n"\ + "\n`wControl mode - Virtual Joypad:`` This is the default control method, simple to use.\n"\ + "\n`wControl mode - Drag Anywhere:`` This control scheme allows you to draw an angle with your finger and dink will walk in that angle. It doesn't matter where you draw it on the screen. As long as you don't let your finger up, he'll keep moving.\n"\ + + "\n`wPushing:`` If you make Dink walk against an object for one second, he will begin to push it. Useful when you see rocks blocking cave entrances.\n"\ + "\n`wTrees:`` Some trees can be burned down with magic to reveal secrets.\n"\ + "\n`wQuick save/load:`` In addition to the full auto state save whenever you exit the game, and the normal save system, you can use `wQuick Save/Load`` from the pause menu. It's very useful to beat a tough boss.\n"\ + "\n`wSave Machines:`` Use Save Machines frequently and don't only rely on quick saves as they may sometimes put you in a difficult spot.\n"\ + "\n`wAuto Save:`` Your game is automatically saved every five minutes to save slot 10 as long as you have more than 30% health.\n"\ + "\n`wFPS Lock:`` If enabled, the game is limited to 30 frames per second. This should be enabled on slower devices for smoother gameplay.\n"\ + "\n`wInstalling DMODS by Browse:`` Click Browse from the Add-On menu to see a selection of recommended DMODs to install.\n"\ + "\n`wInstalling DMODS from URL:`` Click Install from URL from the Add-On menu.\n"\ + "\n`wIf the game is slow:`` Try turning Pic Smoothing to off in the options menu.\n"\ + ; +} else +{ + + if (IsIPADSize) + { + +//iphone + msg += \ + "`6Thanks for buying `wDink Smallwood HD`` for iPhone, iPod Touch, and iPad. Here are some tips and info to get started.\n"\ + "\n`wControls - Virtual Joypad:`` This is the default control method, simple to use.\n"\ + "\n`wControls - Drag Anywhere:`` This control scheme allows you to draw an angle with your finger and dink will walk in that angle. It doesn't matter where you draw it on the screen. As long as you don't let your finger up, he'll keep moving.\n"\ + "\n`wControls - Fling Mode:`` This control scheme is optimized for the Fling analog joystick for iPad from Ten One Design.\n"\ + "\n`wPushing:`` If you make Dink walk against an object for one second, he will begin to push it. Useful when you see rocks blocking cave entrances.\n"\ + "\n`wTrees:`` Some trees can be burned down with magic to reveal secrets.\n"\ + "\n`wQuick save/load:`` In addition to the full auto state save whenever you exit the game, and the normal save system, you can use `wQuick Save/Load`` from the pause menu. It's very useful to beat a tough boss.\n"\ + "\n`wSave Machines:`` Use Save Machines frequently and don't only rely on quick saves as they may sometimes put you in a difficult spot.\n"\ + "\n`wAuto Save:`` Your game is automatically saved every five minutes to save slot 10 as long as you have more than 30% health.\n"\ + "\n`wFPS Lock:`` If enabled, the game is limited to 30 frames per second. This should be enabled on slower devices for smoother gameplay.\n"\ + "\n`wHow to import saves from desktop (iOS 3.2+):`` Drag and drop a save.dat file in the Dink HD Documents file sharing area in iTunes. Import happens when the main menu is visited. Use save_.dat to import a save to an installed DMOD.\n"\ + ; + } else + { + msg += \ + "`6Thanks for buying `wDink Smallwood HD`` for iPhone, iPod Touch, and iPad. Here are some tips and info to get started.\n"\ + "\n`wControls - Virtual Joypad:`` This is the default control method, simple to use.\n"\ + "\n`wControls - Drag Anywhere:`` This control scheme allows you to draw an angle with your finger and dink will walk in that angle. It doesn't matter where you draw it on the screen. As long as you don't let your finger up, he'll keep moving.\n"\ + "\n`wPushing:`` If you make Dink walk against an object for one second, he will begin to push it. Useful when you see rocks blocking cave entrances.\n"\ + "\n`wTrees:`` Some trees can be burned down with magic to reveal secrets.\n"\ + "\n`wQuick save/load:`` In addition to the full auto state save whenever you exit the game, and the normal save system, you can use `wQuick Save/Load`` from the pause menu. It's very useful to beat a tough boss.\n"\ + "\n`wSave Machines:`` Use Save Machines frequently and don't only rely on quick saves as they may sometimes put you in a difficult spot.\n"\ + "\n`wAuto Save:`` Your game is automatically saved every five minutes to save slot 10 as long as you have more than 30% health.\n"\ + "\n`wFPS Lock:`` If enabled, the game is limited to 30 frames per second. This should be enabled on slower devices for smoother gameplay.\n"\ + "\n`wHow to import saves from desktop (iOS 3.2+):`` Drag and drop a save.dat file in the Dink HD Documents file sharing area in iTunes. Import happens when the main menu is visited. Use save_.dat to import a save to an installed DMOD.\n"\ + + ; + } +} + +if (!IsDesktop()) +{ + + +msg += \ +"\n`wAdd-on warning:`` Depending on your device's speed and memory not all quest add-ons may be smoothly playable.\n"\ +"\n`wOutdated instructions warning:`` Sometimes quest add-ons will refer to controls not available, like pressing a specific key. Keep in mind most add-ons were developed for the Windows version of the game.\n"\ +"\n`wKeyboard:`` You can work around these issues by using the in-game keyboard option, available from the pause menu.\n"; +} + + Entity *pEnt = CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg); + y += pEnt->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + //some special links: + Entity *pButton; + + pButton = CreateTextButtonEntity(pParent, "email", iPhoneMapX(x), y, "Have a suggestion, bug report, or need help? Tap here to email us", true); + pButton->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + y += pButton->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + pButton = CreateTextButtonEntity(pParent, "list", iPhoneMapX(x), y, "Subscribe to the RTsoft Newsletter", true); + pButton->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + y += pButton->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + pButton = CreateTextButtonEntity(pParent, "twitter", iPhoneMapX(x), y, "Click here for the RTsoft twitter page", true); + pButton->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + y += pButton->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + pButton = CreateTextButtonEntity(pParent, "forums", iPhoneMapX(x), y, "Visit the official RTsoft Dink Forums", true); + pButton->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + y += pButton->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + + if (GetApp()->CanDownloadDMODS()) + { + + pButton = CreateTextButtonEntity(pParent, "dinknetwork", iPhoneMapX(x), y, "Want to download/make DMODs? Tap here to visit the Dink Network", true); + pButton->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + y += pButton->GetVar("size2d")->GetVector2().y; + y += ySpacer; + } + + + "\nFound a bug or have a question? Email us at `wsupport@rtsoft.com``.\n"\ + "\nCheck out our other wacky games:\n"; + + vTextBoxPos = CL_Vec2f(iPhoneMapX(x),y); + msg = "\nIf you like Dink, please check out our other games:\n"; + pEnt = CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg); + y += pEnt->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + + if (!IsLargeScreen()) + { + blurbSpacingY = iPhoneMapX(95); //for whatever reason we need more on the small iphone screen + } + + AddBlurb(pParent, x, y, "mindwall_ad", "`wMind Wall```8 is a unique 3D arcade puzzler that is instantly understood, beautifully simple to control, and diabolically difficult to master."); + y += iPhoneMapY(blurbSpacingY); + y += ySpacer; + + AddBlurb(pParent, x, y, "ds_ad", "`wDungeon Scroll```8 - If a word game and a dungeon crawler had a baby, this would be it. Arrange tiles to create magic words and blast rats, spiders and skeletons. But beware, a great evil looms beneath the depths."); + y += iPhoneMapY(blurbSpacingY); + y += ySpacer; + + if (IsDesktop()) + { + string adText = "`wDink Smallwood HD for iOS```8 - Love Dink? Then get it on your iPhone and iPad!"; + + if (GetEmulatedPlatformID() == PLATFORM_ID_WINDOWS) + { + adText = "`wDink Smallwood HD for mobile```8 - Love Dink? Then get it for your iPhone, iPad, or Android device!"; + } + AddBlurb(pParent, x, y, "dink_ad", adText); + y += iPhoneMapY(blurbSpacingY); + y += ySpacer; + } + + + + //credits: + + pTitle = CreateTextLabelEntity(pParent, "Title", x, y, "Credits"); + SetupTextEntity(pTitle, FONT_LARGE); + y += pTitle->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + vTextBoxPos = CL_Vec2f(iPhoneMapX(x),y); + + msg = "`8`$Dink Smallwood HD`` was created by `wSeth A. Robinson`` (code) and `wJustin Martin`` (graphics).\n\n"\ + "`8The original `$Dink Smallwood`` was created by `wSeth A. Robinson`` (engine/scripting/music), `wJustin Martin`` (graphics), `wGreg Smith`` (scripting/music), and `wShawn Teal``. It also featured music by `wJoel Bakker``."\ + "\n\nSpecial thanks to `wDan Walma`` and the `wdinksmallwood.net`` community for their `$Dink`` improvements."\ + "\n\n"\ + "This product is less buggy thanks to:\n\n`w"\ + "Shawn Teal\n"\ + "Myra Russell\n"\ + "David Stathis\n"\ + "Steve Gargolinski\n"\ + "Linus Lindberg\n"\ + "Phil Hassey\n"\ + "Kyle/Ragura\n"\ + "John H. Anthony\n"\ + "L McMillan\n"\ + "scratcher\n"\ + "Skull\n"\ + "Yeoldetoast\n"\ + "metatarasal\n"\ + "Sparrowhawk\n"\ + "ToKu\n"\ + "synbi\n"\ + "Impact\n"\ + "Andrew Perry\n"\ + "Rob, Marcus, Davor\n"\ + "Brett Profitt\n"\ + "Chris Black\n"\ + "Erik Harrison\n"\ + "James Hutt\n"; + + if (GetEmulatedPlatformID() == PLATFORM_ID_WINDOWS || GetEmulatedPlatformID() == PLATFORM_ID_IOS) + { + + msg += "`8\nFMOD Sound System, copyright (c) Firelight Technologies Pty, Ltd., 1994-2010."; + } + + + pEnt = CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg); + y += pEnt->GetVar("size2d")->GetVector2().y; + y += ySpacer; + + + //ads +/* + Entity *pLogo; + if (IsLargeScreen()) + { + pLogo = CreateOverlayButtonEntity(pParent, "logo", "interface/logo_88_88.rttex", x, y); + } else + { + pLogo = CreateOverlayButtonEntity(pParent, "logo", "interface/rtsoft_logo.rttex", x, y); + } + + pLogo->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + + y += iPhoneMapY(86); + + //add the dscroll ad + pLogo = CreateOverlayButtonEntity(pParent, "dscroll", "interface/ds_ad.rttex", x, y); + EntityRetinaRemapIfNeeded(pLogo, false, true, true); + pLogo->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + float textX = iPhoneMapX(170); + + //some text to go with the ad + Entity * pTextEnt = CreateTextLabelEntity(pParent, "text", textX-20, y, "Do you like word games and\nkilling things? Then tap the\n"\ + "icon on the left to check out\nDungeon Scroll for iPhone!"); + SetupTextEntity(pTextEnt, FONT_SMALL, 0.8f); + + y += iPhoneMapY(120); + + //add the blip ad + pLogo = CreateOverlayButtonEntity(pParent, "blip", "interface/ba_ad.rttex", x, y); + EntityRetinaRemapIfNeeded(pLogo, false, true, true); + pLogo->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + + //some text to go with the ad + pTextEnt = CreateTextLabelEntity(pParent, "text", textX-20, y, "Three player on one iPhone\nis now possible! Tap the icon\nto see Blip Arcade!"); + SetupTextEntity(pTextEnt, FONT_SMALL, 0.8f); + + y += iPhoneMapY(120); + +*/ + + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); +} + +Entity * AboutMenuCreate( Entity *pParentEnt) +{ + + Entity *pBG = NULL; + pBG = CreateOverlayEntity(pParentEnt, "AboutMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + + pBG->SetName("AboutMenu"); + AddFocusIfNeeded(pBG, true, 500); + pBG->AddComponent(new FocusRenderComponent); + + //add the header + + CL_Vec2f vTextAreaPos = iPhoneMap(2,10); + float offsetFromBottom = iPhoneMapY(42); + float offsetFromRight = iPhoneMapY(0); + + CL_Vec2f vTextAreaBounds = (GetScreenSize()- CL_Vec2f(offsetFromRight,offsetFromBottom))-vTextAreaPos; + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("pos2d")->Set(vTextAreaPos); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + //pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + /* + //too slow/broken on Android, we'll do it another way + EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + */ + + Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + + AboutMenuAddScrollContent(pBG); + // ZoomFromPositionEntity(pBG, CL_Vec2f(0, -GetScreenSizeYf()), 500); + //the continue button + Entity *pEnt; + + //pEnt = CreateOverlayRectEntity(pBG, CL_Rectf(0, GetScreenSizeYf()-offsetFromBottom, GetScreenSizeXf(), 320), MAKE_RGBA(0,0,0,100)); + + eFont fontID = FONT_SMALL; + + pEnt = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(5), iPhoneMapY(BACK_BUTTON_Y), "Back", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&AboutMenuOnSelect); + SetupTextEntity(pEnt, fontID); + AddHotKeyToButton(pEnt, VIRTUAL_KEY_BACK); + + SlideScreen(pBG, true, 500); + +// pBG->GetFunction("OnPostIntroTransition")->sig_function.connect(&OnPostIntroTransition); +// GetMessageManager()->CallEntityFunction(pBG, 1000, "OnPostIntroTransition", &VariantList(pBG, string(""))); + + + return pBG; +} \ No newline at end of file diff --git a/source/GUI/AboutMenu.h b/source/GUI/AboutMenu.h new file mode 100644 index 0000000..b36c80a --- /dev/null +++ b/source/GUI/AboutMenu.h @@ -0,0 +1,7 @@ +#ifndef AboutMenu_h__ +#define AboutMenu_h__ +#include "BaseApp.h" +Entity * AboutMenuCreate(Entity *pParentEnt); + + +#endif // AboutMenu_h__ \ No newline at end of file diff --git a/source/GUI/BrowseMenu.cpp b/source/GUI/BrowseMenu.cpp new file mode 100644 index 0000000..e8adf5d --- /dev/null +++ b/source/GUI/BrowseMenu.cpp @@ -0,0 +1,369 @@ +#include "PlatformPrecomp.h" +#include "BrowseMenu.h" +#include "MainMenu.h" +#include "DMODInstallMenu.h" +#include "GameMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "PopUpMenu.h" +#include "util/TextScanner.h" +#include "EnterURLMenu.h" +#include "Renderer/SoftSurface.h" +#include "QuickTipMenu.h" +#include "DMODMenu.h" +#include "Network/NetHTTP.h" +#include "Entity/HTTPComponent.h" + + +struct DMODEntry +{ + string m_name; + string m_url; + string m_author; + float m_size; + float m_rating; + string m_description; + uint32 m_date; + float m_version; +}; + +void BrowseMenuAddScrollContent(Entity *pParent, TextScanner &t); +Entity * ShowScoreMessage(Entity *pMenu, string msg); + +void BrowseMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + Entity *pMenu = GetEntityRoot()->GetEntityByName("BrowseMenu"); + + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[0].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + DMODMenuCreate(pEntClicked->GetParent()->GetParent(), true); + return; + } + + //they must have clicked on a DMOD if they got this far + if (pEntClicked->GetName() == "install") + { + //save position of the scroll bar first + EntityComponent *pScrollerComp = pMenu->GetEntityByName("scroll")->GetComponentByName("Scroll"); + //GetApp()->GetVar("DMODProgress2d")->Set(pScrollerComp->GetVar("progress2d")->GetVector2()); + + string dmodurl = pEntClicked->GetParent()->GetVar("dmodurl")->GetString(); + string dmodName = pEntClicked->GetParent()->GetVar("dmodtitle")->GetString(); + + SendFakeInputMessageToEntity(GetEntityRoot(), MESSAGE_TYPE_GUI_CLICK_END, pVList->m_variant[0].GetVector2()); //otherwise the menu may never get the touch release message + + DisableAllButtonsEntity(pMenu); + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + DMODInstallMenuCreate(pEntClicked->GetParent()->GetParent()->GetParent()->GetParent()->GetParent(), dmodurl, GetDMODRootPath() , "", true, dmodName); + + } + + /* + if (pEntClicked->GetName() == "rtsoft") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Leave the game and visit `wrtsoft.com``?", "http://www.rtsoft.com/iphone", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + */ + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +string VersionToString(float v) +{ + char tmp[32]; + sprintf(tmp, "%.2f", v); + if (tmp[3] == '0') + { + //cut off this, not needed + tmp[3] = 0; + } + + return string(tmp); + +} +void AddEntryBar(Entity *pParent, float &x, float &y, DMODEntry &s, int count) +{ + Entity *pBG = CreateOverlayEntity(pParent, s.m_name, ReplaceWithLargeInFileName("interface/iphone/browse_dmod_bar.rttex"),x, y); + + y += pBG->GetVar("size2d")->GetVector2().y; + + pBG->GetVar("dmodurl")->Set(s.m_url); //save for later + pBG->GetVar("dmodtitle")->Set(s.m_name); //save for later + //title + char stTemp[512]; + sprintf(stTemp, "`6%s ``V%s`6%s - ``%.2f mb``", s.m_name.c_str(), VersionToString(s.m_version).c_str(), s.m_author.c_str(), s.m_size); + Entity *pTitle = CreateTextLabelEntity(pBG, "title", iPhoneMapX2X( 16) ,iPhoneMapY2X( 13), stTemp); + Entity *pDescription = CreateTextBoxEntity(pBG, "descrip", iPhoneMap2X(16, 34), iPhoneMap2X(425, 54), "`6"+s.m_description); + + //Entity *pIcon = CreateButtonHotspot(pBG, "icon_hotspot", GetDMODBarIconOffset(), GetDMODBarIconSize(), Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_IGNORE_DRAGGING); + //SetTouchPaddingEntity(pIcon, CL_Rectf(0,iPhoneMapY2X(5),0,iPhoneMapY2X(5))); + //pIcon->GetFunction("OnButtonSelected")->sig_function.connect(&BrowseMenuOnSelect); + + //processing the icon image might be slow, lets do it a bit later, sequencing the timing by using the y, which should be going up + + //the delete icon part + { + CL_Vec2f iconPos = iPhoneMap2X(379,10); + //CL_Vec2f iconSize = iPhoneMap2X(27, 27); + Entity *pIcon = CreateOverlayButtonEntity(pBG, "install", ReplaceWithLargeInFileName("interface/iphone/browse_install.rttex"), iconPos.x, iconPos.y); + SetButtonStyleEntity(pIcon, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_IGNORE_DRAGGING); + SetTouchPaddingEntity(pIcon, CL_Rectf(0,0,0,0)); + pIcon->GetFunction("OnButtonSelected")->sig_function.connect(&BrowseMenuOnSelect); + } + + //add animation effect + ZoomToPositionFromThisOffsetEntity(pBG, CL_Vec2f(GetScreenSizeXf(), 0), 500, INTERPOLATE_EASE_TO, 10); +} + + +void BrowseMenuAddScrollContent(Entity *pParent, TextScanner &t) +{ + pParent = pParent->GetEntityByName("scroll_child"); + + pParent->RemoveAllEntities(); + float x = iPhoneMapX(5); + float y = 0; + + //Entity *pEnt; + + int dmodsAdded = 0; + + string msg = t.GetMultipleLineStrings("msg", "|"); + vector p = StringTokenize(msg, "|"); + + if (p.size() == 2 && p[1].length() > 1) + { + + StringReplace("", "\n", p[1]); + //add a message we just downloaded + CL_Vec2f vTextBoxPos(x+iPhoneMapX(5),y); + CL_Vec2f vTextBounds(iPhoneMapX(434), iPhoneMapY(200)); + Entity *pEnt = CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, p[1]); + y += pEnt->GetVar("size2d")->GetVector2().y; + y += iPhoneMapY(5); + + } + + string line; + while ( string(line = t.GetMultipleLineStrings("add", "|")).length() > 0) + { + //LogMsg(line.c_str()); + vector p = StringTokenize(line, "|"); + + if (p.size() < 7) + { + continue; + } + DMODEntry s; + s.m_name = p[1]; + s.m_url = p[2]; + s.m_author = p[3]; + s.m_size = atof(p[4].c_str()); + s.m_rating = atof(p[5].c_str()); + s.m_description = p[6]; + s.m_version = atof(p[7].c_str()); + +// s.m_date = atol(p[5].c_str()); + + //m_onlineScores.push_back(s); + AddEntryBar(pParent, x, y,s, dmodsAdded); + dmodsAdded++; + y += iPhoneMapY(5); + + } + + + + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); + DisableHorizontalScrolling(pParent->GetParent()); + +} + + + +void OnDownloadError(VariantList *pVList) +{ + NetHTTP::eError e = (NetHTTP::eError)pVList->m_variant[1].GetUINT32(); + + string msg = "`4Unable to connect. Try later. ("+toString(e)+")"; + if (e == NetHTTP::ERROR_COMMUNICATION_TIMEOUT) + { + msg = "`4Connection timed out. Try Later."; + } + + ShowScoreMessage(pVList->m_variant[0].GetComponent()->GetParent(), msg); +} + + +Entity * ShowScoreMessage(Entity *pMenu, string msg) +{ + Entity *pInfo = pMenu->GetEntityByName("Info"); + if (pInfo) + { + pInfo->GetComponentByName("TextRender")->GetVar("text")->Set(msg); + pInfo->RemoveComponentByName("Typer"); // a thing that types stuff + } else + { + pInfo = CreateTextLabelEntity(pMenu, "Info", iPhoneMapX(130), iPhoneMapY(220), msg); + } + + return pInfo; +} + + +void OnDownloadHTTPFinish(VariantList *pVList) +{ + Entity *pMenu = pVList->m_variant[0].GetComponent()->GetParent(); + + TextScanner t((char*)pVList->m_variant[1].GetString().c_str()); + string line; + + // ShowScoreMessage(pMenu, t.GetParmString("msg",1)); + ShowScoreMessage(pMenu, ""); + //GetApp()->GetVar("score_msg")->Set(t.GetParmString("msg",1)); + + //GetHighScoreManager()->SetupOnlineScores(t); + //GetApp()->GetVar("cur_score")->Set(uint32(0)); //reset score drawing + //ScoresAddStuffToScroll(NULL); + BrowseMenuAddScrollContent(pMenu, t); + + // AddHighScores(pMenu, -1); +} + + +void DownloadDMODList(Entity *pMenu) +{ + pMenu->RemoveComponentByName("HTTP"); //just in case it already exists + + //get the internet stuff going + EntityComponent *pComp = pMenu->AddComponent(new HTTPComponent); + + VariantList vPostData; + + vPostData.m_variant[0].Set("version"); + vPostData.m_variant[1].Set(toString(GetApp()->GetVersion())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + vPostData.m_variant[0].Set("build"); + vPostData.m_variant[1].Set(toString(GetApp()->GetBuild())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + vPostData.m_variant[0].Set("platform"); + vPostData.m_variant[1].Set(toString(GetEmulatedPlatformID())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + VariantList v; + + string url; + uint32 port; + GetApp()->GetServerInfo(url, port); + + v.m_variant[0].Set(url); + v.m_variant[1].Set(port); + v.m_variant[2].Set("dink/getaddons.php"); + pComp->GetFunction("Init")->sig_function(&v); + pComp->GetFunction("OnError")->sig_function.connect(&OnDownloadError); + pComp->GetFunction("OnFinish")->sig_function.connect(&OnDownloadHTTPFinish); + + Entity *pEnt = ShowScoreMessage(pMenu, "`6"); + EntityComponent *pTyper = pEnt->AddComponent(new TyperComponent); + pTyper->GetVar("text")->Set("Downloading add-on list..."); + pTyper->GetVar("speedMS")->Set(uint32(50)); + //KillScores(); + +} + +void BrowseOnPostIntroTransition(VariantList *pVList) +{ + + Entity *pBG = pVList->Get(0).GetEntity(); + + DownloadDMODList(pBG); + + //CreateQuickTipFirstTimeOnly(pBG, "interface/iphone/quicktip_dmod.rttex", false); +} + +Entity * BrowseMenuCreate( Entity *pParentEnt ) +{ + //GetMessageManager()->SendGame(MESSAGE_TYPE_PLAY_MUSIC, "audio/title.mp3", 200); + GetBaseApp()->ClearError(); + + Entity *pBG = NULL; + + if (IsLargeScreen()) + { + pBG = CreateOverlayEntity(pParentEnt, "BrowseMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + + } else + { + //pBG = CreateOverlayEntity(pParentEnt, "BrowseMenu", "interface/iphone/dmod_bg.rttex", 0,0); + pBG = CreateOverlayEntity(pParentEnt, "BrowseMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + } + + pBG->SetName("BrowseMenu"); + AddFocusIfNeeded(pBG, true, 500); + pBG->AddComponent(new FocusRenderComponent); + + CL_Vec2f vTextAreaPos = iPhoneMap(2,10); + float offsetFromBottom = iPhoneMapY(42); + float offsetFromRight = iPhoneMapY(0); + + CL_Vec2f vTextAreaBounds = (GetScreenSize()- CL_Vec2f(offsetFromRight,offsetFromBottom))-vTextAreaPos; + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("pos2d")->Set(vTextAreaPos); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + /* + Entity *pLabel = CreateTextLabelEntity(pBG, "scanning", GetScreenSizeXf()/2, GetScreenSizeYf()/2, "Updating add-on browse list..."); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); + FadeOutAndKillEntity(pLabel, true, 300, 501); + + */ + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + //pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + //EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + //pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + + Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + + // ZoomFromPositionEntity(pBG, CL_Vec2f(0, -GetScreenSizeYf()), 500); + //the continue button + Entity *pEnt; + + //pEnt = CreateOverlayRectEntity(pBG, CL_Rectf(0, GetScreenSizeYf()-offsetFromBottom, GetScreenSizeXf(), 320), MAKE_RGBA(0,0,0,100)); + + eFont fontID = FONT_SMALL; + + pEnt = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(25), iPhoneMapY(BACK_BUTTON_Y), "Back", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&BrowseMenuOnSelect); + SetupTextEntity(pEnt, fontID); + AddHotKeyToButton(pEnt, VIRTUAL_KEY_BACK); + + SlideScreen(pBG, true, 500); + pBG->GetFunction("OnPostIntroTransition")->sig_function.connect(&BrowseOnPostIntroTransition); + VariantList vList(pBG, string("")); + GetMessageManager()->CallEntityFunction(pBG, 500, "OnPostIntroTransition", &vList); + + return pBG; +} \ No newline at end of file diff --git a/source/GUI/BrowseMenu.h b/source/GUI/BrowseMenu.h new file mode 100644 index 0000000..b2024f6 --- /dev/null +++ b/source/GUI/BrowseMenu.h @@ -0,0 +1,7 @@ +#ifndef BrowseMenu_h__ +#define BrowseMenu_h__ +#include "BaseApp.h" +Entity * BrowseMenuCreate(Entity *pParentEnt); + + +#endif // BrowseMenu_h__ \ No newline at end of file diff --git a/source/GUI/DMODInstallMenu.cpp b/source/GUI/DMODInstallMenu.cpp new file mode 100644 index 0000000..58f45e1 --- /dev/null +++ b/source/GUI/DMODInstallMenu.cpp @@ -0,0 +1,348 @@ +#include "PlatformPrecomp.h" +#include "DMODInstallMenu.h" +#include "Entity/EntityUtils.h" +#include "DMODMenu.h" +#include "dink/dink.h" +#include "GameMenu.h" +#include "Entity/UnpackArchiveComponent.h" +#include "Network/NetUtils.h" +#include "MainMenu.h" +#include "BrowseMenu.h" +#include "Network/NetHTTP.h" +#include "Entity/HTTPComponent.h" + + +void DMODInstallMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + Entity *pMenu = pEntClicked->GetParent(); + + LogMsg("Clicked %s entity", pEntClicked->GetName().c_str()); + + if (pEntClicked->GetName() == "Back") + { + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + if (pMenu->GetVar("exitto")->GetString() == "main") + { + MainMenuCreate(pMenu->GetParent()); + } else if (pMenu->GetVar("exitto")->GetString() == "browse") + { + BrowseMenuCreate(pEntClicked->GetParent()->GetParent()); + + } else if (pMenu->GetVar("exitto")->GetString() == "play") + { + + InitDinkPaths(GetBaseAppPath(), "dink", pMenu->GetVar("dmoddir")->GetString()); + + GameCreate(pMenu->GetParent(), 0, ""); + } else + { + DMODMenuCreate(pEntClicked->GetParent()->GetParent()); + } + + } + + GetEntityRoot()->PrintTreeAsText(); //useful for Loading +} + +void DMODInstallUpdateStatus(Entity *pMenu, string msg) +{ + if (!pMenu) + { + pMenu = GetEntityRoot()->GetEntityByName("DMODInstall"); + } + + Entity *pStatus = pMenu->GetEntityByName("status"); + if (pStatus) + { + pStatus->GetComponentByName("TextRender")->GetVar("text")->Set(msg); + } + +} + +void DMODInstallShowMsg(Entity *pMenu, string myMsg, bool bSuccess = false) +{ + Entity *pMsg = pMenu->GetEntityByName("status"); + + Entity *pLabel = pMenu->GetEntityByName("title_label"); + if (pLabel) + { + pLabel->RemoveComponentByName("Typer"); // a thing that types stuff + + if (!bSuccess) + { + pLabel->GetComponentByName("TextRender")->GetVar("text")->Set("Error!"); + } else + { + pLabel->GetComponentByName("TextRender")->GetVar("text")->Set("Success!"); + } + } + if (pMsg) + { + pMsg->RemoveComponentByName("Typer"); // a thing that types stuff + pMsg->GetComponentByName("TextRender")->GetVar("text")->Set(myMsg); + } + + Entity *pSkip = pMenu->GetEntityByName("Back"); + + if (pSkip) + { + pSkip->GetComponentByName("TextRender")->GetVar("text")->Set("`wContinue"); + } + +} + +void DMODSetTitleLabel(Entity *pMenu, string myMsg) +{ + + Entity *pLabel = pMenu->GetEntityByName("title_label"); + if (pLabel) + { + //pLabel->RemoveComponentByName("Typer"); // a thing that types stuff + + pLabel->GetComponentByName("TextRender")->GetVar("text")->Set(myMsg); + + } + + +} + +void DMODInstallOnError(VariantList *pVList) +{ + NetHTTP::eError e = (NetHTTP::eError)pVList->m_variant[1].GetUINT32(); + + string msg = "`4Unable to connect to the\nnetwork.``\nPlease try again later."; + + switch (e) + { + + case NetHTTP::ERROR_COMMUNICATION_TIMEOUT: + msg = "`4Connection timed out. Try Later?"; + break; + + case NetHTTP::ERROR_CANT_RESOLVE_URL: + msg = "`4Can't find website. Bad url?"; + break; + + case NetHTTP::ERROR_WRITING_FILE: + msg = "`4Error writing file. Out of space?"; + break; + + case NetHTTP::ERROR_404_FILE_NOT_FOUND: + msg = "`4Server gave a 404: File not found. Bad url?"; + break; + } + + + DMODInstallShowMsg(pVList->m_variant[0].GetComponent()->GetParent(), msg); +} + + +void DMODUnpackOnError(VariantList *pVList) +{ + int error = pVList->m_variant[1].GetUINT32(); + + string msg = "`4Error "+toString(error)+" unpacking. Out of space or malformed .dmod file?"; + + DMODInstallShowMsg(pVList->m_variant[0].GetComponent()->GetParent(), msg); +} + +void DMODInstallSetProgressBar(float progress) +{ + Entity *pBar = GetEntityRoot()->GetEntityByName("bar"); + + if (pBar) + { + pBar->GetComponentByName("ProgressBar")->GetVar("progress")->Set(progress); + } +} + + +void OnDMODUnpackStatusUpdate(VariantList *pVList) +{ + int curBytes = pVList->Get(1).GetUINT32(); + int totalBytes = pVList->Get(2).GetUINT32(); + + int barSize = 1024*1024*5; //5 megs of unpacking will fill up one bar + float progress = float( (curBytes%barSize)) /float(barSize); + + //LogMsg("prog: %.2f", progress); + DMODInstallUpdateStatus(NULL, "Writing "+toString(curBytes/1024)+"K"); + DMODInstallSetProgressBar(progress); +} + +void OnDMODUnpackFinish(VariantList *pVList) +{ + Entity *pMenu = pVList->m_variant[0].GetComponent()->GetParent(); + + DMODInstallSetProgressBar(1); + DMODInstallShowMsg(pMenu, pMenu->GetVar("originalFileName")->GetString()+" installed. Tap continue.", true); + + RemoveFile(GetDMODRootPath()+"temp.dmod"); + RemoveFile("temp.dmod"); + + if (pMenu->GetVar("autoplay")->GetUINT32() == 1) + { + pMenu->GetVar("exitto")->Set("play"); + pMenu->GetVar("dmoddir")->Set(GetDMODRootPath()+ pVList->m_variant[0].GetComponent()->GetVar("firstDirCreated")->GetString()); + + } +} + +void OnDMODInstallHTTPFinish(VariantList *pVList) +{ + Entity *pMenu = pVList->m_variant[0].GetComponent()->GetParent(); + +#ifdef _DEBUG + LogMsg("Finish signal received"); +#endif + + DMODSetTitleLabel(pMenu, string("Installing ")+pMenu->GetVar("originalFileName")->GetString()+"..."); + EntityComponent *pUnpack = pMenu->AddComponent(new UnpackArchiveComponent); + pUnpack->GetVar("sourceFileName")->Set(pMenu->GetVar("tempFileName")->GetString()); + + pUnpack->GetVar("deleteSourceOnFinish")->Set(uint32(1)); + + pUnpack->GetVar("destDirectory")->Set(pMenu->GetVar("installDirectory")->GetString()); + DMODInstallSetProgressBar(0); + + pUnpack->GetFunction("OnError")->sig_function.connect(&DMODUnpackOnError); + pUnpack->GetFunction("OnFinish")->sig_function.connect(&OnDMODUnpackFinish); + pUnpack->GetFunction("OnStatusUpdate")->sig_function.connect(&OnDMODUnpackStatusUpdate); + +} + +void OnDMODInstallStatusUpdate(VariantList *pVList) +{ + int curBytes = pVList->Get(1).GetUINT32(); + int totalBytes = pVList->Get(2).GetUINT32(); + + if (totalBytes == 0) + { + DMODInstallUpdateStatus(NULL, "Network active, getting file data..."); + } else + { + DMODInstallUpdateStatus(NULL, ""+toString(curBytes/1024)+"K/"+toString(totalBytes/1024)+"K"); + } + + //also update the progress bar thingie + if (totalBytes == 0) totalBytes = 1; //avoid /1 error + DMODInstallSetProgressBar(float(curBytes)/float(totalBytes)); +} + +void InitNetStuff(VariantList *pVList) +{ + Entity *pMenu = pVList->m_variant[0].GetEntity(); + //get the internet stuff going + EntityComponent *pComp = pMenu->AddComponent(new HTTPComponent); + + string url = pMenu->GetVar("dmodURL")->GetString(); + string tempFileName = pMenu->GetVar("tempFileName")->GetString(); + + string domain; + string request; + int port = 80; + + BreakDownURLIntoPieces(url, domain, request, port); + VariantList v; + v.m_variant[0].Set(tempFileName); + pComp->GetFunction("SetFileOutput")->sig_function(&v); + + v.Reset(); + + v.m_variant[0].Set(domain); + v.m_variant[1].Set(uint32(port)); + v.m_variant[2].Set(request); + pComp->GetFunction("Init")->sig_function(&v); + + pComp->GetFunction("OnError")->sig_function.connect(&DMODInstallOnError); + pComp->GetFunction("OnFinish")->sig_function.connect(&OnDMODInstallHTTPFinish); + pComp->GetFunction("OnStatusUpdate")->sig_function.connect(&OnDMODInstallStatusUpdate); +} + + +Entity * DMODInstallMenuCreate(Entity *pParentEnt, string dmodURL, string installDirectory, string sourceFileName, bool bFromBrowseMenu, string dmodName) +{ + Entity *pBG = CreateOverlayEntity(pParentEnt, "DMODInstall", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + AddFocusIfNeeded(pBG, true); + + Entity *pButtonEntity; + float x = GetScreenSizeXf()/2; + float yStart = iPhoneMapY(230); + float y = yStart; + float ySpacer = iPhoneMapY(50); + Entity *pProgressBar = pBG->AddEntity(new Entity("bar")); + Entity *pTitleLabel = CreateTextLabelEntity(pBG, "title_label", iPhoneMapX(100), iPhoneMapY(80), "Please wait"); + + //save these for later + pBG->GetVar("dmodURL")->Set(dmodURL); + pBG->GetVar("dmodName")->Set(dmodName); + pBG->GetVar("installDirectory")->Set(installDirectory); + pBG->GetVar("tempFileName")->Set(GetDMODRootPath()+"temp.dmod"); + pBG->GetVar("originalFileName")->Set(GetFileNameFromString(dmodURL)); + pBG->GetVar("fromBrowseMenu")->Set(uint32(bFromBrowseMenu)); + + if (IsLargeScreen()) + { + //SetupTextEntity(pTitleLabel, FONT_LARGE); + } + //SetAlignmentEntity(pTitleLabel, ALIGNMENT_CENTER); + + EntityComponent *pTyper = pTitleLabel->AddComponent(new TyperComponent); + pTyper->GetVar("text")->Set("......."); + pTyper->GetVar("speedMS")->Set(uint32(500)); + + EntityComponent *pBar = pProgressBar->AddComponent(new ProgressBarComponent); + pProgressBar->GetVar("pos2d")->Set(CL_Vec2f(iPhoneMapX(80),iPhoneMapY(120))); + pProgressBar->GetVar("size2d")->Set(CL_Vec2f(iPhoneMapX(310),iPhoneMapY(15))); + pProgressBar->GetVar("color")->Set(MAKE_RGBA(200,200,0,60)); + pBar->GetVar("interpolationTimeMS")->Set(uint32(1)); //update faster + pBar->GetVar("borderColor")->Set(MAKE_RGBA(200,200,0,180)); + + pButtonEntity = CreateTextButtonEntity(pBG, "Back", x, y, "Cancel"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DMODInstallMenuOnSelect); + SetAlignmentEntity(pButtonEntity, ALIGNMENT_CENTER); + AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + + Entity *pStatus = CreateTextLabelEntity(pBG, "status", x, iPhoneMapY(180), "Initializing..."); + SetAlignmentEntity(pStatus, ALIGNMENT_CENTER); + + if (bFromBrowseMenu) + { + Entity *pStatus = CreateTextLabelEntity(pBG, "title", x, iPhoneMapY(30), "-= Installing "+dmodName+" =-"); + + SetAlignmentEntity(pStatus, ALIGNMENT_CENTER); + pBG->GetVar("exitto")->Set("browse"); + + } + + if (!sourceFileName.empty()) + { + //don't download, we already have the file + pBG->GetVar("tempFileName")->Set(sourceFileName); + pBG->GetVar("originalFileName")->Set(GetFileNameFromString(sourceFileName)); + + EntityComponent *pCrapComp = pBG->AddComponent(new EntityComponent("CRAP")); //I don't need this, but the function want a component and gets the parent for the menu, so fine + pBG->GetVar("exitto")->Set("main"); + + //start the install in 500 ms, so we don't lag out the screen transition + pBG->GetFunction("StartInstall")->sig_function.connect(&OnDMODInstallHTTPFinish); + VariantList vList(pCrapComp); + GetMessageManager()->CallEntityFunction(pBG, 500, "StartInstall", &vList); + pStatus->GetVar("text")->Set("New .dmod file detected"); + } else + { + pBG->GetVar("autoplay")->Set(uint32(1)); + + pBG->GetFunction("InitNetStuff")->sig_function.connect(&InitNetStuff); + VariantList vList(pBG); + GetMessageManager()->CallEntityFunction(pBG, 500, "InitNetStuff", &vList); + } + + + SlideScreen(pBG, true, 500); + return pBG; +} + diff --git a/source/GUI/DMODInstallMenu.h b/source/GUI/DMODInstallMenu.h new file mode 100644 index 0000000..aaf7c2d --- /dev/null +++ b/source/GUI/DMODInstallMenu.h @@ -0,0 +1,7 @@ +#ifndef DMODInstallMenu_h__ +#define DMODInstallMenu_h__ + +#include "App.h" + +Entity * DMODInstallMenuCreate(Entity *pParentEnt, string dmodURL, string installDirectory, string sourceFileName = "", bool bFromBrowseMenu = false, string dmodName = ""); +#endif // DMODInstallMenu_h__ \ No newline at end of file diff --git a/source/GUI/DMODMenu.cpp b/source/GUI/DMODMenu.cpp new file mode 100644 index 0000000..8e06c39 --- /dev/null +++ b/source/GUI/DMODMenu.cpp @@ -0,0 +1,605 @@ +#include "PlatformPrecomp.h" +#include "DMODMenu.h" +#include "MainMenu.h" +#include "DMODInstallMenu.h" +#include "GameMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "PopUpMenu.h" +#include "util/TextScanner.h" +#include "EnterURLMenu.h" +#include "Renderer/SoftSurface.h" +#include "QuickTipMenu.h" +#include "BrowseMenu.h" +#include "ReadTextMenu.h" + +void DMODMenuAddScrollContent(Entity *pParent); + +void DMODMenuOnRemoveDMOD(VariantList *pVList) +{ + Entity *pMenu = pVList->Get(0).GetEntity(); + + string dmodDirToDelete = pMenu->GetVar("dmodDirToDelete")->GetString(); + + if (!dmodDirToDelete.empty()) + { + RemoveDirectoryRecursively(dmodDirToDelete); + DMODMenuAddScrollContent(pMenu); + } + LogMsg("Removing DMOD"); +} + +void DMODMenuOnSessionNew(VariantList *pVList) +{ + Entity *pMenu = pVList->Get(0).GetEntity(); + + DisableAllButtonsEntity(pMenu); + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + GameCreate(pMenu->GetParent(), 0, ""); +} + +void DMODMenuOnSessionContinue(VariantList *pVList) +{ + Entity *pMenu = pVList->Get(0).GetEntity(); + + DisableAllButtonsEntity(pMenu); + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + GameCreate(pMenu->GetParent(), 0, g_dglo.m_savePath+"continue_state.dat"); +} + +void DMODMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + Entity *pMenu = GetEntityRoot()->GetEntityByName("DMODMenu"); + + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[0].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + DisableAllButtonsEntity(pMenu); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + MainMenuCreate(pEntClicked->GetParent()->GetParent()); + return; + } + + if (pEntClicked->GetName() == "getmore") + { + DisableAllButtonsEntity(pMenu); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + EnterURLMenuCreate(pEntClicked->GetParent()->GetParent()); + return; + } + + if (pEntClicked->GetName() == "browse") + { + DisableAllButtonsEntity(pMenu); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + BrowseMenuCreate(pEntClicked->GetParent()->GetParent()); + return; + } + + //they must have clicked on a DMOD if they got this far + if (pEntClicked->GetName() == "icon_hotspot") + { + //save position of the scroll bar first + + string dmoddir = pEntClicked->GetParent()->GetVar("dmodgamedir")->GetString(); + + SendFakeInputMessageToEntity(GetEntityRoot(), MESSAGE_TYPE_GUI_CLICK_END, pVList->m_variant[0].GetVector2()); //otherwise the menu may never get the touch release message + + //first check to see if it's a valid dmod + + if (!FileExists(dmoddir+"/dmod.diz")) + { + //don't look valid.. + PopUpCreate(pMenu, "This add-on appears to be missing or damaged. Delete and re-install.", "", "cancel", "Continue", "", "", true); + return; + } + InitDinkPaths(GetBaseAppPath(), "dink", dmoddir); + + pMenu = GetEntityRoot()->GetEntityByName("DMODMenu"); + + //next, see if there is a save-on-quit save state existing for this dmod + if (FileExists(g_dglo.m_savePath+"/continue_state.dat")) + { + PopUpCreate(pMenu, "Continue your last playing session?", "", "cancel", "Abort", "SessionContinue", "Continue", true,"SessionNew", "No" ); + return; + } + + DisableAllButtonsEntity(pMenu); + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + GameCreate(pMenu->GetParent(), 0, ""); + } + + if (pEntClicked->GetName() == "delete_hotspot") + { + + EntityComponent *pScrollerComp = pMenu->GetEntityByName("scroll")->GetComponentByName("Scroll"); + GetApp()->GetVar("DMODProgress2d")->Set(pScrollerComp->GetVar("progress2d")->GetVector2()); + + string dmoddir = pEntClicked->GetParent()->GetVar("dmodgamedir")->GetString(); + string dmodtitle = pEntClicked->GetParent()->GetVar("dmodtitle")->GetString(); + SendFakeInputMessageToEntity(GetEntityRoot(), MESSAGE_TYPE_GUI_CLICK_END, pVList->m_variant[0].GetVector2()); //otherwise the menu may never get the touch release message + + if (!dmoddir.empty()) + { + Entity *pMenu = GetEntityRoot()->GetEntityByName("DMODMenu"); + pMenu->GetVar("dmodDirToDelete")->Set(dmoddir); + PopUpCreate(pMenu, "Remove "+dmodtitle+" and its saved games?", "", "cancel", "Cancel", "RemoveDMOD", "Remove", true); + } + } + + if (pEntClicked->GetName() == "view_info") + { + DisableAllButtonsEntity(pMenu); + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + string textfile = pEntClicked->GetParent()->GetVar("textfile")->GetString(); + ReadTextMenuCreate(pMenu->GetParent(), textfile, "file"); + } + +/* + if (pEntClicked->GetName() == "rtsoft") + { + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Leave the game and visit `wrtsoft.com``?", "http://www.rtsoft.com/iphone", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } +*/ + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + +CL_Vec2f GetDMODBarIconOffset() +{ + if (IsLargeScreen()) + { + return CL_Vec2f(44,20); //fix a slight offset problem + } + + return iPhoneMap2X(23,11); +} + +CL_Vec2f GetDMODBarIconSize() +{ + return iPhoneMap2X(99, 74); +} + +void DMODSetupExtra(VariantList *pVList) +{ + Entity *pBG = pVList->Get(0).GetEntity(); + + //locate the file + string dmodDir = pBG->GetVar("dmodgamedir")->GetString()+"/"; + string iconFile = dmodDir+"preview.bmp"; + + if (!FileExists(iconFile)) + { + //try again + iconFile = dmodDir+"graphics/title-01.bmp"; + + if (!FileExists(iconFile)) + { + iconFile = dmodDir+"graphics/title/title-01.bmp"; + } + } + + if (!FileExists(iconFile)) + { + //give up, nothing to show + return; + } + + SoftSurface s8bit; + if (!s8bit.LoadFile(iconFile, SoftSurface::COLOR_KEY_NONE, false)) + { + return; + } + + //if it was 8bit, this will convert it to 32 + + SoftSurface s; + s.Init(s8bit.GetWidth(),s8bit.GetHeight(), SoftSurface::SURFACE_RGBA); + s.Blit(0,0, &s8bit); + s.FlipY(); + + SurfaceAnim *pSurf; + + pSurf = new SurfaceAnim; + + pSurf->SetTextureType(Surface::TYPE_DEFAULT); //insure no mipmaps are created + pSurf->InitBlankSurface(s.GetWidth(),s.GetHeight()); + pSurf->UpdateSurfaceRect(rtRect(0,0, s.GetWidth(), s.GetHeight()), s.GetPixelData()); + + //add the icon + Entity *pEnt = CreateOverlayEntity(pBG, "icon", "", GetDMODBarIconOffset().x,GetDMODBarIconOffset().y); + OverlayRenderComponent *pOverlay = (OverlayRenderComponent*) pEnt->GetComponentByName("OverlayRender"); + pOverlay->SetSurface(pSurf, true); + + EntitySetScaleBySize(pEnt,GetDMODBarIconSize()); +} + + +void AddDMODBar(Entity *pParent, float &x, float &y, string title, string description, string iconFileName, float dmodSize, string dmodgamedir, int count) +{ + Entity *pBG = CreateOverlayEntity(pParent, dmodgamedir, ReplaceWithLargeInFileName("interface/iphone/dmod_bar.rttex"), iPhoneMapX(x), iPhoneMapY(y)); + + if (IsLargeScreen()) + { + y += pBG->GetVar("size2d")->GetVector2().y/2; + } else + { + y += pBG->GetVar("size2d")->GetVector2().y; + } + + pBG->GetVar("dmodgamedir")->Set(dmodgamedir); //save for later + pBG->GetVar("dmodtitle")->Set(title); //save for later + //title + Entity *pTitle = CreateTextLabelEntity(pBG, "title", iPhoneMapX2X( 130) ,iPhoneMapY2X( 10), title); + Entity *pDescription = CreateTextBoxEntity(pBG, "descrip", iPhoneMap2X(129, 33), iPhoneMap2X(277, 53), description, 0.7f); + + Entity *pIcon = CreateButtonHotspot(pBG, "icon_hotspot", GetDMODBarIconOffset(), GetDMODBarIconSize(), Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_IGNORE_DRAGGING); + SetTouchPaddingEntity(pIcon, CL_Rectf(0,iPhoneMapY2X(5),0,iPhoneMapY2X(5))); + pIcon->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); + + //processing the icon image might be slow, lets do it a bit later, sequencing the timing by using the y, which should be going up + pBG->GetFunction("SetupExtra")->sig_function.connect(&DMODSetupExtra); + VariantList vList(pBG); + GetMessageManager()->CallEntityFunction(pBG, 800+count*200, "SetupExtra", &vList); + + //the delete icon part +bool bCanDelete = true; + +if (!GetDMODStaticRootPath().empty()) +{ + if (GetPathFromString(dmodgamedir) == GetDMODStaticRootPath()) + { + //we better not let people delete this.. + bCanDelete = false; + } +} + +if (bCanDelete) +{ + CL_Vec2f iconPos = iPhoneMap2X(408,10); + //Entity *pIcon = CreateButtonHotspot(pBG, "delete_hotspot", iconPos, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_IGNORE_DRAGGING); + Entity *pIcon = CreateOverlayButtonEntity(pBG, "delete_hotspot", ReplaceWithLargeInFileName("interface/iphone/dmod_delete_button.rttex"), iconPos.x, iconPos.y); + SetTouchPaddingEntity(pIcon, CL_Rectf(0,0,0,0)); + pIcon->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); +} + //add an "info" icon? + + string dmodDir = dmodgamedir+"/"; + string infoFile = dmodDir+"readme.txt"; + + if (!FileExists(infoFile)) + { + infoFile = dmodDir+"read me please.txt"; + } + + if (!FileExists(infoFile)) + { + infoFile = dmodDir+"credits.txt"; + } + + if (!FileExists(infoFile)) + { + infoFile = dmodDir+"dmod.diz"; + } + + if (FileExists(infoFile)) + { + pBG->GetVar("textfile")->Set(infoFile); //save for later + + + CL_Vec2f iconPos = iPhoneMap2X(405,56); + Entity *pIcon = CreateOverlayButtonEntity(pBG, "view_info", ReplaceWithLargeInFileName("interface/iphone/dmod_info_button.rttex"), iconPos.x, iconPos.y); + SetButtonStyleEntity(pIcon, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_IGNORE_DRAGGING); + SetTouchPaddingEntity(pIcon, CL_Rectf(0,0,0,0)); + pIcon->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); + + + } + + + + //add animation effect + ZoomToPositionFromThisOffsetEntity(pBG, CL_Vec2f(GetScreenSizeXf(), 0), 500, INTERPOLATE_EASE_TO, 10); +} +void GetParsedDMODInfo(string dmodPath, string &nameOut, float versionOut, string ©right, string &dmodwebsite, string &description) +{ + + TextScanner t(dmodPath+"/dmod.diz", false); + + if (!t.IsLoaded()) + { + //error, unable to load DMOD diz + nameOut = GetFileNameFromString(dmodPath); + copyright = "No dmod.diz found. Corrupted?"; + versionOut = 0; + return; + } + + nameOut = t.GetLine(0); + + int maxNameChars = 39; + + if (nameOut.length() > maxNameChars) + { + TruncateString(nameOut, maxNameChars); + description += "..."; + } + description.clear(); + + for (int i=1; i < t.m_lines.size(); i++) + { + description += t.GetLine(i); + + if (i == 1) + { + description = TrimLeft(description); + } + if (description.length() > 400) + { + break; + } + + if (i < t.m_lines.size()-1 && description.size()>0) + { + description += " "; + } + + } + + int maxChars = 205; + + if (description.length() > maxChars) + { + TruncateString(description, maxChars); + description += "..."; + } +} + + +void DMODMenuAddScrollContent(Entity *pParent) +{ + pParent = pParent->GetEntityByName("scroll_child"); + + pParent->RemoveAllEntities(); + float x = 5; + float y = 0; + + //Entity *pEnt; + + vector temp = GetDirectoriesAtPath(GetDMODRootPath()); + vector files; + + //actually, you know what? Let's add the path to each one + for (int i=0; i < temp.size(); i++) + { + temp[i] = GetDMODRootPath()+temp[i]; + if (FileExists(temp[i]+"/dink.dat")) + { + //looks valid + files.push_back(temp[i]); + } + } + + if (!GetDMODStaticRootPath().empty()) + { + vector staticFiles = GetDirectoriesAtPath(GetDMODStaticRootPath()); + + for (int i=0; i < staticFiles.size(); i++) + { + //merge in if not a duplicate + for (int n=0; n < files.size(); n++) + { + if (GetFileNameFromString(files[n]) == staticFiles[i]) + { + //duplicate + continue; + } + + } + + files.push_back(GetDMODStaticRootPath()+staticFiles[i]); + + } + + } + + + + int dmodsAdded = 0; + + for (unsigned int i=0; i < files.size(); i++) + { +#ifdef WIN32 + + if ( IsInString(files[i], "/audio") || IsInString(files[i],"/dink" )|| IsInString(files[i] ,"/game") || IsInString(files[i],"/interface")) continue; + if (IsInString(files[i] ,"/develop") ) continue; +#else + if (IsInString(files[i],"/Snapshot") || IsInString(files[i], "/Snapshots")) continue; +#endif + string dmodName, dmodCopyright, dmodwebsite, description; + float version = 0; + + GetParsedDMODInfo(files[i], dmodName, version, dmodCopyright, dmodwebsite, description ); + AddDMODBar(pParent, x, y, dmodName, description, "", 20.3f, files[i], dmodsAdded); + dmodsAdded++; + } + + if (dmodsAdded == 0) + { + CL_Vec2f vTextBoxPos(iPhoneMapX(20),iPhoneMapY(y)); + CL_Vec2f vTextBounds(iPhoneMapX(434), iPhoneMapY(200)); + string msg = "`6No add-on stories are currently installed. Click ``Browse`6 below to get some."; + + if (!GetApp()->CanDownloadDMODS()) + { + //a better message would be: + msg = "`6No add-on stories are currently available."; + } + CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg); + } + + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); + DisableHorizontalScrolling(pParent->GetParent()); + +} + +void OnDMODMenuDelete(Entity *pMenu) +{ + if (IsBaseAppInitted()) + { + EntityComponent *pScrollerComp = pMenu->GetEntityByName("scroll")->GetComponentByName("Scroll"); + if (pScrollerComp) + { + GetApp()->GetVar("DMODProgress2d")->Set(pScrollerComp->GetVar("progress2d")->GetVector2()); + } + } +} + + +void OnPostIntroTransition(VariantList *pVList) +{ + Entity *pBG = pVList->Get(0).GetEntity(); + DMODMenuAddScrollContent(pBG); + +if (GetEmulatedPlatformID() == PLATFORM_ID_WEBOS) +{ + + CreateQuickTipFirstTimeOnly(pBG, "interface/generic/quicktip_dmod.rttex", true); +} else +if (GetEmulatedPlatformID() == PLATFORM_ID_BBX) +{ + CreateQuickTipFirstTimeOnly(pBG, "interface/generic/quicktip_dmod.rttex", true); + +} else +if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) +{ + CreateQuickTipFirstTimeOnly(pBG, "interface/android/quicktip_dmod.rttex", true); +} else if (GetEmulatedPlatformID() == PLATFORM_ID_WINDOWS) +{ + CreateQuickTipFirstTimeOnly(pBG, "interface/win/quicktip_dmod.rttex", true); +} else if (GetEmulatedPlatformID() == PLATFORM_ID_OSX) +{ + CreateQuickTipFirstTimeOnly(pBG, "interface/osx/quicktip_dmod.rttex", true); +} else +{ + CreateQuickTipFirstTimeOnly(pBG, "interface/iphone/quicktip_dmod.rttex", true); +} + + //get notified when this is deleted so we can save the default settings + pBG->sig_onRemoved.connect(&OnDMODMenuDelete); + +} + + +Entity * DMODMenuCreate( Entity *pParentEnt, bool bFadeIn /*= false*/ ) +{ + //GetMessageManager()->SendGame(MESSAGE_TYPE_PLAY_MUSIC, "audio/title.mp3", 200); + GetBaseApp()->ClearError(); + + Entity *pBG = NULL; + + if (IsLargeScreen()) + { + pBG = CreateOverlayEntity(pParentEnt, "DMODMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + } else + { + pBG = CreateOverlayEntity(pParentEnt, "DMODMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + } + + pBG->SetName("DMODMenu"); + AddFocusIfNeeded(pBG, true, 500); + pBG->AddComponent(new FocusRenderComponent); + + CL_Vec2f vTextAreaPos = iPhoneMap(2,10); + float offsetFromBottom = iPhoneMapY(42); + float offsetFromRight = iPhoneMapY(0); + + CL_Vec2f vTextAreaBounds = (GetScreenSize()- CL_Vec2f(offsetFromRight,offsetFromBottom))-vTextAreaPos; + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("pos2d")->Set(vTextAreaPos); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + Entity *pLabel = CreateTextLabelEntity(pBG, "scanning", GetScreenSizeXf()/2, GetScreenSizeYf()/2, "Preparing quest list..."); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); + FadeOutAndKillEntity(pLabel, true, 300, 501); + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + //pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + //EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + //pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + + Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + +// ZoomFromPositionEntity(pBG, CL_Vec2f(0, -GetScreenSizeYf()), 500); + //the continue button + Entity *pEnt; + + //pEnt = CreateOverlayRectEntity(pBG, CL_Rectf(0, GetScreenSizeYf()-offsetFromBottom, GetScreenSizeXf(), 320), MAKE_RGBA(0,0,0,100)); + + eFont fontID = FONT_SMALL; + + pEnt = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(25), iPhoneMapY(BACK_BUTTON_Y), "Back", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); + SetupTextEntity(pEnt, fontID); + AddHotKeyToButton(pEnt, VIRTUAL_KEY_BACK); + + if (GetApp()->CanDownloadDMODS()) + { + + pEnt = CreateTextButtonEntity(pBG, "getmore", iPhoneMapX(330), iPhoneMapY(BACK_BUTTON_Y), "Install by URL", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); + SetupTextEntity(pEnt, fontID); + + + pEnt = CreateTextButtonEntity(pBG, "browse", iPhoneMapX(170), iPhoneMapY(BACK_BUTTON_Y), "Browse", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&DMODMenuOnSelect); + SetupTextEntity(pEnt, fontID); + + } + pBG->GetFunction("RemoveDMOD")->sig_function.connect(&DMODMenuOnRemoveDMOD); + pBG->GetFunction("SessionNew")->sig_function.connect(&DMODMenuOnSessionNew); + pBG->GetFunction("SessionContinue")->sig_function.connect(&DMODMenuOnSessionContinue); + + + if (bFadeIn) + { + // FadeInEntity(pBG, true, 500); + SlideScreen(pBG, true, 500); + } else + { + SlideScreen(pBG, true, 500); + } + + VariantList vList(GetApp()->GetVar("DMODProgress2d")->GetVector2()); + GetMessageManager()->CallComponentFunction(pScrollComp, 501, "SetProgress", &vList); + + pBG->GetFunction("OnPostIntroTransition")->sig_function.connect(&OnPostIntroTransition); + VariantList vTemp(pBG, string("")); + GetMessageManager()->CallEntityFunction(pBG, 500, "OnPostIntroTransition", &vTemp); + + return pBG; +} \ No newline at end of file diff --git a/source/GUI/DMODMenu.h b/source/GUI/DMODMenu.h new file mode 100644 index 0000000..403230a --- /dev/null +++ b/source/GUI/DMODMenu.h @@ -0,0 +1,7 @@ +#ifndef DMODMenu_h__ +#define DMODMenu_h__ +#include "BaseApp.h" +Entity * DMODMenuCreate(Entity *pParentEnt, bool bFadeIn = false); + + +#endif // DMODMenu_h__ \ No newline at end of file diff --git a/source/GUI/DebugMenu.cpp b/source/GUI/DebugMenu.cpp new file mode 100644 index 0000000..6d8ceeb --- /dev/null +++ b/source/GUI/DebugMenu.cpp @@ -0,0 +1,163 @@ +#include "PlatformPrecomp.h" +#include "DebugMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "LogMenu.h" + +void DebugMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity", pEntClicked->GetName().c_str()); + + if (pEntClicked->GetName() == "FPS") + { + GetBaseApp()->SetFPSVisible(!GetBaseApp()->GetFPSVisible()); + } + + + if (pEntClicked->GetName() == "music_on") + { + GetAudioManager()->Play("audio/intro.ogg", true, true); + } + + if (pEntClicked->GetName() == "music_off") + { + GetAudioManager()->StopMusic(); + } + + if (pEntClicked->GetName() == "log") + { + RemoveFocusIfNeeded(pEntClicked->GetParent()); + SlideScreen(pEntClicked->GetParent(), false); + LogMenuCreate(pEntClicked->GetParent()->GetParent()); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + } + + + if (pEntClicked->GetName() == "Back") + { + //slide it off the screen and then kill the whole menu tree + RemoveFocusIfNeeded(pEntClicked->GetParent()); + SlideScreen(pEntClicked->GetParent(), false); + AddFocusIfNeeded(pEntClicked->GetParent()->GetParent()); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + } + + if (pEntClicked->GetName() == "AddStrength") + { + //slide it off the screen and then kill the whole menu tree + DinkModStrength(1); + } + + if (pEntClicked->GetName() == "AddDefense") + { + //slide it off the screen and then kill the whole menu tree + DinkModDefense(1); + } + + if (pEntClicked->GetName() == "AddMagic") + { + //slide it off the screen and then kill the whole menu tree + DinkModMagic(1); + } + + if (pEntClicked->GetName() == "AddLife") + { + //slide it off the screen and then kill the whole menu tree + DinkModLifeMax(10); + } + + if (pEntClicked->GetName() == "FillLife") + { + //slide it off the screen and then kill the whole menu tree + DinkFillLife(); + } + + if (pEntClicked->GetName() == "AddGold") + { + //slide it off the screen and then kill the whole menu tree + DinkModGold(100); + } + + if (pEntClicked->GetName() == "empty_cache") + { + DinkUnloadGraphicsCache(); + LogMsg("Cache emptied"); + } + if (pEntClicked->GetName() == "AddBow") + { + //slide it off the screen and then kill the whole menu tree + DinkAddBow(); + } + + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +Entity * DebugMenuCreate(Entity *pParentEnt) +{ + //Entity *pBG = CreateOverlayEntity(pParentEnt, "DebugMenu", "interface/generic_bg.rttex", 0,0); + + Entity *pBG = CreateOverlayRectEntity(pParentEnt, CL_Vec2f(0,0), GetScreenSize(), MAKE_RGBA(0,0,0,140)); + + AddFocusIfNeeded(pBG); + + Entity *pButtonEntity; + float x = iPhoneMapX(30); + float y = iPhoneMapY(30); + float ySpacer = iPhoneMapY(40); + + pButtonEntity = CreateTextButtonEntity(pBG, "FPS", x, y, "Toggle FPS Display"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + //pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + +if (GetApp()->GetCheatsEnabled()) +{ + pButtonEntity = CreateTextButtonEntity(pBG, "empty_cache", x, y, "Empty graphic cache"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + +} + pButtonEntity = CreateTextButtonEntity(pBG, "log", x, y, "View log"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "Back", x, y, "Back"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + //pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + + + if (GetApp()->GetCheatsEnabled()) + { + //buttons on right + x = iPhoneMapX(200); + y = iPhoneMapY(30); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddStrength", x, y, "Increase Strength"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddDefense", x, y, "Increase Defense"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddMagic", x, y, "Increase Magic"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddLife", x, y, "Increase Life"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "FillLife", x, y, "Refill Life"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddGold", x, y, "Add 100 Gold"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + + pButtonEntity = CreateTextButtonEntity(pBG, "AddBow", x, y, "Add Bow"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&DebugMenuOnSelect); + } + SlideScreen(pBG, true, 500); + + + return pBG; +} + diff --git a/source/GUI/DebugMenu.h b/source/GUI/DebugMenu.h new file mode 100644 index 0000000..2e6240f --- /dev/null +++ b/source/GUI/DebugMenu.h @@ -0,0 +1,7 @@ +#ifndef DebugMenu_h__ +#define DebugMenu_h__ + +#include "App.h" + +Entity * DebugMenuCreate(Entity *pParentEnt); +#endif // DebugMenu_h__ \ No newline at end of file diff --git a/source/GUI/EnterURLMenu.cpp b/source/GUI/EnterURLMenu.cpp new file mode 100644 index 0000000..172b2ee --- /dev/null +++ b/source/GUI/EnterURLMenu.cpp @@ -0,0 +1,114 @@ +#include "PlatformPrecomp.h" +#include "EnterURLMenu.h" +#include "Entity/EntityUtils.h" +#include "DMODMenu.h" +#include "DMODInstallMenu.h" +#include "dink/dink.h" +#include "PopUpMenu.h" + +void EnterURLMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + Entity *pMenu = pEntClicked->GetParent(); + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[0].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + //slide it off the screen and then kill the whole menu tree + pEntClicked->GetParent()->RemoveComponentByName("FocusInput"); + DisableAllButtonsEntity(pMenu); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + DMODMenuCreate(pEntClicked->GetParent()->GetParent(), true); + } + + + if (pEntClicked->GetName() == "Continue") + { + string name = GetEntityRoot()->GetEntityByName("name_input_box")->GetComponentByName("InputTextRender")->GetVar("text")->GetString(); + DisableAllButtonsEntity(pMenu); + GetApp()->GetVar("dmod_download_url")->Set(name); //save it to our database so we can remember the default + LogMsg("Read %s for the name", GetApp()->GetVar("name")->GetString().c_str()); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + + DMODInstallMenuCreate(pEntClicked->GetParent()->GetParent(), GetApp()->GetVar("dmod_download_url")->GetString(), GetDMODRootPath() ); + } + + if (pEntClicked->GetName() == "paste") + { + string text = GetClipboardText(); + + if (!text.empty()) + { + GetEntityRoot()->GetEntityByName("name_input_box")->GetComponentByName("InputTextRender")->GetVar("text")->Set(""); //clear it first + GetMessageManager()->SendGUI(MESSAGE_TYPE_GUI_PASTE, Variant(text), 0); + } else + { + //kill the keyboard + GetEntityRoot()->GetEntityByName("name_input_box")->GetComponentByName("InputTextRender")->GetFunction("CloseKeyboard")->sig_function(NULL); + PopUpCreate(pMenu, "Paste buffer is currently empty.", "", "cancel", "Continue", "", "", false); + + } + } +} + +Entity * EnterURLMenuCreate(Entity *pParentEnt) +{ + Entity *pBG = CreateOverlayEntity(pParentEnt, "EnterURLMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + AddFocusIfNeeded(pBG); + + Entity *pButtonEntity; + CL_Vec2f vTextAreaPos = iPhoneMap(25,40); + CL_Vec2f vTextAreaBounds = iPhoneMap(384,234); + + string title = "`$Add-On Download from URL"; + pButtonEntity = CreateTextLabelEntity(pBG, "title", vTextAreaPos.x, vTextAreaPos.y, title); + pButtonEntity->GetComponentByName("TextRender")->GetVar("font")->Set(uint32(FONT_LARGE)); + pButtonEntity->GetVar("scale2d")->Set(CL_Vec2f(0.6f, 0.6f)); + vTextAreaPos.y += iPhoneMapY(25); + + string msg = "Enter a URL to a .dmod file to download and install. (example: http://rtsoft.com/NewQuest.dmod )"; + + switch (GetEmulatedPlatformID()) + { + case PLATFORM_ID_WINDOWS: + msg = "Enter a URL to a .dmod file to download and install. (example: http://rtsoft.com/NewQuest.dmod ) Use Ctrl-V to paste from the clipboard."; + break; + } + + Entity *pText = CreateTextBoxEntity(pBG, "text", vTextAreaPos, vTextAreaBounds, msg); + + pButtonEntity = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(25), iPhoneMapY(284), "Back", false); + pButtonEntity->GetFunction("OnButtonSelected")->sig_function.connect(&EnterURLMenuOnSelect); + AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + + + //the continue button + pButtonEntity = CreateTextButtonEntity(pBG, "Continue", iPhoneMapX(356), iPhoneMapY(284), "Continue", false); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&EnterURLMenuOnSelect); + + //create button for pasting +if (GetEmulatedPlatformID() != PLATFORM_ID_WEBOS) +{ + pButtonEntity = CreateTextButtonEntity(pBG, "paste", vTextAreaPos.x, vTextAreaPos.y+iPhoneMapX(80), "[tap here to paste]"); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&EnterURLMenuOnSelect); +} + + //create input box + + pButtonEntity = CreateInputTextEntity(pBG, "name_input_box", vTextAreaPos.x, vTextAreaPos.y+iPhoneMapX(49), GetApp()->GetShared()->GetVarWithDefault("dmod_download_url", string(""))->GetString(), + iPhoneMapX(450), 0); + pButtonEntity->GetComponentByName("InputTextRender")->GetVar("inputLengthMax")->Set(uint32(255)); + pButtonEntity->GetComponentByName("InputTextRender")->GetVar("filtering")->Set(uint32(InputTextRenderComponent::FILTERING_LOOSE)); + pButtonEntity->GetComponentByName("InputTextRender")->GetVar("inputType")->Set(uint32(InputTextRenderComponent::INPUT_TYPE_URL)); + //pButtonEntity->GetComponentByName("InputTextRender")->GetVar("font")->Set(uint32(FONT_LARGE)); + + //a way to get our CreateTextBox function called in 500 seconds, but not called if the entity doesn't exist at that time + + SlideScreen(pBG, true); + return pBG; +} + + diff --git a/source/GUI/EnterURLMenu.h b/source/GUI/EnterURLMenu.h new file mode 100644 index 0000000..bf8a37b --- /dev/null +++ b/source/GUI/EnterURLMenu.h @@ -0,0 +1,16 @@ +// *************************************************************** +// EnterURLMenu - Creation date: 01/5/2010 +// ------------------------------------------------------------ +// Robinson Technologies Copyright (C) 2010 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef EnterURLMenu_h__ +#define EnterURLMenu_h__ +#include "App.h" + +Entity * EnterURLMenuCreate(Entity *pParentEnt); + +#endif // EnterURLMenu_h__ \ No newline at end of file diff --git a/source/GUI/ExpiredMenu.cpp b/source/GUI/ExpiredMenu.cpp new file mode 100644 index 0000000..b376eb0 --- /dev/null +++ b/source/GUI/ExpiredMenu.cpp @@ -0,0 +1,28 @@ +#include "PlatformPrecomp.h" +#include "ExpiredMenu.h" +#include "App.h" +#include "Entity/EntityUtils.h" +#include "Entity/CustomInputComponent.h" + +void ExpiredMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); +} + + +Entity * ExpiredMenuCreate(Entity *pParentEnt) +{ + + Entity *pBG = CreateOverlayEntity(pParentEnt, "ExpiredMenu", "interface/main_bg.rttex", 0,0); + AddFocusIfNeeded(pBG); + + //for android, so the back key (or escape on windows) will quit out of the game + EntityComponent *pComp = pBG->AddComponent(new CustomInputComponent); + //tell the component which key has to be hit for it to be activated + pComp->GetFunction("OnActivated")->sig_function.connect(1, boost::bind(&App::OnExitApp, GetApp(), _1)); + pComp->GetVar("keycode")->Set(uint32(VIRTUAL_KEY_BACK)); + + CreateTextLabelEntity(pBG, "text", 20, 100, "This beta has expired.\n\nPlease visit www.codedojo.com to see if there\nis a new one."); + return pBG; +} \ No newline at end of file diff --git a/source/GUI/ExpiredMenu.h b/source/GUI/ExpiredMenu.h new file mode 100644 index 0000000..ec8321a --- /dev/null +++ b/source/GUI/ExpiredMenu.h @@ -0,0 +1,5 @@ +#ifndef ExpiredMenu_h__ +#define ExpiredMenu_h__ +class Entity; +Entity * ExpiredMenuCreate(Entity *pParentEnt); +#endif // ExpiredMenu_h__ \ No newline at end of file diff --git a/source/GUI/GameMenu.cpp b/source/GUI/GameMenu.cpp new file mode 100644 index 0000000..ca80d8a --- /dev/null +++ b/source/GUI/GameMenu.cpp @@ -0,0 +1,1389 @@ +#include "PlatformPrecomp.h" +#include "GameMenu.h" +#include "Entity/EntityUtils.h" +#include "MainMenu.h" +#include "Component/FPSControlComponent.h" +#include "Component/CursorComponent.h" +#include "Component/InventoryComponent.h" +#include "Component/ActionButtonComponent.h" +#include "DebugMenu.h" +#include "PauseMenu.h" +#include "PopUpMenu.h" +#include "Component/DragControlComponent.h" +#include "QuickTipMenu.h" +#include "Entity/SelectButtonWithCustomInputComponent.h" +#include "Entity/ArcadeInputComponent.h" + +#ifdef _DEBUG +#define AUTO_SAVE_MS (1000*8) + +#else +#define AUTO_SAVE_MS (1000*60*5) + +#endif + +void UpdatePauseMenuPosition(Entity *pBG); + +void ShowQuickMessage(string msg) +{ + + Entity *pMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + assert(pMenu); + if (!pMenu) return; + Entity *pEnt = CreateTextLabelEntity(pMenu, "GameMsg", GetScreenSizeXf()/2, iPhoneMapY(100), msg); + + //SetupTextEntity(pEnt, FONT_LARGE); + SetAlignmentEntity(pEnt, ALIGNMENT_CENTER); + + FadeInEntity(pEnt); + FadeOutAndKillEntity(pEnt, true, 1000, 1000); + +} + +void GameOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + Entity *pMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + + if (pEntClicked->GetName() == "pause") + { + if (g_dglos.g_wait_for_button.active == true) + { + //sjoy.joybit[5] = TRUE + g_dglo.m_dirInput[DINK_INPUT_BUTTON5] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON5] = true; + + return; + } + + if (!pMenu->GetEntityByName("PauseMenu")) + { + pMenu->RemoveComponentByName("FocusInput"); + PauseMenuCreate(pMenu); + } + } + + if (pEntClicked->GetName() == "attack") + { + + if (DinkIsWaitingForSkippableDialog()) + { + if (DinkSkipDialogLine()) + { + //g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + //don't really attack + return; + } + } + + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = true; + return; + } + + if (pEntClicked->GetName() == "magic") + { + if (DinkIsWaitingForSkippableDialog()) + { + if (DinkSkipDialogLine()) + { + //g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + //don't really attack + return; + } + } + g_dglo.m_dirInput[DINK_INPUT_BUTTON3] = true; + return; + } + + if (pEntClicked->GetName() == "inventory") + { + if (IsDisabledEntity(pEntClicked)) return; + g_dglo.m_dirInput[DINK_INPUT_BUTTON4] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON4] = true; + //DisableAllButtonsEntity(pEntClicked); + return; + } + + if (pEntClicked->GetName() == "examine") + { + g_dglo.m_dirInput[DINK_INPUT_BUTTON2] = true; + //SendFakeInputMessageToEntity(GetEntityRoot(), MESSAGE_TYPE_GUI_CLICK_END, pVList->m_variant[0].GetVector2()); //otherwise the menu may never get the touch release message + return; + } + + if (pEntClicked->GetName() == "arrow_up") + { + g_dglo.m_dirInput[DINK_INPUT_UP] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_UP] = true; //turn off right away + return; + } + + if (pEntClicked->GetName() == "arrow_down") + { + g_dglo.m_dirInput[DINK_INPUT_DOWN] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_DOWN] = true; //turn off right away + return; + } + + if (pEntClicked->GetName() == "select") + { + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; //turn off right away + return; + } + + if (pEntClicked->GetName() == "viewMode") + { + LogMsg("Got viewmode command"); + g_dglo.ToggleView(); + return; + } + if (pEntClicked->GetName() == "speedup") + { + + if (g_dglo.m_bSpeedUpMode) + { + //turn it off + GetAudioManager()->Play("audio/speedup_end.wav"); + + DinkSetSpeedUpMode(false); + FlashStopEntity(pEntClicked); + SetAlphaEntity(pEntClicked, GetApp()->GetVar("gui_transparency")->GetFloat()); + } else + { + + //turn it on + GetAudioManager()->Play("audio/speedup_start.wav"); + DinkSetSpeedUpMode(true); + FlashStartEntity(pEntClicked, 2500); + } + return; + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + +void GameOnStopSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + Entity *pMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + + //LogMsg("UNClicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + + if (pEntClicked->GetName() == "attack") + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + return; + } + + if (pEntClicked->GetName() == "magic") + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON3] = true; + return; + } + + if (pEntClicked->GetName() == "inventory") + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON4] = true; + return; + } + + if (pEntClicked->GetName() == "examine") + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON2] = true; + return; + } + + if (pEntClicked->GetName() == "speedup") + { + + return; + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +void KillControls(float fadeTimeMS) +{ + Entity *pControls =GetEntityRoot()->GetEntityByName("Controls"); + + if (!pControls) return; + + if (fadeTimeMS != 0) + { + pControls->SetName("DYING"); //so we won't find it again + RemoveFocusIfNeeded(pControls); + + VariantList vList(pControls); + pControls->GetFunction("OnKillingControls")->sig_function(&vList); //just in case someone wants to listen to this message to do + //something like stop a fade in-in progress + FadeEntity(pControls, true, 0, fadeTimeMS, 0); + } + + g_dglo.m_lastGameMode = DINK_GAME_MODE_NONE; + g_dglo.m_bFullKeyboardActive = false; + + KillEntity(pControls, fadeTimeMS); +} + +void AddViewModeHotspot(Entity *pBG) +{ + if (!GetApp()->GetUsingTouchScreen()) return; + + CL_Vec2f vBarSize = iPhoneMap(CL_Vec2f(220,35)); + + if (IsIPADSize) + { + vBarSize = iPhoneMap(CL_Vec2f(310,35)); + } + + if (GetApp()->GetIconsOnLeft()) + { + vBarSize = iPhoneMap(CL_Vec2f(180,35)); + if (IsIPADSize) + { + vBarSize = iPhoneMap(CL_Vec2f(270,35)); + } + } + + Entity * pButtonEntity = CreateButtonHotspot(pBG, "viewMode", iPhoneMap(CL_Vec2f(70,0)), vBarSize); + pButtonEntity->GetVar("color")->Set(MAKE_RGBA(255,0,0,0)); + pButtonEntity->GetShared()->GetFunction("OnTouchStart")->sig_function.connect(&GameOnSelect); + + if (GetApp()->GetIconsOnLeft()) + { + pButtonEntity->GetVar("pos2d")->Set(iPhoneMap(CL_Vec2f(100,0))); + + } + CL_Vec2f vPos = pButtonEntity->GetVar("pos2d")->GetVector2(); + CL_Vec2f vSize = pButtonEntity->GetVar("size2d")->GetVector2(); + + + + if (GetApp()->GetVar("showViewHint")->GetUINT32() == 1) + { + GetApp()->GetVar("showViewHint")->Set(uint32(0)); //so this won't be shown again + //give hint to the user about clicking it + //add a bg bar to make the text easier to see + //go above the GUI menu otherwise it's fading will effect us + Entity * pOverlay = CreateOverlayRectEntity(pBG->GetParent(), vPos, vSize, MAKE_RGBA(0,0,0,150)); + //make the label on top + CL_Vec2f vLabelPos = vSize/2; //remember, we're a child of the box above, so 0 means the left part of the box, not the screen + Entity *pLabel = CreateTextLabelEntity(pOverlay, "label",vLabelPos.x, vLabelPos.y, "Tap here to toggle view"); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); + + + //fade them in + FadeInEntity(pOverlay, true, 500, 1000); + //fade them out + FadeOutAndKillEntity(pOverlay, true, 1400, 2500); + } + +} + +float FlipXIfNeeded(float x) +{ + if (GetApp()->GetIconsOnLeft()) + { + return GetScreenSizeXf()-x; + } + return x; +} + +CL_Vec2f FlipXIfNeeded(CL_Vec2f vPos) +{ + if (GetApp()->GetIconsOnLeft()) + { + vPos.x = GetScreenSizeXf()-vPos.x; + } + return vPos; +} + +void AddSpeedUpButton(Entity *pBG) +{ + + if (!GetApp()->GetUsingTouchScreen()) return; + + GetBaseApp()->GetEntityRoot()->RemoveEntityByName("speedup", true); + + + CL_Vec2f vPos = FlipXIfNeeded (iPhoneMap(CL_Vec2f(480-115, 4))); + + if (IsIPADSize) + { + vPos = CL_Vec2f(FlipXIfNeeded(GetScreenSizeXf()-4), 4); + } + + /*if (IsIphone4()) + { + vPos = CL_Vec2f(GetScreenSizeXf()-170, 4); + } + */ + + Entity * pButtonEntity = CreateOverlayButtonEntity(pBG, "speedup", ReplaceWithLargeInFileName("interface/iphone/speed_up_button.rttex"), vPos.x, vPos.y); + pButtonEntity->GetVar("ignoreTouchesOutsideRect")->Set(uint32(1)); //ignore touch-up messages not in our rect + SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_LEFT); + SetButtonClickSound(pButtonEntity, ""); //no sound + + + SetAlphaEntity(pButtonEntity, GetApp()->GetVar("gui_transparency")->GetFloat()); + //pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); +} + +void BuildMouseModeControls(float fadeTimeMS) +{ + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + + Entity *pVirtualStickEnt = pBG->AddEntity(new Entity); + pVirtualStickEnt->AddComponent(new CursorComponent); +} + +void OnGameKillKeyboard(VariantList *pVList) +{ + g_dglo.m_bFullKeyboardActive = false; + //g_dglo.m_bLastFullKeyboardActive = false; + +} + + + +void OnGameProcessHWKey(VariantList *pVList) +{ + if (pVList->Get(0).GetFloat() != MESSAGE_TYPE_GUI_CHAR) return; + + if (DinkCanRunScriptNow()) + { + + char c = toupper(char(pVList->Get(2).GetUINT32())); + + if (c > 28 && c < 255) + { + + switch (c) + { + + case 77: + case 109: + //open map + g_dglo.m_dirInput[DINK_INPUT_BUTTON6] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON6] = true; + break; + + default: + DinkLoadPlayerScript(string("key-"+toString(int(c)))); + } + } + } + //LogMsg("Got a %c (%d)", char(pVList->Get(2).GetUINT32()), pVList->Get(2).GetUINT32()); +} + +void OnGameProcessKey(VariantList *pVList) +{ + + + if (DinkCanRunScriptNow()) + { + + char c = toupper(char(pVList->Get(1).GetUINT32())); + + if (c > 28 && c < 255) + { + + switch (c) + { + /* + case 32: + case 54: + case 55: + case 37: + case 38: + case 39: + case 40: + */ + case 77: + //open map + g_dglo.m_dirInput[DINK_INPUT_BUTTON6] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON6] = true; + break; + + default: + DinkLoadPlayerScript(string("key-"+toString(toupper(c)))); + } + } + } + //LogMsg("Got a %c (%d)", char(pVList->Get(1).GetUINT32()), pVList->Get(1).GetUINT32()); +} + +void BuildFullKeyboardControls(float fadeTimeMS) +{ + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + + Entity *pInput = CreateInputTextEntity(pBG, "input", -500,100, ""); + EntityComponent *pInputComp = pInput->GetComponentByName("InputTextRender"); + + pInputComp->GetVar("filtering")->Set(uint32(InputTextRenderComponent::FILTERING_LOOSE)); + pInputComp->GetFunction("ActivateKeyboard")->sig_function(NULL); //open it now + pInputComp->GetFunction("CloseKeyboard")->sig_function.connect(&OnGameKillKeyboard); //get notified when it closes + pInputComp->GetFunction("OnChar")->sig_function.connect(&OnGameProcessKey); //get notified when it closes + pInputComp->GetVar("inputLengthMax")->Set(uint32(255)); + + Entity *pBut = CreateTextButtonEntity(pBG, "close_keyboard", 200, 5, "Close Keyboard", false); + //and run a function here so we can turn it off globally + pBut->GetFunction("OnButtonSelected")->sig_function.connect(&OnGameKillKeyboard); + //pVirtualStickEnt->AddComponent(new CursorComponent); +} + +void BuildInventoryControls(float fadeTimeMS) +{ + + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + AddViewModeHotspot(pBG); + GetEntityRoot()->GetComponentByName("ArcadeInput")->GetVar("trackball_mode")->Set(uint32(ArcadeInputComponent::TRACKBALL_MODE_MENU_SELECTION)); + + if (IsInFlingMode()) + { + Entity *pStick = pBG->AddEntity(new Entity()); + pStick->AddComponent(new FPSControlComponent); + + //add an actual selection button + + Entity *pButtonEntity = CreateOverlayButtonEntity(pBG, "select", ReplaceWithLargeInFileName("interface/iphone/button_arrow_back.rttex"), + iPadMapX(864), iPadMapY(120)); + pButtonEntity->GetVar("alpha")->Set(GetApp()->GetVar("gui_transparency")->GetFloat()); + //FadeInEntity(pButtonEntity); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&GameOnSelect); + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + //pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonStyleEntity(pButtonEntity, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH); + SetButtonClickSound(pButtonEntity, ""); //no sound + } + + Entity *pVirtualStickEnt = pBG->AddEntity(new Entity(new InventoryComponent)); + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar()) + { + float trans = 0.0f; + Entity *pButtonEntity; + + pButtonEntity = CreateButtonHotspot(pBG, "attack", iPhoneMap(113, 272), iPhoneMap(55, 46)); + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + + SetButtonClickSound(pButtonEntity, ""); //no sound + + //I made this touchspot too big on purpose, easier to hit it. + pButtonEntity = CreateButtonHotspot(pBG, "attack", iPhoneMap(412, 272), iPhoneMap(62, 46)); + + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(20,15,40,40)); + SetButtonClickSound(pButtonEntity, ""); //no sound + } + + +} + +void BuildShowingBMPControls(float fadeTimeMS) +{ + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + + Entity * pButtonEntity = CreateButtonHotspot(pBG, "select", CL_Vec2f(40, 40), GetScreenSize()); + //pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetVar("color")->Set(MAKE_RGBA(0,0,0,0)); //invisible + + pButtonEntity->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + + Entity *pLabel = CreateTextLabelEntity(pBG, "label", GetScreenSizeXf()/2, iPhoneMapY(285), "(tap to continue)"); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); +} + + +void BuildControls(float fadeTimeMS) +{ + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + + float iconX = FlipXIfNeeded(iPhoneMapX(400)); + float iconStartY = iPhoneMapY(-2); + float iconSpacerY = iPhoneMapY(97); + float trans = 0.0f; + Entity *pButtonEntity; + + + if (GetApp()->GetUsingTouchScreen()) + { + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar()) + { + //not zoomed in + + if (IsIPADSize) + { + iconX = FlipXIfNeeded(864); + iconStartY = 120; + iconSpacerY = iPhoneMapY(72); + + } else if (IsIphone4Size) + { + iconX = FlipXIfNeeded(820); + iconStartY = 5; + } + + } else + { + //adjust for fullscreen view + if (IsIPADSize) + { + iconX = FlipXIfNeeded(890); + iconStartY = 100; + iconSpacerY = iPhoneMapY(72); + + } else if (IsIphone4Size) + { + iconX = FlipXIfNeeded(820); + iconStartY = 5; + iconSpacerY = iPhoneMapY(76); + } else + { + //old iphone + iconSpacerY = iPhoneMapY(76); + iconX = FlipXIfNeeded(iPhoneMapX(416)); + } + } + + +float iconY = iconStartY; + + //make the area where if you touch it the screen zoom will change + + AddViewModeHotspot(pBG); + + //game icons + pButtonEntity = CreateOverlayButtonEntity(pBG, "inventory", ReplaceWithLargeInFileName("interface/iphone/button_inventory.rttex"), iconX, iconY); + + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + pButtonEntity->GetVar("alpha")->Set(trans); + iconY += iconSpacerY; + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + + + pButtonEntity = CreateActionButtonEntity(pBG, "magic", ReplaceWithLargeInFileName("interface/iphone/button_magic_base.rttex"), iconX, iconY); + iconY += iconSpacerY; + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + + pButtonEntity = CreateOverlayButtonEntity(pBG, "examine", ReplaceWithLargeInFileName("interface/iphone/button_examine.rttex"), iconX, iconY); + iconY += iconSpacerY; + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + //SetButtonRepeatDelayMS(pButtonEntity, 1); + + //pButtonEntity->GetComponentByName("Button2D")->GetVar("buttonStyle")->Set((uint32) Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH); + SetButtonClickSound(pButtonEntity, ""); //no sound + + + pButtonEntity->GetParent()->MoveEntityToBottomByAddress(pButtonEntity); + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar()) + { + pButtonEntity = CreateButtonHotspot(pBG, "magic", CL_Vec2f(iPhoneMapX(113), iPhoneMapY(272)), CL_Vec2f(iPhoneMapX(55), iPhoneMapY(46)), Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH); + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + + //I made this touchspot too big on purpose, easier to hit it. + pButtonEntity = CreateButtonHotspot(pBG, "attack", CL_Vec2f(iPhoneMapX(412), iPhoneMapY(272)), CL_Vec2f(iPhoneMapX(62), iPhoneMapY(46)), Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH); + iconY += iconSpacerY; + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + pButtonEntity->GetVar("ignoreTouchesOutsideRect")->Set(uint32(1)); //ignore touch-up messages not in our rect + SetButtonRepeatDelayMS(pButtonEntity, 0); + + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(20,15,40,40)); + SetButtonClickSound(pButtonEntity, ""); //no sound + + } else + { + + pButtonEntity = CreateActionButtonEntity(pBG, "attack", ReplaceWithLargeInFileName("interface/iphone/button_item_base.rttex"), iconX, iconY); + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + + iconY += iconSpacerY; + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + pButtonEntity->GetVar("ignoreTouchesOutsideRect")->Set(uint32(1)); //ignore touch-up messages not in our rect + + SetButtonClickSound(pButtonEntity, ""); //no sound + pButtonEntity->GetParent()->MoveEntityToBottomByAddress(pButtonEntity); + } + + FadeEntity(pBG, true, GetApp()->GetVar("gui_transparency")->GetFloat(), fadeTimeMS, 0); + } + + eControlStyle controlStyle = (eControlStyle) GetApp()->GetVar("controlStyle")->GetUINT32(); + + switch(controlStyle) + { + case CONTROLS_JOYPAD: + case CONTROLS_FLING: + { + Entity *pVirtualStickEnt = pBG->AddEntity(new Entity()); + pVirtualStickEnt->AddComponent(new FPSControlComponent); + + if (GetApp()->GetUsingTouchScreen()) + { + + bool moveStick = false; + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar()) + { + moveStick = true; + //ignore touches around the magic button + Entity *pVirtualStickArrowEnt = pBG->GetEntityByName("arrow_gui"); //in case we need it later on + + /* + EntityComponent *pFilter = pVirtualStickArrowEnt->AddComponent(new FilterInputComponent); + pFilter->GetVar("mode")->Set(uint32(FilterInputComponent::MODE_IGNORE_ABSOLUTE_CLIP_RECT)); + pFilter->GetVar("clipRect")->Set(CL_Rectf(iPhoneMapX(113), iPhoneMapY(272),iPhoneMapX(113+55), iPhoneMapY(272+46))); + */ + } + + if (moveStick) + { + //make some changes to the virtual pad arrow to fit this layout better + Entity *pVirtualStickArrowEnt = pBG->GetEntityByName("arrow_gui"); //in case we need it later on + + CL_Vec2f vArrowPos = CL_Vec2f(FlipXIfNeeded(iPhoneMapX(80)), iPhoneMapY(201)); + + if (IsIPADSize) + { + vArrowPos = CL_Vec2f( FlipXIfNeeded(149-30), 520+30); + if (IsInFlingMode()) + { + + vArrowPos.y = C_FLING_JOYSTICK_Y; + } + } + + pVirtualStickArrowEnt->GetVar("pos2d")->Set(vArrowPos); + } + } + } + break; + + case CONTROLS_DRAG_ANYWHERE: + { + Entity *pControls = pBG->AddEntity(new Entity()); + pControls->AddComponent(new DragControlComponent); + } + break; + + + default: + + assert(!"Just no"); + } +} + + +void BuildDialogModeControls(float fadeTimeMS) +{ + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + + if (!pBG) + { + assert(!"herm"); + return; + } + + pBG = pBG->AddEntity(new Entity("Controls")); + + if (!GetApp()->GetUsingTouchScreen()) return; + + float trans = 0.0f; + Entity *pButtonEntity; + + //GetEntityRoot()->GetComponentByName("ArcadeInput")->GetVar("trackball_mode")->Set(uint32(ArcadeInputComponent::TRACKBALL_MODE_MENU_SELECTION)); + + //make the area where if you touch it the screen zoom will change + AddViewModeHotspot(pBG); + + //game icons + float posX = iPhoneMapX(1); + + CL_Vec2f vUpArrowPos = iPhoneMap(posX,70); + CL_Vec2f vDownArrowPos = iPhoneMap(posX,212); + CL_Vec2f vOkPos = iPhoneMap(409, 136+90); + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED) + { + float posX = iPhoneMapX(10); + vUpArrowPos = iPhoneMap(posX,46); + vDownArrowPos = iPhoneMap(posX,181); + vOkPos = iPhoneMap(398,110+70); + } + + if (IsIPADSize) + { + posX = 17; + vUpArrowPos = CL_Vec2f(posX,277+50); + vDownArrowPos = CL_Vec2f(posX,404+50); + vOkPos = CL_Vec2f(815+50,330+60+70); + + if (g_dglo.GetActiveView() == DinkGlobals::VIEW_ZOOMED) + { + posX = 2; + vUpArrowPos = CL_Vec2f(posX,277+50+100); + vDownArrowPos = CL_Vec2f(posX,404+50+100); + vOkPos = CL_Vec2f(815+50+10,330+60+80+70); + } + } + + if (IsInFlingMode()) + { + + Entity *pStick = pBG->AddEntity(new Entity()); + pStick->AddComponent(new FPSControlComponent); + + + /* + posX = 47; + vUpArrowPos = CL_Vec2f(posX, (277+50+90)-20); + vDownArrowPos = CL_Vec2f(posX, (404+50+90) + 20); + */ + } + + if (GetApp()->GetIconsOnLeft()) + { + //flip controls around + vUpArrowPos = FlipXIfNeeded(vUpArrowPos); + vDownArrowPos = FlipXIfNeeded(vDownArrowPos); + vOkPos = FlipXIfNeeded(vOkPos); + } + + if (!IsInFlingMode()) + { + + + pButtonEntity = CreateOverlayButtonEntity(pBG, "arrow_up", ReplaceWithLargeInFileName("interface/iphone/button_arrow_up.rttex"), vUpArrowPos.x, vUpArrowPos.y); + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + Entity * pUp = pButtonEntity; + + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "arrow_down", ReplaceWithLargeInFileName("interface/iphone/button_arrow_down.rttex"), vDownArrowPos.x, vDownArrowPos.y); + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + Entity * pDown = pButtonEntity; + } + + pButtonEntity = CreateOverlayButtonEntity(pBG, "select", ReplaceWithLargeInFileName("interface/iphone/button_arrow_back.rttex"), vOkPos.x, vOkPos.y); + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&GameOnSelect); + if (GetApp()->GetIconsOnLeft()) SetAlignmentEntity(pButtonEntity, ALIGNMENT_UPPER_RIGHT); + //pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + //SetButtonStyleEntity(pButtonEntity, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH_RELEASE); + SetButtonClickSound(pButtonEntity, ""); //no sound + //SetButtonRepeatDelayMS(pButtonEntity, 1); + + Entity * pSelect = pButtonEntity; + + FadeEntity(pBG, true, GetApp()->GetVar("gui_transparency")->GetFloat(), fadeTimeMS, 0); + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED) + { + if (IsDrawingDinkStatusBar()) + { + //let's let the punch icon also select, it just feels natural + pButtonEntity = CreateButtonHotspot(pBG, "select", CL_Vec2f(iPhoneMapX(412), iPhoneMapY(272)), CL_Vec2f(iPhoneMapX(62), iPhoneMapY(46))); + + pButtonEntity->GetVar("alpha")->Set(trans); + pButtonEntity->GetShared()->GetFunction("OnOverStart")->sig_function.connect(&GameOnSelect); + pButtonEntity->GetShared()->GetFunction("OnOverEnd")->sig_function.connect(&GameOnStopSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + } + } +} + +void RecomputeAspectRatio(); + +void UpdateControlsGUIIfNeeded() +{ + + if (g_dglo.m_lastGameMode != GetDinkGameMode() + || g_dglo.m_lastSubGameMode != GetDinkSubGameMode() + //|| g_dglo.m_bWaitingForSkippableConversation != DinkIsWaitingForSkippableDialog() + || g_dglo.m_lastActiveView != g_dglo.GetActiveView() + || g_dglo.m_lastIsUpdatingDinkStatusBar != IsDrawingDinkStatusBar() + || g_dglo.m_bFullKeyboardActive != g_dglo.m_bLastFullKeyboardActive + ) + { + + if (g_dglo.m_bLastFullKeyboardActive && g_dglo.m_bFullKeyboardActive) + { + //don't care, leave the keyboard up + return; + } + + //kill any existing controls + KillControls(300); + + g_dglo.m_lastGameMode = GetDinkGameMode(); + g_dglo.m_lastSubGameMode = GetDinkSubGameMode(); + g_dglo.m_bWaitingForSkippableConversation = DinkIsWaitingForSkippableDialog(); + g_dglo.m_lastActiveView = g_dglo.GetActiveView(); + g_dglo.m_lastIsUpdatingDinkStatusBar = IsDrawingDinkStatusBar(); + g_dglo.m_bLastFullKeyboardActive = g_dglo.m_bFullKeyboardActive; + + GetEntityRoot()->GetComponentByName("ArcadeInput")->GetVar("trackball_mode")->Set(uint32(ArcadeInputComponent::TRACKBALL_MODE_WALKING)); + + Entity *pMainMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + RecomputeAspectRatio(); + + AddSpeedUpButton(pMainMenu); + UpdatePauseMenuPosition(pMainMenu); + + if (g_dglo.m_bFullKeyboardActive) + { + BuildFullKeyboardControls(300); + return; + } + + if (g_dglo.m_lastSubGameMode == DINK_SUB_GAME_MODE_DIALOG) + { + BuildDialogModeControls(300); + return; + } + + if (g_dglo.m_lastSubGameMode == DINK_SUB_GAME_MODE_SHOWING_BMP) + { + BuildShowingBMPControls(300); + return; + } + if (g_dglo.m_lastGameMode == DINK_GAME_MODE_INVENTORY) + { + BuildInventoryControls(300); + return; + } + + if (g_dglo.m_lastGameMode == DINK_GAME_MODE_MOUSE) + { + BuildMouseModeControls(300); + return; + } + + BuildControls(300); + } +} + +void OnGameMenuDelete(VariantList *pVList) +{ + finiObjects(); +} + +void ApplyAspectRatioGLMatrix(); + +void OnGameMenuRender(VariantList *pVList) +{ + + //apply matrix + glMatrixMode(GL_MODELVIEW); + + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED) + { + //clear background if needed + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + } + + //apply scale offset + ApplyAspectRatioGLMatrix(); + + + + + updateFrame(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + //remove matrix + + +} +void OnAutoSave(VariantList *pVList) +{ + if (GetDinkGameState() == DINK_GAME_STATE_PLAYING && DinkGetHealthPercent() > 0.3f) + { + if (GetDinkGameMode() == DINK_GAME_MODE_NORMAL && + ( GetDinkSubGameMode() == DINK_SUB_GAME_MODE_NORMAL || GetDinkSubGameMode() == DINK_SUB_GAME_MODE_NONE) + ) + { + SaveAutoSave(); + + //reschedule this function to run again in a bit + GetMessageManager()->CallEntityFunction(pVList->Get(0).GetEntity(), AUTO_SAVE_MS, "OnAutoSave", pVList); + return; + } + + } + + //if we got here, we failed to save due to it being dangerous because of low health. Let's try again in a few seconds... + GetMessageManager()->CallEntityFunction(pVList->Get(0).GetEntity(), 5000, "OnAutoSave", pVList); + +} + +void OnArcadeInput(VariantList *pVList) +{ + + int vKey = pVList->Get(0).GetUINT32(); + bool bIsDown = pVList->Get(1).GetUINT32() != 0; + + //LogMsg("GameMenuArcade: Key %d, down is %d", vKey, int(bIsDown)); + + switch (vKey) + { + case 9: //tab + //LogMsg("Tab: %d", int(bIsDown)); + DinkSetSpeedUpMode(bIsDown); + break; + + case VIRTUAL_KEY_F1: + + if (bIsDown) + SaveStateWithExtra(); + break; + + case VIRTUAL_KEY_F8: + { + if (bIsDown) + { + + + string fName = DinkGetSavePath()+"quicksave.dat"; + + if (FileExists(fName)) + { + LoadStateWithExtra(); + } else + { + ShowQuickMessage("No state to load yet."); + } + } + } + break; + case VIRTUAL_KEY_GAME_MAGIC: + + if (bIsDown) + { + if (DinkIsWaitingForSkippableDialog()) + { + if (DinkSkipDialogLine()) + { + return; + } + } + g_dglo.m_dirInput[DINK_INPUT_BUTTON3] = true; + } else + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON3] = true; + + } + break; + + + //EXAMINE + case VIRTUAL_KEY_GAME_TALK: + + /* + if (DinkIsWaitingForSkippableDialog()) + { + if (DinkSkipDialogLine()) + { + return; + } + } + */ + + if (bIsDown) + { + g_dglo.m_dirInput[DINK_INPUT_BUTTON2] = true; + } else + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON2] = true; + + } + break; + + case VIRTUAL_KEY_GAME_INVENTORY: //inventory + + if (bIsDown) + { + g_dglo.m_dirInput[DINK_INPUT_BUTTON4] = true; + } else + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON4] = true; + + } + break; + + case VIRTUAL_KEY_GAME_FIRE: //select//atack + + if (bIsDown) + { + if (DinkIsWaitingForSkippableDialog()) + { + if (DinkSkipDialogLine()) + { + return; + } + } + + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = true; + } else + { + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = true; + + } + break; + } + + + if (GetDinkSubGameMode() == DINK_SUB_GAME_MODE_DIALOG || GetDinkGameMode() == DINK_GAME_MODE_INVENTORY || GetDinkGameMode() == + DINK_GAME_MODE_MOUSE) + { + switch(vKey) + { + case VIRTUAL_KEY_DIR_LEFT: + SendKey(DINK_INPUT_LEFT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_RIGHT: + SendKey(DINK_INPUT_RIGHT, bIsDown); + break; + + case VIRTUAL_KEY_DIR_UP: + SendKey(DINK_INPUT_UP, bIsDown); + break; + + case VIRTUAL_KEY_DIR_DOWN: + SendKey(DINK_INPUT_DOWN, bIsDown); + break; + } + } + +} + +void OnRawCharInput(VariantList *pVList) +{ + + int vKey = pVList->Get(0).GetUINT32(); + bool bIsDown = pVList->Get(1).GetUINT32() != 0; + + //LogMsg("GameMenuRaw: Key %d, down is %d", vKey, int(bIsDown)); + + +} + +void UpdatePauseMenuPosition(Entity *pBG) +{ + Entity *pPause = pBG->GetEntityByName("pause"); + + assert(pPause); + + CL_Vec2f vPausePos = CL_Vec2f(12,0); + + if (IsLargeScreen()) + { + vPausePos = CL_Vec2f(27,0); + } + + vPausePos.x = FlipXIfNeeded(vPausePos.x); + + pPause->GetVar("pos2d")->Set(vPausePos); + + if (GetApp()->GetIconsOnLeft()) + { + SetAlignmentEntity(pPause, ALIGNMENT_UPPER_RIGHT); + } else + { + + SetAlignmentEntity(pPause, ALIGNMENT_UPPER_LEFT); + } + +} + +void GameFinishLoading(Entity *pBG) +{ + float trans = rt_max(0.4, GetApp()->GetVar("gui_transparency")->GetFloat()); + Entity *pButtonEntity; + DestroyUnusedTextures(); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "pause", ReplaceWithLargeInFileName("interface/iphone/pause_icon.rttex"), 0, 0); + + UpdatePauseMenuPosition(pBG); + + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + //SetButtonStyleEntity(pButtonEntity, Button2DComponent::BUTTON_STYLE_CLICK_ON_TOUCH); + + AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + //AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_PROPERTIES); + + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&GameOnSelect); + SetButtonClickSound(pButtonEntity, ""); //no sound + + if (!GetApp()->GetUsingTouchScreen()) + { + pButtonEntity->GetVar("alpha")->Set(0.0f); + } else + { + pButtonEntity->GetVar("alpha")->Set(trans); + } + + FadeOutAndKillEntity(pBG->GetEntityByName("game_loading"), true, 300, 50); + + pBG->GetShared()->GetFunction("OnRender")->sig_function.connect(&OnGameMenuRender); + pBG->GetShared()->GetFunction("OnDelete")->sig_function.connect(&OnGameMenuDelete); + + + GetBaseApp()->m_sig_arcade_input.connect(pBG->GetFunction("OnArcadeInput")->sig_function); + pBG->GetShared()->GetFunction("OnArcadeInput")->sig_function.connect(&OnArcadeInput); + + +//if (IsDesktop()) +{ + GetBaseApp()->m_sig_input.connect(&OnGameProcessHWKey); +} + + /* + GetBaseApp()->m_sig_raw_keyboard.connect(pBG->GetFunction("OnRawCharInput")->sig_function); + pBG->GetShared()->GetFunction("OnRawCharInput")->sig_function.connect(&OnRawCharInput); +*/ + + AddSpeedUpButton(pBG); + SetDinkGameState(DINK_GAME_STATE_PLAYING); + + if (GetPrimaryGLX() != 0) + { + SetupOrtho(); + DinkOnForeground(); //rebuild lost surfaces + + if (GetDinkGameState() != DINK_GAME_STATE_PLAYING) + { + PrepareForGL(); + } + + } + + if (AUTO_SAVE_MS != 0) + { + //AutoSave + pBG->GetFunction("OnAutoSave")->sig_function.connect(&OnAutoSave); + VariantList vList(pBG); + GetMessageManager()->CallEntityFunction(pBG, AUTO_SAVE_MS, "OnAutoSave", &vList); + } +} + + +void GameSetProgressBar(float progress) +{ + Entity *pBar = GetEntityRoot()->GetEntityByName("bar"); + + if (pBar) + { + pBar->GetComponentByName("ProgressBar")->GetVar("progress")->Set(progress); + } +} + +void ShowQuickTip(VariantList *pVList) +{ + Entity *pBG = pVList->m_variant[0].GetEntity(); + CreateQuickTip(pBG, pVList->m_variant[1].GetString(), false); +} + + +void GameLoadPiece(VariantList *pVList) +{ + Entity *pBG = pVList->m_variant[0].GetEntity(); + string stateToLoad = pVList->m_variant[2].GetString(); + + float &progress = pBG->GetVar("progress")->GetFloat(); + int gameIdToLoad = pVList->m_variant[1].GetUINT32(); + + + if (pBG->GetVar("didInit")->GetUINT32() == 0) + { + //initialize Dink + if (!InitDinkEngine()) + { + LogMsg("Error initializing videohw"); + Entity *pMenu = DinkQuitGame(); + PopUpCreate(pMenu, "Error initializing Dink engine. Don't know why!", "", "cancel", "Continue", "", "", true); + return; + + + } + pBG->GetVar("didInit")->Set(uint32(1)); + + } + if (progress == 1) + { + //we're done + GameFinishLoading(pBG); + return; + } + + if (!stateToLoad.empty()) + { + //loading a state + + if (progress == 0) + { + //first time, setup paths only + bool bSuccess = LoadState(stateToLoad, true); + + if (!bSuccess) + { + RemoveFile(stateToLoad, false); + Entity *pMenu = DinkQuitGame(); + PopUpCreate(pMenu, "Error loading save state. Probably an older version, sorry.", "", "cancel", "Continue", "", "", true); + return; + } + } else + { + bool bSuccess = LoadState(stateToLoad, false); + + if (!IsInString(stateToLoad, "autosave.dat")) + { + //instead of removing it, let it stay around in case there is a game crash? + //RemoveFile(stateToLoad, false); //SETH changed 8/28/2017 + } + + //we're done + progress = 1; + g_dglo.m_curLoadState = FINISHED_LOADING; + GameSetProgressBar(progress); + VariantList vList(pBG, uint32(gameIdToLoad), stateToLoad); + GetMessageManager()->CallEntityFunction(pBG, 1, "GameLoadPiece", &vList); + return; + } + + } + + if (!LoadGameChunk(gameIdToLoad, progress)) + { + LogMsg("Error initializing game engine"); + return; + } + + GameSetProgressBar(progress); + //reschedule this to run again + VariantList vList(pBG, uint32(gameIdToLoad), stateToLoad); + GetMessageManager()->CallEntityFunction(pBG, 1, "GameLoadPiece", &vList); +} + + + +Entity * GameCreate(Entity *pParentEnt, int gameIDToLoad, string stateToLoad, string msgToShow) +{ + Entity *pBG = pParentEnt->AddEntity(new Entity("GameMenu")); + AddFocusIfNeeded(pBG); + + Entity *pLoading = CreateOverlayEntity(pBG, "game_loading", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + if (msgToShow.empty()) + { + msgToShow = "Loading..."; + } + + Entity *pLabel = CreateTextLabelEntity(pLoading, "load_label", GetScreenSizeXf()/2, GetScreenSizeYf()/2, msgToShow); + SetupTextEntity(pLabel, FONT_LARGE); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); + pBG->GetFunction("GameLoadPiece")->sig_function.connect(&GameLoadPiece); + VariantList vList(pBG, uint32(gameIDToLoad), stateToLoad); + GetMessageManager()->CallEntityFunction(pBG, 501, "GameLoadPiece", &vList); + SlideScreen(pBG, true); + + Entity *pProgressBar = pLoading->AddEntity(new Entity("bar")); + EntityComponent *pBar = pProgressBar->AddComponent(new ProgressBarComponent); + pProgressBar->GetVar("pos2d")->Set(CL_Vec2f(iPhoneMapX(80),iPhoneMapY(120))); + pProgressBar->GetVar("size2d")->Set(CL_Vec2f(iPhoneMapX(310),iPhoneMapY(15))); + pProgressBar->GetVar("color")->Set(MAKE_RGBA(200,200,0,60)); + pBar->GetVar("interpolationTimeMS")->Set(uint32(1)); //update faster + pBar->GetVar("borderColor")->Set(MAKE_RGBA(200,200,0,180)); + pBG->GetFunction("ShowQuickTip")->sig_function.connect(&ShowQuickTip); + return pBG; +} + +bool IsInFlingMode() +{ + return (GetApp()->GetShared()->GetVar("controlStyle")->GetUINT32() == CONTROLS_FLING); +} + diff --git a/source/GUI/GameMenu.h b/source/GUI/GameMenu.h new file mode 100644 index 0000000..eb08091 --- /dev/null +++ b/source/GUI/GameMenu.h @@ -0,0 +1,16 @@ +#ifndef Game_h__ +#define Game_h__ + +#include "App.h" + +Entity * GameCreate(Entity *pParentEnt, int gameIDToLoad, string stateToLoad, string msgToShow = ""); +void KillControls(float fadeTimeMS = 300); +void BuildControls(float fadeTimeMS = 300); +void UpdateControlsGUIIfNeeded(); +void ShowQuickMessage(string msg); +void GameOnSelect(VariantList *pVList); +CL_Vec2f FlipXIfNeeded(CL_Vec2f vPos); +float FlipXIfNeeded(float x); +bool IsInFlingMode(); + +#endif // Game_h__ \ No newline at end of file diff --git a/source/GUI/LoadMenu.cpp b/source/GUI/LoadMenu.cpp new file mode 100644 index 0000000..719253e --- /dev/null +++ b/source/GUI/LoadMenu.cpp @@ -0,0 +1,127 @@ +#include "PlatformPrecomp.h" +#include "LoadMenu.h" +#include "Entity/EntityUtils.h" +#include "MainMenu.h" +#include "dink/dink.h" +#include "GameMenu.h" + +#define C_SAVE_GAME_COUNT 10 + +void LoadMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity", pEntClicked->GetName().c_str()); + + if (pEntClicked->GetName() == "Back") + { + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + MainMenuCreate(pEntClicked->GetParent()->GetParent()); + //LoadMenuCreate(GetParent() + } + + int num = atol(pEntClicked->GetName().c_str()); + + if (num > 0) + { + //let's load this sucka + DisableAllButtonsEntity(pEntClicked->GetParent()); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + + if (num == 10) + { + string fName = GetSavePath()+"dink/"+"autosave.dat"; + GameCreate(pEntClicked->GetParent()->GetParent(), 0, fName); + + } else + { + GameCreate(pEntClicked->GetParent()->GetParent(), num, ""); + } + + } + GetEntityRoot()->PrintTreeAsText(); //useful for Loading +} + +void SetupLoadButton(Entity *pParent, int x, float *pY, int gameID) +{ + gameID++; //it's 1 based, not 0 based + + const float ySpacer = 46; + if (gameID > 5) x += 200; + + char stTemp[256]; + char stFormatted[256]; + string clickKey = ""; //none + int gameTime; + + if (gameID == 10) + { + string autoSave = DinkGetSavePath() + "autosave.dat"; + + if (!FileExists(autoSave)) + { + sprintf(stFormatted, "Auto Save - None yet", gameID); + } else + { + gameTime = 0; + string description = "Unknown"; + + VariantDB db; + bool bFileExisted = false; + + if (db.Load(DinkGetSavePath()+"autosavedb.dat", &bFileExisted, false) && bFileExisted ) + { + gameTime = db.GetVar("minutes")->GetUINT32(); + description = db.GetVar("description")->GetString(); + } + + + sprintf(stFormatted, "Auto Save - %d:%02d - %s", (gameTime / 60), gameTime - ((gameTime / 60) * 60), description.c_str()); + clickKey = toString(gameID); + } + } else + + if (load_game_small(gameID, stTemp, &gameTime)) + { + sprintf(stFormatted, "Slot %d - %d:%02d - %s", gameID, (gameTime / 60), gameTime - ((gameTime / 60) * 60) , stTemp); + clickKey = toString(gameID); + } else + { + sprintf(stFormatted, "Slot %d - Empty", gameID); + } + + string butText = stFormatted; + Entity * pButtonEntity = CreateTextButtonEntity(pParent, clickKey, iPhoneMapX(x), iPhoneMapY(*pY), butText, false); *pY += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&LoadMenuOnSelect); + //pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); +} + +Entity * LoadMenuCreate(Entity *pParentEnt) +{ + Entity *pBG = CreateOverlayEntity(pParentEnt, "LoadMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + AddFocusIfNeeded(pBG, true); + + Entity *pButtonEntity; + float x = 80; + float yStart = 40; + float y = yStart; + float ySpacer = 50; + + for (int i=0; i < C_SAVE_GAME_COUNT; i++) + { + if (i == 5) y = yStart; + + SetupLoadButton(pBG, x, &y, i); + } + + pButtonEntity = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(x), iPhoneMapY(y), "Back"); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&LoadMenuOnSelect); + //pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + SlideScreen(pBG, true, 500); + return pBG; +} + diff --git a/source/GUI/LoadMenu.h b/source/GUI/LoadMenu.h new file mode 100644 index 0000000..2dfc0ad --- /dev/null +++ b/source/GUI/LoadMenu.h @@ -0,0 +1,7 @@ +#ifndef LoadMenu_h__ +#define LoadMenu_h__ + +#include "App.h" + +Entity * LoadMenuCreate(Entity *pParentEnt); +#endif // LoadMenu_h__ \ No newline at end of file diff --git a/source/GUI/LogMenu.cpp b/source/GUI/LogMenu.cpp new file mode 100644 index 0000000..affef71 --- /dev/null +++ b/source/GUI/LogMenu.cpp @@ -0,0 +1,98 @@ +#include "PlatformPrecomp.h" +#include "LogMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "MainMenu.h" + +void LogEnd(Entity *pMenu) +{ + //slide it off the screen and then kill the whole menu tree + RemoveFocusIfNeeded(pMenu); + //SlideScreen(pEntClicked->GetParent(), false); + AddFocusIfNeeded(pMenu->GetParent()); + FadeOutEntity(pMenu, true, 499); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); +} + +void LogMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity", pEntClicked->GetName().c_str()); + + Entity *pMenu = GetEntityRoot()->GetEntityByName("LogMenu"); + + if (pEntClicked->GetName() == "Back") + { + LogEnd(pMenu); + } + + GetEntityRoot()->PrintTreeAsText(); //useful for Log +} + + + +void LogAddScrollContent(Entity *pParent) +{ + pParent = pParent->GetEntityByName("scroll_child"); + float x = iPhoneMapX(5); + float y = 0; + + + CL_Vec2f vTextBoxPos(iPhoneMapX(20),y); + CL_Vec2f vTextBounds(iPhoneMapX(434), iPhoneMapY(200)); + string msg = GetBaseApp()->GetConsole()->GetAsSingleString(); + + CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, msg, 0.7f); + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); +} + + +Entity * LogMenuCreate(Entity *pParentEnt) +{ + Entity *pBG = CreateOverlayRectEntity(pParentEnt, CL_Vec2f(0,0), GetScreenSize(), MAKE_RGBA(0,0,0,140)); + + pBG->SetName("LogMenu"); + AddFocusIfNeeded(pBG, true); + + Entity *pButtonEntity; + + //setup a scrolling window + + CL_Vec2f vTextAreaPos = CL_Vec2f(0,0); + float offsetFromBottom = iPhoneMapY(30); + + CL_Vec2f vTextAreaBounds = GetScreenSize()-CL_Vec2f(15,offsetFromBottom); + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + + //Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + //SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + LogAddScrollContent(pBG); + + VariantList vList(CL_Vec2f(0.0f, 1.0f)); + pScrollComp->GetFunction("SetProgress")->sig_function(&vList); //scroll to the end + + pButtonEntity = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(35), iPhoneMapY(300), "CONTINUE", false); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&LogMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + + FadeInEntity(pBG, true); + return pBG; +} + diff --git a/source/GUI/LogMenu.h b/source/GUI/LogMenu.h new file mode 100644 index 0000000..acd91e9 --- /dev/null +++ b/source/GUI/LogMenu.h @@ -0,0 +1,8 @@ +#ifndef LogMenu_h__ +#define LogMenu_h__ + +#include "App.h" + +Entity * LogMenuCreate(Entity *pParentEnt); + +#endif // LogMenu_h__ \ No newline at end of file diff --git a/source/GUI/MainMenu.cpp b/source/GUI/MainMenu.cpp new file mode 100644 index 0000000..5782a49 --- /dev/null +++ b/source/GUI/MainMenu.cpp @@ -0,0 +1,601 @@ +#include "PlatformPrecomp.h" +#include "MainMenu.h" +#include "Entity/EntityUtils.h" +#include "DebugMenu.h" +#include "GameMenu.h" +#include "LoadMenu.h" +#include "dink/dink.h" +#include "DMODMenu.h" +#include "PauseMenu.h" +#include "DMODInstallMenu.h" +#include "PopUpMenu.h" +#include "OptionsMenu.h" +#include "AboutMenu.h" +#include "FileSystem/StreamingInstance.h" +#include "Entity/CustomInputComponent.h" +#include "Entity/HTTPComponent.h" + +bool g_bMainMenuFirstTime = true; +bool g_bDidVersionCheck = false; + +Entity * VersionShowScoreMessage(Entity *pMenu, string msg); + +void ReloadMainMenu(VariantList *pVList) +{ + MainMenuCreate(pVList->Get(0).GetEntity()); +} + +void OnVersionDownloadError(VariantList *pVList) +{ + NetHTTP::eError e = (NetHTTP::eError)pVList->m_variant[1].GetUINT32(); + + string msg = "`4Unable to check for updates. (" + toString(e) + ")"; + if (e == NetHTTP::ERROR_COMMUNICATION_TIMEOUT) + { + msg = "`4Unable to check for updates. (timed out)"; + } + + Entity *pMenu = pVList->m_variant[0].GetComponent()->GetParent(); + + VersionShowScoreMessage(pMenu, msg); + + //kill current menu + GetMessageManager()->CallEntityFunction(pMenu, 1000, "OnDelete", NULL); + + //reload the main menu in a bit + + VariantList vList(pMenu->GetParent()); + GetMessageManager()->CallStaticFunction(ReloadMainMenu, 1000, &vList, TIMER_SYSTEM); +} + + +Entity * VersionShowScoreMessage(Entity *pMenu, string msg) +{ + Entity *pInfo = pMenu->GetEntityByName("Info"); + if (pInfo) + { + pInfo->GetComponentByName("TextRender")->GetVar("text")->Set(msg); + pInfo->RemoveComponentByName("Typer"); // a thing that types stuff + } + else + { + pInfo = CreateTextLabelEntity(pMenu, "Info", iPhoneMapX(130), iPhoneMapY(220), msg); + } + + return pInfo; +} + + +void OnVersionDownloadHTTPFinish(VariantList *pVList) +{ + Entity *pMenu = pVList->m_variant[0].GetComponent()->GetParent(); + + TextScanner t((char*)pVList->m_variant[1].GetString().c_str()); + string line; + + LogMsg(t.GetAll().c_str()); + + // ShowScoreMessage(pMenu, t.GetParmString("msg",1)); + //GetApp()->GetVar("score_msg")->Set(t.GetParmString("msg",1)); + + string key = PlatformIDAsString(GetEmulatedPlatformID()); +#ifdef RT_IS_BETA + key += "_beta"; +#endif + + vector lines; + + + for (int i = 0; i < t.GetLineCount(); i++) + { + lines = StringTokenize(t.GetLine(i), "|"); + + if (lines.size() > 2 && lines[0] == key) + { + VersionShowScoreMessage(pMenu, ""); + + float version = StringToFloat(lines[1]); + if (version > GetApp()->GetVersion() + 0.001f) //the extra for an epsilon to flight floating point weirdness, trust me + { + PopUpCreate(pMenu, "New version detected! Download it now?", lines[2], + "cancel_update", "`wCancel", "url_update", "`wDownload", true); + return; + } + } + } + VersionShowScoreMessage(pMenu, "No new updates found."); + + + //kill current menu + GetMessageManager()->CallEntityFunction(pMenu, 1000, "OnDelete", NULL); + + //reload the main menu in a bit + + VariantList vList(pMenu->GetParent()); + GetMessageManager()->CallStaticFunction(ReloadMainMenu, 1000, &vList, TIMER_SYSTEM); +} + + + +void MainMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + + if (pEntClicked->GetName() == "New") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + InitDinkPaths(GetBaseAppPath(), "dink", ""); + + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + GameCreate(pEntClicked->GetParent()->GetParent(), 0, ""); + GetApp()->GetVar("showViewHint")->Set(uint32(0)); //so this won't be shown here + + } + + if (pEntClicked->GetName() == "Load") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + InitDinkPaths(GetBaseAppPath(), "dink", ""); + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + LoadMenuCreate(pEntClicked->GetParent()->GetParent()); + } + + if (pEntClicked->GetName() == "Continue") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + InitDinkPaths(GetBaseAppPath(), "dink", ""); + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + GameCreate(pEntClicked->GetParent()->GetParent(), 0, GetSavePath()+"dink/"+string("continue_state.dat")); + } + + if (pEntClicked->GetName() == "Debug") + { + //overlay the debug menu over this one + pEntClicked->GetParent()->RemoveComponentByName("FocusInput"); + DebugMenuCreate(pEntClicked->GetParent()); + } + + if (pEntClicked->GetName() == "Add-ons") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + // DMODInstallMenuCreate(pEntClicked->GetParent()->GetParent(), "files.dinknetwork.com/three_amulets-v1_1.dmod", ""); + DMODMenuCreate(pEntClicked->GetParent()->GetParent()); + } + + + if (pEntClicked->GetName() == "Options") + { + //DisableAllButtonsEntity(pEntClicked->GetParent()); + pEntClicked->GetParent()->RemoveComponentByName("FocusInput"); + pEntClicked->GetParent()->RemoveComponentByName("FocusUpdate"); + + //SlideScreen(pEntClicked->GetParent(), false); + //GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + OptionsMenuCreate(pEntClicked->GetParent()); + } + + if (pEntClicked->GetName() == "About") + { + DisableAllButtonsEntity(pEntClicked->GetParent()); + //RemoveFocusIfNeeded(pEntClicked->GetParent()); //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + AboutMenuCreate(pEntClicked->GetParent()->GetParent()); + } + + if (pEntClicked->GetName() == "rtsoftlogo") + { + PopUpCreate(pEntClicked->GetParent(), "Would you like to visit `wrtsoft.com``?", "http://www.rtsoft.com/iphone", + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +string GetNextDMODToInstall() +{ + //if (!GetApp()->CanDownloadDMODS()) return ""; //ignore it + + vector files = GetFilesAtPath(GetSavePath()); + + //LogMsg("listing files"); + + for (unsigned int i=0; i < files.size(); i++) + { + //LogMsg(files[i].c_str()); + if (GetFileExtension(files[i]) == "dmod") + { + return files[i]; + } + } + + return ""; +} + +void MainOnStartLoading(VariantList *pVList) +{ + Entity *pBG = pVList->m_variant[0].GetEntity(); + + string fileName = pVList->m_variant[1].GetString(); + + DisableAllButtonsEntity(pBG); + SlideScreen(pBG, false); + GetMessageManager()->CallEntityFunction(pBG, 500, "OnDelete", NULL); + + string fName = GetNextDMODToInstall(); + if (!fName.empty()) + { + DMODInstallMenuCreate(pBG->GetParent(), "", GetDMODRootPath(), GetSavePath()+fName); + } else + { + GameCreate(pBG->GetParent(), 0, fileName, "Continuing last game..."); + } +} + + +void ImportSaveFileIfApplicable(string fName) +{ + if (GetFileExtension(fName) != "dat") return; + + if (fName == "save.dat") return; //it's not this one + if (fName == "state.dat") return; //it's not this one + if (fName == "continue_state.dat") return; //it's not this one + if (fName == "autosave.dat") return; //it's not this one + if (fName == "autosavedb.dat") return; //it's not this one + if (fName == "quicksave.dat") return; //it's not this one + if (fName == "quickload.dat") return; //it's not this one + + + //check for any dmod name specified after a _ + + size_t index = fName.find_last_of('_'); + size_t periodPos = fName.find_last_of('.'); + + if (periodPos == string::npos || GetFileExtension(fName) != "dat") return; + + string dmodName = ""; + + if (index != string::npos) + { + //yeah, it has one + dmodName = fName.substr(index+1, periodPos-(index+1)); + } + + //ok, ready to copy it. But figure out where, and what the filename should be + string destPath = GetSavePath()+"dink/"; + string destFile = fName; + + //modify if needed for a dmod + + if (!dmodName.empty()) + { + destPath = GetDMODRootPath()+dmodName+"/"; + destFile = fName.substr(0, index); + destFile += fName.substr(periodPos, fName.size()-periodPos); + } + + LogMsg("Importing %s to %s", (GetSavePath()+fName).c_str(), (destPath+destFile).c_str()); + GetFileManager()->Copy(GetSavePath()+fName, destPath+destFile, false); + + RemoveFile(GetSavePath()+fName, false); +} + +void CheckForImportedSavedGames() +{ + if (!GetEmulatedPlatformID() == PLATFORM_ID_IOS) return; + + vector files = GetFilesAtPath(GetSavePath()); + + for (uint32 i=0; i < files.size(); i++) + { + ImportSaveFileIfApplicable(files[i]); + } +} + +void MainMenuContinueLast(VariantList *pVList) +{ + Entity *pBG = pVList->Get(0).GetEntity(); + + pBG->GetFunction("OnStartLoading")->sig_function.connect(&MainOnStartLoading); + VariantList vList(pBG, GetSavePath()+string("state.dat")); + GetMessageManager()->CallEntityFunction(pBG, 1000, "OnStartLoading", &vList); + g_bMainMenuFirstTime = false; + + LogMsg("Continuing"); +} + +void MainMenuContinueLastNewStyle(VariantList *pVList) +{ + Entity *pBG = pVList->Get(0).GetEntity(); + + pBG->GetFunction("OnStartLoading")->sig_function.connect(&MainOnStartLoading); + VariantList vList(pBG, ReadLastPathSaved()+string("continue_state.dat")); + GetMessageManager()->CallEntityFunction(pBG, 1000, "OnStartLoading", &vList); + g_bMainMenuFirstTime = false; + WriteLastPathSaved(""); + LogMsg("Contining"); +} + +void MainMenuCancelLast(VariantList *pVList) +{ + Entity *pMenu = pVList->Get(0).GetEntity(); + + WriteLastPathSaved(""); + RemoveFile(GetSavePath()+"state.dat", false); + + //kill current menu + GetMessageManager()->CallEntityFunction(pMenu, 0, "OnDelete", NULL); + + //reload the main menu + MainMenuCreate(pMenu->GetParent()); +} + +void CheckForNewVersion(Entity *pMenu) +{ + + pMenu->RemoveComponentByName("HTTP"); //just in case it already exists + + //get the internet stuff going + EntityComponent *pComp = pMenu->AddComponent(new HTTPComponent); + + VariantList vPostData; + + vPostData.m_variant[0].Set("version"); + vPostData.m_variant[1].Set(toString(GetApp()->GetVersion())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + vPostData.m_variant[0].Set("build"); + vPostData.m_variant[1].Set(toString(GetApp()->GetBuild())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + vPostData.m_variant[0].Set("platform"); + vPostData.m_variant[1].Set(toString(GetEmulatedPlatformID())); + pComp->GetFunction("AddPostData")->sig_function(&vPostData); + + VariantList v; + + string url; + uint32 port; + GetApp()->GetServerInfo(url, port); + + v.m_variant[0].Set(url); + v.m_variant[1].Set(port); + v.m_variant[2].Set("dink/versions.php"); + pComp->GetFunction("OnError")->sig_function.connect(&OnVersionDownloadError); + pComp->GetFunction("OnFinish")->sig_function.connect(&OnVersionDownloadHTTPFinish); + pComp->GetFunction("Init")->sig_function(&v); + + Entity *pEnt = VersionShowScoreMessage(pMenu, "`6"); + EntityComponent *pTyper = pEnt->AddComponent(new TyperComponent); + pTyper->GetVar("text")->Set("Checking rtsoft.com for updates..."); + pTyper->GetVar("speedMS")->Set(uint32(50)); +} + +Entity * MainMenuCreate( Entity *pParentEnt, bool bFadeIn ) +{ + CheckForImportedSavedGames(); + + GetApp()->GetVar("showViewHint")->Set(uint32(1)); //show that one tip + + Entity *pBG = CreateOverlayEntity(pParentEnt, "MainMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + + OverlayRenderComponent *pOverlay = (OverlayRenderComponent*) pBG->GetComponentByName("OverlayRender"); + if (!pOverlay->GetSurfaceAnim()) + { + + LogMsg("Can't find media. If running from Visual Studio, make sure you set the active dir to ../bin first!"); +#ifdef WINAPI + MessageBox(NULL, "Can't find media. If running from Visual Studio, make sure you set the active dir to ../bin and have run media/update_media.bat first!", "Woah nelly!" , 0); +#endif + } + //Entity *pBG = pParentEnt->AddEntity(new Entity); + GetBaseApp()->ClearError(); + AddFocusIfNeeded(pBG, true); + + + pBG->GetFunction("ContinueLast")->sig_function.connect(&MainMenuContinueLast); + pBG->GetFunction("ContinueLastNewStyle")->sig_function.connect(&MainMenuContinueLastNewStyle); + pBG->GetFunction("CancelLast")->sig_function.connect(&MainMenuCancelLast); + + Entity *pButtonEntity; + float x = 50; + float yStart = 200; + float y = yStart; + float ySpacer = 55; + eFont fontID = FONT_LARGE; + float fontScale = 1; + float fireAnimY = 240; + CL_Vec2f vRtsoftLogoPt = CL_Vec2f(402, 149); + + CL_Vec2f vNewButPt = CL_Vec2f(26, 199); + CL_Vec2f vLoadButPt = CL_Vec2f(135, 199); + CL_Vec2f vAddonButPt = CL_Vec2f(26, 245); + CL_Vec2f vContinueButPt = CL_Vec2f(246, 198); + + CL_Vec2f vAboutButPt = CL_Vec2f(251, 245); + + CL_Vec2f vOptionsButPt = CL_Vec2f(360, 246); + + if (IsIPADSize) + { + vNewButPt = CL_Vec2f(0, 468); + vLoadButPt = CL_Vec2f(256, 468); + fireAnimY = GetScreenSizeYf()-256; + vRtsoftLogoPt = CL_Vec2f(830, 370); + + vAddonButPt = CL_Vec2f(13, 565); + vContinueButPt = CL_Vec2f(525, 468); + vAboutButPt = CL_Vec2f(525, 565); + vOptionsButPt = CL_Vec2f(748, 565); + } else if (IsIphone4Size) + { + vNewButPt = CL_Vec2f(66, 364); + vLoadButPt = CL_Vec2f(277, 362); + fireAnimY = GetScreenSizeYf()-160; + vRtsoftLogoPt = CL_Vec2f(775, 262); + + vAddonButPt = CL_Vec2f(67, 453); + vContinueButPt = CL_Vec2f(498, 364 ); + vAboutButPt = CL_Vec2f(512, 454); + vOptionsButPt = CL_Vec2f(716, 455); + } + + + +#ifdef RT_IS_BETA + Entity *pText = CreateTextLabelEntity(pBG, "text", GetScreenSizeXf()/2, GetScreenSizeYf()-20, + "`wBeta Version("+GetApp()->GetVersionString()+")"); + SetAlignmentEntity(pText, ALIGNMENT_CENTER); + +#endif + + if (!g_bDidVersionCheck && IsDesktop()) + { + g_bDidVersionCheck = true; + CheckForNewVersion(pBG); + return pBG; + } + + + Entity *pEntDinkLogo = CreateOverlayEntity(pBG, "dinklogo", ReplaceWithDeviceNameInFileName("interface/iphone/logo_dink.rttex"), 0, 0); + + pButtonEntity = CreateOverlayEntity(pBG, "flameAnim", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_anim_fire.rttex"), 0, fireAnimY); + SetupAnimEntity(pButtonEntity, 1, 4, 0, 0); + AnimateEntity(pButtonEntity, 0, 3, 125, InterpolateComponent::ON_FINISH_REPEAT, 0); + + //for android, so the back key (or escape on windows/OSX) will quit out of the game + EntityComponent *pComp = pBG->AddComponent(new CustomInputComponent); + //tell the component which key has to be hit for it to be activated + pComp->GetFunction("OnActivated")->sig_function.connect(1, boost::bind(&App::OnExitApp, GetApp(), _1)); + pComp->GetVar("keycode")->Set(uint32(VIRTUAL_KEY_BACK)); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "rtsoftlogo", ReplaceWithDeviceNameInFileName("interface/iphone/logo_rtsoft.rttex"), vRtsoftLogoPt.x, vRtsoftLogoPt.y); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0, 0, 0, -10)); //no padding, it overlaps other buttons.. + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + FadeInEntity(pButtonEntity, false, 300, 1000); + + + if ( ! GetNextDMODToInstall().empty()) + { + pBG->GetFunction("OnStartLoading")->sig_function.connect(&MainOnStartLoading); + VariantList vList(pBG, string("")); + GetMessageManager()->CallEntityFunction(pBG, 1000, "OnStartLoading", &vList); + + } else + { + + if (FileExists(GetSavePath()+"state.dat")) + { + PopUpCreate(pBG, "Continue your last session?", "", "CancelLast", "Cancel", "ContinueLast", "Continue", true); + return pBG; + } else if (!ReadLastPathSaved().empty()) + { + PopUpCreate(pBG, "Continue your last session?", "", "CancelLast", "Cancel", "ContinueLastNewStyle", "Continue", true); + return pBG; + } else + { + + if (g_bMainMenuFirstTime) + { +#ifdef RT_MOGA_ENABLED + ShowTextMessage("Moga enabled test version - not for distribution"); +#endif + PlayMenuMusic(); + } + + ZoomToPositionFromThisOffsetEntity(pEntDinkLogo, CL_Vec2f(0, -300), 2000, INTERPOLATE_EASE_TO, 5); + pButtonEntity = CreateOverlayButtonEntity(pBG, "New", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_new.rttex"), vNewButPt.x, vNewButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 100); + + //SetupTextEntity(pButtonEntity, fontID, fontScale); + pButtonEntity = CreateOverlayButtonEntity(pBG, "Add-ons", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_addon10.rttex"), vAddonButPt.x, vAddonButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + //SetupTextEntity(pButtonEntity, fontID, fontScale); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 1000); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "Load", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_load.rttex"), vLoadButPt.x, vLoadButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + //SetupTextEntity(pButtonEntity, fontID, fontScale); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 400); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "Continue", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_continue.rttex"), vContinueButPt.x, vContinueButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 700); + + if (!FileExists(GetSavePath()+"dink/"+string("continue_state.dat"))) + { + pButtonEntity->GetVar("color")->Set(MAKE_RGBA(100,100,100,255)); + DisableAllButtonsEntity(pButtonEntity, false); + } + + pButtonEntity = CreateOverlayButtonEntity(pBG, "About", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_about.rttex"), vAboutButPt.x, vAboutButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 1300); + + pButtonEntity = CreateOverlayButtonEntity(pBG, "Options", ReplaceWithDeviceNameInFileName("interface/iphone/main_but_options.rttex"), vOptionsButPt.x, vOptionsButPt.y); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + SetTouchPaddingEntity(pButtonEntity, CL_Rectf(0,0,0,0)); + FadeInEntity(pButtonEntity, false, 500, 1500); + + DestroyUnusedTextures(); + } + + //pButtonEntity = CreateTextButtonEntity(pBG, "Debug", x, y, "Debug and MP3 Music"); y += ySpacer; + //pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect); + //pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + } + + if (bFadeIn) + { + FadeInEntity(pBG, true, 500, 0); + } else + { + + if (g_bMainMenuFirstTime) + { + g_bMainMenuFirstTime = false; + } else + { + SlideScreen(pBG, true); + } + } + + return pBG; +} + + +Entity * AddTitle( Entity *pEnt, string title) +{ + Entity *pTitle; + + float titleHeight = 25; + float scale = 1; + float x = 480/2; + + pTitle = CreateTextLabelEntity(pEnt, "Title", x, titleHeight, title); + pTitle->GetVar("scale2d")->Set(CL_Vec2f(scale, scale)); + pTitle->GetComponentByName("TextRender")->GetVar("font")->Set(uint32(FONT_LARGE)); + EntityRetinaRemapIfNeeded(pTitle, true, false, true); + pTitle->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + return pTitle; +} \ No newline at end of file diff --git a/source/GUI/MainMenu.h b/source/GUI/MainMenu.h new file mode 100644 index 0000000..3373c4d --- /dev/null +++ b/source/GUI/MainMenu.h @@ -0,0 +1,9 @@ +#ifndef MainMenu_h__ +#define MainMenu_h__ + +#include "App.h" + +#define BACK_BUTTON_Y 293 +Entity * MainMenuCreate(Entity *pParentEnt, bool bFadeIn = false); +Entity * AddTitle( Entity *pEnt, string title); +#endif // MainMenu_h__ \ No newline at end of file diff --git a/source/GUI/OptionsMenu.cpp b/source/GUI/OptionsMenu.cpp new file mode 100644 index 0000000..42d8d2a --- /dev/null +++ b/source/GUI/OptionsMenu.cpp @@ -0,0 +1,552 @@ +#include "PlatformPrecomp.h" +#include "OptionsMenu.h" +#include "Entity/EntityUtils.h" +#include "App.h" +#include "../dink/Dink.h" +#include "Entity/SliderComponent.h" +#include "MainMenu.h" +#include "PauseMenu.h" +#include "GameMenu.h" +#include "Gamepad/GamepadManager.h" +#include "PopUpMenu.h" + +#ifdef PLATFORM_IOS +#include "Gamepad/GamepadProvider60Beat.h" +#endif + +#include "Gamepad/GamepadProvideriCade.h" + +void UpdateOptionsGUI(); + +void OptionsMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + Entity *pMenu = pEntClicked->GetParent(); + + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + if (pEntClicked->GetName() == "music_0") + { + GetApp()->GetShared()->GetVar("musicDisabled")->Set(uint32(1)); + GetAudioManager()->SetMusicEnabled(0); + } + + if (pEntClicked->GetName() == "music_1") + { + GetApp()->GetShared()->GetVar("musicDisabled")->Set(uint32(0)); + GetAudioManager()->SetMusicEnabled(1); + } + + if (pEntClicked->GetName() == "toggle_fullscreen") + { + GetBaseApp()->OnFullscreenToggleRequest(); + + //if you wanted to set a specific size instead: + //GetBaseApp()->SetVideoMode(200, 200, false); + } + if (pEntClicked->GetName() == "vid_small") + { + GetBaseApp()->SetVideoMode(640, 480, false); + } + + if (pEntClicked->GetName() == "vid_med") + { + GetBaseApp()->SetVideoMode(1024, 768, false); + } + + if (pEntClicked->GetName() == "vid_big") + { + GetBaseApp()->SetVideoMode(1280, 960, false); + } + + if (pEntClicked->GetName() == "controls_0") + { + GetApp()->GetShared()->GetVar("controlStyle")->Set(uint32(CONTROLS_JOYPAD)); + } + + if (pEntClicked->GetName() == "controls_1") + { + GetApp()->GetShared()->GetVar("controlStyle")->Set(uint32(CONTROLS_DRAG_ANYWHERE)); + } + + if (pEntClicked->GetName() == "controls_2") + { + GetApp()->GetShared()->GetVar("controlStyle")->Set(uint32(CONTROLS_FLING)); + } + + + if (pEntClicked->GetName() == "buttons_0") + { + GetApp()->GetShared()->GetVar("buttons")->Set(uint32(0)); + } + + if (pEntClicked->GetName() == "buttons_1") + { + GetApp()->GetShared()->GetVar("buttons")->Set(uint32(1)); + } + + if (pEntClicked->GetName() == "fps_limit_0") + { + GetApp()->GetShared()->GetVar("fpsLimit")->Set(uint32(VIDEO_FPS_LIMIT_ON)); + GetApp()->UpdateVideoSettings(); + } + if (pEntClicked->GetName() == "fps_limit_1") + { + GetApp()->GetShared()->GetVar("fpsLimit")->Set(uint32(VIDEO_FPS_LIMIT_OFF)); + GetApp()->UpdateVideoSettings(); + } + + if (pEntClicked->GetName() == "smoothing_0") + { + GetApp()->GetShared()->GetVar("smoothing")->Set(uint32(1)); + GetApp()->UpdateVideoSettings(); + DinkUnloadUnusedGraphicsByUsageTime(0); //unload anything not used in the last second + DinkReInitSurfacesAfterVideoChange(); + DinkOnForeground(); + } + + if (pEntClicked->GetName() == "smoothing_1") + { + GetApp()->GetShared()->GetVar("smoothing")->Set(uint32(0)); + GetApp()->UpdateVideoSettings(); + DinkUnloadUnusedGraphicsByUsageTime(0); //unload anything not used in the last second + DinkReInitSurfacesAfterVideoChange(); + DinkOnForeground(); + + } + + if (pEntClicked->GetName() == "check_stretch") + { + bool bChecked = IsCheckboxChecked(pEntClicked); + GetApp()->GetVar("check_stretch")->Set(uint32(bChecked)); + GetApp()->UpdateVideoSettings(); + DinkUnloadUnusedGraphicsByUsageTime(0); //unload anything not used in the last second + DinkReInitSurfacesAfterVideoChange(); + DinkOnForeground(); + } + + if (pEntClicked->GetName() == "sbeat_ad") + { + string url = "http://www.60beat.com/?Click=326"; + PopUpCreate(pEntClicked->GetParent()->GetParent()->GetParent(), "Would you like to visit 60beat's webpage and learn more about their gamepad?", url, + "cancel", "`wCancel", "url", "`wLaunch", true); + return; + } + + if (pEntClicked->GetName() == "check_icade") + { + bool bChecked = IsCheckboxChecked(pEntClicked); + GetApp()->GetVar("check_icade")->Set(uint32(bChecked)); + + GetGamepadManager()->RemoveProviderByName("iCade"); + GetApp()->RemoveAndroidKeyboardKeys(); + + if (bChecked) + { + GetApp()->AddIcadeProvider(); + GetApp()->RemoveAndAttachAllAvailableGamepads(); + } else + { + GetApp()->AddDroidKeyboardKeys(); + //GetBaseApp()->SetAllowScreenDimming(true); + } + } + +#ifdef PLATFORM_IOS + + /* + if (pEntClicked->GetName() == "check_60beat") + { + bool bChecked = IsCheckboxChecked(pEntClicked); + GetApp()->GetVar("check_60beat")->Set(uint32(bChecked)); + + GetGamepadManager()->RemoveProviderByName("60Beat"); + + if (bChecked) + { + GetGamepadManager()->AddProvider(new GamepadProvider60Beat); + GetBaseApp()->SetAllowScreenDimming(false); + GetApp()->RemoveAndAttachAllAvailableGamepads(); + } else + { + //GetBaseApp()->SetAllowScreenDimming(true); + } + } + */ +#endif + + if (pEntClicked->GetName() == "Back") + { + RemoveFocusIfNeeded(pMenu); + ZoomToPositionEntity(pMenu, CL_Vec2f(GetScreenSizeXf(),0), 500); //slide up + KillEntity(pMenu, 500); + AddFocusIfNeeded(pMenu->GetParent(), true, 500); + } + + if (pEntClicked->GetName() == "sound_1") + { + GetApp()->GetShared()->GetVar("sound")->Set(uint32(1)); + GetAudioManager()->SetSoundEnabled(true); + + //restart music if applicable + bool bMusicDisabled = GetApp()->GetShared()->GetVar("musicDisabled")->GetUINT32() != 0; + + if (GetDinkGameState() == DINK_GAME_STATE_PLAYING) + { + } else + { + PlayMenuMusic(); + } + + UpdateOptionsGUI(); + + return; + } + if (pEntClicked->GetName() == "sound_0") + { + GetApp()->GetShared()->GetVar("sound")->Set(uint32(0)); + GetAudioManager()->SetSoundEnabled(false); + GetAudioManager()->StopMusic(); + UpdateOptionsGUI(); + return; + } + + if (pEntClicked->GetName() == "FPS") + { + GetBaseApp()->SetFPSVisible(!GetBaseApp()->GetFPSVisible()); + return; + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +void OnProgressChangedMusic(Variant *pDataObject) +{ + float musicVol = pDataObject->GetFloat(); + GetApp()->GetVar("music_vol")->Set(musicVol); + //LogMsg("Music vol changed to %.2f", musicVol); + GetAudioManager()->SetMusicVol(musicVol); +} + +void OnProgressChangedGUI(Variant *pDataObject) +{ + float guiTrans = pDataObject->GetFloat(); + GetApp()->GetVar("gui_transparency")->Set(guiTrans); + UpdateOptionsGUI(); +} + + +void UpdateOptionsGUI() +{ + float alpha = GetApp()->GetVar("gui_transparency")->GetFloat(); + + Entity *inventoryIcon = GetEntityRoot()->GetEntityByName("options_inventory"); + + if (inventoryIcon) + { + inventoryIcon->GetVar("alpha")->Set( alpha); + } + + bool bSound = GetApp()->GetShared()->GetVar("sound")->GetUINT32() != 0; + + if (bSound) + { + //enable the music slider + } + +} + +void OptionsMenuAddScrollContent(Entity *pParent) +{ + pParent = pParent->GetEntityByName("scroll_child"); + pParent->RemoveAllEntities(); + + Entity *pBG = pParent; + + Entity *pEnt; + float y = iPhoneMapY(70); + float startX = iPhoneMapX(28); + float offsetX = iPhoneMapX(0); + float spacerX = iPhoneMapX(46); + float spacerY = iPhoneMapY(40); + float columnX = 140; + + eFont fontID = FONT_SMALL; + + //title at the top + pEnt = CreateTextLabelEntity(pBG, "title", GetScreenSizeXf()/2, iPhoneMapY(40), "Options"); + SetupTextEntity(pEnt, FONT_LARGE); + SetAlignmentEntity(pEnt, ALIGNMENT_CENTER); + + if (IsDesktop()) + { + pEnt = CreateTextButtonEntity(pBG, "toggle_fullscreen", startX, y, "Toggle fullscreen (or Alt-Enter)"); + pEnt->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + y += spacerY; + + pEnt = CreateTextButtonEntity(pBG, "vid_small", startX, y, "640X480"); + pEnt->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + + pEnt = CreateTextButtonEntity(pBG, "vid_med", startX+350, y, "1024X768"); + pEnt->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + + pEnt = CreateTextButtonEntity(pBG, "vid_big", startX+700, y, "1280X960"); + pEnt->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + y += spacerY; + + } + + //control method + + if (GetApp()->GetUsingTouchScreen()) + { + + pEnt = CreateTextLabelEntity(pBG, "", startX, y, "Controls:"); + SetupTextEntity(pEnt,fontID); + offsetX = iPhoneMapX(columnX); + pEnt = CreateTextButtonEntity(pBG, "controls_0", offsetX, y, "Virtual Joypad", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + + float smallSpacerX = spacerX; + if (IsIPADSize) + { + smallSpacerX = 34; + } + offsetX += pEnt->GetVar("size2d")->GetVector2().x + smallSpacerX; + + pEnt = CreateTextButtonEntity(pBG, "controls_1", offsetX, y, "Drag Anywhere", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + smallSpacerX; + + if (IsIPADSize) + { + pEnt = CreateTextButtonEntity(pBG, "controls_2", offsetX, y, "Fling Mode", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + smallSpacerX; + } + + uint32 controlsID = GetApp()->GetVar("controlStyle")->GetUINT32(); + SetupLightBarSelect(pBG, "controls_", controlsID, MAKE_RGBA(190, 0, 35, 255)); + + y += spacerY; + y += spacerY; + + + /* + if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) + { + bool bUse60Beat = GetApp()->GetVar("check_60beat")->GetUINT32() != 0; + pEnt = CreateCheckbox(pBG, "check_60beat", "Use 60beat® GamePad", startX, y, bUse60Beat, FONT_SMALL, 1.0f); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + + //add the image to the right + CL_Sizef vCheckBoxSizeWithText = MeasureEntityAndChildren(pEnt).get_size(); + offsetX = startX + vCheckBoxSizeWithText.width+iPhoneMapX(20); + + Entity *pAd = CreateOverlayButtonEntity(pBG, "sbeat_ad", "interface/sixtybeat_ad.rttex", offsetX, y+vCheckBoxSizeWithText.height/2); + pAd->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + + SetAlignmentEntity(pAd, ALIGNMENT_LEFT_CENTER); + //We don't want it too big, scale it down if needed + EntityScaleiPad(pAd, true); + y += GetSize2DEntity(pAd).y; + //y += spacerY; + } + + */ + + + //********* icade option + + string bName = "iCade Controller Mode"; + + if (GetEmulatedPlatformID() == PLATFORM_ID_IOS) + { + //bName = "Bluetooth Arcade Stick Mode"; + } + + bool bUseicade = GetApp()->GetVar("check_icade")->GetUINT32() != 0; + pEnt = CreateCheckbox(pBG, "check_icade", "Use "+bName, startX, y, bUseicade, FONT_SMALL, 1.0f); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + y += GetSize2DEntity(pEnt).y; + y += spacerY; + + + pEnt = CreateTextLabelEntity(pBG, "", startX, y, "GUI Icons:"); + SetupTextEntity(pEnt,fontID); + offsetX = iPhoneMapX(columnX); + pEnt = CreateTextButtonEntity(pBG, "buttons_0", offsetX, y, "Right side", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + pEnt = CreateTextButtonEntity(pBG, "buttons_1", offsetX, y, "Left side", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + uint32 buttons = GetApp()->GetVar("buttons")->GetUINT32(); + SetupLightBarSelect(pBG, "buttons_", buttons, MAKE_RGBA(190, 0, 35, 255)); + y += spacerY; + } + + + + bool bStretchToFit = GetApp()->GetVar("check_stretch")->GetUINT32() != 0; + pEnt = CreateCheckbox(pBG, "check_stretch", "Force screen stretching (ignore aspect ratio)", startX, y, bStretchToFit, FONT_SMALL, 1.0f); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + y += GetSize2DEntity(pEnt).y; + y += spacerY; + + + + //fps limit + pEnt = CreateTextLabelEntity(pBG, "", startX, y, "FPS lock:"); + SetupTextEntity(pEnt,fontID); + offsetX = iPhoneMapX(columnX); + pEnt = CreateTextButtonEntity(pBG, "fps_limit_0", offsetX, y, "On", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + pEnt = CreateTextButtonEntity(pBG, "fps_limit_1", offsetX, y, "Off", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + uint32 videoFPS = GetApp()->GetVar("fpsLimit")->GetUINT32(); + SetupLightBarSelect(pBG, "fps_limit_", videoFPS, MAKE_RGBA(190, 0, 35, 255)); + + if (GetPlatformID() != PLATFORM_ID_IOS) + { + y += spacerY; + //audio on/off button + + pEnt = CreateTextLabelEntity(pBG, "", startX, y, "Audio:"); + SetupTextEntity(pEnt,fontID); + offsetX = iPhoneMapX(columnX); + pEnt = CreateTextButtonEntity(pBG, "sound_1", offsetX, y, "On", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + pEnt = CreateTextButtonEntity(pBG, "sound_0", offsetX, y, "Off", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + bool bSound = GetApp()->GetShared()->GetVar("sound")->GetUINT32() != 0; + SetupLightBarSelect(pBG, "sound_", bSound, MAKE_RGBA(190, 0, 35, 255)); + } + + //music vol slider + y += spacerY+iPhoneMapY2X(26); + EntityComponent *pSliderComp = CreateSlider(pBG, startX, y, iPhoneMapX(360), "interface/slider_button.rttex", "Min", "Music volume", "Max"); + pSliderComp->GetVar("progress")->Set( GetApp()->GetVar("music_vol")->GetFloat()); + pSliderComp->GetVar("progress")->GetSigOnChanged()->connect(&OnProgressChangedMusic); + + //transparency slider + if (GetApp()->GetUsingTouchScreen()) + { + y += spacerY+iPhoneMapY2X(36); + pSliderComp = CreateSlider(pBG, startX, y, iPhoneMapX(360), "interface/slider_button.rttex", "Min", "Game Interface Visibility", "Max"); + + //a thing to visually show them how much alpha they've set it too + Entity *pChest = CreateOverlayEntity(pBG, "options_inventory", ReplaceWithLargeInFileName("interface/iphone/button_inventory.rttex"), startX+iPhoneMapX(363), y-iPhoneMapY(34)); + SetAlignmentEntity(pChest, ALIGNMENT_UPPER_LEFT); + UpdateOptionsGUI(); + + pSliderComp->GetVar("progress")->Set( GetApp()->GetVar("gui_transparency")->GetFloat()); + pSliderComp->GetVar("progress")->GetSigOnChanged()->connect(&OnProgressChangedGUI); + y += spacerY; + } else + { + y += spacerY; + + } + +//if (GetPlatformID() != PLATFORM_ID_IOS) +{ + //smoothing + pEnt = CreateTextLabelEntity(pBG, "", startX, y, "Pic smoothing:"); + SetupTextEntity(pEnt,fontID); + offsetX = iPhoneMapX(columnX); + pEnt = CreateTextButtonEntity(pBG, "smoothing_0", offsetX, y, "On", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + pEnt = CreateTextButtonEntity(pBG, "smoothing_1", offsetX, y, "Off", false); + SetupTextEntity(pEnt,fontID); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(OptionsMenuOnSelect); + offsetX += pEnt->GetVar("size2d")->GetVector2().x + spacerX; + + uint32 smoothing = !GetApp()->GetVar("smoothing")->GetUINT32(); + SetupLightBarSelect(pBG, "smoothing_", smoothing, MAKE_RGBA(190, 0, 35, 255)); + + //show fps + y += spacerY; + pEnt = CreateTextButtonEntity(pBG, "FPS",startX, y, "Toggle FPS Display"); + pEnt->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); +} + + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); +} + +Entity * OptionsMenuCreate( Entity *pParentEnt) +{ + Entity *pBG = CreateOverlayEntity(pParentEnt, "OptionsMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + AddFocusIfNeeded(pBG, true, 500); + +//add the header + + CL_Vec2f vTextAreaPos = iPhoneMap(2,10); + float offsetFromBottom = iPhoneMapY(42); + float offsetFromRight = iPhoneMapY(0); + + CL_Vec2f vTextAreaBounds = (GetScreenSize()- CL_Vec2f(offsetFromRight,offsetFromBottom))-vTextAreaPos; + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("pos2d")->Set(vTextAreaPos); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + //pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + + /* + //too slow/broken on Android, we'll do it another way + EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + */ + + Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + OptionsMenuAddScrollContent(pBG); + // ZoomFromPositionEntity(pBG, CL_Vec2f(0, -GetScreenSizeYf()), 500); + //the continue button + Entity *pEnt; + + //pEnt = CreateOverlayRectEntity(pBG, CL_Rectf(0, GetScreenSizeYf()-offsetFromBottom, GetScreenSizeXf(), 320), MAKE_RGBA(0,0,0,100)); + + eFont fontID = FONT_SMALL; + + pEnt = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(5), iPhoneMapY(BACK_BUTTON_Y), "Back", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&OptionsMenuOnSelect); + SetupTextEntity(pEnt, fontID); + AddHotKeyToButton(pEnt, VIRTUAL_KEY_BACK); + + ZoomFromPositionEntity(pBG, CL_Vec2f( GetScreenSizeXf(),0), 500); + + return pBG; +} + diff --git a/source/GUI/OptionsMenu.h b/source/GUI/OptionsMenu.h new file mode 100644 index 0000000..d8731f7 --- /dev/null +++ b/source/GUI/OptionsMenu.h @@ -0,0 +1,9 @@ +#ifndef OptionsMenu_h__ +#define OptionsMenu_h__ + +#include "App.h" + + + +Entity * OptionsMenuCreate(Entity *pParentEnt); +#endif // OptionsMenu_h__ \ No newline at end of file diff --git a/source/GUI/ParticleTestMenu.cpp b/source/GUI/ParticleTestMenu.cpp new file mode 100644 index 0000000..ff42a08 --- /dev/null +++ b/source/GUI/ParticleTestMenu.cpp @@ -0,0 +1,39 @@ +#include "ParticleTestMenu.h" +#include "Entity/EntityUtils.h" +#include "MainMenu.h" +#include "Component/ParticleTestComponent.h" + +void ParticleTestOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + MainMenuCreate(pEntClicked->GetParent()->GetParent()); + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + +Entity * ParticleTestCreate(Entity *pParentEnt) +{ + Entity *pBG = CreateOverlayEntity(pParentEnt, "ParticleTest", "interface/generic_bg.rttex", 0,0); + AddFocusIfNeeded(pBG); + + Entity *pParticleEnt = pBG->AddEntity(new Entity(new ParticleTestComponent)); + + Entity *pButtonEntity; + pButtonEntity = CreateTextButtonEntity(pBG, "Back", 240, 290, "Back"); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&ParticleTestOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + SlideScreen(pBG, true); + + + return pBG; +} + diff --git a/source/GUI/ParticleTestMenu.h b/source/GUI/ParticleTestMenu.h new file mode 100644 index 0000000..ae96f1e --- /dev/null +++ b/source/GUI/ParticleTestMenu.h @@ -0,0 +1,7 @@ +#ifndef ParticleTest_h__ +#define ParticleTest_h__ + +#include "App.h" + +Entity * ParticleTestCreate(Entity *pParentEnt); +#endif // ParticleTest_h__ \ No newline at end of file diff --git a/source/GUI/PauseMenu.cpp b/source/GUI/PauseMenu.cpp new file mode 100644 index 0000000..14ae544 --- /dev/null +++ b/source/GUI/PauseMenu.cpp @@ -0,0 +1,421 @@ +#include "PlatformPrecomp.h" +#include "PauseMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "MainMenu.h" +#include "DebugMenu.h" +#include "GameMenu.h" +#include "DMODMenu.h" +#include "OptionsMenu.h" +#include "PopUpMenu.h" +#include "Entity/SelectButtonWithCustomInputComponent.h" + +void PlayMenuMusic() +{ + GetAudioManager()->Play("dink/sound/3.ogg", true, true, true); +} + +Entity * DinkQuitGame() +{ + + SetDinkGameState(DINK_GAME_STATE_NOT_PLAYING); + + Entity *pMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + + assert(pMenu); + if (!pMenu) return NULL; + + GetBaseApp()->SetGameTickPause(false); + //AddFocusIfNeeded(pMenu); + + SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + + Entity *pFinalMenu = NULL; + + if (g_dglo.m_dmodGameDir.empty()) + { + pFinalMenu = MainMenuCreate(pMenu->GetParent(), true); + } else + { + pFinalMenu = DMODMenuCreate(pMenu->GetParent(), true); + } + + PlayMenuMusic(); + return pFinalMenu; +} + +Entity * DinkRestartGame() +{ + + SetDinkGameState(DINK_GAME_STATE_NOT_PLAYING); + + Entity *pMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + + assert(pMenu); + if (!pMenu) return NULL; + + GetBaseApp()->SetGameTickPause(false); + AddFocusIfNeeded(pMenu); + + string dmodDirAndPath = RemoveTrailingBackslash(g_dglo.m_dmodGamePathWithDir); + + LogMsg("Restarting dmod %s", dmodDirAndPath.c_str()); + InitDinkPaths(GetBaseAppPath(), "dink", dmodDirAndPath); + //SlideScreen(pMenu, false); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + + Entity *pFinalMenu = NULL; + GameCreate(pMenu->GetParent(), 0, "", "Restarting..."); + /* + if (g_dglo.m_dmodGameDir.empty()) + { + pFinalMenu = MainMenuCreate(pMenu->GetParent(), true); + } else + { + pFinalMenu = DMODMenuCreate(pMenu->GetParent(), true); + } + + + PlayMenuMusic(); + */ + return pFinalMenu; +} + +void PauseEnd(Entity *pMenu) +{ + //slide it off the screen and then kill the whole menu tree + RemoveFocusIfNeeded(pMenu); + DisableAllButtonsEntity(pMenu); + //SlideScreen(pEntClicked->GetParent(), false); + AddFocusIfNeeded(pMenu->GetParent()); + FadeOutEntity(pMenu, true, 499); + GetMessageManager()->CallEntityFunction(pMenu, 500, "OnDelete", NULL); + GetBaseApp()->SetGameTickPause(false); + +} + +void PrepareForPopup(Entity *pMainMenuEnt, VariantList *pVList) +{ + SendFakeInputMessageToEntity(GetEntityRoot(), MESSAGE_TYPE_GUI_CLICK_END, pVList->m_variant[0].GetVector2()); //otherwise the menu may never get the touch release message + pMainMenuEnt->RemoveComponentByName("FocusInput"); + pMainMenuEnt->RemoveComponentByName("FocusUpdate"); + GetMessageManager()->RemoveComponentByName(pMainMenuEnt, 500, "FocusRender"); +} + +void UpdatePauseButtons(Entity *pMenu) +{ + Entity *pEnt = pMenu->GetEntityByName("QuickLoad"); + + if (!pEnt) + { + assert(0); + return; + } + unsigned int color = MAKE_RGBA(255,255,255,255); + + if (!FileExists(DinkGetSavePath()+"quicksave.dat")) + { + + //we'll, let's make it look not highlighted + color = MAKE_RGBA(255,255,255,100); + + } + + MorphToColorEntity(pEnt, false, 500, color, 0); +} + + +void PauseMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity", pEntClicked->GetName().c_str()); + + Entity *pMenu = GetEntityRoot()->GetEntityByName("PauseMenu"); + + if (pEntClicked->GetName() == "Back") + { + GetAudioManager()->Play("audio/pause_close.wav"); + PauseEnd(pMenu); + } + + if (pEntClicked->GetName() == "OldOptions") + { + PauseEnd(pMenu); + + g_dglo.m_dirInput[DINK_INPUT_BUTTON5] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON5] = true; + } + + if (pEntClicked->GetName() == "Map") + { + PauseEnd(pMenu); + + g_dglo.m_dirInput[DINK_INPUT_BUTTON6] = true; + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON6] = true; + } + if (pEntClicked->GetName() == "Keyboard") + { + PauseEnd(pMenu); + + g_dglo.m_bFullKeyboardActive = true; + } + + if (pEntClicked->GetName() == "Quit") + { + //slide it off the screen and then kill the whole menu tree + RemoveFocusIfNeeded(pMenu); + SaveState(g_dglo.m_savePath+"continue_state.dat"); + WriteLastPathSaved(""); + //kill our state.dat if it existed, not needed now, this can exist if an iphone goes into suspend, but then is resumed + RemoveFile(GetSavePath()+"state.dat", false); + //SlideScreen(pEntClicked->GetParent()->GetParent(), false); + DinkQuitGame(); + } + + if (pEntClicked->GetName() == "Debug") + { + //overlay the debug menu over this one + pMenu->RemoveComponentByName("FocusInput"); + DebugMenuCreate(pMenu); + } + + if (pEntClicked->GetName() == "Options") + { + //overlay the debug menu over this one + PrepareForPopup(pMenu, pVList); + OptionsMenuCreate(pMenu); + } + if (pEntClicked->GetName() == "empty_cache") + { + DinkUnloadGraphicsCache(); + LogMsg("Cache emptied"); + } + + if (pEntClicked->GetName() == "QuickSave") + { + SaveStateWithExtra(); + UpdatePauseButtons(pMenu); + PauseEnd(pMenu); + + } + + if (pEntClicked->GetName() == "QuickLoad") + { + LogMsg("loading state"); + string fName = DinkGetSavePath()+"quicksave.dat"; + + if (FileExists(fName)) + { + + bool bSuccess = LoadState(fName, true); + + if (!bSuccess) + { + RemoveFile(fName, false); + GetAudioManager()->Play("audio/buzzer2.wav"); + PopUpCreate(pMenu, "Error loading save state. Probably an older version, sorry.", "", "cancel", "Continue", "", "", true); + } else + { + LoadStateWithExtra(); + PauseEnd(pMenu); + } + + } else + { + //disabled, play buzzer sound + GetAudioManager()->Play("audio/buzzer2.wav"); + } + + UpdatePauseButtons(pMenu); + + } + + GetEntityRoot()->PrintTreeAsText(); //useful for Pause +} + + +void OnPauseArcadeInput(VariantList *pVList) +{ + int vKey = pVList->Get(0).GetUINT32(); + bool bIsDown = pVList->Get(1).GetUINT32() != 0; + + //LogMsg("GameMenuArcade: Key %d, down is %d", vKey, int(bIsDown)); + + Entity *pQuickSaveEnt = GetEntityRoot()->GetEntityByName("QuickSave"); + Entity *pQuickLoadEnt = GetEntityRoot()->GetEntityByName("QuickLoad"); + + if (!EntityHasInputFocus(GetEntityRoot()->GetEntityByName("PauseMenu"))) + { + return; + } + + if (!bIsDown) + { + switch (vKey) + { + case VIRTUAL_KEY_DIR_LEFT: + BobEntityStop(pQuickSaveEnt); + break; + + case VIRTUAL_KEY_DIR_RIGHT: + BobEntityStop(pQuickLoadEnt); + break; + + } + } + + int bobAmount =iPadMapY(40); + int bobCycleMS = 300; + + if (bIsDown) + { + switch (vKey) + { + case VIRTUAL_KEY_DIR_LEFT: + + BobEntity(pQuickSaveEnt, bobAmount, 0, bobCycleMS); + break; + + case VIRTUAL_KEY_DIR_RIGHT: + BobEntity(pQuickLoadEnt, bobAmount, 0, bobCycleMS); + break; + + case VIRTUAL_KEY_GAME_FIRE: + case VIRTUAL_KEY_GAME_INVENTORY: + case VIRTUAL_KEY_GAME_TALK: + + if ( IsEntityBobbing(pQuickSaveEnt) ) + { + FakeClickAnEntity(pQuickSaveEnt); + } else if (IsEntityBobbing(pQuickLoadEnt) ) + { + FakeClickAnEntity(pQuickLoadEnt); + } else + { + GetAudioManager()->Play("audio/buzzer2.wav"); + } + break; + default: ; + } + } +} + +Entity * PauseMenuCreate(Entity *pParentEnt) +{ + + //Entity *pBG = pParentEnt->AddEntity(new Entity("PauseMenu")); + Entity * pBG = CreateOverlayRectEntity(pParentEnt, CL_Vec2f(0,0), GetScreenSize(), MAKE_RGBA(0,0,0,140)); + pBG->SetName("PauseMenu"); + + //so we can snag gamepad messages too: + GetBaseApp()->m_sig_arcade_input.connect(pBG->GetFunction("OnArcadeInput")->sig_function); + pBG->GetShared()->GetFunction("OnArcadeInput")->sig_function.connect(&OnPauseArcadeInput); + + + Entity * pBackdrop = CreateOverlayRectEntity(pBG, CL_Vec2f(0,0), CL_Vec2f(0,0), MAKE_RGBA(0,0,0,140)); + Entity *pTextBG = pBG->AddEntity(new Entity("PauseTextBG")); + + GetAudioManager()->Play("audio/pause_open.wav"); + + pBackdrop->GetVar("pos2d")->Set(GetScreenSize()/2); + pTextBG->GetVar("pos2d")->Set(GetScreenSize()/2+CL_Vec2f(0,iPhoneMapY(-30))); + GetBaseApp()->SetGameTickPause(true); + AddFocusIfNeeded(pBG, true); + KillControls(); + + g_dglo.m_bLastFullKeyboardActive = false; + + Entity *pButtonEntity; + float x = 0; + float y = iPhoneMapX(-70); + float ySpacer = iPhoneMapY(40); + eFont fontID = FONT_SMALL; + float fontScale = 1; + + pButtonEntity = CreateTextButtonEntity(pBG , "Debug", iPhoneMapX(440), iPhoneMapY(20), "Cheats", false); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + //pButtonEntity->GetVar("color")->Set(MAKE_RGBA(0,0,0,0)); + + //quick save/load buttons first + + pButtonEntity = CreateOverlayButtonEntity(pBG , "QuickSave", ReplaceWithLargeInFileName("interface/iphone/button_quicksave.rttex"), iPhoneMapX(85), GetScreenSizeYf()/2); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + + pButtonEntity = CreateOverlayButtonEntity(pBG , "QuickLoad", ReplaceWithLargeInFileName("interface/iphone/button_quickload.rttex"), iPhoneMapX(395), GetScreenSizeYf()/2); + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + UpdatePauseButtons(pBG); + + pButtonEntity = CreateTextButtonEntity(pTextBG, "Map", x, y, "VIEW MAP", false); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + SetupTextEntity(pButtonEntity, fontID, fontScale); + if (!DinkCanRunScriptNow()) + { + pButtonEntity->GetVar("color")->Set(MAKE_RGBA(255,255,255,50)); + } + + pButtonEntity = CreateTextButtonEntity(pTextBG, "OldOptions", x, y, "DINK MENU", false); y += ySpacer; + pButtonEntity->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + SetupTextEntity(pButtonEntity, fontID, fontScale); + + if (!DinkCanRunScriptNow()) + { + pButtonEntity->GetVar("color")->Set(MAKE_RGBA(255,255,255,50)); + } + + if (GetApp()->GetUsingTouchScreen()) + { + pButtonEntity = CreateTextButtonEntity(pTextBG, "Keyboard", x, y, "FULL KEYBOARD", false); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + SetupTextEntity(pButtonEntity, fontID,fontScale); + } + + pButtonEntity = CreateTextButtonEntity(pTextBG, "Quit", x, y, "QUIT", false); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + + + SetupTextEntity(pButtonEntity, fontID, fontScale); + + pButtonEntity = CreateTextButtonEntity(pTextBG, "Options", x, y, "OPTIONS", false); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + SetupTextEntity(pButtonEntity, fontID,fontScale); + + pButtonEntity = CreateTextButtonEntity(pTextBG, "Back", x, y, "CONTINUE", false); y += ySpacer; + pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&PauseMenuOnSelect); + pButtonEntity->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + SetupTextEntity(pButtonEntity, fontID, fontScale); + SetButtonClickSound(pButtonEntity, ""); //no sound + + EntityComponent *pKeys = AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_BACK); + //work around problem of it instantly closing + pKeys->GetVar("disabled")->Set(uint32(1)); + GetMessageManager()->SetComponentVariable(pKeys, 500, "disabled", uint32(0)); //enable it again + + /* + pKeys = AddHotKeyToButton(pButtonEntity, VIRTUAL_KEY_PROPERTIES); + //work around problem of it instantly closing + pKeys->GetVar("disabled")->Set(uint32(1)); + GetMessageManager()->SetComponentVariable(pKeys, 1, "disabled", uint32(0)); //enable it again +*/ + + CL_Rectf size = MeasureEntityAndChildren(pTextBG); + + size.expand(iPhoneMapY(27)); + pBackdrop->GetVar("size2d")->Set(CL_Vec2f(size.get_width(), size.get_height())); + pBackdrop->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + FadeInEntity(pBG, true, 450); + return pBG; +} + diff --git a/source/GUI/PauseMenu.h b/source/GUI/PauseMenu.h new file mode 100644 index 0000000..6eddbd4 --- /dev/null +++ b/source/GUI/PauseMenu.h @@ -0,0 +1,10 @@ +#ifndef PauseMenu_h__ +#define PauseMenu_h__ + +#include "App.h" + +Entity * PauseMenuCreate(Entity *pParentEnt); +Entity * DinkQuitGame(); //kills dink and loads the appropriate last menu and returns a pointer to it +void PlayMenuMusic(); +Entity * DinkRestartGame(); +#endif // PauseMenu_h__ \ No newline at end of file diff --git a/source/GUI/PopUpMenu.cpp b/source/GUI/PopUpMenu.cpp new file mode 100644 index 0000000..9d8e0db --- /dev/null +++ b/source/GUI/PopUpMenu.cpp @@ -0,0 +1,251 @@ +#include "PlatformPrecomp.h" +#include "PopUpMenu.h" +#include "Entity/EntityUtils.h" +#include "App.h" + +Entity * PopUpRestoreFocusToOriginalMenu(Entity *pEntClicked) +{ + Entity *pFinishMenu = GetEntityRoot()->GetEntityByName(pEntClicked->GetParent()->GetParent()->GetVar("finishMenuName")->GetString()); + assert(pFinishMenu); + + if (pFinishMenu) + { + if (pEntClicked->GetParent()->GetParent()->GetVar("requireMoveMessages")->GetUINT32() == 1) + { + AddFocusIfNeeded(pFinishMenu, true, 0); + } else + { + pFinishMenu->AddComponent(new FocusInputComponent); + } + } + return pFinishMenu; +} + +void ReloadMainMenu(VariantList *pVList); + +//general purpose pop up menu, I've hardcoded various behaviors here, it knows what to do based on the button name + +void PopUpMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + + FadeOutEntity(pEntClicked->GetParent()->GetParent(), true, 300); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent()->GetParent(), 500, "OnDelete", NULL); + DisableAllButtonsEntity(pEntClicked->GetParent()->GetParent()); + Entity *pDarken = GetEntityRoot()->GetEntityByName("pop_up_darken"); + + FadeScreen(pDarken, 0, 0, 400, true); + KillEntity(pDarken, 400); + pDarken->SetName(""); + + //set the game pause state back to whatever it was originally + GetApp()->SetGameTickPause(pEntClicked->GetParent()->GetParent()->GetVar("gamePaused")->GetUINT32() != 0); + + + if (pEntClicked->GetName() == "url") + { + LogMsg("Launch url: %s", pEntClicked->GetVar("url")->GetString().c_str()); + LaunchURL(pEntClicked->GetVar("url")->GetString()); + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + } else if (pEntClicked->GetName() == "url_update") + { + LogMsg("Launch url: %s", pEntClicked->GetVar("url")->GetString().c_str()); + LaunchURL(pEntClicked->GetVar("url")->GetString()); + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + //kill current menu + //GetMessageManager()->CallEntityFunction(pFinishMenu, 200, "OnDelete", NULL); + + PopUpCreate(pFinishMenu, "Please close the game and install the new version!", "", "cancel", "", "", "", true); + + } + else + + /* + if (pEntClicked->GetName() == "music_disable") + { + //add control back + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + + GetApp()->GetShared()->GetVar("musicDisabled")->Set(uint32(1)); + GetAudioManager()->SetMusicEnabled(false); + + string msg = "Music disabled. You can re-enable it from the `wOptions`` menu later."; + PopUpCreate(pFinishMenu, msg, "", "cancel", "Continue", "", "", true); + GetAudioManager()->Play(GetApp()->GetMainMenuMusic(), true, true); //because music is disabled this won't play, but it will remember this if + //we enable music again so we still want it + + } else + + if (pEntClicked->GetName() == "music_on") + { + //add control back + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + GetAudioManager()->Play(GetApp()->GetMainMenuMusic(), true, true); + + } else + + if (pEntClicked->GetName() == "quit_game") + { + + Entity *pGameMenu = GetEntityRoot()->GetEntityByName("GameMenu"); + + //GetApp()->SetGameType(GAME_TYPE_NONE); + //slide it off the screen and then kill the whole menu tree + SlideScreen(pGameMenu, false, 500, 10); + GetMessageManager()->CallEntityFunction(pGameMenu, 900, "OnDelete", NULL); + //SummaryMenuCreate(pGameMenu->GetParent()); + GetBaseApp()->SetGameTickPause(false); + + + } else +*/ + + if (pEntClicked->GetName() == "cancel") + { + //add control back + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + }if (pEntClicked->GetName() == "cancel_update") + { + //add control back + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + //kill current menu + GetMessageManager()->CallEntityFunction(pFinishMenu, 100, "OnDelete", NULL); + + VariantList vList(pFinishMenu->GetParent()); + GetMessageManager()->CallStaticFunction(ReloadMainMenu, 200, &vList, TIMER_SYSTEM); + } + else + + if (pEntClicked->GetName() == "reset") + { + //add control back + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + GetAudioManager()->Play("audio/tip_start.wav"); + //GetHighScoreManager()->ResetLocalScores(); + //belay that order, show another pop up... + PopUpCreate(pFinishMenu, "Local high scores have been reset.", "", "cancel", "Continue", "", "", true); + + } else + { + //unhandled + Entity *pFinishMenu = PopUpRestoreFocusToOriginalMenu(pEntClicked); + + //call this function on the original guy, just in case they want to do something with it + VariantList vList(pFinishMenu, pEntClicked->GetName()); + pFinishMenu->GetFunction(pEntClicked->GetName())->sig_function(&vList); + + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + +void PopUpCreate(Entity *pEnt, string msg, string url, string button1Action, string button1Label, string button2Action, string button2Label, + bool bRequireMoveMessages, string button3Action, string button3Label) +{ + pEnt->RemoveComponentByName("FocusInput"); + + bool bGamePaused = GetBaseApp()->GetGameTickPause(); + GetBaseApp()->SetGameTickPause(true); + // GetMessageManager()->RemoveComponentByName(pEnt, 201, "FocusInput"); //hack that works around a problem of pending FocusInput messages coming in + + //remember where we should give focus to later + string parentName = pEnt->GetName(); + assert(!parentName.empty()); + + //let's build our own menu right on the GUI branch of the tree + pEnt = GetEntityRoot()->GetEntityByName("GUI"); + Entity *pDarken = pEnt->AddEntity(new Entity("pop_up_darken")); + pDarken->AddComponent(new FocusRenderComponent); + pDarken->AddComponent(new FocusUpdateComponent); + FadeScreen(pDarken, 0, 0.7, 400, false); //fade the whole GUI + + //add our prompt + Entity *pBG = CreateOverlayEntity(pEnt, "pop_up", ReplaceWithLargeInFileName("interface/iphone/pop_up.rttex"), 0,0); + + //Ok, at this point we can check the image dimensions and center it based on the bitmap size itself + pBG->GetVar("pos2d")->Set( (GetScreenSize()/2) - pBG->GetVar("size2d")->GetVector2()/2); + + // pBG->AddComponent(new FocusInputComponent); + pBG->GetVar("finishMenuName")->Set(parentName); + + if (bRequireMoveMessages) + { + pBG->GetVar("requireMoveMessages")->Set(uint32(1)); + } + + AddFocusIfNeeded(pBG); + CL_Vec2f vTextArea = pBG->GetVar("size2d")->GetVector2(); + float padding = 30; + vTextArea.x -= iPhoneMapX2X(padding*2); + + //add our msg and word wrap it + Entity *pText = CreateTextBoxEntity(pBG, "pop_up_text", (pBG->GetVar("size2d")->GetVector2()/2)+CL_Vec2f(0, iPhoneMapY2X(-17)), vTextArea, msg); + SetAlignmentEntity(pText, ALIGNMENT_CENTER); + float textHeight = pText->GetVar("size2d")->GetVector2().y; + + FadeInEntity(pBG, true, 300); + + //pText->GetVar("color")->Set(MAKE_RGBA(203,177,137,255)); + + pBG->GetVar("gamePaused")->Set(uint32(bGamePaused != 0)); //remember this for later + Entity *pButton = NULL; + CL_Vec2f vButtonSize; + Entity *pLabel; + Entity *pButton1, *pButton2; + + float buttonHeight = iPhoneMapY2X(120); + if (textHeight > iPhoneMapY2X(50)) + { + //well, we need more space for this much text. Move the buttons down a bit. + buttonHeight = iPhoneMapY2X(135); + } + //add the buttons + pButton = CreateOverlayEntity(pBG, "button1", ReplaceWithLargeInFileName("interface/iphone/pop_up_button.rttex"), iPhoneMapX2X(21), buttonHeight); + pButton1 = pButton; + vButtonSize = pButton->GetVar("size2d")->GetVector2(); + //add the text label + pLabel = CreateTextButtonEntity(pButton, button1Action, vButtonSize.x/2, vButtonSize.y/2, "`w"+button1Label, false); + pLabel->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + pLabel->GetFunction("OnButtonSelected")->sig_function.connect(&PopUpMenuOnSelect); + pLabel->GetVar("url")->Set(url); //just in case we want to know this later, store it in the button itself + FadeInEntity(pButton, true, 300, 250); + if (button2Label.empty()) + { + //we only have one button? Fine, center it. + pButton->GetVar("pos2d")->Set(iPhoneMapX(88), buttonHeight); + } else + { + pButton = CreateOverlayEntity(pBG, "button2", ReplaceWithLargeInFileName("interface/iphone/pop_up_button.rttex"), iPhoneMapY2X(180), buttonHeight); + pButton2 = pButton; + vButtonSize = pButton->GetVar("size2d")->GetVector2(); + //add the text label + pLabel = CreateTextButtonEntity(pButton, button2Action, vButtonSize.x/2, vButtonSize.y/2, "`w"+button2Label, false); + pLabel->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + pLabel->GetFunction("OnButtonSelected")->sig_function.connect(&PopUpMenuOnSelect); + pLabel->GetVar("url")->Set(url); //just in case we want to know this later, store it in the button itself + FadeInEntity(pButton, true, 300, 350); + + if (button3Label.empty()) + { + //we only have two buttons? fine. Done then + } else + { + pButton1->GetVar("pos2d")->Set(iPhoneMapX2X(20), buttonHeight); + pButton2->GetVar("pos2d")->Set(iPhoneMapX2X(180), buttonHeight); + + //move stuff around and add a third button + pButton = CreateOverlayEntity(pBG, "button2", ReplaceWithLargeInFileName("interface/iphone/pop_up_button.rttex"), iPhoneMapX2X(100), buttonHeight); + vButtonSize = pButton->GetVar("size2d")->GetVector2(); + //add the text label + pLabel = CreateTextButtonEntity(pButton, button3Action, vButtonSize.x/2, vButtonSize.y/2, "`w"+button3Label, false); + pLabel->GetVar("alignment")->Set(uint32(ALIGNMENT_CENTER)); + pLabel->GetFunction("OnButtonSelected")->sig_function.connect(&PopUpMenuOnSelect); + pLabel->GetVar("url")->Set(url); //just in case we want to know this later, store it in the button itself + FadeInEntity(pButton, true, 300, 450); + } + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} diff --git a/source/GUI/PopUpMenu.h b/source/GUI/PopUpMenu.h new file mode 100644 index 0000000..be79ff6 --- /dev/null +++ b/source/GUI/PopUpMenu.h @@ -0,0 +1,7 @@ +#ifndef PopUpMenu_h__ +#define PopUpMenu_h__ +#include "PlatformSetup.h" +class Entity; +void PopUpCreate(Entity *pEnt, string msg, string url, string button1Action, string button1Label, string button2Action , string button2Label, + bool bRequireMoveMessages, string button3Action= "", string button3Label=""); +#endif // PopUpMenu_h__ diff --git a/source/GUI/QuickTipMenu.cpp b/source/GUI/QuickTipMenu.cpp new file mode 100644 index 0000000..8ad44a2 --- /dev/null +++ b/source/GUI/QuickTipMenu.cpp @@ -0,0 +1,122 @@ +#include "PlatformPrecomp.h" +#include "QuickTipMenu.h" +#include "App.h" +#include "Entity/EntityUtils.h" +#include "Entity/SelectButtonWithCustomInputComponent.h" + +void QuickTipMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + DisableAllButtonsEntity(pEntClicked->GetParent()); + + GetAudioManager()->Play("audio/tip_end.wav"); + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + GetEntityRoot()->PrintTreeAsText(); //useful for debugging + Entity *pDarken = GetEntityRoot()->GetEntityByName("pop_up_darken"); + FadeScreen(pDarken, 0, 0, 400, true); + KillEntity(pDarken, 400); + pDarken->SetName(""); + + //set the game pause state back to whatever it was originally + GetApp()->SetGameTickPause(pEntClicked->GetParent()->GetParent()->GetVar("gamePaused")->GetUINT32() != 0); + + if (pEntClicked->GetName() == "continue") + { + //slide it off the screen and then kill the whole menu tree + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + + Entity *pFinishMenu = GetEntityRoot()->GetEntityByName(pEntClicked->GetParent()->GetVar("finishMenuName")->GetString()); + assert(pFinishMenu); + if (pFinishMenu) + { + if (pEntClicked->GetParent()->GetVar("requireMoveMessages")->GetUINT32() == 1) + { + AddFocusIfNeeded(pFinishMenu, true, 100); + } else + { + AddFocusIfNeeded(pFinishMenu, false, 100); + } + } + + return; + } + +} + +Entity * CreateQuickTipFirstTimeOnly(Entity *pParentEnt, string tipFileName, bool bRequireMoveMessages) +{ + //we access the app database to make sure this is only shown once + string key = "tip_"+tipFileName; + +#ifdef _DEBUG + //cheat to always show quicktips + GetApp()->GetShared()->DeleteVarsStartingWith("tip_"); //for testing +#endif + + if (GetApp()->GetShared()->GetVarIfExists(key)) + { + return NULL; //already showed this I guess + } + + //mark it as shown + GetApp()->GetVar(key)->Set("shown"); + return CreateQuickTip(pParentEnt, tipFileName, bRequireMoveMessages); +} + +Entity * CreateQuickTip(Entity *pParentEnt, string tipFileName, bool bRequireMoveMessages) +{ + tipFileName = ReplaceWithLargeInFileNameAndOSSpecific(tipFileName); + + pParentEnt->RemoveComponentByName("FocusInput"); + + bool bGamePaused = GetBaseApp()->GetGameTickPause(); + GetBaseApp()->SetGameTickPause(true); + + Entity *pEnt; + //let's build our own menu right on the GUI branch of the tree + pEnt = GetEntityRoot()->GetEntityByName("GUI"); + Entity *pDarken = pEnt->AddEntity(new Entity("pop_up_darken")); + pDarken->AddComponent(new FocusRenderComponent); + pDarken->AddComponent(new FocusUpdateComponent); + FadeScreen(pDarken, 0, 0.5, 400, false); //fade the whole GUI + + Entity *pBG = CreateOverlayEntity(GetEntityRoot()->GetEntityByName("GUI"), "QuickTipMenu", "", 0,0); + + SurfaceAnim *pSurf = new SurfaceAnim; + pSurf->LoadFile(tipFileName); + + OverlayRenderComponent *pOverlay = (OverlayRenderComponent*) pBG->GetComponentByName("OverlayRender"); + pOverlay->SetSurface(pSurf, true); + + + if (bRequireMoveMessages) + { + pBG->GetVar("requireMoveMessages")->Set(uint32(1)); + } + CL_Vec2f vSize = pBG->GetVar("size2d")->GetVector2(); + + pBG->GetVar("pos2d")->Set( (GetScreenSize()/2) - (vSize/2) ); + pBG->GetVar("gamePaused")->Set(uint32(bGamePaused != 0)); //remember this for later + + string parentName = pParentEnt->GetName(); + assert(!parentName.empty()); + pBG->GetVar("finishMenuName")->Set(parentName); + AddFocusIfNeeded(pBG, false, 1000); //don't allow input for a bit so they don't accidentally dismiss the tip + + Entity *pButtonEntity; + + //back button + pButtonEntity = CreateButtonHotspot(pBG, "continue", CL_Vec2f(0,0), GetScreenSize()); + + GetMessageManager()->AddComponent(pButtonEntity, 1000, new SelectButtonWithCustomInputComponent); + + //pButtonEntity = CreateOverlayButtonEntity(pBG, "continue", "interface/quicktips/tip_continue.rttex", 178, 184); + pButtonEntity->GetFunction("OnButtonSelected")->sig_function.connect(&QuickTipMenuOnSelect); + SlideScreen(pBG, true); + GetEntityRoot()->PrintTreeAsText(); //useful for debugging + //FadeInEntity(pBG, true, 300); + GetAudioManager()->Play("audio/tip_start.wav"); + + return pBG; +} diff --git a/source/GUI/QuickTipMenu.h b/source/GUI/QuickTipMenu.h new file mode 100644 index 0000000..2fbf352 --- /dev/null +++ b/source/GUI/QuickTipMenu.h @@ -0,0 +1,8 @@ +#ifndef QuickTipMenu_h__ +#define QuickTipMenu_h__ +#include "PlatformSetup.h" +class Entity; + +Entity * CreateQuickTipFirstTimeOnly(Entity *pParentEnt, string tipFileName, bool bRequireMoveMessages); +Entity * CreateQuickTip(Entity *pParentEnt, string tipFileName, bool bRequireMoveMessages); +#endif // QuickTipMenu_h__ \ No newline at end of file diff --git a/source/GUI/ReadTextMenu.cpp b/source/GUI/ReadTextMenu.cpp new file mode 100644 index 0000000..041722f --- /dev/null +++ b/source/GUI/ReadTextMenu.cpp @@ -0,0 +1,127 @@ +#include "PlatformPrecomp.h" +#include "ReadTextMenu.h" +#include "MainMenu.h" +#include "GameMenu.h" +#include "Entity/EntityUtils.h" +#include "dink/dink.h" +#include "PopUpMenu.h" +#include "util/TextScanner.h" +#include "DMODMenu.h" + + + +void ReadTextMenuAddScrollContent(Entity *pParent, TextScanner &t); + + +void ReadTextMenuOnSelect(VariantList *pVList) //0=vec2 point of click, 1=entity sent from +{ + Entity *pEntClicked = pVList->m_variant[1].GetEntity(); + LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[1].Print().c_str()); + Entity *pMenu = GetEntityRoot()->GetEntityByName("ReadTextMenu"); + + //LogMsg("Clicked %s entity at %s", pEntClicked->GetName().c_str(),pVList->m_variant[0].Print().c_str()); + + if (pEntClicked->GetName() == "Back") + { + DisableAllButtonsEntity(pMenu); + SlideScreen(pEntClicked->GetParent(), false); + GetMessageManager()->CallEntityFunction(pEntClicked->GetParent(), 500, "OnDelete", NULL); + DMODMenuCreate(pEntClicked->GetParent()->GetParent(), true); + return; + } + + GetEntityRoot()->PrintTreeAsText(); //useful for debugging +} + + +void ReadTextMenuAddScrollContent(Entity *pParent) +{ + TextScanner t(pParent->GetVar("textfile")->GetString(), false); + + pParent = pParent->GetEntityByName("scroll_child"); + + pParent->RemoveAllEntities(); + float x = 5; + float y = 0; + + //Entity *pEnt; + + CL_Vec2f vTextBoxPos(iPhoneMapX(20),iPhoneMapY(y)); + CL_Vec2f vTextBounds(iPhoneMapX(434), iPhoneMapY(200)); + + + CreateTextBoxEntity(pParent, "", vTextBoxPos, vTextBounds, t.GetAll()); + + VariantList vList(pParent->GetParent()); + ResizeScrollBounds(&vList); +} + + +void ReadTextOnPostIntroTransition(VariantList *pVList) +{ + Entity *pBG = pVList->Get(0).GetEntity(); + ReadTextMenuAddScrollContent(pBG); +} + +Entity * ReadTextMenuCreate( Entity *pParentEnt, string fileName, string prettyFileName ) +{ + + GetBaseApp()->ClearError(); + + Entity *pBG = NULL; + pBG = CreateOverlayEntity(pParentEnt, "ReadTextMenu", ReplaceWithDeviceNameInFileName("interface/iphone/bkgd_stone.rttex"), 0,0); + AddFocusIfNeeded(pBG, true, 500); + pBG->AddComponent(new FocusRenderComponent); + pBG->GetVar("textfile")->Set(fileName); + + CL_Vec2f vTextAreaPos = iPhoneMap(2,10); + float offsetFromBottom = iPhoneMapY(42); + float offsetFromRight = iPhoneMapY(0); + + CL_Vec2f vTextAreaBounds = (GetScreenSize()- CL_Vec2f(offsetFromRight,offsetFromBottom))-vTextAreaPos; + Entity *pScroll = pBG->AddEntity(new Entity("scroll")); + pScroll->GetVar("pos2d")->Set(vTextAreaPos); + pScroll->GetVar("size2d")->Set(vTextAreaBounds); + pScroll->AddComponent(new TouchHandlerComponent); + + + Entity *pLabel = CreateTextLabelEntity(pBG, "Reading "+prettyFileName, GetScreenSizeXf()/2, GetScreenSizeYf()/2, "Updating add-on ReadText list..."); + SetAlignmentEntity(pLabel, ALIGNMENT_CENTER); + FadeOutAndKillEntity(pLabel, true, 300, 501); + + + EntityComponent *pFilter = pScroll->AddComponent(new FilterInputComponent); + + EntityComponent *pScrollComp = pScroll->AddComponent(new ScrollComponent); + EntityComponent *pScrollBarComp = pScroll->AddComponent(new ScrollBarRenderComponent); //also let's add a visual way to see the scroller position + //pScroll->GetVar("color")->Set(MAKE_RGBA(61,155, 193, 255)); + Entity *pScrollChild = pScroll->AddEntity(new Entity("scroll_child")); + pScrollComp->GetVar("fingerTracking")->Set(uint32(1)); + + //EntityComponent *pClip = pScroll->AddComponent(new RenderClipComponent); + //pClip->GetVar("clipMode")->Set(uint32(RenderClipComponent::CLIP_MODE_BOTTOM)); + + Entity *pOverlay = CreateOverlayEntity(pBG, "", ReplaceWithDeviceNameInFileName("interface/iphone/bg_stone_overlay.rttex"), 0, GetScreenSizeYf()); + SetAlignmentEntity(pOverlay, ALIGNMENT_DOWN_LEFT); + + + // ZoomFromPositionEntity(pBG, CL_Vec2f(0, -GetScreenSizeYf()), 500); + //the continue button + Entity *pEnt; + + //pEnt = CreateOverlayRectEntity(pBG, CL_Rectf(0, GetScreenSizeYf()-offsetFromBottom, GetScreenSizeXf(), 320), MAKE_RGBA(0,0,0,100)); + + eFont fontID = FONT_SMALL; + + pEnt = CreateTextButtonEntity(pBG, "Back", iPhoneMapX(40), iPhoneMapY(BACK_BUTTON_Y), "Back", false); + pEnt->GetFunction("OnButtonSelected")->sig_function.connect(&ReadTextMenuOnSelect); + SetupTextEntity(pEnt, fontID); + AddHotKeyToButton(pEnt, VIRTUAL_KEY_BACK); + + SlideScreen(pBG, true, 500); + pBG->GetFunction("OnPostIntroTransition")->sig_function.connect(&ReadTextOnPostIntroTransition); + VariantList vList(pBG, string("")); + GetMessageManager()->CallEntityFunction(pBG, 500, "OnPostIntroTransition", &vList); + + return pBG; +} \ No newline at end of file diff --git a/source/GUI/ReadTextMenu.h b/source/GUI/ReadTextMenu.h new file mode 100644 index 0000000..a352457 --- /dev/null +++ b/source/GUI/ReadTextMenu.h @@ -0,0 +1,7 @@ +#ifndef ReadTextMenu_h__ +#define ReadTextMenu_h__ +#include "BaseApp.h" +Entity * ReadTextMenuCreate( Entity *pParentEnt, string fileName, string prettyFileName ); + + +#endif // ReadTextMenu_h__ \ No newline at end of file diff --git a/source/StackWalker/StackUtils.cpp b/source/StackWalker/StackUtils.cpp new file mode 100644 index 0000000..bf86dae --- /dev/null +++ b/source/StackWalker/StackUtils.cpp @@ -0,0 +1,122 @@ +#include "StackUtils.h" + +#include +#include + + +// For more info about "PreventSetUnhandledExceptionFilter" see: +// "SetUnhandledExceptionFilter" and VC8 +// http://blog.kalmbachnet.de/?postid=75 +// and +// Unhandled exceptions in VC8 and above… for x86 and x64 +// http://blog.kalmbach-software.de/2008/04/02/unhandled-exceptions-in-vc8-and-above-for-x86-and-x64/ +// Even better: http://blog.kalmbach-software.de/2013/05/23/improvedpreventsetunhandledexceptionfilter/ + + +class StackWalkerToConsole : public StackWalker +{ +protected: + virtual void OnOutput(LPCSTR szText) + { + LogMsg(szText); + } +}; + + +#if defined _M_X64 || defined _M_IX86 +static BOOL PreventSetUnhandledExceptionFilter() +{ + HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); + if (hKernel32 == NULL) return FALSE; + void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); + if (pOrgEntry == NULL) return FALSE; + +#ifdef _M_IX86 + // Code for x86: + // 33 C0 xor eax,eax + // C2 04 00 ret 4 + unsigned char szExecute[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; +#elif _M_X64 + // 33 C0 xor eax,eax + // C3 ret + unsigned char szExecute[] = { 0x33, 0xC0, 0xC3 }; +#else +#error "The following code only works for x86 and x64!" +#endif + + DWORD dwOldProtect = 0; + BOOL bProt = VirtualProtect(pOrgEntry, sizeof(szExecute), + PAGE_EXECUTE_READWRITE, &dwOldProtect); + + SIZE_T bytesWritten = 0; + BOOL bRet = WriteProcessMemory(GetCurrentProcess(), + pOrgEntry, szExecute, sizeof(szExecute), &bytesWritten); + + if ((bProt != FALSE) && (dwOldProtect != PAGE_EXECUTE_READWRITE)) + { + DWORD dwBuf; + VirtualProtect(pOrgEntry, sizeof(szExecute), dwOldProtect, &dwBuf); + } + return bRet; +} +#else +#pragma message("This code works only for x86 and x64!") +#endif + +static BOOL s_bUnhandledExeptionFilterSet = FALSE; +static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs) +{ +#ifdef _M_IX86 + if (pExPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + { + static char MyStack[1024 * 128]; // be sure that we have enought space... + // it assumes that DS and SS are the same!!! (this is the case for Win32) + // change the stack only if the selectors are the same (this is the case for Win32) + //__asm push offset MyStack[1024*128]; + //__asm pop esp; + __asm mov eax, offset MyStack[1024 * 128]; + __asm mov esp, eax; + } +#endif + + LogMsg("DINK CRASHED! STACK TRACE BELOW"); + LogMsg("---------------------------------------------------------"); + + StackWalkerToConsole sw; // output to console + sw.ShowCallstack(GetCurrentThread(), pExPtrs->ContextRecord); + + LogMsg("---------------------------------------------------------"); + + TCHAR lString[500]; + + + _stprintf_s(lString, + _T("Dink crashed! Info on where it crashed was written to %slog.txt. If you're a tester, give Seth that file so he can fix it!"), + GetBaseAppPath().c_str() + ); + + + FatalAppExit(-1, lString); + return EXCEPTION_CONTINUE_SEARCH; +} + +void InitUnhandledExceptionFilter() +{ + /* + TCHAR szModName[_MAX_PATH]; + if (GetModuleFileName(NULL, szModName, sizeof(szModName) / sizeof(TCHAR)) != 0) + { + _tcscpy_s(s_szExceptionLogFileName, szModName); + _tcscat_s(s_szExceptionLogFileName, _T(".exp.log")); + } + */ + if (s_bUnhandledExeptionFilterSet == FALSE) + { + // set global exception handler (for handling all unhandled exceptions) + SetUnhandledExceptionFilter(CrashHandlerExceptionFilter); +#if defined _M_X64 || defined _M_IX86 + PreventSetUnhandledExceptionFilter(); +#endif + s_bUnhandledExeptionFilterSet = TRUE; + } +} \ No newline at end of file diff --git a/source/StackWalker/StackUtils.h b/source/StackWalker/StackUtils.h new file mode 100644 index 0000000..4084d42 --- /dev/null +++ b/source/StackWalker/StackUtils.h @@ -0,0 +1,5 @@ +#pragma once +#include +#include "StackWalker.h" + +void InitUnhandledExceptionFilter(); \ No newline at end of file diff --git a/source/StackWalker/StackWalker.cpp b/source/StackWalker/StackWalker.cpp new file mode 100644 index 0000000..e61575a --- /dev/null +++ b/source/StackWalker/StackWalker.cpp @@ -0,0 +1,1365 @@ +/********************************************************************** + * + * StackWalker.cpp + * http://stackwalker.codeplex.com/ + * + * + * History: + * 2005-07-27 v1 - First public release on http://www.codeproject.com/ + * http://www.codeproject.com/threads/StackWalker.asp + * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack + * (to simplify the usage) + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL + * (should also be enough) + * - Changed to compile correctly with the PSDK of VC7.0 + * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: + * it uses LPSTR instead of LPCSTR as first paremeter) + * - Added declarations to support VC5/6 without using 'dbghelp.h' + * - Added a 'pUserData' member to the ShowCallstack function and the + * PReadProcessMemoryRoutine declaration (to pass some user-defined data, + * which can be used in the readMemoryFunction-callback) + * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default + * - Added example for doing an exception-callstack-walking in main.cpp + * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) + * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! + * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx + * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx + * Fixed Bug: Compiling with "/Wall" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx + * Fixed Bug: Now checking SymUseSymSrv + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx + * Fixed Bug: Support for recursive function calls + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx + * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx + * Fixed Bug: SymDia is number 7, not 9! + * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! + * Thanks to Teajay which reported the bug... + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx + * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory + * Thanks to Luiz Salamon which reported this "bug"... + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx + * 2009-04-10 v9 License slihtly corrected ( replaced) + * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ + * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available + * 2010-04-15 v12 Added support for VS2010 RTM + * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx + * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed: + * http://stackwalker.codeplex.com/workitem/10511 + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2013, Jochen Kalmbach + * All rights reserved. + * + * 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 Jochen Kalmbach 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 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. + * + **********************************************************************/ +#include +#include +#include +#include +#pragma comment(lib, "version.lib") // for "VerQueryValue" +#pragma warning(disable:4826) + +#include "StackWalker.h" + + +// If VC7 and later, then use the shipped 'dbghelp.h'-file +#pragma pack(push,8) +#if _MSC_VER >= 1300 +#include +#else +// inline the important dbghelp.h-declarations... +typedef enum { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, + SymDia, + SymVirtual, + NumSymTypes +} SYM_TYPE; +typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; +typedef struct _IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; +typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; +typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat +} ADDRESS_MODE; +typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64, *LPADDRESS64; +typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 Reserved[8]; +} KDHELP64, *PKDHELP64; +typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64, *LPSTACKFRAME64; +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead + ); +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( + HANDLE hProcess, + DWORD64 AddrBase + ); +typedef +DWORD64 +(__stdcall *PGET_MODULE_BASE_ROUTINE64)( + HANDLE hProcess, + DWORD64 Address + ); +typedef +DWORD64 +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( + HANDLE hProcess, + HANDLE hThread, + LPADDRESS64 lpaddr + ); +#define SYMOPT_CASE_INSENSITIVE 0x00000001 +#define SYMOPT_UNDNAME 0x00000002 +#define SYMOPT_DEFERRED_LOADS 0x00000004 +#define SYMOPT_NO_CPP 0x00000008 +#define SYMOPT_LOAD_LINES 0x00000010 +#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 +#define SYMOPT_LOAD_ANYTHING 0x00000040 +#define SYMOPT_IGNORE_CVREC 0x00000080 +#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 +#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 +#define SYMOPT_EXACT_SYMBOLS 0x00000400 +#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 +#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 +#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 +#define SYMOPT_PUBLICS_ONLY 0x00004000 +#define SYMOPT_NO_PUBLICS 0x00008000 +#define SYMOPT_AUTO_PUBLICS 0x00010000 +#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 +#define SYMOPT_SECURE 0x00040000 +#define SYMOPT_DEBUG 0x80000000 +#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration +#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; +#endif // _MSC_VER < 1300 +#pragma pack(pop) + +// Some missing defines (for VC5/6): +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + + +// secure-CRT_functions are only available starting with VC8 +#if _MSC_VER < 1400 +#define strcpy_s(dst, len, src) strcpy(dst, src) +#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src) +#define strcat_s(dst, len, src) strcat(dst, src) +#define _snprintf_s _snprintf +#define _tcscat_s _tcscat +#endif + +static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) +{ + if (nMaxDestSize <= 0) return; + strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE); + szDest[nMaxDestSize-1] = 0; // INFO: _TRUNCATE will ensure that it is nul-terminated; but with older compilers (<1400) it uses "strncpy" and this does not!) +} // MyStrCpy + +// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') +#define USED_CONTEXT_FLAGS CONTEXT_FULL + + +class StackWalkerInternal +{ +public: + StackWalkerInternal(StackWalker *parent, HANDLE hProcess) + { + m_parent = parent; + m_hDbhHelp = NULL; + pSC = NULL; + m_hProcess = hProcess; + m_szSymPath = NULL; + pSFTA = NULL; + pSGLFA = NULL; + pSGMB = NULL; + pSGMI = NULL; + pSGO = NULL; + pSGSFA = NULL; + pSI = NULL; + pSLM = NULL; + pSSO = NULL; + pSW = NULL; + pUDSN = NULL; + pSGSP = NULL; + } + ~StackWalkerInternal() + { + if (pSC != NULL) + pSC(m_hProcess); // SymCleanup + if (m_hDbhHelp != NULL) + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + m_parent = NULL; + if(m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + } + BOOL Init(LPCSTR szSymPath) + { + if (m_parent == NULL) + return FALSE; + // Dynamically load the Entry-Points for dbghelp.dll: + // First try to load the newsest one from + TCHAR szTemp[4096]; + // But before wqe do this, we first check if the ".local" file exists + if (GetModuleFileName(NULL, szTemp, 4096) > 0) + { + _tcscat_s(szTemp, _T(".local")); + if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) + { + // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" + // Ok, first try the new path according to the archtitecture: +#ifdef _M_IX86 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_X64 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_IA64 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + // If still not found, try the old directories... + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#if defined _M_X64 || defined _M_IA64 + // Still not found? Then try to load the (old) 64-Bit version: + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + } + } + if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one + m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") ); + if (m_hDbhHelp == NULL) + return FALSE; + pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" ); + pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" ); + + pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" ); + pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" ); + pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" ); + + pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" ); + pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" ); + pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" ); + pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); + pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" ); + pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" ); + pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" ); + pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" ); + + if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || + pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || + pSW == NULL || pUDSN == NULL || pSLM == NULL ) + { + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + pSC = NULL; + return FALSE; + } + + // SymInitialize + if (szSymPath != NULL) + m_szSymPath = _strdup(szSymPath); + if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) + this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); + + DWORD symOptions = this->pSGO(); // SymGetOptions + symOptions |= SYMOPT_LOAD_LINES; + symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; + //symOptions |= SYMOPT_NO_PROMPTS; + // SymSetOptions + symOptions = this->pSSO(symOptions); + + char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; + if (this->pSGSP != NULL) + { + if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) + this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); + } + char szUserName[1024] = {0}; + DWORD dwSize = 1024; + GetUserNameA(szUserName, &dwSize); + this->m_parent->OnSymInit(buf, symOptions, szUserName); + + return TRUE; + } + + StackWalker *m_parent; + + HMODULE m_hDbhHelp; + HANDLE m_hProcess; + LPSTR m_szSymPath; + +#pragma pack(push,8) +typedef struct IMAGEHLP_MODULE64_V3 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name + // new elements: 07-Jun-2002 + CHAR LoadedPdbName[256]; // pdb file name + DWORD CVSig; // Signature of the CV record in the debug directories + CHAR CVData[MAX_PATH * 3]; // Contents of the CV record + DWORD PdbSig; // Signature of PDB + GUID PdbSig70; // Signature of PDB (VC 7 and up) + DWORD PdbAge; // DBI age of pdb + BOOL PdbUnmatched; // loaded an unmatched pdb + BOOL DbgUnmatched; // loaded an unmatched dbg + BOOL LineNumbers; // we have line number information + BOOL GlobalSymbols; // we have internal symbol information + BOOL TypeInfo; // we have type information + // new elements: 17-Dec-2003 + BOOL SourceIndexed; // pdb supports source server + BOOL Publics; // contains public symbols +}; + +typedef struct IMAGEHLP_MODULE64_V2 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +}; +#pragma pack(pop) + + + // SymCleanup() + typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess ); + tSC pSC; + + // SymFunctionTableAccess64() + typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase ); + tSFTA pSFTA; + + // SymGetLineFromAddr64() + typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, + OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line ); + tSGLFA pSGLFA; + + // SymGetModuleBase64() + typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr ); + tSGMB pSGMB; + + // SymGetModuleInfo64() + typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); + tSGMI pSGMI; + + // SymGetOptions() + typedef DWORD (__stdcall *tSGO)( VOID ); + tSGO pSGO; + + // SymGetSymFromAddr64() + typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, + OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol ); + tSGSFA pSGSFA; + + // SymInitialize() + typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ); + tSI pSI; + + // SymLoadModule64() + typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile, + IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ); + tSLM pSLM; + + // SymSetOptions() + typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions ); + tSSO pSSO; + + // StackWalk64() + typedef BOOL (__stdcall *tSW)( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); + tSW pSW; + + // UnDecorateSymbolName() + typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName, + DWORD UndecoratedLength, DWORD Flags ); + tUDSN pUDSN; + + typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); + tSGSP pSGSP; + + +private: + // **************************************** ToolHelp32 ************************ + #define MAX_MODULE_NAME32 255 + #define TH32CS_SNAPMODULE 0x00000008 + #pragma pack( push, 8 ) + typedef struct tagMODULEENTRY32 + { + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + char szModule[MAX_MODULE_NAME32 + 1]; + char szExePath[MAX_PATH]; + } MODULEENTRY32; + typedef MODULEENTRY32 * PMODULEENTRY32; + typedef MODULEENTRY32 * LPMODULEENTRY32; + #pragma pack( pop ) + + BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) + { + // CreateToolhelp32Snapshot() + typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID); + // Module32First() + typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + // Module32Next() + typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + + // try both dlls... + const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") }; + HINSTANCE hToolhelp = NULL; + tCT32S pCT32S = NULL; + tM32F pM32F = NULL; + tM32N pM32N = NULL; + + HANDLE hSnap; + MODULEENTRY32 me; + me.dwSize = sizeof(me); + BOOL keepGoing; + size_t i; + + for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ) + { + hToolhelp = LoadLibrary( dllname[i] ); + if (hToolhelp == NULL) + continue; + pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); + pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First"); + pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next"); + if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) ) + break; // found the functions! + FreeLibrary(hToolhelp); + hToolhelp = NULL; + } + + if (hToolhelp == NULL) + return FALSE; + + hSnap = pCT32S( TH32CS_SNAPMODULE, pid ); + if (hSnap == (HANDLE) -1) + { + FreeLibrary(hToolhelp); + return FALSE; + } + + keepGoing = !!pM32F( hSnap, &me ); + int cnt = 0; + while (keepGoing) + { + this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize); + cnt++; + keepGoing = !!pM32N( hSnap, &me ); + } + CloseHandle(hSnap); + FreeLibrary(hToolhelp); + if (cnt <= 0) + return FALSE; + return TRUE; + } // GetModuleListTH32 + + // **************************************** PSAPI ************************ + typedef struct _MODULEINFO { + LPVOID lpBaseOfDll; + DWORD SizeOfImage; + LPVOID EntryPoint; + } MODULEINFO, *LPMODULEINFO; + + BOOL GetModuleListPSAPI(HANDLE hProcess) + { + // EnumProcessModules() + typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); + // GetModuleFileNameEx() + typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); + // GetModuleBaseName() + typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); + // GetModuleInformation() + typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize ); + + HINSTANCE hPsapi; + tEPM pEPM; + tGMFNE pGMFNE; + tGMBN pGMBN; + tGMI pGMI; + + DWORD i; + //ModuleEntry e; + DWORD cbNeeded; + MODULEINFO mi; + HMODULE *hMods = 0; + char *tt = NULL; + char *tt2 = NULL; + const SIZE_T TTBUFLEN = 8096; + int cnt = 0; + + hPsapi = LoadLibrary( _T("psapi.dll") ); + if (hPsapi == NULL) + return FALSE; + + pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" ); + pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" ); + pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" ); + pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); + if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) + { + // we couldn´t find all functions + FreeLibrary(hPsapi); + return FALSE; + } + + hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE))); + tt = (char*) malloc(sizeof(char) * TTBUFLEN); + tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); + if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) + goto cleanup; + + if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ) + { + //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); + goto cleanup; + } + + if ( cbNeeded > TTBUFLEN ) + { + //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); + goto cleanup; + } + + for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ ) + { + // base address, size + pGMI(hProcess, hMods[i], &mi, sizeof(mi)); + // image file name + tt[0] = 0; + pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); + // module name + tt2[0] = 0; + pGMBN(hProcess, hMods[i], tt2, TTBUFLEN ); + + DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage); + if (dwRes != ERROR_SUCCESS) + this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); + cnt++; + } + + cleanup: + if (hPsapi != NULL) FreeLibrary(hPsapi); + if (tt2 != NULL) free(tt2); + if (tt != NULL) free(tt); + if (hMods != NULL) free(hMods); + + return cnt != 0; + } // GetModuleListPSAPI + + DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) + { + CHAR *szImg = _strdup(img); + CHAR *szMod = _strdup(mod); + DWORD result = ERROR_SUCCESS; + if ( (szImg == NULL) || (szMod == NULL) ) + result = ERROR_NOT_ENOUGH_MEMORY; + else + { + if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) + result = GetLastError(); + } + ULONGLONG fileVersion = 0; + if ( (m_parent != NULL) && (szImg != NULL) ) + { + // try to retrive the file-version: + if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) + { + VS_FIXEDFILEINFO *fInfo = NULL; + DWORD dwHandle; + DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); + if (dwSize > 0) + { + LPVOID vData = malloc(dwSize); + if (vData != NULL) + { + if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) + { + UINT len; + TCHAR szSubBlock[] = _T("\\"); + if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0) + fInfo = NULL; + else + { + fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); + } + } + free(vData); + } + } + } + + // Retrive some additional-infos about the module + IMAGEHLP_MODULE64_V3 Module; + const char *szSymType = "-unknown-"; + if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) + { + switch(Module.SymType) + { + case SymNone: + szSymType = "-nosymbols-"; + break; + case SymCoff: // 1 + szSymType = "COFF"; + break; + case SymCv: // 2 + szSymType = "CV"; + break; + case SymPdb: // 3 + szSymType = "PDB"; + break; + case SymExport: // 4 + szSymType = "-exported-"; + break; + case SymDeferred: // 5 + szSymType = "-deferred-"; + break; + case SymSym: // 6 + szSymType = "SYM"; + break; + case 7: // SymDia: + szSymType = "DIA"; + break; + case 8: //SymVirtual: + szSymType = "Virtual"; + break; + } + } + LPCSTR pdbName = Module.LoadedImageName; + if (Module.LoadedPdbName[0] != 0) + pdbName = Module.LoadedPdbName; + this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion); + } + if (szImg != NULL) free(szImg); + if (szMod != NULL) free(szMod); + return result; + } +public: + BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) + { + // first try toolhelp32 + if (GetModuleListTH32(hProcess, dwProcessId)) + return true; + // then try psapi + return GetModuleListPSAPI(hProcess); + } + + + BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo) + { + memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); + if(this->pSGMI == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + // First try to use the larger ModuleInfo-Structure + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... + if (pData == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); + static bool s_useV3Version = true; + if (s_useV3Version) + { + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + free(pData); + return TRUE; + } + s_useV3Version = false; // to prevent unneccessarry calls with the larger struct... + } + + // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + free(pData); + return TRUE; + } + free(pData); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } +}; + +// ############################################################# +StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) +{ + this->m_options = OptionsAll; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} +StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) +{ + this->m_options = options; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + if (szSymPath != NULL) + { + this->m_szSymPath = _strdup(szSymPath); + this->m_options |= SymBuildPath; + } + else + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} + +StackWalker::~StackWalker() +{ + if (m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + if (this->m_sw != NULL) + delete this->m_sw; + this->m_sw = NULL; +} + +BOOL StackWalker::LoadModules() +{ + if (this->m_sw == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + if (m_modulesLoaded != FALSE) + return TRUE; + + // Build the sym-path: + char *szSymPath = NULL; + if ( (this->m_options & SymBuildPath) != 0) + { + const size_t nSymPathLen = 4096; + szSymPath = (char*) malloc(nSymPathLen); + if (szSymPath == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + szSymPath[0] = 0; + // Now first add the (optional) provided sympath: + if (this->m_szSymPath != NULL) + { + strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + strcat_s(szSymPath, nSymPathLen, ".;"); + + const size_t nTempLen = 1024; + char szTemp[nTempLen]; + // Now add the current directory: + if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + // Now add the path for the main-module: + if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p) + { + // locate the rightmost path separator + if ( (*p == '\\') || (*p == '/') || (*p == ':') ) + { + *p = 0; + break; + } + } // for (search for path separator...) + if (strlen(szTemp) > 0) + { + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + } + if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + // also add the "system32"-directory: + strcat_s(szTemp, nTempLen, "\\system32"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + if ( (this->m_options & SymUseSymSrv) != 0) + { + if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, "SRV*"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, "\\websymbols"); + strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); + } + else + strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); + } + } // if SymBuildPath + + // First Init the whole stuff... + BOOL bRet = this->m_sw->Init(szSymPath); + if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; + if (bRet == FALSE) + { + this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); + if (bRet != FALSE) + m_modulesLoaded = TRUE; + return bRet; +} + + +// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction +// This has to be done due to a problem with the "hProcess"-parameter in x64... +// Because this class is in no case multi-threading-enabled (because of the limitations +// of dbghelp.dll) it is "safe" to use a static-variable +static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; +static LPVOID s_readMemoryFunction_UserData = NULL; + +BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) +{ + CONTEXT c; + CallstackEntry csEntry; + IMAGEHLP_SYMBOL64 *pSym = NULL; + StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; + IMAGEHLP_LINE64 Line; + int frameNum; + bool bLastEntryCalled = true; + int curRecursionCount = 0; + + if (m_modulesLoaded == FALSE) + this->LoadModules(); // ignore the result... + + if (this->m_sw->m_hDbhHelp == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + s_readMemoryFunction = readMemoryFunction; + s_readMemoryFunction_UserData = pUserData; + + if (context == NULL) + { + // If no context is provided, capture the context + // See: https://stackwalker.codeplex.com/discussions/446958 +#if _WIN32_WINNT <= 0x0501 + // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available! + if (hThread == GetCurrentThread()) +#else + if (GetThreadId(hThread) == GetCurrentThreadId()) +#endif + { + GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); + } + else + { + SuspendThread(hThread); + memset(&c, 0, sizeof(CONTEXT)); + c.ContextFlags = USED_CONTEXT_FLAGS; + + // TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture... + // This does only work if we are x64 and the target process is x64 or x86; + // It cannnot work, if this process is x64 and the target process is x64... this is not supported... + // See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html + if (GetThreadContext(hThread, &c) == FALSE) + { + ResumeThread(hThread); + return FALSE; + } + } + } + else + c = *context; + + // init STACKFRAME for first call + STACKFRAME64 s; // in/out stackframe + memset(&s, 0, sizeof(s)); + DWORD imageType; +#ifdef _M_IX86 + // normally, call ImageNtHeader() and use machine info from PE header + imageType = IMAGE_FILE_MACHINE_I386; + s.AddrPC.Offset = c.Eip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Ebp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Esp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_X64 + imageType = IMAGE_FILE_MACHINE_AMD64; + s.AddrPC.Offset = c.Rip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Rsp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Rsp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_IA64 + imageType = IMAGE_FILE_MACHINE_IA64; + s.AddrPC.Offset = c.StIIP; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.IntSp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrBStore.Offset = c.RsBSP; + s.AddrBStore.Mode = AddrModeFlat; + s.AddrStack.Offset = c.IntSp; + s.AddrStack.Mode = AddrModeFlat; +#else +#error "Platform not supported!" +#endif + + pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + if (!pSym) goto cleanup; // not enough memory... + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; + + memset(&Line, 0, sizeof(Line)); + Line.SizeOfStruct = sizeof(Line); + + memset(&Module, 0, sizeof(Module)); + Module.SizeOfStruct = sizeof(Module); + + for (frameNum = 0; ; ++frameNum ) + { + // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) + // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can + // assume that either you are done, or that the stack is so hosed that the next + // deeper frame could not be found. + // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! + if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ) + { + // INFO: "StackWalk64" does not set "GetLastError"... + this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); + break; + } + + csEntry.offset = s.AddrPC.Offset; + csEntry.name[0] = 0; + csEntry.undName[0] = 0; + csEntry.undFullName[0] = 0; + csEntry.offsetFromSmybol = 0; + csEntry.offsetFromLine = 0; + csEntry.lineFileName[0] = 0; + csEntry.lineNumber = 0; + csEntry.loadedImageName[0] = 0; + csEntry.moduleName[0] = 0; + if (s.AddrPC.Offset == s.AddrReturn.Offset) + { + if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) ) + { + this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); + break; + } + curRecursionCount++; + } + else + curRecursionCount = 0; + if (s.AddrPC.Offset != 0) + { + // we seem to have a valid PC + // show procedure info (SymGetSymFromAddr64()) + if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE) + { + MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); + // UnDecorateSymbolName() + this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY ); + this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE ); + } + else + { + this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); + } + + // show line number info, NT5.0-method (SymGetLineFromAddr64()) + if (this->m_sw->pSGLFA != NULL ) + { // yes, we have SymGetLineFromAddr64() + if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) + { + csEntry.lineNumber = Line.LineNumber; + MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); + } + else + { + this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); + } + } // yes, we have SymGetLineFromAddr64() + + // show module info (SymGetModuleInfo64()) + if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE) + { // got module info OK + switch ( Module.SymType ) + { + case SymNone: + csEntry.symTypeString = "-nosymbols-"; + break; + case SymCoff: + csEntry.symTypeString = "COFF"; + break; + case SymCv: + csEntry.symTypeString = "CV"; + break; + case SymPdb: + csEntry.symTypeString = "PDB"; + break; + case SymExport: + csEntry.symTypeString = "-exported-"; + break; + case SymDeferred: + csEntry.symTypeString = "-deferred-"; + break; + case SymSym: + csEntry.symTypeString = "SYM"; + break; +#if API_VERSION_NUMBER >= 9 + case SymDia: + csEntry.symTypeString = "DIA"; + break; +#endif + case 8: //SymVirtual: + csEntry.symTypeString = "Virtual"; + break; + default: + //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType ); + csEntry.symTypeString = NULL; + break; + } + + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); + csEntry.baseOfImage = Module.BaseOfImage; + MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); + } // got module info OK + else + { + this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); + } + } // we seem to have a valid PC + + CallstackEntryType et = nextEntry; + if (frameNum == 0) + et = firstEntry; + bLastEntryCalled = false; + this->OnCallstackEntry(et, csEntry); + + if (s.AddrReturn.Offset == 0) + { + bLastEntryCalled = true; + this->OnCallstackEntry(lastEntry, csEntry); + SetLastError(ERROR_SUCCESS); + break; + } + } // for ( frameNum ) + + cleanup: + if (pSym) free( pSym ); + + if (bLastEntryCalled == false) + this->OnCallstackEntry(lastEntry, csEntry); + + if (context == NULL) + ResumeThread(hThread); + + return TRUE; +} + +BOOL __stdcall StackWalker::myReadProcMem( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead + ) +{ + if (s_readMemoryFunction == NULL) + { + SIZE_T st; + BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st); + *lpNumberOfBytesRead = (DWORD) st; + //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); + return bRet; + } + else + { + return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); + } +} + +void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + if (fileVersion == 0) + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); + else + { + DWORD v4 = (DWORD) (fileVersion & 0xFFFF); + DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF); + DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF); + DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF); + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); + } + //OnOutput(buffer); +} + +void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + if ( (eType != lastEntry) && (entry.offset != 0) ) + { + if (entry.name[0] == 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); + if (entry.undName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); + if (entry.undFullName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); + if (entry.lineFileName[0] == 0) + { + MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); + if (entry.moduleName[0] == 0) + MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name); + } + else + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name); + buffer[STACKWALK_MAX_NAMELEN-1] = 0; + OnOutput(buffer); + } +} + +void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr); + OnOutput(buffer); +} + +void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); + //OnOutput(buffer); + // Also display the OS-version +#if _MSC_VER <= 1200 + OSVERSIONINFOA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); + ver.dwOSVersionInfoSize = sizeof(ver); + if (GetVersionExA(&ver) != FALSE) + { + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, + ver.szCSDVersion); + OnOutput(buffer); + } +#else + OSVERSIONINFOEXA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); + ver.dwOSVersionInfoSize = sizeof(ver); +#if _MSC_VER >= 1900 +#pragma warning(push) +#pragma warning(disable: 4996) +#endif + if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) + { + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, + ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); + //OnOutput(buffer); + } +#if _MSC_VER >= 1900 +#pragma warning(pop) +#endif +#endif +} + +void StackWalker::OnOutput(LPCSTR buffer) +{ + OutputDebugStringA(buffer); +} diff --git a/source/StackWalker/StackWalker.h b/source/StackWalker/StackWalker.h new file mode 100644 index 0000000..9319ba3 --- /dev/null +++ b/source/StackWalker/StackWalker.h @@ -0,0 +1,219 @@ +/********************************************************************** + * + * StackWalker.h + * + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2009, Jochen Kalmbach + * All rights reserved. + * + * 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 Jochen Kalmbach 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 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. + * + * **********************************************************************/ +// #pragma once is supported starting with _MCS_VER 1000, +// so we need not to check the version (because we only support _MSC_VER >= 1100)! +#pragma once + +#include + +#if _MSC_VER >= 1900 +#pragma warning(disable : 4091) +#endif + +// special defines for VC5/6 (if no actual PSDK is installed): +#if _MSC_VER < 1300 +typedef unsigned __int64 DWORD64, *PDWORD64; +#if defined(_WIN64) +typedef unsigned __int64 SIZE_T, *PSIZE_T; +#else +typedef unsigned long SIZE_T, *PSIZE_T; +#endif +#endif // _MSC_VER < 1300 + +class StackWalkerInternal; // forward +class StackWalker +{ +public: + typedef enum StackWalkOptions + { + // No addition info will be retrived + // (only the address is available) + RetrieveNone = 0, + + // Try to get the symbol-name + RetrieveSymbol = 1, + + // Try to get the line for this symbol + RetrieveLine = 2, + + // Try to retrieve the module-infos + RetrieveModuleInfo = 4, + + // Also retrieve the version for the DLL/EXE + RetrieveFileVersion = 8, + + // Contains all the abouve + RetrieveVerbose = 0xF, + + // Generate a "good" symbol-search-path + SymBuildPath = 0x10, + + // Also use the public Microsoft-Symbol-Server + SymUseSymSrv = 0x20, + + // Contains all the abouve "Sym"-options + SymAll = 0x30, + + // Contains all options (default) + OptionsAll = 0x3F + } StackWalkOptions; + + StackWalker( + int options = RetrieveLine, // 'int' is by design, to combine the enum-flags + //int options = OptionsAll, // 'int' is by design, to combine the enum-flags + LPCSTR szSymPath = NULL, + DWORD dwProcessId = GetCurrentProcessId(), + HANDLE hProcess = GetCurrentProcess() + ); + StackWalker(DWORD dwProcessId, HANDLE hProcess); + virtual ~StackWalker(); + + typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead, + LPVOID pUserData // optional data, which was passed in "ShowCallstack" + ); + + BOOL LoadModules(); + + BOOL ShowCallstack( + HANDLE hThread = GetCurrentThread(), + const CONTEXT *context = NULL, + PReadProcessMemoryRoutine readMemoryFunction = NULL, + LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback + ); + +#if _MSC_VER >= 1300 +// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" +// in older compilers in order to use it... starting with VC7 we can declare it as "protected" +protected: +#endif + enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols + +protected: + // Entry for each Callstack-Entry + typedef struct CallstackEntry + { + DWORD64 offset; // if 0, we have no valid entry + CHAR name[STACKWALK_MAX_NAMELEN]; + CHAR undName[STACKWALK_MAX_NAMELEN]; + CHAR undFullName[STACKWALK_MAX_NAMELEN]; + DWORD64 offsetFromSmybol; + DWORD offsetFromLine; + DWORD lineNumber; + CHAR lineFileName[STACKWALK_MAX_NAMELEN]; + DWORD symType; + LPCSTR symTypeString; + CHAR moduleName[STACKWALK_MAX_NAMELEN]; + DWORD64 baseOfImage; + CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; + } CallstackEntry; + + typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; + + virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); + virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); + virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); + virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); + virtual void OnOutput(LPCSTR szText); + + StackWalkerInternal *m_sw; + HANDLE m_hProcess; + DWORD m_dwProcessId; + BOOL m_modulesLoaded; + LPSTR m_szSymPath; + + int m_options; + int m_MaxRecursionCount; + + static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); + + friend StackWalkerInternal; +}; // class StackWalker + + +// The "ugly" assembler-implementation is needed for systems before XP +// If you have a new PSDK and you only compile for XP and later, then you can use +// the "RtlCaptureContext" +// Currently there is no define which determines the PSDK-Version... +// So we just use the compiler-version (and assumes that the PSDK is +// the one which was installed by the VS-IDE) + +// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... +// But I currently use it in x64/IA64 environments... +//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) + +#if defined(_M_IX86) +#ifdef CURRENT_THREAD_VIA_EXCEPTION +// TODO: The following is not a "good" implementation, +// because the callstack is only valid in the "__except" block... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + EXCEPTION_POINTERS *pExp = NULL; \ + __try { \ + throw 0; \ + } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ + if (pExp != NULL) \ + memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + } while(0); +#else +// The following should be enough for walking the callstack... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + __asm call x \ + __asm x: pop eax \ + __asm mov c.Eip, eax \ + __asm mov c.Ebp, ebp \ + __asm mov c.Esp, esp \ + } while(0); +#endif + +#else + +// The following is defined for x86 (XP and higher), x64 and IA64: +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + RtlCaptureContext(&c); \ +} while(0); +#endif diff --git a/source/dink/FFReader.cpp b/source/dink/FFReader.cpp new file mode 100644 index 0000000..2d50b80 --- /dev/null +++ b/source/dink/FFReader.cpp @@ -0,0 +1,236 @@ +#include "PlatformPrecomp.h" +#include "FFReader.h" + +FFReader::FFReader() +{ + m_fp = NULL; +} + +FFReader::~FFReader() +{ + Kill(); +} + +void FFReader::Kill() +{ + if (m_fp) + { + fclose(m_fp); + m_fp = NULL; + } + + m_fileHeader.clear(); + m_bUsingBaseDinkFF = false; + m_error = ERROR_NONE; +} + +int FFReader::GetFFRecordIndexFromFileName(const string &fName) +{ + assert(m_fp); + + for (unsigned int i=0; i < m_fileHeader.size(); i++) + { + if (strcmp(fName.c_str(), m_fileHeader[i].name) == 0) + return i; + } + + return -1; +} + +bool FFReader::DoesFileExist( const string &fName ) +{ + + //LogMsg("Checking for %s", (m_basePath+fName).c_str()); + + if (m_fp) + { + if (GetFFRecordIndexFromFileName(fName) != -1) return true; + } + + if (!m_dmodGamePath.empty()) + { + if (FileExists(m_dmodGamePath+m_basePath+fName)) return true; + } + + if (!FileExists(m_gamePath+m_basePath+fName)) + { + //LogMsg("Can't find %s", (m_basePath+fName).c_str()); + return false; + } + return true; +} + +void FFReader::Init( const string &gamePath, const string &dmodGamePath, const string &basePath, bool bUsingDinkPak ) +{ + + if (m_basePath == basePath && m_dmodGamePath == dmodGamePath) + { + //optimization, detect when we don't have to reload this + return; + } + + Kill(); + + m_dmodBasePath = basePath; + + if (!bUsingDinkPak) + { + m_gamePath = GetBaseAppPath()+gamePath; + m_basePath = basePath; + + } else + { + //using dink.pak + m_basePath = gamePath+basePath; + + } + + m_dmodGamePath = dmodGamePath; + //first scan for an .ff file + assert(!m_fp); + + + + if (!dmodGamePath.empty()) + { + m_fp = fopen((m_dmodGamePath+m_dmodBasePath+"dir.ff").c_str(), "rb"); + } + + if (!m_fp) + { + m_fp = fopen((m_gamePath+m_basePath+"dir.ff").c_str(), "rb"); + + if (m_fp) + { + m_bUsingBaseDinkFF = true; + } + } + + if (!m_fp) return; //no ff to scan in this case + + int totalFiles; + FFFileInfo f; + fread(&totalFiles, sizeof(int), 1, m_fp); + + for (int i=0; i < totalFiles; i++) + { + fread(&f, sizeof(f), 1, m_fp); + assert(strlen(f.name) < 13); + ToLowerCase(f.name); + m_fileHeader.push_back(f); + } + + //LogMsg("FFScanning %s, %d entries", basePath.c_str(), m_fileHeader.size()); + +} + +int FFReader::GetNextFFIndex(int index) +{ + if (m_fileHeader[index+1].offset != 0) + { + return index+1; + } + + assert(index+2 < m_fileHeader.size() ); + return index+2; +} + +void FFReader::SetError(eErrorType error) +{ + m_error = error; + if (error == ERROR_LOW_MEM) + { + GetBaseApp()->SetLastError(BaseApp::ERROR_MEM); + } +} + +byte * FFReader::LoadFFIntoMemory(int index, int *pSizeOut) +{ + int byteSize = m_fileHeader[GetNextFFIndex(index)].offset-m_fileHeader[index].offset; + if (pSizeOut) *pSizeOut = byteSize; + + fseek(m_fp, m_fileHeader[index].offset, SEEK_SET); + + + byte *pMem = new byte[byteSize+1]; //extra one for a null we're going to attach + +#ifdef _DEBUG +/* + if (Random(60) == 1) + { + //fake a memory error + SAFE_DELETE_ARRAY(pMem); + + } +*/ +#endif + if (!pMem) + { + LogError("Out of mem!"); + SetError(ERROR_LOW_MEM); + return NULL; + } + + pMem[byteSize] = 0; //ending null, useful if we loaded a text file + fread(pMem, byteSize, 1, m_fp); + return pMem; +} + + +byte * FFReader::LoadFileIntoMemory( string const &fName, int *pSizeOut ) +{ + +#ifdef _DEBUG + //LogMsg("loading for %s", (m_basePath+fName).c_str()); +#endif + int len; + byte *pBuff = NULL; + + if (m_fp) + { + if (m_bUsingBaseDinkFF && !m_dmodGamePath.empty()) + { + //you know what? Let's do a last minute try in the dmod dir as well. + + if (FileExists(m_dmodGamePath+m_dmodBasePath+fName)) + { + //pBuff = LoadFileIntoMemoryBasic(m_dmodGamePath+m_basePath+fName, &len, false, false); + pBuff = GetFileManager()->Get(m_dmodGamePath+m_dmodBasePath+fName, &len, false); + + if (!pBuff) SetError(ERROR_LOW_MEM); + return pBuff; + } + } + + + int index = GetFFRecordIndexFromFileName(fName); + + if (index != -1) + { + //we found it! + return LoadFFIntoMemory(index, pSizeOut); + } + } else + { + + if (!m_dmodGamePath.empty()) + { + + if (FileExists(m_dmodGamePath+m_dmodBasePath+fName)) + { + //pBuff = LoadFileIntoMemoryBasic(m_dmodGamePath+m_basePath+fName, &len, false, false); + pBuff = GetFileManager()->Get(m_dmodGamePath+m_dmodBasePath+fName, &len,false); + if (!pBuff) SetError(ERROR_LOW_MEM); + return pBuff; + + } + } + //pBuff = LoadFileIntoMemoryBasic(m_gamePath+m_basePath+fName, &len, false, false); + pBuff = GetFileManager()->Get(m_gamePath+m_basePath+fName,&len, false); + if (len == UINT_MAX) SetError(ERROR_LOW_MEM); + return pBuff; + + } + + return NULL; +} \ No newline at end of file diff --git a/source/dink/FFReader.h b/source/dink/FFReader.h new file mode 100644 index 0000000..ad25f96 --- /dev/null +++ b/source/dink/FFReader.h @@ -0,0 +1,60 @@ +// *************************************************************** +// FFReader - Creation date: 12/31/2009 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2009 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef FFReader_h__ +#define FFReader_h__ + +#include "BaseApp.h" + +#pragma pack(push, 1) +struct FFFileInfo +{ + int offset; + char name[13]; +}; +#pragma pack(pop) + +class FFReader +{ +public: + enum eErrorType + { + ERROR_NONE, + ERROR_LOW_MEM + }; + + + FFReader(); + virtual ~FFReader(); + + bool DoesFileExist(const string &fName); + void Init( const string &gamePath, const string &dmodGamePath, const string &baseDir, bool bUsingDinkPak); + byte * LoadFileIntoMemory(string const &fName, int *pSizeout); //you need to delete [] what this gives you on your own + eErrorType GetLastError() {return m_error;} + +private: + + void Kill(); + int GetFFRecordIndexFromFileName(const string &fName); + byte * LoadFFIntoMemory(int index, int *pSizeOut); + int GetNextFFIndex(int index); + void SetError(eErrorType error); + string m_gamePath; + string m_dmodGamePath; + string m_basePath; + FILE *m_fp; + bool m_bUsingBaseDinkFF; + eErrorType m_error; + string m_dmodBasePath; + + vector m_fileHeader; + +}; + +#endif // FFReader_h__ \ No newline at end of file diff --git a/source/dink/ScriptAccelerator.cpp b/source/dink/ScriptAccelerator.cpp new file mode 100644 index 0000000..df125f6 --- /dev/null +++ b/source/dink/ScriptAccelerator.cpp @@ -0,0 +1,38 @@ +#include "PlatformPrecomp.h" +#include "ScriptAccelerator.h" +#include "util/MiscUtils.h" + +ScriptAccelerator::ScriptAccelerator() +{ +} + +ScriptAccelerator::~ScriptAccelerator() +{ +} + +void ScriptAccelerator::Kill() +{ + m_data.clear(); +} + +void ScriptAccelerator::AddPosition(string label, int current) +{ + label = ToUpperCaseString(label); + m_data[label] = ScriptPosition(current); +} + +ScriptPosition * ScriptAccelerator::GetPositionByName( string label ) +{ + label = ToUpperCaseString(label); + + ScriptMap::iterator itor = m_data.find(label); + + if (itor != m_data.end()) + { + //bingo! + return &(itor->second); + } + + return NULL; + +} \ No newline at end of file diff --git a/source/dink/ScriptAccelerator.h b/source/dink/ScriptAccelerator.h new file mode 100644 index 0000000..bfac136 --- /dev/null +++ b/source/dink/ScriptAccelerator.h @@ -0,0 +1,46 @@ +// *************************************************************** +// ScriptAccelerator - Creation date: 01/23/2010 +// ------------------------------------------------------------- +// Robinson Technologies Copyright (C) 2010 - All Rights Reserved +// +// *************************************************************** +// Programmer(s): Seth A. Robinson (seth@rtsoft.com) +// *************************************************************** + +#ifndef ScriptAccelerator_h__ +#define ScriptAccelerator_h__ + +#include "PlatformSetup.h" + +class ScriptPosition +{ +public: + + ScriptPosition(){}; + ScriptPosition(int pos) : current (pos){}; + + + int current; +}; + + +typedef map ScriptMap; + + +class ScriptAccelerator +{ +public: + ScriptAccelerator(); + virtual ~ScriptAccelerator(); + + void Kill(); + ScriptPosition * GetPositionByName(string label); + void AddPosition(string label, int current); + +private: + + ScriptMap m_data; + +}; + +#endif // ScriptAccelerator_h__ \ No newline at end of file diff --git a/source/dink/dink.cpp b/source/dink/dink.cpp new file mode 100644 index 0000000..d0a3672 --- /dev/null +++ b/source/dink/dink.cpp @@ -0,0 +1,17078 @@ +#include "PlatformPrecomp.h" +#include "dink.h" +#include "FFReader.h" +#include "../GUI/GameMenu.h" +#include +#include "../GUI/PauseMenu.h" +#include "../GUI/QuickTipMenu.h" +#include "ScriptAccelerator.h" +#include "Renderer/SoftSurface.h" +#include "FileSystem/StreamingInstance.h" +#include +void ThinkSprite(int h, bool get_frame); +void ApplyAspectRatioGLMatrix(); + +bool pre_figure_out(const char *line, int load_seq, bool bLoadSpriteOnly); + +#define C_DINK_SCREEN_TRANSITION_TIME_MS 400 + +const float SAVE_FORMAT_VERSION = 1.8f; +const int C_DINK_FADE_TIME_MS = 300; + +const float G_TRANSITION_SCALE_TRICK = 1.01f; + +float g_dinkFadeAlpha = 0; +DinkGlobals g_dglo; +DinkGlobalsStatic g_dglos; //static data, made to write/read from disk + +int32 g_spriteRank[C_MAX_SPRITES_AT_ONCE]; + +int32 C_DINK_MEM_MAX_ALLOWED = (1024*1024*10); +int32 C_DINK_TEX_MEM_MAX_ALLOWED = (1024*1024*30); + +//avoid texture thrashing with this +int32 C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*8); +int32 C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*16); +uint32 g_DebugKeyTimer = 0; + +#ifdef _WIN32 + extern bool g_bHasFocus; + #define C_DINK_KEYBOARD_INPUT +#endif + +std::map* g_customSpriteMap[C_MAX_SPRITES_AT_ONCE]; + +eDinkGameState g_dinkGameState = DINK_GAME_STATE_NOT_PLAYING; +int water_timer; +bool fire_forward; +int fire_flip; + +bool no_cheat; +bool g_itemScreenActive; + +int32 last_saved_game; +bool g_b_kill_app; //if true, will close app as soon as the message pump is +Surface g_transitionSurf; +Surface g_onePixelSurf; //used for drawing blocks of color + +SoundBankDummy soundbank[num_soundbanks+1]; +soundstruct soundinfo[num_soundbanks+1]; +seth_sound g_soundInfo[max_sounds]; + +player_short_info short_play; + +char *g_scriptBuffer[C_MAX_SCRIPTS]; //pointers to buffers we may need +refinfo *g_scriptInstance[C_MAX_SCRIPTS]; +SpriteStruct g_sprite[C_MAX_SPRITES_AT_ONCE]; //max sprite control systems at once + +ScriptAccelerator g_scriptAccelerator[C_MAX_SCRIPTS]; +hardness g_hmap; + +seth_joy sjoy; + +map_info g_MapInfo; + +int32 * pvision, * plife, * presult, * pspeed, * ptiming, *plifemax, *pexper, *pmap, +*pstrength, * pcur_weapon,* pcur_magic, *pdefense, *pgold, *pmagic, *plevel, *plast_text, *pmagic_level; +int32 *pupdate_status, *pmissile_target, *penemy_sprite, *pmagic_cost, *pmissle_source; + +bool no_transition; +bool g_abort_this_flip; + +bool sound_on; +bool turn_on_plane; + +char returnstring[200]; +char slist[10][200]; +int32 g_nlist[10]; +char in_default[200]; +bool g_bInitiateScreenMove; +bool g_bTransitionActive; +bool debug_mode; +uint16 decipher_savegame; +uint32 g_soundTimer = 0; + +void FreeSequence(int h); + +LPDIRECTDRAWSURFACE lpDDSBackGround; // Offscreen surface +LPDIRECTDRAWSURFACE lpDDSBuffer; // Offscreen surface +LPDIRECTDRAWSURFACE g_tileScreens[C_TILE_SCREEN_COUNT]; // Game pieces +LPDIRECTDRAWSURFACE g_pSpriteSurface[C_MAX_SPRITES]; + +bool IsCorruptedSeq(int seq); +//redink1 added for recursive scope checking +void decipher_string(char line[200], int script); +void check_midi(void); +bool ReloadSequence(int seqID, int frame = 0, bool bScanOnly = false); +void kill_sprite_all (int sprite); +bool add_time_to_saved_game(int num); +void move(int u, int amount, char kind, char kindy); +void draw_box(rtRect32 box, int color); +void run_through_tag_list_push(int h); +void random_blood(int mx, int my, int h); +int check_if_move_is_legal(int u); +void change_dir_to_diag( int *dir); + +int hurt_thing(int h, int damage, int special); +void kill_all_scripts_for_real(void); +bool check_sprite_status(int spriteID); +bool InitSound(); +bool DestroySound( void ); +int get_var(int script, char* name); +void init_scripts(void); +int load_script(const char *pScript, int sprite, bool set_sprite, bool bQuietError=false); +void update_status_all(void); +int add_sprite(int x1, int y, int brain,int pseq, int pframe ); +void load_info(); //redink1 +void add_exp(int num, int h, bool addEvenIfNotLastSpriteHit=false); +bool locate(int script, char proc[20]); + +bool SoundStopEffect( int sound ); +void draw_status_all(void); +bool SoundDestroyEffect( int sound ); +int SoundPlayEffect( int sound,int min,int plus ,int sound3d, bool repeat); +void SoundLoadBanks( void); +bool StopMidi(void); +bool check_seq_status(int h, int frame = 0); +bool PlayMidi(const char *sFileName); +void get_word(char line[300], int word, char *crap); + +void run_script (int script); + +void program_idata(void); +void BuildScreenBackground( bool bFullRebuild = true); +int realhard(int tile); +void kill_repeat_sounds_all( void ); +int process_line (int script, char *s, bool doelse); +void SetDefaultVars(bool bFullClear); +int getpic(int h); +bool check_pic_status(int picID); +bool get_box (int spriteID, rtRect32 * box_crap, rtRect32 * box_real ); +void fill_screen(int num); + +#define C_MAX_BACKGROUND_SPRITES_AT_ONCE 100 //too many and it will slow down +void BackgroundSpriteManager::Clear() +{ + m_sprites.clear(); +} + +void BackgroundSpriteManager::Render(LPDIRECTDRAWSURFACE lpdest) +{ + //LogMsg("Drawing %d sprites", m_sprites.size()); + rtRect32 box_crap,box_real; + DDBLTFX ddbltfx; + ddbltfx.dwSize = sizeof( ddbltfx); + ddbltfx.dwFillColor = 0; + + deque::iterator itor = m_sprites.begin(); + + while (itor != m_sprites.end()) + { + + if (!check_pic_status(itor->pic)) + { + #ifdef _DEBUG + LogMsg("Hmm, bad tilepic at %d..", itor->pic); + #endif + continue; + } + lpdest->Blt(&itor->dstRect, g_pSpriteSurface[itor->pic], + &itor->srcRect , DDBLT_KEYSRC ,&ddbltfx); + + itor++; + } + + +} + +void BackgroundSpriteManager::Add(int spriteID) +{ + + BackgroundSprite s; + s.pic = getpic(spriteID); + get_box(spriteID, &s.dstRect, &s.srcRect); + m_sprites.push_back(s); + + if (m_sprites.size() > C_MAX_BACKGROUND_SPRITES_AT_ONCE) + { + m_sprites.pop_front(); + } +} + +int next_raise(void) +{ + int crap = *plevel; + assert(crap >= 0 && crap < 200); + int num = ((100 * crap) * crap); + + if (num > 99999) num = 99999; + return(num); +} + +void OffsetRect(rtRect32 *pR, int x, int y) +{ + pR->AdjustPosition(x,y); +} +void OffsetRect(rtRect *pR, int x, int y) +{ + pR->AdjustPosition(x,y); +} + + +void InflateRect(rtRect32 *pR, int x, int y) +{ + pR->Inflate(x,y); +} + +char * rt_ltoa( int num, char *pDest, int bufSize) +{ + sprintf(pDest, "%d", num); + return pDest; +} + +void KillScriptAccelerators() +{ + for (int i=0; i < C_MAX_SCRIPTS; i++) + { + g_scriptAccelerator[i].Kill(); + } +} + +void ResetDinkTimers() +{ + g_soundTimer = 0; + g_DebugKeyTimer = 0; +} + +void SoundLoadBanks( void) {} + +void OneTimeDinkInit() +{ + + for (int i = 0; i < C_MAX_SPRITES_AT_ONCE; i++) + { + g_customSpriteMap[i] = NULL; + } + + //defaults for memory class 1 device + C_DINK_MEM_MAX_ALLOWED = (1024*1024*10); + C_DINK_TEX_MEM_MAX_ALLOWED = (1024*1024*30); + + //avoid texture thrashing with this + C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*8); + C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*16); + + + if (GetDeviceMemoryClass() >= C_DEVICE_MEMORY_CLASS_2) + { + C_DINK_MEM_MAX_ALLOWED = (1024*1024*20); + C_DINK_TEX_MEM_MAX_ALLOWED = (1024*1024*60); + + //avoid texture thrashing with this + C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*16); + C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*32); + } + + if (GetDeviceMemoryClass() >= C_DEVICE_MEMORY_CLASS_3) + { + C_DINK_MEM_MAX_ALLOWED = (1024*1024*40); + C_DINK_TEX_MEM_MAX_ALLOWED = (1024*1024*100); + + //avoid texture thrashing with this + C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*32); + C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*64); + } + + if (GetDeviceMemoryClass() >= C_DEVICE_MEMORY_CLASS_4) + { + C_DINK_MEM_MAX_ALLOWED = (1024*1024*80); + C_DINK_TEX_MEM_MAX_ALLOWED = (1024*1024*200); + + //avoid texture thrashing with this + C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*64); + C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP = (1024*1024*128); + } + + + static bool bInitted = false; + g_dglos.g_DinkUpdateTimerMS = 0; + if (bInitted) return; + + lpDDSBackGround = NULL; // Offscreen surface + lpDDSBuffer = NULL; // Offscreen surface + + for (int i=0; i < C_TILE_SCREEN_COUNT; i++) + { + g_tileScreens[i] = NULL; + } + + bInitted = true; + g_dglos.g_curPicIndex = 1; //we actually need this set before finiObjects is called + + memset(g_dglos.g_picInfo, 0, sizeof(pic_info)*C_MAX_SPRITES); + memset(g_sprite, 0, sizeof(SpriteStruct) *C_MAX_SPRITES_AT_ONCE); + memset(g_dglos.g_seq, 0, sizeof(sequence) * C_MAX_SEQUENCES); + memset(g_dglos.g_scriptCallback, 0, sizeof(call_back) * C_MAX_SCRIPT_CALLBACKS); + + memset(&g_dglos.g_hitmap, 0, sizeof(hit_map)); + memset(&g_hmap, 0, sizeof(hardness)); + +//just to help me keep track of memory better + GetApp()->ModMemUsed(sizeof(pic_info)*C_MAX_SPRITES); + GetApp()->ModMemUsed(sizeof(SpriteStruct) *C_MAX_SPRITES_AT_ONCE); + GetApp()->ModMemUsed(sizeof(sequence) * C_MAX_SEQUENCES); + GetApp()->ModMemUsed( sizeof(call_back) * C_MAX_SCRIPT_CALLBACKS); + + GetApp()->ModMemUsed( sizeof(hit_map)); + GetApp()->ModMemUsed( sizeof(hardness)); +} + +void finiObjects() +{ + if (last_saved_game > 0) + { + LogMsg("Modifying saved game."); + + if (!add_time_to_saved_game(last_saved_game)) + LogMsg("Error modifying saved game."); + } + + for (int i=1; i < C_MAX_SPRITES_AT_ONCE; i++) + { + SAFE_DELETE(g_customSpriteMap[i]); + } + + memset(g_sprite, 0, sizeof(SpriteStruct) *C_MAX_SPRITES_AT_ONCE); + + for (int i=1; i < C_MAX_SPRITES; i++) + { + SAFE_DELETE(g_pSpriteSurface[i]); + } + g_dglos.g_curPicIndex = 1; + + kill_all_scripts_for_real(); + + for (int i=0; i < C_TILE_SCREEN_COUNT; i++) + { + SAFE_DELETE(g_tileScreens[i]); + } + + SAFE_DELETE(lpDDSBuffer); + SAFE_DELETE(lpDDSBackGround); + + g_transitionSurf.HardKill(); + + KillVideoEngine(); + + g_dglo.m_iniScanner.Kill(); + + g_b_kill_app = true; + LogMsg("Game shutdown run"); + + GetAudioManager()->KillCachedSounds(false, true, 0, 100, true); +} + +void clear_talk(void) +{ + memset(&g_dglos.g_talkInfo, 0, sizeof(g_dglos.g_talkInfo)); + g_dglos.g_playerInfo.mouse = 0; +} + +#if !defined PLATFORM_LINUX && !defined PLATFORM_HTML5 +/* Case insensitive strncmp. Non-ISO, deprecated. */ + +int strnicmp(const char *pStr1, const char *pStr2, size_t Count) +{ + char c1, c2; + int v; + + if (Count == 0) + return 0; + + do { + c1 = *pStr1++; + c2 = *pStr2++; + /* the casts are necessary when pStr1 is shorter & char is signed */ + v = (uint32) tolower(c1) - (uint32) tolower(c2); + } while ((v == 0) && (c1 != '\0') && (--Count > 0)); + + return v; +} +#endif + +bool compare(char *orig, char *comp) +{ + int len; + len = strlen(comp); + if (strlen(orig) != len) return(false); + + if (strnicmp(orig,comp,len) == 0) + { + return(true); + } + + //Msg("I'm sorry, but %s does not equal %s.",orig, comp); + return(false); +} + +bool CreateBufferFromWaveFile(char* FileName, uint32 dwBuf) +{ + g_soundInfo[dwBuf].m_fileName = FileName; + return true; +} + +bool getkey(int key) +{ + if (sjoy.realkey[key]) return(true); else return(false); +} + +//add hardness from a sprite + +int getpic(int h) +{ + if (g_sprite[h].pseq == 0) return(0); + if (g_sprite[h].pseq > C_MAX_SEQUENCES) + { + + LogMsg("Sequence %d? But max is %d!", g_sprite[h].pseq, C_MAX_SEQUENCES); + return(0); + } + return(g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]); +} + + + + +string GetFileLocationString(const string fName) +{ + if (!fName[0]) + { + return fName; + } + + if (!g_dglo.m_dmodGameDir.empty()) + { + //extra checks for dmod stuff + + if (FileExists(g_dglo.m_dmodGamePathWithDir+fName)) + { + //found it + return g_dglo.m_dmodGamePathWithDir+fName; + } + } + + if (GetEmulatedPlatformID() == PLATFORM_ID_IOS || GetEmulatedPlatformID() == PLATFORM_ID_OSX || GetEmulatedPlatformID() == PLATFORM_ID_HTML5) + { + //actually, we need to do this to grab stuff from the .pak we added + if (FileExists(g_dglo.m_gameDir+fName)) + { + //found it + return g_dglo.m_gameDir+fName; + } + } + + //default, from dink dir + return g_dglo.m_gamePathWithDir + fName; +} + +void add_hardness (int sprite, int num) +{ + + for (int xx = g_sprite[sprite].x + g_dglos.g_picInfo[getpic(sprite)].hardbox.left; xx < g_sprite[sprite].x + g_dglos.g_picInfo[getpic(sprite)].hardbox.right; xx++) + { + for (int yy = g_sprite[sprite].y + g_dglos.g_picInfo[getpic(sprite)].hardbox.top; yy < g_sprite[sprite].y + g_dglos.g_picInfo[getpic(sprite)].hardbox.bottom; yy++) + { + if ( (xx-20 > 600) | (xx-20 < 0)| (yy > 400) | (yy < 0)) + { + } else + + g_dglos.g_hitmap.x[xx-20].y[yy] = num; + } + } +} + + +void setup_anim (int seq, int sequence,int delay) +{ + + for (int o = 1; o <= g_dglos.g_seq[sequence].last; o++) + { + g_dglos.g_seq[seq].frame[o] = g_dglos.g_seq[sequence].s+o; + g_dglos.g_seq[seq].delay[o] = delay; + g_dglos.g_picInfo[g_dglos.g_seq[seq].frame[o]].m_parentSeq = seq; //so we can know who the parent is if we need to reload later + } + +#ifdef _DEBUG + if (seq == 452) + { + + //LogMsg("yo, yo!"); + + } +#endif + //g_dglos.g_seq[seq].frame[g_dglos.g_seq[sequence].last+1] = 0; +} + +byte get_hard(int h,int x1, int y1) +{ + int value; + + //redink1 fix for screenlock bug + if (g_dglos.screenlock) + { + if ( x1 < 0 && x1 > -5 ) x1 = 0; + else if ( x1 > 599 && x1 < 605 ) x1 = 599; + + if ( y1 < 0 && y1 > -5 ) y1 = 0; + else if ( y1 > 399 && x1 < 405 ) y1 = 399; + } + if (x1 < 0 || y1 < 0 || x1 > 599 || y1 > 399) return(0); + value = g_dglos.g_hitmap.x[x1].y[y1]; + return(value); +} + +byte get_hard_play(int h,int x1, int y1) +{ + int value; + x1 -= 20; + + //redink1 fix for screenlock bug + if (g_dglos.screenlock) + { + if ( x1 < 0 && x1 > -5 ) x1 = 0; + else if ( x1 > 599 && x1 < 605 ) x1 = 599; + + if ( y1 < 0 && y1 > -5 ) y1 = 0; + else if ( y1 > 399 && x1 < 405 ) y1 = 399; + } + if (x1 < 0 || y1 < 0 || x1 > 599 || y1 > 399) return(0); + + value = g_dglos.g_hitmap.x[x1].y[y1]; + + if (value > 100) + { + if (g_dglos.g_smallMap.sprite[value-100].prop != 0) + { + g_dglos.flub_mode = value; + value = 0; + } + } + return(value); +} + + +byte get_hard_map(int h,int x1, int y1) +{ + if ((x1 < 0) || (y1 < 0)) return(0); + if ((x1 > 599) ) return(0); + if (y1 > 399) return(0); + + int til = (x1 / 50) + ( ((y1 / 50)) * 12); + int offx = x1 - ((x1 / 50) * 50); + int offy = y1 - ((y1 / 50) * 50); + + //Msg("tile %d ",til); + + return( g_hmap.tile[ realhard(til ) ].x[offx].y[offy]); +} + +void fill_hardxy(rtRect32 box) +{ + //Msg("filling hard of %d %d %d %d", box.top, box.left, box.right, box.bottom); + + if (box.right > 599) box.right = 600; //redink1 screenlock bug + if (box.top < 0) box.top = 0; + if (box.bottom > 399) box.bottom = 400; //redink1 screenlock bug + if (box.left < 0) box.left = 0; + + for (int x1 = box.left; x1 < box.right; x1++) + { + for (int y1 = box.top; y1 < box.bottom; y1++) + { + g_dglos.g_hitmap.x[x1].y[y1] = get_hard_map(0,x1,y1); + } + } +} + +void add_exp(int num, int h, bool addEvenIfNotLastSpriteHit) +{ + //redink1 fix - made work with all sprites when using add_exp DinkC command + if (addEvenIfNotLastSpriteHit == false) + { + if (g_sprite[h].last_hit != 1) return; + } + + if (num > 0) + { + + check_sprite_status(h); + //add experience + *pexper += num; + int crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,8,0,0); + + g_sprite[crap2].y -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].yoffset; + g_sprite[crap2].x -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].xoffset; + g_sprite[crap2].y -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].box.bottom / 3; + g_sprite[crap2].x += g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].box.right / 5; + g_sprite[crap2].y -= 30; + g_sprite[crap2].speed = 1; + g_sprite[crap2].hard = 1; + g_sprite[crap2].brain_parm = 5000; + g_sprite[crap2].my = -1; + g_sprite[crap2].kill = 1000; + g_sprite[crap2].dir = 8; + g_sprite[crap2].damage = num; + if (*pexper > 99999) *pexper = 99999; + } + +} + +int realhard(int tile) +{ + // if (pam.t[tile].num > 3000) Msg("Hard is %d", pam.t[tile].num ); + if (g_dglos.g_smallMap.t[tile].althard > 0) return(g_dglos.g_smallMap.t[tile].althard); else return(g_hmap.index[g_dglos.g_smallMap.t[tile].num]); +} + +void fill_whole_hard(void) +{ + + for (int til=0; til < 96; til++) + { + int offx = (til * 50 - ((til / 12) * 600)); + int offy = (til / 12) * 50; + + for (int x = 0; x < 50; x++) + { + for (int y = 0; y < 50; y++) + { + g_dglos.g_hitmap.x[offx +x].y[offy+y] = g_hmap.tile[ realhard(til) ].x[x].y[y]; + } + } + } +} + +void DrawCollision() +{ + rtRect32 box_crap; + DDBLTFX ddbltfx; + + + for (int x1=0; x1 < 600; x1++) + for (int y1=0; y1 < 400; y1++) + { + if (g_dglos.g_hitmap.x[x1].y[y1] == 1) + { + + ddbltfx.dwFillColor = 1; + + ddbltfx.dwSize = sizeof(ddbltfx); + box_crap.top = y1; + box_crap.bottom = y1+1; + box_crap.left = x1+g_gameAreaLeftOffset; //20 is to compensate for the border + box_crap.right = x1+1+g_gameAreaLeftOffset; + lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + + } + + if (g_dglos.g_hitmap.x[x1].y[y1] == 2) + { + + ddbltfx.dwFillColor = 128; + + ddbltfx.dwSize = sizeof(ddbltfx); + box_crap.top = y1; + box_crap.bottom = y1+1; + box_crap.left = x1+g_gameAreaLeftOffset; //20 is to compensate for the border + box_crap.right = x1+1+g_gameAreaLeftOffset; + lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + + } + + + if (g_dglos.g_hitmap.x[x1].y[y1] == 3) + { + + ddbltfx.dwFillColor = 45; + ddbltfx.dwSize = sizeof(ddbltfx); + box_crap.top = y1; + box_crap.bottom = y1+1; + box_crap.left = x1+g_gameAreaLeftOffset; //20 is to compensate for the border + box_crap.right = x1+1+g_gameAreaLeftOffset; + lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + + } + + if (g_dglos.g_hitmap.x[x1].y[y1] > 100) + { + if (g_dglos.g_smallMap.sprite[ (g_dglos.g_hitmap.x[x1].y[y1]) - 100].prop == 1) + { + + + ddbltfx.dwFillColor = 20; + + //draw a little pixel + ddbltfx.dwSize = sizeof(ddbltfx); + box_crap.top = y1; + box_crap.bottom = y1+1; + box_crap.left = x1+g_gameAreaLeftOffset; //20 is to compensate for the border + box_crap.right = x1+1+g_gameAreaLeftOffset; + lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + } else + { +#ifdef _DEBUG + /* + if (x1 == 423+20 && y1 == 120) + { + //if (Random(200) == 0) + LogMsg("Drawing g_dglos.g_smallMap.sprite %d's hardness..", (g_dglos.g_hitmap.x[x1].y[y1]) - 100); + int hh= 5; + } + */ +#endif + //draw a little pixel + + if (x1 > 580) + { + ddbltfx.dwFillColor = 70; + + } else + { + + ddbltfx.dwFillColor = 23; + } + ddbltfx.dwSize = sizeof(ddbltfx); + box_crap.top = y1; + box_crap.bottom = y1+1; + box_crap.left = x1+g_gameAreaLeftOffset; //20 is to compensate for the border + box_crap.right = x1+1+g_gameAreaLeftOffset; + lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + + } + } + } +} + + +bool LoadTileScreenIfNeeded(int h, bool &bRequireRebuild) +{ + bRequireRebuild = false; + if (g_tileScreens[h]) return true; //already loaded + string fName = "tiles/ts"; + if (h < 10) fName += "0"; + fName += toString(h)+".bmp"; + assert(!g_tileScreens[h]); +#ifdef _DEBUG +LogMsg("Loading tilescreen %s", fName.c_str()); +#endif + g_tileScreens[h] = LoadBitmapIntoSurface(GetFileLocationString(fName).c_str(), TRANSPARENT_NONE, IDirectDrawSurface::MODE_NORMAL); + + if (g_tileScreens[h] && g_tileScreens[h]->m_pSurf->GetSurfaceType() != SoftSurface::SURFACE_PALETTE_8BIT) + { + //we're going to require a hicolor backbuffer. + if (lpDDSBackGround->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + { + LogMsg("Detected high color tilescreen bmps. Converting backbuffers to 32 bit on the fly."); + + //switch it + delete lpDDSBackGround; + lpDDSBackGround = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, true); + + bRequireRebuild = true; + + } + + } + + if (g_tileScreens[h]->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT && lpDDSBuffer->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + //if (0) + + { + //test to make sure the palettes are the same.. some dmods change them slightly which breaks things (Cast Awakening) + + if (!g_tileScreens[h]->m_pSurf->IsPaletteTheSame(lpDDSBuffer->m_pSurf->GetPalette(), lpDDSBuffer->m_pSurf->GetPaletteColorCount())) + { + + if (lpDDSBackGround->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + { + //switch it + delete lpDDSBackGround; + lpDDSBackGround = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, true); + bRequireRebuild = true; + + } + + LogMsg("Detected tilescreen palette doesn't match backbuffers. Converting backbuffers to 32 bit on the fly."); + delete lpDDSBuffer; + lpDDSBuffer = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, true); + } + } + + if (g_tileScreens[h]->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_NONE) + { + //some kind of error + LogMsg("Error loading tilescreen %d", h); + delete g_tileScreens[h]; + g_tileScreens[h] = 0; + } + return g_tileScreens[h] != NULL; + +} + +void fix_dead_sprites( void ) +{ + + for (int i = 1; i < 100; i++) + { + if (g_dglos.g_playerInfo.spmap[*pmap].type[i] == 6) + { + + if ((g_dglos.g_dinkTick > (g_dglos.g_playerInfo.spmap[*pmap].last_time + 300000)) || + (g_dglos.g_dinkTick +400000 < g_dglos.g_playerInfo.spmap[*pmap].last_time + 300000) ) + { + //this sprite can come back online now + g_dglos.g_playerInfo.spmap[*pmap].type[i] = 0; + } + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[i] == 7) + { + + if (g_dglos.g_dinkTick > (g_dglos.g_playerInfo.spmap[*pmap].last_time + 180000)) + { + //this sprite can come back online now + g_dglos.g_playerInfo.spmap[*pmap].type[i] = 0; + } + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[i] == 8) + { + + if (g_dglos.g_dinkTick > (g_dglos.g_playerInfo.spmap[*pmap].last_time + 60000)) + { + //this sprite can come back online now + g_dglos.g_playerInfo.spmap[*pmap].type[i] = 0; + } + } + } +} + +void load_map(const int num) +{ + FILE * fp; + int holdme,lsize; + + LogMsg("Loading map %d...",num); + + StreamingInstance *pFile = GetFileManager()->GetStreaming(GetFileLocationString(g_dglos.current_map), NULL, false); + +// fp = fopen( GetFileLocationString(g_dglos.current_map).c_str(), "rb"); + + + + if (!pFile) + { + LogMsg("Cannot find %s file!!!",g_dglos.current_map); + return; + } + + //redink1 set correctly so Dink appears on mini-map for warps and such + //doesn't work, because 'num' is actually the offset in map.dat, not the map screen number + //if (map.indoor[num] == 0) + // play.last_map = num; + + lsize = sizeof(struct small_map); + holdme = (lsize * (num-1)); + //fseek( fp, holdme, SEEK_SET); + + + //pFile->SeekFromStart(holdme); //only will work if the file is uncompressed in the zip + + //another way is this.. + const int bufferSize = 1024*4; + + char buffer[bufferSize]; + + while (holdme > 0) + { + int bytesRead = pFile->Read((byte*)buffer, rt_min(holdme, bufferSize)); + + holdme -= bytesRead; + + + } + + + + //Msg("Trying to read %d bytes with offset of %d",lsize,holdme); + pFile->Read((byte*)&g_dglos.g_smallMap, lsize); + //int shit = fread( &g_dglos.g_smallMap, lsize, 1, fp); /* current player */ + // Msg("Read %d bytes.",shit); + //if (shit == 0) LogMsg("ERROR: Couldn't read map %d?!?", num); +// fclose(fp); + delete pFile; + + g_sprite[1].move_active = false; + g_sprite[1].move_nohard = false; + g_sprite[1].freeze = false; + g_dglos.screenlock = 0; + fill_whole_hard(); + fix_dead_sprites(); + check_midi(); +} + +void save_game(int num) +{ + FILE * fp; + char crap[256]; + //redink1 created this + char info_temp[200]; + + CreateDirectoryRecursively(g_dglo.m_savePath, g_dglo.m_gameDir); + sprintf(crap, "%ssave%d.dat", g_dglo.m_savePath.c_str(), num); + fp = fopen(crap, "wb"); + + if (!fp) + { + LogError("Unable to save game to %s", crap); + return; + } + //lets set some vars first + + g_dglos.g_playerInfo.x = g_sprite[1].x; + g_dglos.g_playerInfo.y = g_sprite[1].y; + g_dglos.g_playerInfo.version = C_DINK_VERSION; + g_dglos.g_playerInfo.pseq = g_sprite[1].pseq; + g_dglos.g_playerInfo.pframe = g_sprite[1].pframe; + g_dglos.g_playerInfo.seq = g_sprite[1].seq; + g_dglos.g_playerInfo.frame = g_sprite[1].frame; + g_dglos.g_playerInfo.size = g_sprite[1].size; + g_dglos.g_playerInfo.dir = g_sprite[1].dir; + g_dglos.g_playerInfo.strength = g_sprite[1].strength; + g_dglos.g_playerInfo.defense = g_sprite[1].defense; + g_dglos.g_playerInfo.que = g_sprite[1].que; + g_dglos.g_playerInfo.minutes = ( GetBaseApp()->GetGameTick()-g_dglos.time_start) / (1000*60); + //g_dglos.g_playerInfo.m_gameTime = GetBaseApp()->GetGameTick(); + //g_dglos.time_start = GetBaseApp()->GetGameTick(); + g_dglos.g_playerInfo.base_idle = g_sprite[1].base_idle; + g_dglos.g_playerInfo.base_walk = g_sprite[1].base_walk; + g_dglos.g_playerInfo.base_hit = g_sprite[1].base_hit; + + //redink1 - save game things for storing new map, palette, and tile information + strncpy(g_dglos.g_playerInfo.mapdat, g_dglos.current_map, 50); + strncpy(g_dglos.g_playerInfo.dinkdat, g_dglos.current_dat, 50); + + //redink1 code for custom save game names + strcpy(info_temp,g_dglos.save_game_info); + decipher_string(info_temp, 0); + strncpy(g_dglos.g_playerInfo.gameinfo,info_temp,77); + //sprintf(play.gameinfo, "Level %d",*plevel); + + last_saved_game = num; + fwrite(&g_dglos.g_playerInfo,sizeof(g_dglos.g_playerInfo),1,fp); + fclose(fp); +} + + +void kill_all_vars(void) +{ + memset(&g_dglos.g_playerInfo, 0, sizeof(g_dglos.g_playerInfo)); +} + +bool attach(void) +{ + + for (int i = 1; i < max_vars; i++) + { + if (compare((char*)"&life", g_dglos.g_playerInfo.var[i].name)) + { + plife = &g_dglos.g_playerInfo.var[i].var; + + } + if (compare((char*)"&vision", g_dglos.g_playerInfo.var[i].name)) + { + pvision = &g_dglos.g_playerInfo.var[i].var; + + } + if (compare((char*)"&result", g_dglos.g_playerInfo.var[i].name)) + { + presult = &g_dglos.g_playerInfo.var[i].var; + + } + if (compare((char*)"&speed", g_dglos.g_playerInfo.var[i].name)) + { + pspeed = &g_dglos.g_playerInfo.var[i].var; + + } + if (compare((char*)"&timing", g_dglos.g_playerInfo.var[i].name)) + { + ptiming = &g_dglos.g_playerInfo.var[i].var; + } + + if (compare((char*)"&lifemax", g_dglos.g_playerInfo.var[i].name)) + { + plifemax = &g_dglos.g_playerInfo.var[i].var; + } + + if (compare((char*)"&exp", g_dglos.g_playerInfo.var[i].name)) pexper = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&strength", g_dglos.g_playerInfo.var[i].name)) pstrength = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&defense", g_dglos.g_playerInfo.var[i].name)) pdefense = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&gold", g_dglos.g_playerInfo.var[i].name)) pgold = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&magic", g_dglos.g_playerInfo.var[i].name)) pmagic = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&level", g_dglos.g_playerInfo.var[i].name)) plevel = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&player_map", g_dglos.g_playerInfo.var[i].name)) pmap = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&cur_weapon", g_dglos.g_playerInfo.var[i].name)) pcur_weapon = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&cur_magic", g_dglos.g_playerInfo.var[i].name)) pcur_magic = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&last_text", g_dglos.g_playerInfo.var[i].name)) plast_text = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&magic_level", g_dglos.g_playerInfo.var[i].name)) pmagic_level = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&update_status", g_dglos.g_playerInfo.var[i].name)) pupdate_status = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&missile_target", g_dglos.g_playerInfo.var[i].name)) pmissile_target = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&enemy_sprite", g_dglos.g_playerInfo.var[i].name)) penemy_sprite = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&magic_cost", g_dglos.g_playerInfo.var[i].name)) pmagic_cost = &g_dglos.g_playerInfo.var[i].var; + if (compare((char*)"&missle_source", g_dglos.g_playerInfo.var[i].name)) pmissle_source = &g_dglos.g_playerInfo.var[i].var; + } + + if (!pstrength) + { + LogError("Corrupted save or .c file? strength global var not set."); + return false; + } + g_dglos.g_guiStrength = *pstrength; + g_dglos.g_guiMagic = *pmagic; + g_dglos.g_guiGold = *pgold; + g_dglos.g_guiDefense = *pdefense; + g_dglos.g_guiLife = *plife; + g_dglos.g_guiLifeMax = *plifemax; + g_dglos.g_guiExp = *pexper; + g_dglos.g_guiMagicLevel = *pmagic_level; + g_dglos.g_guiRaise = next_raise(); + + return true; //no error + +} + + +bool add_time_to_saved_game(int num) +{ + /* + FILE * fp; + char crap[256]; + + sprintf(crap, "%ssave%d.dat", g_dglo.m_gamePath.c_str(), num); + + fp = fopen(crap, "rb"); + if (!fp) + { + LogMsg("Couldn't load save game %d", num); + return(false); + } + else + { + fread(&g_dglos.g_playerInfo,sizeof(g_dglos.g_playerInfo),1,fp); + fclose(fp); + } + + //great, now let's resave it with added time + LogMsg("Ok, adding time."); + + g_dglos.g_playerInfo.minutes += 0; + + + + sprintf(crap, "save%d.dat", num); + fp = fopen(crap, "wb"); + if (fp) + { + fwrite(&g_dglos.g_playerInfo,sizeof(g_dglos.g_playerInfo),1,fp); + fclose(fp); + } + LogMsg("Wrote it.(%d of time)", g_dglos.g_playerInfo.minutes); + */ + + return(true); +} + +bool load_game(int num) +{ + FILE * fp; + char crap[256]; + + //lets get rid of our magic and weapon scripts + if (g_dglos.weapon_script != 0) + { + if (locate(g_dglos.weapon_script, "DISARM")) + { + run_script(g_dglos.weapon_script); + } + } + + if (g_dglos.magic_script != 0) if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + + g_dglos.g_bowStatus.active = false; + g_dglos.weapon_script = 0; + g_dglos.magic_script = 0; + g_dglos.midi_active = true; + + if (last_saved_game > 0) + { + LogMsg("Modifying saved game."); + + if (!add_time_to_saved_game(last_saved_game)) + LogMsg("Error modifying saved game."); + } + StopMidi(); + + for (int i=1; i < C_MAX_SPRITES_AT_ONCE; i++) + { + + kill_sprite_all(i); + } + + SetDefaultVars(false); + + g_sprite[1].active = true; + g_dglos.g_gameMode = 2; + g_sprite[1].noclip = 0; + g_sprite[1].brain = 1; + g_sprite[1].nocontrol = 0; + + sprintf(crap, "%ssave%d.dat", g_dglo.m_savePath.c_str(), num); + + fp = fopen(crap, "rb"); + if (!fp) + { + LogMsg("Couldn't load save game %d", num); + return(false); + } + else + { + fread(&g_dglos.g_playerInfo,sizeof(g_dglos.g_playerInfo),1,fp); + fclose(fp); + + //redink1 - new map, if exist + if (strlen(g_dglos.g_playerInfo.mapdat) > 0 && strlen(g_dglos.g_playerInfo.dinkdat) > 0) + { + strcpy(g_dglos.current_map, g_dglos.g_playerInfo.mapdat); + strcpy(g_dglos.current_dat, g_dglos.g_playerInfo.dinkdat); + ToLowerCase(g_dglos.current_map); + ToLowerCase(g_dglos.current_dat); + load_info(); + } + + g_sprite[1].damage = 0; + g_sprite[1].x = g_dglos.g_playerInfo.x; + g_sprite[1].y = g_dglos.g_playerInfo.y; + g_dglos.walk_off_screen = 0; + g_sprite[1].nodraw = 0; + g_dglos.g_pushingEnabled = 1; + g_sprite[1].pseq = g_dglos.g_playerInfo.pseq; + g_sprite[1].pframe = g_dglos.g_playerInfo.pframe; + g_sprite[1].size = g_dglos.g_playerInfo.size; + g_sprite[1].seq = g_dglos.g_playerInfo.seq; + g_sprite[1].frame = g_dglos.g_playerInfo.frame; + g_sprite[1].dir = g_dglos.g_playerInfo.dir; + g_sprite[1].strength = g_dglos.g_playerInfo.strength; + g_sprite[1].defense = g_dglos.g_playerInfo.defense; + g_sprite[1].que = g_dglos.g_playerInfo.que; + + if (g_dglos.g_playerInfo.m_gameTime != 0) + { + GetApp()->SetGameTick(g_dglos.g_playerInfo.m_gameTime); + } else + { + //convert from old style of dink timing + GetApp()->SetGameTick(g_dglos.g_playerInfo.minutes*1000*60); + g_dglos.time_start = 0; + } + //g_dglos.time_start = GetBaseApp()->GetGameTick(); + + g_sprite[1].base_idle = g_dglos.g_playerInfo.base_idle; + g_sprite[1].base_walk = g_dglos.g_playerInfo.base_walk; + g_sprite[1].base_hit = g_dglos.g_playerInfo.base_hit; + + int script = load_script("main", 0, true); + locate(script, "main"); + run_script(script); + //lets attach our vars to the scripts + + attach(); + + *pupdate_status = 1; + LogMsg("Attached vars."); + + //redink1 fixes + g_dglos.dinkspeed = 3; + + if (*pcur_weapon != 0) + { + if (g_dglos.g_playerInfo.g_itemData[*pcur_weapon].active == false) + { + *pcur_weapon = 1; + g_dglos.weapon_script = 0; + LogMsg("Loadgame error: Player doesn't have armed weapon - changed to 1."); + } else + { + + g_dglos.weapon_script = load_script(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, 1000, false); + if (locate(g_dglos.weapon_script, "DISARM")) run_script(g_dglos.weapon_script); + + g_dglos.weapon_script = load_script(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, 1000, false); + if (locate(g_dglos.weapon_script, "ARM")) run_script(g_dglos.weapon_script); + } + } + + if (*pcur_magic != 0) + { + if (g_dglos.g_playerInfo.g_itemData[*pcur_magic].active == false) + { + *pcur_magic = 0; + g_dglos.magic_script = 0; + LogMsg("Loadgame error: Player doesn't have armed magic - changed to 0."); + } else + { + + g_dglos.magic_script = load_script(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, 1000, false); + if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + g_dglos.magic_script = load_script(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, 1000, false); + if (locate(g_dglos.magic_script, "ARM")) run_script(g_dglos.magic_script); + } + } + kill_repeat_sounds_all(); + load_map(g_MapInfo.loc[*pmap]); + LogMsg("Loaded map."); + BuildScreenBackground(); + LogMsg("Map drawn."); + + //stop any weird noises from happening on load + g_dglos.g_guiStrength = *pstrength; + g_dglos.g_guiMagic = *pmagic; + g_dglos.g_guiGold = *pgold; + g_dglos.g_guiDefense = *pdefense; + + + //redink1 fixes + g_dglos.g_guiExp = *pexper; + draw_status_all(); + + + LogMsg("Status drawn."); + last_saved_game = num; + return(true); + } +} + +void kill_cur_item( void ) +{ + + if (*pcur_weapon != 0) + { + if (g_dglos.g_playerInfo.g_itemData[*pcur_weapon].active == true) + { + if (g_dglos.weapon_script != 0) if (locate(g_dglos.weapon_script, "DISARM")) run_script(g_dglos.weapon_script); + g_dglos.weapon_script = load_script(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, 0, false); + g_dglos.g_playerInfo.g_itemData[*pcur_weapon].active = false; + *pcur_weapon = 0; + if (g_dglos.weapon_script != 0) if (locate(g_dglos.weapon_script, "HOLDINGDROP")) run_script(g_dglos.weapon_script); + + if (g_dglos.weapon_script != 0) if (locate(g_dglos.weapon_script, "DROP")) run_script(g_dglos.weapon_script); + g_dglos.weapon_script = 0; + } else + { + LogMsg("Error: Can't kill cur item, none armed."); + } + } +} + + + +void kill_cur_item_script( char name[20]) +{ + int select = 0; + for (int i = 1; i < 17; i++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active) + if (compare(g_dglos.g_playerInfo.g_itemData[i].name, name)) + { + select = i; + goto found; + } + } + + return; + +found: + + if (*pcur_weapon == select) + { + //holding it right now + if (locate(g_dglos.weapon_script, "HOLDINGDROP")) run_script(g_dglos.weapon_script); + if (locate(g_dglos.weapon_script, "DISARM")) run_script(g_dglos.weapon_script); + + *pcur_weapon = 0; + g_dglos.weapon_script = 0; + } + + int script = load_script(g_dglos.g_playerInfo.g_itemData[select].name, 0, false); + g_dglos.g_playerInfo.g_itemData[select].active = false; + + if (locate(script, "DROP")) run_script(script); + + draw_status_all(); +} + +void kill_cur_magic_script( char name[20]) +{ + int select = 0; + for (int i = 1; i < 9; i++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active) + if (compare(g_dglos.g_playerInfo.g_MagicData[i].name, name)) + { + select = i; + goto found; + } + } + + return; + +found: + + if (*pcur_magic == select) + + { + //holding it right now + if (locate(g_dglos.magic_script, "HOLDINGDROP")) run_script(g_dglos.magic_script); + if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + + + *pcur_weapon = 0; + g_dglos.magic_script = 0; + } + + int script = load_script(g_dglos.g_playerInfo.g_MagicData[select].name, 0, false); + g_dglos.g_playerInfo.g_MagicData[select].active = false; + + if (locate(script, "DROP")) run_script(script); + + draw_status_all(); +} + + +void kill_cur_magic( void ) +{ + + if (*pcur_magic != 0) + { + if (g_dglos.g_playerInfo.g_MagicData[*pcur_magic].active == true) + { + + if (g_dglos.magic_script != 0) if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + g_dglos.magic_script = load_script(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, 0, false); + g_dglos.g_playerInfo.g_MagicData[*pcur_magic].active = false; + *pcur_magic = 0; + + if (g_dglos.magic_script != 0) if (locate(g_dglos.magic_script, "HOLDINGDROP")) run_script(g_dglos.magic_script); + if (g_dglos.magic_script != 0) if (locate(g_dglos.magic_script, "DROP")) run_script(g_dglos.magic_script); + g_dglos.magic_script = 0; + } else + { + LogMsg("Error: Can't kill cur magic, none armed."); + } + } +} + +void update_screen_time(void ) +{ + //Msg("Cur time is %d", play.spmap[*pmap].last_time); + //Msg("Map is %d..", *pmap); + g_dglos.g_playerInfo.spmap[*pmap].last_time = g_dglos.g_dinkTick; + //Msg("Time was saved as %d", play.spmap[*pmap].last_time); +} + +bool load_game_small(int num, char * line, int *mytime) +{ + FILE * fp; + char crap[255]; + sprintf(crap, "%ssave%d.dat", g_dglo.m_savePath.c_str(), num); + + + fp = fopen(crap, "rb"); + if (!fp) + { + //LogMsg("Couldn't quickload save game %d", num); + line[0] = 0; + *mytime = 0; + return(false); + } + + + fread(&short_play,sizeof(player_short_info),1,fp); + fclose(fp); + *mytime = short_play.minutes; + strcpy(line, short_play.gameinfo); + return(true); + +} + + +void load_info() +{ + FILE * fp; + string fName = GetFileLocationString(g_dglos.current_dat); + //redink1 changed 'crap' to 'current_dat' + + StreamingInstance *pFile = GetFileManager()->GetStreaming(GetFileLocationString(g_dglos.current_dat), NULL, false); + + + //fp = fopen(fName.c_str(), "rb"); + if (!pFile) + { + LogMsg("Unable to load_info() on %s", fName.c_str()); + return; + } + else + { + LogMsg("World data loaded."); + + pFile->Read((byte*)&g_MapInfo, sizeof(struct map_info)); + //fread(&g_MapInfo,sizeof(struct map_info),1,fp); + delete pFile; + //fclose(fp); + } +} + + +bool load_hard(void) +{ + //FILE * fp; + string fName = GetFileLocationString("hard.dat"); + + StreamingInstance *pFile = GetFileManager()->GetStreaming(fName, NULL, false); + + //fp = fopen(fName.c_str(), "rb"); + if (!pFile) + { + return false; + } + else + { + //fread(&g_hmap,sizeof(struct hardness),1,fp); + pFile->Read((byte*)&g_hmap, sizeof(struct hardness)); + delete(pFile); + } + return true; +} + +void blit_background(void) +{ + rtRect32 rcRect( 0,0,C_DINK_SCREENSIZE_X,C_DINK_SCREENSIZE_Y); + lpDDSBack->BltFast( 0, 0, lpDDSBackGround, + &rcRect, DDBLTFAST_NOCOLORKEY); +} + +void draw_wait() +{ + LogMsg("waiting.."); +} + + +bool LoadSpriteSingleFrame(string fNameBase, int seq, int oo, int picIndex, eTransparencyType transType, FFReader *pReader, rtRect32 hardbox, int xoffset, int yoffset, int notanim) +{ + + int work; + string fName = fNameBase; + if (oo < 10) fName += "0"; + fName += toString(oo)+".bmp"; + + + byte *pMem = pReader->LoadFileIntoMemory(fName, NULL); + + if (g_dglos.g_seq[seq].m_spaceAllowed != 0) + { + if ( pMem && oo > g_dglos.g_seq[seq].m_spaceAllowed) + { + //LogMsg("Truncating anim to fit in existing seq %d", seq); + SAFE_DELETE_ARRAY(pMem); + } + } + + if (pReader->GetLastError() != FFReader::ERROR_NONE) + { + LogMsg("Low mem error"); + assert(!"Low mem"); + FreeSequence(seq); + return false; + } + + if (pMem) + { + #ifdef _DEBUG + //LogMsg("Loaded %s", (fName).c_str()); + #endif + //assert(!g_dglos.g_picInfo[g_cur_sprite].pSurface); + SAFE_DELETE(g_pSpriteSurface[picIndex]); +#ifdef _DEBUG +if (seq == 421 && oo == 26) +{ + LogMsg("Woah, "); +} + +if (fName == "ds-cr-01.bmp") +{ + LogMsg("Found it"); +} +#endif + g_pSpriteSurface[picIndex] = LoadBitmapIntoSurface("", transType, IDirectDrawSurface::MODE_SHADOW_GL, pMem); + } else + { + + if (oo == 1) + { + LogMsg("load_sprites: Anim %s not found.",(fName).c_str()); + //assert(0); + return false; + } + return false; + } + + SAFE_DELETE_ARRAY(pMem); + + if (picIndex > 0) + { + int surfSizeX, surfSizeY; + GetSizeOfSurface(g_pSpriteSurface[picIndex], &surfSizeX, &surfSizeY); + + g_dglos.g_picInfo[picIndex].box.top = 0; + g_dglos.g_picInfo[picIndex].box.left = 0; + g_dglos.g_picInfo[picIndex].box.right = surfSizeX; + g_dglos.g_picInfo[picIndex].box.bottom = surfSizeY; + } + + if (!g_dglos.g_picInfo[picIndex].m_bCustomSettingsApplied) + { + +#ifdef _DEBUG + if (seq == 180 && oo == 3) + { + //LogMsg("Woah nelly"); + } +#endif + //set the default offset stuff + + + if ( (oo > 1) && g_dglos.g_seq[seq].m_bIsAnim) //yes, it should be a &, but it breaks old dmods + { +// g_dglos.g_picInfo[picIndex].yoffset = g_dglos.g_picInfo[g_dglos.g_seq[seq].s+1].yoffset; +// g_dglos.g_picInfo[picIndex].xoffset = g_dglos.g_picInfo[g_dglos.g_seq[seq].s+1].xoffset; + + g_dglos.g_picInfo[picIndex].yoffset = yoffset; + g_dglos.g_picInfo[picIndex].xoffset = xoffset; + + } else + { + if (yoffset > 0) + g_dglos.g_picInfo[picIndex].yoffset = yoffset; else + { + g_dglos.g_picInfo[picIndex].yoffset = (g_dglos.g_picInfo[picIndex].box.bottom - + (g_dglos.g_picInfo[picIndex].box.bottom / 4)) - (g_dglos.g_picInfo[picIndex].box.bottom / 30); + } + + if (xoffset > 0) + g_dglos.g_picInfo[picIndex].xoffset = xoffset; else + { + g_dglos.g_picInfo[picIndex].xoffset = (g_dglos.g_picInfo[picIndex].box.right - + (g_dglos.g_picInfo[picIndex].box.right / 2)) + (g_dglos.g_picInfo[picIndex].box.right / 6); + } + + if (oo == 1 && g_dglos.g_seq[seq].m_bIsAnim) + { + //save it to this seq's settings + g_dglos.g_seq[seq].m_xoffset = g_dglos.g_picInfo[picIndex].xoffset; + g_dglos.g_seq[seq].m_yoffset = g_dglos.g_picInfo[picIndex].yoffset; + } + } + } + + if (!g_dglos.g_picInfo[picIndex].m_bCustomSettingsApplied) + { + g_dglos.g_picInfo[picIndex].hardbox.Clear(); + /* + if ( (oo > 1) && g_dglos.g_seq[seq].m_bIsAnim) + { + g_dglos.g_picInfo[picIndex].hardbox = hardbox; //reset it + } + */ + + + //ok, setup main offsets, lets build the hard block + + if (hardbox.right > 0) + { + //forced setting + g_dglos.g_picInfo[picIndex].hardbox.left = hardbox.left; + g_dglos.g_picInfo[picIndex].hardbox.right = hardbox.right; + } + else + { + //guess setting + work = g_dglos.g_picInfo[picIndex].box.right / 4; + g_dglos.g_picInfo[picIndex].hardbox.left -= work; + g_dglos.g_picInfo[picIndex].hardbox.right += work; + } + + if (hardbox.bottom > 0) + { + g_dglos.g_picInfo[picIndex].hardbox.top = hardbox.top; + g_dglos.g_picInfo[picIndex].hardbox.bottom = hardbox.bottom; + } + else + { + work = g_dglos.g_picInfo[picIndex].box.bottom / 10; + g_dglos.g_picInfo[picIndex].hardbox.top -= work; + g_dglos.g_picInfo[picIndex].hardbox.bottom += work; + } + } + + return true; +} + +bool load_sprites(char org[512], int seq, int speed, int xoffset, int yoffset, rtRect32 hardbox, eTransparencyType transType, bool leftalign, bool bScanOnly = false, + int frame = 0) +{ +//LogMsg("Cur pic is %d", g_curPicIndex); + /* + if (notanim) + { + g_dglos.g_seq[seq].m_bUsingLoadOnDemand = true; + if (g_dglos.g_seqData[seq].last != 0) + { + LogMsg("Already loaded"); + return true; + } + } + */ + +#ifdef _DEBUG + + if (seq == 424) + { + LogMsg("Loading status bar"); + } +#endif + char hold[5]; + + ToLowerCase(org); + + string tempStr(org); + StringReplace("\\", "/", tempStr); + + static FFReader reader; + + reader.Init(g_dglo.m_gameDir, g_dglo.m_dmodGamePathWithDir, GetPathFromString(tempStr), g_dglo.m_bUsingDinkPak); + + string fNameBase = GetFileNameFromString(tempStr); + +#ifdef _DEBUG + if (frame == 0) + { + if (!reader.DoesFileExist(fNameBase+"01.bmp")) + { + LogMsg("Can't find %s", (string(org)+"01.bmp").c_str()); + return true; //might be a serious error, not sure + } + } +#endif + +#ifdef _DEBUG + //LogMsg("Loading %s", org); +#endif + + if (frame != 0) + { + //special code for loading a single frame... + + LoadSpriteSingleFrame(fNameBase, seq, frame, g_dglos.g_seq[seq].s+frame, transType, &reader, hardbox, xoffset, yoffset, false); + return true; + } + + // redink1 added to fix bug where loading sequences over others wouldn't work quite right. + int save_cur = g_dglos.g_curPicIndex; + bool reload = false; + + if (g_dglos.g_seq[seq].last != 0) + { + FreeSequence(seq); + // Msg("Saving sprite %d", save_cur); + g_dglos.g_curPicIndex = g_dglos.g_seq[seq].s+1; +#ifdef _DEBUG + //LogMsg("Reloading: Temp g_curPicIndex is %d", g_curPicIndex); +#endif + reload = true; + } else + { + //LogMsg("Not reloading.."); + g_dglos.g_seq[seq].s = g_dglos.g_curPicIndex -1; + } + + if (bScanOnly) + { + if (reload) + { + g_dglos.g_curPicIndex = save_cur; + return true; + } + + for (int oo = 1; oo <= C_MAX_SPRITE_FRAMES; oo++) + { + if (oo < 10) strcpy(hold, "0"); else strcpy(hold,""); + + if (reader.DoesFileExist(fNameBase+string(hold)+toString(oo)+".bmp")) + { + g_dglos.g_curPicIndex++; + + } else + { + if (oo == 1) + { + LogMsg("load_sprites: Anim %s not found.",tempStr.c_str()); + //assert(0); + } + g_dglos.g_seq[seq].m_spaceAllowed = (oo - 1); + g_dglos.g_seq[seq].last = (oo - 1); + + setup_anim(seq,seq,speed); + break; + } + } + return true; + } + + +#ifdef _DEBUG + + if (seq == 424) + { + + LogMsg("hey"); + + } +#endif + + for (int oo = 1; oo <= C_MAX_SPRITE_FRAMES; oo++) + { + + if (LoadSpriteSingleFrame(fNameBase, seq, oo, g_dglos.g_curPicIndex, transType, &reader, hardbox, xoffset, yoffset, false)) + { + g_dglos.g_curPicIndex++; + + if (!reload) + save_cur++; + } else + { + if (oo > 1) + { + g_dglos.g_seq[seq].m_spaceAllowed = (oo - 1); + g_dglos.g_seq[seq].last = (oo - 1); + + //make reloaded anims of different lengths work right, without breaking anims like idle that replay frames, confusing the length + if (g_dglos.g_seq[seq].frame[g_dglos.g_seq[seq].last] == g_dglos.g_seq[seq].s+g_dglos.g_seq[seq].last && !g_dglos.g_seq[seq].m_bFrameSetUsed) + { + + + //looks like it was a standard anim without any extra frames added, truncate it here + g_dglos.g_seq[seq].frame[g_dglos.g_seq[seq].last+1] = 0; + } + //setup_anim(seq,seq,speed); + + } + break; + } + + } + g_dglos.g_curPicIndex = save_cur; + return true; +} + +eTransparencyType GetTransparencyOverrideForSequence(eTransparencyType defaultTrans, int seqID) +{ + switch (seqID) + { + case 442: //level# + return TRANSPARENT_WHITE; + case 423: //item menu bg + return TRANSPARENT_WHITE; + case 437: //magic icons + return TRANSPARENT_BLACK; + case 438: //item icons + + return TRANSPARENT_BLACK; + } + + return defaultTrans; +} + +void ReadFromLoadSequenceString(char ev[15][100] ) +{ + + // name seq speed offsetx offsety hardx hardy + int seqID = atol(ev[3]); + +#ifdef _DEBUG + + if (seqID == 452) + { + LogMsg("Found seq %d", seqID); + } +#endif + + int speed = 0; + rtRect32 hardbox; + //redink1 set hardbox to zero memory by default... fixed some weird compiler warnings in debug mode. Might screw up default hard box? + hardbox.Clear(); + + g_dglos.g_seq[seqID].active = true; + g_dglos.g_seq[seqID].m_bIsAnim = false; + +#ifdef _DEBUG + if (seqID == 180) + { + LogMsg("Booya"); + + } +#endif + + assert(strlen(ev[2]) < C_SPRITE_MAX_FILENAME_SIZE); + strcpy(g_dglos.g_seq[seqID].m_fileName, ev[2]); + + if (compare(ev[4], "BLACK")) + { + g_dglos.g_seq[seqID].m_transType = TRANSPARENT_BLACK; + g_dglos.g_seq[seqID].m_bIsAnim = true; + } else if (compare(ev[4], "LEFTALIGN")) + { + g_dglos.g_seq[seqID].m_bLeftAlign = true; + g_dglos.g_seq[seqID].m_transType = GetTransparencyOverrideForSequence(TRANSPARENT_NONE, seqID); + }else if (compare(ev[4], "NOTANIM") /*|| compare(ev[4], "NOTANIN")*/ ) //to work around a typo in MsDink's DMOD, but not to work around the notanin error in seq 424 in original dini.ini's.. yeah, complicated. Why!?!? + { + +#ifdef _DEBUG +if (seqID == 424) +{ + LogMsg("He"); +} +#endif + g_dglos.g_seq[seqID].m_transType = GetTransparencyOverrideForSequence(TRANSPARENT_WHITE, seqID); + } else + { + g_dglos.g_seq[seqID].m_transType = TRANSPARENT_WHITE; + //default, an anim with a lot of properties assigned + + /* + if (ev[9][0] != 0 && ev[10][0] == 0 + && + //(seqID == 119 + //|| seqID == 167 + //|| seqID == 316 + //|| seqID == 421 + //|| seqID == 422 + ) + ) //119, 167, 316, 421, 422 + { + //The original dink.ini has some malformed lines, where anim speed is not specified, yet it's sort of + //required here. Instead of fixing the .ini which would not fix various DMOD's, we'll do a work around + + //LogMsg("MISSING SOMETHING: %s", line); + strcpy(ev[10], ev[9]); + strcpy(ev[9], ev[8]); + strcpy(ev[8], ev[7]); + strcpy(ev[7], ev[6]); + strcpy(ev[6], ev[5]); + strcpy(ev[5], ev[4]); + strcpy(ev[4], "30"); //set the speed + } +*/ + + g_dglos.g_seq[seqID].m_bIsAnim = true; + //yes, an animation! + g_dglos.g_seq[seqID].m_speed = atol(ev[4]); + g_dglos.g_seq[seqID].m_xoffset = atol(ev[5]); + g_dglos.g_seq[seqID].m_yoffset = atol(ev[6]); + g_dglos.g_seq[seqID].m_hardbox.left = atol(ev[7]); + g_dglos.g_seq[seqID].m_hardbox.top = atol(ev[8]); + g_dglos.g_seq[seqID].m_hardbox.right = atol(ev[9]); + g_dglos.g_seq[seqID].m_hardbox.bottom = atol(ev[10]); + +#ifdef _DEBUG + //LogMsg("Hardbox: %s", PrintRect(hardbox).c_str()); +#endif + } + + + + +} + +bool ReloadSequence(int seqID, int frame, bool bScanOnly) +{ + + //handle a possible case where we need to always load frame 1 before any other frame to get the correct offset for anims + if (frame > 1 && !bScanOnly && g_dglos.g_seq[seqID].m_bIsAnim) + { + ReloadSequence(seqID, 1, bScanOnly); + } + + + return load_sprites(g_dglos.g_seq[seqID].m_fileName,seqID,g_dglos.g_seq[seqID].m_speed,g_dglos.g_seq[seqID].m_xoffset,g_dglos.g_seq[seqID].m_yoffset, g_dglos.g_seq[seqID].m_hardbox, + g_dglos.g_seq[seqID].m_transType, g_dglos.g_seq[seqID].m_bLeftAlign, bScanOnly, frame); //Crap +} + +bool figure_out(const char *line, int load_seq) +{ + char ev[15][100]; + rtRect32 hardbox; + hardbox.Clear(); + bool bReturn = true; + + memset(&ev,0, sizeof(ev)); + int myseq = 0,myframe = 0; int special = 0; + int special2 = 0; + + for (int i=1; i <= 14; i++) + { + separate_string(line, i,' ',ev[i]); + // Msg("Word %d is \"%s\"",i,ev[i]); + if (!ev[i][0]) break; + } + + if ( (compare(ev[1],"LOAD_SEQUENCE_NOW")) | ( compare(ev[1],"LOAD_SEQUENCE")) ) + { + // name seq speed offsetx offsety hardx hardy + + + int seqID = atol(ev[3]); + + + + if (!g_dglos.g_seq[seqID].active) + { + ReadFromLoadSequenceString(ev); + + //first time, actually init it + bReturn = load_sprites(g_dglos.g_seq[seqID].m_fileName,seqID,g_dglos.g_seq[seqID].m_speed,g_dglos.g_seq[seqID].m_xoffset,g_dglos.g_seq[seqID].m_yoffset, g_dglos.g_seq[seqID].m_hardbox + , g_dglos.g_seq[seqID].m_transType, g_dglos.g_seq[seqID].m_bLeftAlign, true); + + } else + { + ReadFromLoadSequenceString(ev); + FreeSequence(seqID); //force a full reload, the anim probably changed + ReloadSequence(seqID); + } + + + return bReturn; + } + + return pre_figure_out(line, load_seq, false); + + //assert(!"Uh.. why are people calling other things besides load sequence with init? Should we support that?"); + //return bReturn; +} + +void program_idata(void) +{ + return; +} + +bool pre_figure_out(const char *line, int load_seq, bool bLoadSpriteOnly) +{ + + if (line[0] == 0 || line[0] == ';') return true; + + bool bReturn = true; + + char ev[15][100]; + + memset(&ev,0, sizeof(ev)); + int myseq = 0,myframe = 0; int special = 0; + int special2 = 0; + for (int i=1; i <= 14; i++) + { + separate_string(line, i,' ',ev[i]); + // Msg("Word %d is \"%s\"",i,ev[i]); + if (!ev[i][0]) break; + } + + if (bLoadSpriteOnly) + { + + if ( compare(ev[1],"LOAD_SEQUENCE_NOW") || compare(ev[1],"LOAD_SEQUENCE") ) + // if ( (load_seq == -1) | (load_seq == atol(ev[3])) ) + { + int seqID = atol(ev[3]); + + ReadFromLoadSequenceString(ev); + + bReturn = load_sprites(g_dglos.g_seq[seqID].m_fileName,seqID,g_dglos.g_seq[seqID].m_speed,g_dglos.g_seq[seqID].m_xoffset,g_dglos.g_seq[seqID].m_yoffset, g_dglos.g_seq[seqID].m_hardbox + , g_dglos.g_seq[seqID].m_transType, g_dglos.g_seq[seqID].m_bLeftAlign, true); //Crap + return bReturn; + } + + return true; + } + + if (compare(ev[1],"playmidi")) + { + PlayMidi(ev[2]); + return bReturn; + } + + + if (compare(ev[1],"SET_SPRITE_INFO")) + { + // name seq speed offsetx offsety hardx hardy + //if (k[seq[myseq].frame[myframe]].frame = 0) Msg("Changing sprite that doesn't exist..."); + myseq = atol(ev[2]); + myframe = atol(ev[3]); + + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].xoffset = atol(ev[4]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].yoffset = atol(ev[5]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].hardbox.left = atol(ev[6]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].hardbox.top = atol(ev[7]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].hardbox.right = atol(ev[8]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].hardbox.bottom = atol(ev[9]); + g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].m_bCustomSettingsApplied = true; + + + if (myframe == 1 && g_dglos.g_seq[myseq].m_bIsAnim) + { + //set these to be the default for the whole anim.. (replacing that idata crap from the old source) +#ifdef _DEBUG + //LogMsg("Setting seq %d frame 1 to default for anim", myseq); +#endif + g_dglos.g_seq[myseq].m_xoffset = g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].xoffset; + g_dglos.g_seq[myseq].m_yoffset = g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].yoffset; + //g_dglos.g_seq[myseq].m_hardbox = g_dglos.g_picInfo[g_dglos.g_seq[myseq].frame[myframe]].hardbox; + } + + + } + + if (compare(ev[1],"SET_FRAME_SPECIAL")) + { + // name seq speed offsetx offsety hardx hardy + //if (k[seq[myseq].frame[myframe]].frame = 0) Msg("Changing sprite that doesn't exist..."); + + myseq = atol(ev[2]); + myframe = atol(ev[3]); + special = atol(ev[4]); + + g_dglos.g_seq[myseq].special[myframe] = special; + //LogMsg("Set special. %d %d %d",myseq, myframe, special); + } + + if (compare(ev[1],"SET_FRAME_DELAY")) + { + // name seq speed offsetx offsety hardx hardy + //if (k[seq[myseq].frame[myframe]].frame = 0) Msg("Changing sprite that doesn't exist..."); + + myseq = atol(ev[2]); + myframe = atol(ev[3]); + special = atol(ev[4]); + + g_dglos.g_seq[myseq].delay[myframe] = special; + //LogMsg("Set delay. %d %d %d",myseq, myframe, special); + } + + if (compare(ev[1],"STARTING_DINK_X")) + { + myseq = atol(ev[2]); + g_dglos.g_playerInfo.x = myseq; + } + + if (compare(ev[1],"STARTING_DINK_Y")) + { + myseq = atol(ev[2]); + g_dglos.g_playerInfo.y = myseq; + } + + if (compare(ev[1],"SET_FRAME_FRAME")) + { + + //assert(!"this is actually used?"); + myseq = atol(ev[2]); + myframe = atol(ev[3]); + special = atol(ev[4]); + special2 = atol(ev[5]); + + g_dglos.g_seq[myseq].m_bFrameSetUsed = true; + if (special == -1) + g_dglos.g_seq[myseq].frame[myframe] = special; else + g_dglos.g_seq[myseq].frame[myframe] = g_dglos.g_seq[special].frame[special2]; + + +#ifdef _DEBUG + //LogMsg("Set frame. %d %d %d",myseq, myframe, special); + + if (myseq == 16) + { + //LogMsg("Idle.."); + + } + + #endif + } + + return bReturn; +} + +int draw_num(int mseq, char nums[50], int mx, int my) +{ + int length = 0; + int ddrval; + int rnum = 0; + + if (!check_seq_status(mseq)) return 0; + + for (int i=0; i < strlen(nums); i++) + { + + if (nums[i] == '0') rnum = 10; + else if (nums[i] == '1') rnum = 1; + else if (nums[i] == '2') rnum = 2; + else if (nums[i] == '3') rnum = 3; + else if (nums[i] == '4') rnum = 4; + else if (nums[i] == '5') rnum = 5; + else if (nums[i] == '6') rnum = 6; + else if (nums[i] == '7') rnum = 7; + else if (nums[i] == '8') rnum = 8; + else if (nums[i] == '9') rnum = 9; + else if (nums[i] == '/') rnum = 11; + + if ( (rnum != 11) && (!(mseq == 442)) ) + ddrval = lpDDSBack->BltFast( mx+length, my,g_pSpriteSurface[g_dglos.g_seq[mseq].frame[rnum]], &g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[rnum]].box , DDBLTFAST_NOCOLORKEY); + else + ddrval = lpDDSBack->BltFast( mx+length, my, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[rnum]], &g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[rnum]].box , DDBLTFAST_SRCCOLORKEY); + + length += g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[rnum]].box.right; + + } + return(length); +} + + + +void draw_exp(bool bDraw) +{ + + if (!bDraw) return; + + char buffer[30]; + char nums[30]; + char final[30]; + + //Msg("Drawing exp.. which is %d and %d",fexp, *pexp); + strcpy(final, ""); + strcpy(nums,rt_ltoa(g_dglos.g_guiExp, buffer, 10)); + if (strlen(nums) < 5) + for (int i = 1; i < (6 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + strcat(final,"/"); + + strcpy(nums,rt_ltoa(g_dglos.g_guiRaise, buffer, 10)); + if (strlen(nums) < 5) + for (int i = 1; i < (6 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + draw_num(181, final, 404, 459); +} + +void draw_strength(bool bDraw) +{ + if (!bDraw) return; + + char final[30]; + char buffer[30]; + char nums[30]; + //Msg("Drawing exp.. which is %d and %d",fexp, *pexp); + strcpy(final, ""); + + strcpy(nums,rt_ltoa(g_dglos.g_guiStrength, buffer, 10)); + if (strlen(nums) < 3) + for (int i = 1; i < (4 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + //Msg("Drawing %s..",final); + draw_num(182, final, 81, 415); +} + + +void draw_defense(bool bDraw) +{ + + if (!bDraw) return; + + char final[30]; + char buffer[30]; + char nums[30]; + //Msg("Drawing exp.. which is %d and %d",fexp, *pexp); + strcpy(final, ""); + strcpy(nums,rt_ltoa(g_dglos.g_guiDefense, buffer, 10)); + if (strlen(nums) < 3) + for (int i = 1; i < (4 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + draw_num(183, final, 81, 437); +} + + +void draw_magic(bool bDraw) +{ + + if (!bDraw) return; + char final[30]; + char buffer[30]; + char nums[30]; + //Msg("Drawing exp.. which is %d and %d",fexp, *pexp); + strcpy(final, ""); + strcpy(nums,rt_ltoa(g_dglos.g_guiMagic, buffer, 10)); + if (strlen(nums) < 3) + for (int i = 1; i < (4 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + draw_num(184, final, 81, 459); +} + + +void draw_level() +{ + char final[30]; + char buffer[30]; + + //*plevel = 15; + //Msg("Drawing level.. which is %d ",*plevel); + strcpy(final, rt_ltoa(*plevel, buffer, 10)); + + if (strlen(final) == 1) + + draw_num(442, final, 528, 456); else + draw_num(442, final, 523, 456); +} + + +void draw_gold(bool bDraw) +{ + if (!bDraw) return; + + char final[30]; + char buffer[30]; + char nums[30]; + //Msg("Drawing exp.. which is %d and %d",fexp, *pexp); + strcpy(final, ""); + strcpy(nums,rt_ltoa(g_dglos.g_guiGold, buffer, 10)); + if (strlen(nums) < 5) + for (int i = 1; i < (6 - strlen(nums)); i++) + strcat(final, "0"); + strcat(final, nums); + draw_num(185, final, 298, 457); +} + + +void draw_bar(int life, int seqman) +{ + int ddrval; + int cur = 0; + int curx = 284; + int cury = 412; + int rnum = 3; + int curx_start = curx; + + rtRect32 box; + + if (!check_seq_status(seqman)) return; + + while(1) + { + cur++; + if (cur > life) + { + cur--; + int rem = (cur) - (cur / 10) * 10; + if (rem != 0) + { + + box = g_dglos.g_picInfo[g_dglos.g_seq[seqman].frame[rnum]].box; + //Msg("Drawing part bar . cur is %d", rem); + box.right = (box.right * ((rem) * 10)/100); + //woah, there is part of a bar remaining. Lets do it. + + lpDDSBack->BltFast( curx, cury, g_pSpriteSurface[g_dglos.g_seq[seqman].frame[rnum]], + &box , DDBLTFAST_NOCOLORKEY); + + } + + //are we done? + return; + } + + rnum = 2; + if (cur < 11) rnum = 1; + if (cur == *plifemax) rnum = 3; + + if ( (cur / 10) * 10 == cur) + { + ddrval = lpDDSBack->BltFast( curx, cury, g_pSpriteSurface[g_dglos.g_seq[seqman].frame[rnum]], + &g_dglos.g_picInfo[g_dglos.g_seq[seqman].frame[rnum]].box , DDBLTFAST_NOCOLORKEY); + + //if (ddrval != DD_OK) dderror(ddrval); + curx += g_dglos.g_picInfo[g_dglos.g_seq[seqman].frame[rnum]].box.right-1; + if (cur == 110) + { + cury += g_dglos.g_picInfo[g_dglos.g_seq[seqman].frame[rnum]].box.bottom+5; + curx = curx_start; + + } + + if (cur == 220) return; + } + } +} + +void draw_health() +{ + g_dglos.g_guiLifeMax = *plifemax; + draw_bar(g_dglos.g_guiLifeMax, 190); + g_dglos.g_guiLife = *plife; + draw_bar(g_dglos.g_guiLife, 451); +} + +void draw_icons() +{ + int ddrval; + int seq; + int frame; + + if (*pcur_weapon != 0) if (g_dglos.g_playerInfo.g_itemData[*pcur_weapon].active) + { + //disarm old weapon + //play.item[*pcur_weapon].seq, + seq = g_dglos.g_playerInfo.g_itemData[*pcur_weapon].seq; + frame = g_dglos.g_playerInfo.g_itemData[*pcur_weapon].frame; + + if (!check_seq_status(seq, frame)) return; + + DrawFilledRect(557, 413, + g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]->m_pSurf->GetWidth() + ,g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]->m_pSurf->GetHeight(), MAKE_RGBA(0,0,0,255)); + + + ddrval = lpDDSBack->BltFast( 557, 413, g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]], + &g_dglos.g_picInfo[g_dglos.g_seq[seq].frame[frame]].box, DDBLTFAST_SRCCOLORKEY); + + } + + if (*pcur_magic != 0) if (g_dglos.g_playerInfo.g_MagicData[*pcur_magic].active) + { + //disarm old weapon + //play.mitem[*pcur_magic].seq, + + seq = g_dglos.g_playerInfo.g_MagicData[*pcur_magic].seq; + frame = g_dglos.g_playerInfo.g_MagicData[*pcur_magic].frame; + + if (!check_seq_status(seq, frame)) return; + + DrawFilledRect(153, 413, + g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]->m_pSurf->GetWidth() + ,g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]->m_pSurf->GetHeight(), MAKE_RGBA(0,0,0,255)); + + ddrval = lpDDSBack->BltFast( 153, 413, g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]], + &g_dglos.g_picInfo[g_dglos.g_seq[seq].frame[frame]].box, DDBLTFAST_SRCCOLORKEY); + } +} + + +void draw_vertical(int percent, int mx, int my, int mseq, int mframe) +{ + int ddrval; + int cut; + if (percent > 25) percent = 25; + percent = (percent * 4); + rtRect32 myrect; + myrect = g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box; + int full = myrect.bottom; + cut = (full * percent) / 100; + + myrect.bottom = cut; + my += (full - cut); + + ddrval = lpDDSBack->BltFast( mx, my, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &myrect, DDBLTFAST_NOCOLORKEY); +} + +void draw_virt2(int percent, int mx, int my, int mseq, int mframe) +{ + int ddrval; + int cut; + if (percent > 25) percent = 25; + percent = (percent * 4); + rtRect32 myrect; + myrect = g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box; + int full = myrect.bottom; + cut = (full * percent) / 100; + myrect.bottom = cut; + + ddrval = lpDDSBack->BltFast( mx, my, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &myrect, DDBLTFAST_NOCOLORKEY); +} + +void draw_hor(int percent, int mx, int my, int mseq, int mframe) +{ + int ddrval; + int cut; + if (percent > 25) percent = 25; + percent = (percent * 4); + rtRect32 myrect; + myrect = g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box; + int full = myrect.right; + cut = (full * percent) / 100; + full = cut; + myrect.right = full; + + ddrval = lpDDSBack->BltFast( mx, my, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &myrect, DDBLTFAST_NOCOLORKEY); +} + +void draw_hor2(int percent, int mx, int my, int mseq, int mframe) +{ + int ddrval; + int cut; + if (percent > 25) percent = 25; + percent = (percent * 4); + rtRect32 myrect; + myrect = g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box; + int full = myrect.right; + cut = (full * percent) / 100; + myrect.right = cut; + mx += (full - cut); + ddrval = lpDDSBack->BltFast( mx, my, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &myrect, DDBLTFAST_NOCOLORKEY); +} + +void draw_mlevel(int percent, bool bDraw) +{ + if (!bDraw) return; + + int mseq = 180; + int bary = 6; + int barx = 7; + + if (percent > 0) draw_vertical(percent, 149, 411, mseq, bary); + percent -= 25; + if (percent > 0) draw_hor(percent, 149, 409, mseq, barx); + percent -= 25; + if (percent > 0) draw_virt2(percent, 215, 411, mseq, bary); + percent -= 25; + if (percent > 0) draw_hor2(percent, 149, 466, mseq, barx); +} + + +void draw_status_all(void) +{ + + g_dglos.g_guiStrength = *pstrength; + g_dglos.g_guiMagic = *pmagic; + g_dglos.g_guiGold = *pgold; + g_dglos.g_guiDefense = *pdefense; + + return; + +} + +void BlitGUIOverlay() +{ + + if (GetDinkGameMode() == DINK_GAME_MODE_MOUSE) return; + + if (GetDinkSubGameMode() == DINK_SUB_GAME_MODE_SHOWING_BMP) return; + + + + + rtRect32 rcRect; + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = C_DINK_SCREENSIZE_X; + rcRect.bottom = 80; + + if (*pupdate_status == 0) + { + //draw black bars around things + DrawFilledRect(0, 400, rcRect.right, rcRect.bottom, MAKE_RGBA(0,0,0,255)); + + rcRect.right = 20; + rcRect.bottom = 400; + DrawFilledRect(0, 0, rcRect.right, rcRect.bottom, MAKE_RGBA(0,0,0,255)); + DrawFilledRect(620, 0, rcRect.right, rcRect.bottom, MAKE_RGBA(0,0,0,255)); + + return; + } + + g_dglos.g_guiRaise = next_raise(); + if ( *pexper < g_dglos.g_guiRaise ) + { + g_dglos.g_guiExp = *pexper; + } + else + { + g_dglos.g_guiExp = g_dglos.g_guiRaise - 1; + } + + /* + g_dglos.g_guiStrength = *pstrength; + g_dglos.g_guiMagic = *pmagic; + g_dglos.g_guiGold = *pgold; + g_dglos.g_guiDefense = *pdefense; + */ + g_dglos.g_guiLastMagicDraw = 0; + + if (g_dglo.m_curView == DinkGlobals::VIEW_ZOOMED || g_dglo.m_viewOverride == DinkGlobals::VIEW_ZOOMED) return; + + if (!check_seq_status(180)) return; + + lpDDSBack->BltFast( 0, 400, g_pSpriteSurface[g_dglos.g_seq[180].frame[3]], &rcRect , DDBLTFAST_NOCOLORKEY ); + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = 20; + rcRect.bottom = 400; + + lpDDSBack->BltFast( 0, 0, g_pSpriteSurface[g_dglos.g_seq[180].frame[1]], &rcRect , DDBLTFAST_NOCOLORKEY ); + lpDDSBack->BltFast( 620, 0,g_pSpriteSurface[g_dglos.g_seq[180].frame[2]], &rcRect , DDBLTFAST_NOCOLORKEY ); + + + draw_exp(true); + draw_health(); + draw_strength(true); + draw_defense(true); + draw_magic(true); + draw_gold(true); + draw_level(); + draw_icons(); + + if (*pmagic_cost > 0 && *pmagic_level > 0) + { + draw_mlevel( (float(*pmagic_level) / float(*pmagic_cost))*100, true ); + } + + + + + +} + +bool inside_box(int x1, int y1, rtRect32 box) +{ + if (x1 > box.right) return(false); + if (x1 < box.left) return(false); + if (y1 > box.bottom) return(false); + if (y1 < box.top) return(false); + return(true); +} + +int add_sprite_dumb(int x1, int y, int brain,int pseq, int pframe,int size ) +{ + +#ifdef _DEBUG + + if (pseq == 180) + { + LogMsg("wtf!"); + } +#endif + for (int x=1; x < C_MAX_SPRITES_AT_ONCE; x++) + { + if (g_sprite[x].active == false) + { + SAFE_DELETE(g_customSpriteMap[x]); + memset(&g_sprite[x], 0, sizeof(g_sprite[x])); + + //Msg("Making sprite %d.",x); + g_sprite[x].active = true; + g_sprite[x].x = x1; + g_sprite[x].y = y; + g_sprite[x].my = 0; + g_sprite[x].mx = 0; + g_sprite[x].speed = 0; + g_sprite[x].brain = brain; + g_sprite[x].frame = 0; + g_sprite[x].pseq = pseq; + g_sprite[x].pframe = pframe; + g_sprite[x].size = size; + g_sprite[x].seq = 0; + if (x > g_dglos.last_sprite_created) + g_dglos.last_sprite_created = x; + + g_sprite[x].timer = 0; + g_sprite[x].wait = 0; + g_sprite[x].lpx[0] = 0; + g_sprite[x].lpy[0] = 0; + g_sprite[x].moveman = 0; + g_sprite[x].seq_orig = 0; + + g_sprite[x].base_hit = -1; + g_sprite[x].base_walk = -1; + g_sprite[x].base_die = -1; + g_sprite[x].base_idle = -1; + g_sprite[x].base_attack = -1; + g_sprite[x].last_sound = 0; + g_sprite[x].hard = 1; + + g_sprite[x].alt.Clear(); + g_sprite[x].althard = 0; + g_sprite[x].sp_index = 0; + g_sprite[x].nocontrol = 0; + g_sprite[x].idle = 0; + g_sprite[x].strength = 0; + g_sprite[x].damage = 0; + g_sprite[x].defense = 0; + + if ( g_customSpriteMap[x] == NULL ) + { + g_customSpriteMap[x] = new std::map; + } + else + { + g_customSpriteMap[x]->clear(); + } + return(x); + } + } + + return(0); +} + +bool get_box (int spriteID, rtRect32 * pDstRect, rtRect32 * pSrcRect ) +{ + rtRect32 math; + int32 sz,sy,x_offset,y_offset; + + int32 mplayx = g_gameAreaRightBarStartX; + int32 mplayl = g_gameAreaLeftOffset; + int32 mplayy = C_DINK_ORIGINAL_GAME_AREA_Y; + + if (g_sprite[spriteID].noclip) + { + mplayx = C_DINK_SCREENSIZE_X; + mplayl = 0; + mplayy = C_DINK_SCREENSIZE_Y; + } + + rtRect32 krect; + + if (getpic(spriteID) < 1) + { +#ifdef _DEBUG + LogMsg("Yo, sprite %d has a bad pic. (Map %d) Seq %d, Frame %d",spriteID,*pmap, g_sprite[spriteID].pseq, g_sprite[spriteID].pframe); +#endif + //redink1 added to fix frame-not-in-memory immediately + if (!check_seq_status(g_sprite[spriteID].pseq, g_sprite[spriteID].pframe)) return false; + } + +#ifdef _DEBUG + if (g_sprite[spriteID].pseq == 66 && g_sprite[spriteID].pframe == 1) + { + //LogMsg("Yo"); + } +#endif + + int picID = getpic(spriteID); + if (g_sprite[spriteID].size == 0) g_sprite[spriteID].size = 100; + + int scale = g_sprite[spriteID].size; + + int txoffset = g_dglos.g_picInfo[picID].xoffset; + int tyoffset = g_dglos.g_picInfo[picID].yoffset; + + *pSrcRect = g_dglos.g_picInfo[picID].box; + krect = g_dglos.g_picInfo[picID].box; + + if (scale != 100) + { + sz = ((krect.right * scale) / 100); + sy = ((krect.bottom * scale) / 100); + } else + { + sz = 0; + sy = 0; + } + + if (scale != 100) + { + sz = ((sz - krect.right) / 2); + sy = ((sy - krect.bottom) / 2); + + } + + pDstRect->left = g_sprite[spriteID].x-txoffset-sz; + math.left = g_sprite[spriteID].x-txoffset; + + pDstRect->top = g_sprite[spriteID].y - tyoffset-sy; + math.top = g_sprite[spriteID].y-tyoffset; + + pDstRect->right = (math.left+ (krect.right -krect.left)) + sz; + math.right = math.left+ krect.right; + + pDstRect->bottom = (math.top + (krect.bottom - krect.top)) + sy; + math.bottom = math.top + krect.bottom; + + if ( (g_sprite[spriteID].alt.right != 0) | (g_sprite[spriteID].alt.left != 0) | (g_sprite[spriteID].alt.top != 0) | (g_sprite[spriteID].alt.right != 0)) + { + //redink1 checks for correct box stuff + if (g_sprite[spriteID].alt.left < 0) + g_sprite[spriteID].alt.left = 0; + if (g_sprite[spriteID].alt.left > g_dglos.g_picInfo[picID].box.right) + g_sprite[spriteID].alt.left = g_dglos.g_picInfo[picID].box.right; + if (g_sprite[spriteID].alt.top < 0) + g_sprite[spriteID].alt.top = 0; + if (g_sprite[spriteID].alt.top > g_dglos.g_picInfo[picID].box.bottom) + g_sprite[spriteID].alt.top = g_dglos.g_picInfo[picID].box.bottom; + if (g_sprite[spriteID].alt.right < 0) + g_sprite[spriteID].alt.right = 0; + if (g_sprite[spriteID].alt.right > g_dglos.g_picInfo[picID].box.right) + g_sprite[spriteID].alt.right = g_dglos.g_picInfo[picID].box.right; + if (g_sprite[spriteID].alt.bottom < 0) + g_sprite[spriteID].alt.bottom = 0; + if (g_sprite[spriteID].alt.bottom > g_dglos.g_picInfo[picID].box.bottom) + g_sprite[spriteID].alt.bottom = g_dglos.g_picInfo[picID].box.bottom; + //spr[h].alt.bottom = 10; + pDstRect->left = pDstRect->left + g_sprite[spriteID].alt.left; + pDstRect->top = pDstRect->top + g_sprite[spriteID].alt.top; + pDstRect->right = pDstRect->right - (g_dglos.g_picInfo[picID].box.right - g_sprite[spriteID].alt.right); + pDstRect->bottom = pDstRect->bottom - (g_dglos.g_picInfo[picID].box.bottom - g_sprite[spriteID].alt.bottom); + *pSrcRect = g_sprite[spriteID].alt; + //Msg("I should be changing box size... %d %d,%d,%d",spr[h].alt.right,spr[h].alt.left,spr[h].alt.top,spr[h].alt.bottom); + } + + //********* Check to see if they need to be cut down and do clipping + if (g_sprite[spriteID].size == 0) g_sprite[spriteID].size = 100; + + + if (pDstRect->left < mplayl) + { + x_offset = pDstRect->left * (-1) + mplayl; + pDstRect->left = mplayl; + //box_real->left += (math.left * (-1)) + mplayl; + + if (g_sprite[spriteID].size != 100) + pSrcRect->left += (((x_offset * 100) / (g_sprite[spriteID].size )) ); else + + pSrcRect->left += x_offset; + if (pDstRect->right-1 < mplayl) goto nodraw; + } + + if (pDstRect->top < 0) + { + y_offset = pDstRect->top * (-1); + pDstRect->top = 0; + + //box_real->top += math.top * (-1) + 0; + if (g_sprite[spriteID].size != 100) + pSrcRect->top += (((y_offset * 100) / (g_sprite[spriteID].size )) ); + + else pSrcRect->top += y_offset; + if (pDstRect->bottom-1 < 0) goto nodraw; + } + + if (pDstRect->right > mplayx) + { + x_offset = (pDstRect->right) - mplayx; + pDstRect->right = mplayx; + //x_real->right -= math.right - mplayx; + if (g_sprite[spriteID].size != 100) + pSrcRect->right -= ((x_offset * 100) / (g_sprite[spriteID].size )); + else pSrcRect->right -= x_offset; + if (pDstRect->left+1 > mplayx) goto nodraw; + + // Msg("ok, crap right is %d, real right is %d.",box_crap->right - box_crap->left,box_real->right); + } + + if (pDstRect->bottom > mplayy) + { + y_offset = (pDstRect->bottom) - mplayy; + pDstRect->bottom = mplayy; + if (g_sprite[spriteID].size != 100) + pSrcRect->bottom -= ((y_offset * 100) / (g_sprite[spriteID].size )); + else pSrcRect->bottom -= y_offset; + if (pDstRect->top+1 > mplayy) goto nodraw; + } + + return(true); + +nodraw: + + return(false); +} + + +void kill_callbacks_owned_by_script(int script) +{ + for (int i = 1; i < C_MAX_SCRIPT_CALLBACKS; i++) + { + if (g_dglos.g_scriptCallback[i].owner == script) + { + if (debug_mode) LogMsg("Kill_all_callbacks just killed %d for script %d", i, script); + //killed callback + g_dglos.g_scriptCallback[i].active = false; + } + } +} + +void kill_script(int k) +{ + if (g_scriptInstance[k] != NULL) + { + kill_callbacks_owned_by_script(k); + + //now lets kill all local vars associated with this script + + for (int i = 1; i < max_vars; i++) + { + if (g_dglos.g_playerInfo.var[i].active) if (g_dglos.g_playerInfo.var[i].scope == k) + { + g_dglos.g_playerInfo.var[i].active = false; + } + } + + if (debug_mode) LogMsg("Killed script %s. (num %d)", g_scriptInstance[k]->name, k); + + free(g_scriptInstance[k]); + g_scriptInstance[k] = NULL; + free(g_scriptBuffer[k]); + g_scriptBuffer[k] = NULL; + g_scriptAccelerator[k].Kill(); + } +} + +void kill_all_scripts(void) +{ + for (int k = 1; k < C_MAX_SCRIPTS; k++) + { + if (g_scriptInstance[k] != NULL) if (g_scriptInstance[k]->sprite != 1000) + kill_script(k); + } + + for (int k = 1; k < C_MAX_SCRIPT_CALLBACKS; k++) + { + if (g_dglos.g_scriptCallback[k].active) + { + if ( (g_scriptInstance[g_dglos.g_scriptCallback[k].owner] != NULL) && (g_scriptInstance[g_dglos.g_scriptCallback[k].owner]->sprite == 1000) ) + { + } else + { + if (debug_mode) LogMsg("Killed callback %d. (was attached to script %d.)",k, g_dglos.g_scriptCallback[k].owner); + g_dglos.g_scriptCallback[k].active = 0; + } + } + } +} + +void kill_all_scripts_for_real(void) +{ + for (int k = 1; k < C_MAX_SCRIPTS; k++) + { + if (g_scriptInstance[k] != NULL) + kill_script(k); + } + + for (int k = 1; k < C_MAX_SCRIPT_CALLBACKS; k++) + { + g_dglos.g_scriptCallback[k].active = 0; + } +} + +bool ScriptEOF(int script) +{ + if (!g_scriptInstance[script]) return true; + + return (g_scriptInstance[script]->current >= g_scriptInstance[script]->end); +} + +bool read_next_line(int script, char *line) +{ + if ( (g_scriptInstance[script] == NULL) || (g_scriptBuffer == NULL) ) + { + + LogMsg(" ERROR: Tried to read script %d, it doesn't exist.", script); + return(false); + } + + if (g_scriptInstance[script]->current >= g_scriptInstance[script]->end) + { + //at end of buffer + return(false); + } + + strcpy(line, ""); + + for (int k = g_scriptInstance[script]->current; (k < g_scriptInstance[script]->end); k++) + { + // Msg("..%d",k); + strchar(line, g_scriptBuffer[script][k]); + g_scriptInstance[script]->current++; + + if ( (g_scriptBuffer[script][k] == '\n') || (g_scriptBuffer[script][k] == '\r') ) + { + return(true); + } + + if (g_scriptInstance[script]->current >= g_scriptInstance[script]->end) return(false); + } + + return(false); +} + + +int load_script(const char *pScript, int sprite, bool set_sprite, bool bQuietError) +{ + + string fName = "story/"+ToLowerCaseString(pScript); + + int script; + FILE *stream; + bool comp = false; + + bool bFound = false; + + string fileName; + + if (!g_dglo.m_dmodGameDir.empty()) + { + //first check the dmod path + fileName = g_dglo.m_dmodGamePathWithDir+fName+".d"; + + if (FileExists(fileName)) + { + bFound = true; + comp = true; + } else + { + fileName = g_dglo.m_dmodGamePathWithDir+fName+".c"; + if (FileExists(fileName)) + { + bFound = true; + } + } + } + + if (!bFound) + { + + if (g_dglo.m_bUsingDinkPak) + { + fileName = g_dglo.m_gameDir+fName+".d"; + } else + { + fileName = g_dglo.m_gamePathWithDir+fName+".d"; + } + + + if (FileExists(fileName)) + { + comp = true; + } else + { + if (g_dglo.m_bUsingDinkPak) + { + fileName = g_dglo.m_gameDir+fName+".c"; + } else + { + fileName = g_dglo.m_gamePathWithDir+fName+".c"; + } + + if (!FileExists(fileName)) + { + if (bQuietError) return 0; + LogMsg("Script %s not found. (checked for .C and .D) (requested by %d?)",fileName.c_str(), sprite); + return 0; + } + } + } + + + int k; + + for (k=1; k < C_MAX_SCRIPTS; k++) + { + if (g_scriptBuffer[k] == NULL) + { + //found one not being used + goto found; + } + } + + LogMsg("Couldn't find unused buffer for script."); + return(0); + + +found: +#ifdef _DEBUG + LogMsg("Loading script %s..", fileName.c_str()); +#endif + script = k; + g_scriptAccelerator[script].Kill(); + g_scriptInstance[script] = (struct refinfo *) malloc( sizeof(struct refinfo)); + memset(g_scriptInstance[script], 0, sizeof(struct refinfo)); + + //load compiled script + + FileInstance scriptFile(fileName, false); + if (!scriptFile.IsLoaded()) + { + LogMsg("Script %s not found. (checked for .C and .D) (requested by %d?)",fileName.c_str(), sprite); + return(0); + } + + char * pMemBuffer = new char[1024*128]; + pMemBuffer[0] = 0; + + if (!pMemBuffer) + { + LogMsg("Mem error"); + return false; + } + + // LogMsg("Checking compression..."); + if (comp) + { + dink_decompress(scriptFile.GetAsBytes(), pMemBuffer); + } + else + { + + decompress_nocomp(scriptFile.GetAsBytes(), pMemBuffer); + } + + //LogMsg("file in cbuf"); + + g_scriptInstance[script]->end = (strlen(pMemBuffer) ); + //LogMsg("length of %s is %d!", fileName.c_str(), g_scriptInstance[script]->end); + + g_scriptBuffer[script] = (char *) malloc( g_scriptInstance[script]->end ); + + if (g_scriptBuffer[script] == NULL) + { + LogMsg("Couldn't allocate rbuff %d.",script); + SAFE_DELETE_ARRAY(pMemBuffer); + return(0); + } + // LogMsg("Copying script"); + + memcpy(g_scriptBuffer[script], pMemBuffer, g_scriptInstance[script]->end); + + SAFE_DELETE_ARRAY(pMemBuffer); + + + //LogMsg("Script loaded by sprite %d into space %d.", sprite,script); + strcpy(g_scriptInstance[script]->name, pScript); + g_scriptInstance[script]->sprite = sprite; + + if (set_sprite) + { + if (sprite != 0) if (sprite != 1000) + g_sprite[sprite].script = script; + } + + //LogMsg("Returning script"); + + return (script); +} + + +void strip_beginning_spaces(char *pInput) +{ + char * h; + h = pInput; + + if (pInput[0] != 32) + { + return; + } + + while(h[0] == 32) + { + h = &h[1]; + } + strcpy(pInput, h); +} + + + +bool locate(int script, char proc[20]) +{ + + if (g_scriptInstance[script] == NULL) + { + return(false); + } + + + int saveme = g_scriptInstance[script]->current; + g_scriptInstance[script]->current = 0; + char line[200]; + char ev[3][100]; + char temp[100]; + + //Msg("locate is looking for %s in %s", proc, rinfo[script]->name); + + while(read_next_line(script, line)) + { + strip_beginning_spaces(line); + memset(&ev, 0, sizeof(ev)); + + get_word(line, 1, ev[1]); + if (compare(ev[1], (char*)"VOID")) + { + get_word(line, 2, ev[2]); + + separate_string(ev[2], 1,'(',temp); + + // Msg("Found procedure %s.",temp); + if (compare(temp,proc)) + { + // Msg("Located %s",proc); + //clean up vars so it is ready to run + if (g_scriptInstance[script]->sprite != 1000) + { + g_sprite[g_scriptInstance[script]->sprite].move_active = false; + g_sprite[g_scriptInstance[script]->sprite].move_nohard = false; + + } + g_scriptInstance[script]->skipnext = false; + g_scriptInstance[script]->onlevel = 0; + g_scriptInstance[script]->level = 0; + + return(true); + //this is desired proc + + } + } + + } + + //Msg("Locate ended on %d.", saveme); + g_scriptInstance[script]->current = saveme; + return(false); + +} + +bool locate_goto(char proc[50], int script) +{ + g_scriptInstance[script]->current = 0; + + int procLen = strlen(proc); + + if (proc[procLen - 1] == ';') + { + proc[procLen - 1] = ':'; + } + else + { + //just add it + proc[procLen] = ':'; + proc[procLen + 1] = 0; + } + + ScriptPosition *pScriptPos = g_scriptAccelerator[script].GetPositionByName(proc); + + if (pScriptPos) + { + //LogMsg("Did fast lookup of %s", proc); + //found it, nice shortcut + g_scriptInstance[script]->current = pScriptPos->current; + g_scriptInstance[script]->skipnext = false; + g_scriptInstance[script]->onlevel = 0; + g_scriptInstance[script]->level = 0; + return true; + + } + char line[200]; + + + // Msg("locate is looking for %s", proc); + + while(read_next_line(script, line)) + { + strip_beginning_spaces(line); + + if (strnicmp(line, proc, procLen) == 0) + { + //if (debug_mode) LogMsg("Found goto : Line is %s, word is %s.", line, ev[1]); + + g_scriptInstance[script]->skipnext = false; + g_scriptInstance[script]->onlevel = 0; + g_scriptInstance[script]->level = 0; + + //add it for faster look-up nexttime + g_scriptAccelerator[script].AddPosition(proc, g_scriptInstance[script]->current); + + return(true); + } + + } + LogMsg("ERROR: Cannot goto %s in %s.", proc, g_scriptInstance[script]->name); + return(false); + +} + +void decipher(char *crap, int script) +{ + + if (compare(crap, (char*)"¤t_sprite")) + { + sprintf(crap, "%d",g_scriptInstance[script]->sprite); + //Msg("cur sprite returning %s, ",crap); + return; + } + + if (compare(crap, (char*)"¤t_script")) + { + sprintf(crap, "%d",script); + return; + } + + //v1.08 special variables. + if (compare(crap, (char*)"&return")) + { + sprintf(crap, "%d", g_dglos.g_returnint); + return; + } + + if (compare(crap, (char*)"&arg1")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg1); + return; + } + + if (compare(crap, (char*)"&arg2")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg2); + return; + } + + if (compare(crap, (char*)"&arg3")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg3); + return; + } + + if (compare(crap, (char*)"&arg4")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg4); + return; + } + + if (compare(crap, (char*)"&arg5")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg5); + return; + } + + if (compare(crap, (char*)"&arg6")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg6); + return; + } + + if (compare(crap, (char*)"&arg7")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg7); + return; + } + + if (compare(crap, (char*)"&arg8")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg8); + return; + } + + if (compare(crap, (char*)"&arg9")) + { + sprintf(crap, "%d", g_scriptInstance[script]->arg9); + return; + } + + for (int i = 1; i < max_vars; i ++) + { + if (g_dglos.g_playerInfo.var[i].active == true) if ( i == get_var(script, g_dglos.g_playerInfo.var[i].name)) //redink1 changed for recursive scoping + if (compare(g_dglos.g_playerInfo.var[i].name, crap)) + { + sprintf(crap, "%d",g_dglos.g_playerInfo.var[i].var); + // check_for_real_vars(crap, i); + return; + } + } +} + +//redink1 added, grabs the var index matching 'name' with the shortest scope. Basically iterates for each scope seperate until it finds a match. +int get_var(int script, char* name) +{ + //Can optimize here, by searching through variable array for start and end limits + + //Loop forever... + while (1) + { + //We'll start going through every var, starting at one + int var = 1; + while (var < max_vars) + { + //Okay... make sure the var is active, + //The scope should match the script, + //Then make sure the name is the same. + if (g_dglos.g_playerInfo.var[var].active && g_dglos.g_playerInfo.var[var].scope == script && compare(g_dglos.g_playerInfo.var[var].name, name)) + return var; + + //Otherwise, go to the next var. + var++; + } + + //If we just went through the global list, let's return + if (script <= 0) + break; + + //Bugfix... if there is no rinfo[script] entry (like if kill this task was used), we go directly to the globals. + //Thanks Tal! + //if (!rinfo[script]) + // script = 0; + //Go into the next proc from the script. If there are no parent procs, it should be 0, which is global. + //else + // script = rinfo[script]->proc_return; + + //Changed to not reference the parent procedure's variable list at all... just go on to globals. + script = 0; + } + + return 0; +} + +//redink1 changes for replacing var in string +bool recurse_var_replace(int i, int script, char* line, char* prevar) +{ + while (i < max_vars) + { + //First, make sure the variable is active. + //Then, make sure it is in scope, + //Then, see if the variable name is in the line + //Then, prevar is null, or if prevar isn't null, see if current variable starts with prevar + if (g_dglos.g_playerInfo.var[i].active && + i == get_var(script, g_dglos.g_playerInfo.var[i].name) && + strstr(line, g_dglos.g_playerInfo.var[i].name) && + (prevar == NULL || prevar != NULL && strstr(g_dglos.g_playerInfo.var[i].name, prevar))) + { + //Look for shorter variables + if (!recurse_var_replace(i + 1, script, line, g_dglos.g_playerInfo.var[i].name)) + { + //we didn't find any, so we replace! + char crap[20]; + sprintf(crap, "%d", g_dglos.g_playerInfo.var[i].var); + replace(g_dglos.g_playerInfo.var[i].name, crap, line); + //return true; + } + } + i++; + } + return false; +} + +void decipher_string(char line[200], int script) +{ + char crap[255]; + char buffer[255]; + char crab[255]; + int mytime; + + //redink1 replaced with recursive function for finding longest variable + recurse_var_replace(1, script, line, NULL); + + /*for (int i = 1; i < max_vars; i ++) + { + if (play.var[i].active == true) + if ( (play.var[i].scope == 0) || recurse_scope(play.var[i].scope, script) ) + { + sprintf(crap, "%d", play.var[i].var); + replace(play.var[i].name, crap, line); + + // check_for_real_vars(crap, i); + //break; + } + }*/ + + if ((strchr(line, '&') != NULL) && (script != 0)) + { + replace((char*)"¤t_sprite",rt_ltoa(g_scriptInstance[script]->sprite, buffer, 10), line); + replace((char*)"¤t_script",rt_ltoa(script, buffer, 10), line); + //v1.08 special variables. + replace((char*)"&return",rt_ltoa(g_dglos.g_returnint, buffer, 10), line); + replace((char*)"&arg1",rt_ltoa(g_scriptInstance[script]->arg1, buffer, 10), line); + replace((char*)"&arg2",rt_ltoa(g_scriptInstance[script]->arg2, buffer, 10), line); + replace((char*)"&arg3",rt_ltoa(g_scriptInstance[script]->arg3, buffer, 10), line); + replace((char*)"&arg4",rt_ltoa(g_scriptInstance[script]->arg4, buffer, 10), line); + replace((char*)"&arg5",rt_ltoa(g_scriptInstance[script]->arg5, buffer, 10), line); + replace((char*)"&arg6",rt_ltoa(g_scriptInstance[script]->arg6, buffer, 10), line); + replace((char*)"&arg7",rt_ltoa(g_scriptInstance[script]->arg7, buffer, 10), line); + replace((char*)"&arg8",rt_ltoa(g_scriptInstance[script]->arg8, buffer, 10), line); + replace((char*)"&arg9",rt_ltoa(g_scriptInstance[script]->arg9, buffer, 10), line); + + if (decipher_savegame != 0) + { + if (g_dglos.g_playerInfo.button[decipher_savegame] == 1) replace((char*)"&buttoninfo", "Attack", line); + else + if (g_dglos.g_playerInfo.button[decipher_savegame] == 2) replace((char*)"&buttoninfo", "Talk/Examine", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 3) replace((char*)"&buttoninfo", "Magic", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 4) replace((char*)"&buttoninfo", "Item Screen", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 5) replace((char*)"&buttoninfo", "Main Menu", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 6) replace((char*)"&buttoninfo", "Map", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 7) replace((char*)"&buttoninfo", "Unused", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 8) replace((char*)"&buttoninfo", "Unused", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 9) replace((char*)"&buttoninfo", "Unused", line); + if (g_dglos.g_playerInfo.button[decipher_savegame] == 10) replace((char*)"&buttoninfo", "Unused", line); + } + } + + if (decipher_savegame != 0) + if (compare(line, (char*)"&savegameinfo")) + { + if (decipher_savegame == 10) + { + string autoSave = DinkGetSavePath() + "autosave.dat"; + + if (!FileExists(autoSave)) + { + sprintf(line, "Auto Save - None yet"); + } else + { + mytime = 0; + string description = "Unknown"; + + VariantDB db; + bool bFileExisted = false; + + if (db.Load(DinkGetSavePath()+"autosavedb.dat", &bFileExisted, false) && bFileExisted ) + { + mytime = db.GetVar("minutes")->GetUINT32(); + description = db.GetVar("description")->GetString(); + } + + sprintf(line, "Auto Save - %d:%02d - %s", (mytime / 60), mytime - ((mytime / 60) * 60), description.c_str()); + } + } else + { + + sprintf(crap, "%ssave%d.dat",g_dglo.m_savePath.c_str(), decipher_savegame); + + if (FileExists(crap)) + { + load_game_small(decipher_savegame, crab, &mytime); + //redink1 fix for savegame time bug + sprintf(line, "Slot %d - %d:%02d - %s", decipher_savegame, (mytime / 60), mytime - ((mytime / 60) * 60) , crab); + //sprintf(line, "In Use"); + } else + { + sprintf(line, "Slot %d - Empty",decipher_savegame); + } + } + } +} + +bool get_parms(char proc_name[20], int32 script, char *h, int32 p[10]) +{ + memset(g_nlist, 0, 10 * sizeof(int)); + char crap[256]; + strip_beginning_spaces(h); + if (h[0] == '(') + { + //Msg("Found first (."); + h = &h[1]; + + } else + { + LogMsg("Missing ( in %s, offset %d.", g_scriptInstance[script]->name, g_scriptInstance[script]->current); + return(false); + } + + for (int i = 0; i < 10; i++) + { + strip_beginning_spaces(h); + + if (p[i] == 1) + { + // Msg("Checking for number.."); + + + if (strchr(h, ',') != NULL) + separate_string(h, 1,',',crap); else + if (strchr(h, ')') != NULL) + separate_string(h, 1,')',crap); + + + h = &h[strlen(crap)]; + + + if (crap[0] == '&') + { + replace(" ", "", crap); + // Msg("Found %s, 1st is %c",crap, crap[0]); + decipher(crap, script); + } + + g_nlist[i] = atol( crap); + + } else + + if (p[i] == 2) + { + // Msg("Checking for string.."); + separate_string(h, 2,'"',crap); + h = &h[strlen(crap)+2]; + + //Msg("Found %s",crap); + strcpy(slist[i], crap); + } + + if ( p[i+1] == 0) + { + //finish + strip_beginning_spaces(h); + + if (h[0] == ')') + { + h = &h[1]; + } else + { + + LogMsg("Missing ) in %s, offset %d.", g_scriptInstance[script]->name, g_scriptInstance[script]->current); + h = &h[1]; + + return(false); + } + + strip_beginning_spaces(h); + + if (h[0] == ';') + { + // Msg("Found ending ;"); + h = &h[1]; + + } else + { + //Msg("Missing ; in %s, offset %d.", rinfo[script]->name, rinfo[script]->current); + // h = &h[1]; + return(true); + } + + return(true); + } + + + //got a parm, but there is more to get, lets make sure there is a comma there + strip_beginning_spaces(h); + + if (h[0] == ',') + { + // Msg("Found expected ,"); + h = &h[1]; + + } else + { + LogMsg("Procedure %s does not take %d parms in %s, offset %d. (%s?)", proc_name, i+1, g_scriptInstance[script]->name, g_scriptInstance[script]->current, h); + + return(false); + } + } + + + return(true); +} + +int GetCallbacksActive() +{ + int count = 0; + + for (int k = 1; k < C_MAX_SCRIPT_CALLBACKS; k++) + { + if (g_dglos.g_scriptCallback[k].active) + { + count++; + } + } + + return count; +} + +int GetScriptsActive() +{ + int count = 0; + + for (int k = 1; k < C_MAX_SCRIPTS; k++) + { + if (g_scriptInstance[k]) + { + count++; + } + } + + return count; +} + +int add_callback(char name[20], int n1, int n2, int script) +{ + +#ifdef _DEBUG + //LogMsg("%d callbacks active", GetCallbacksActive()); + +#endif + for (int k = 1; k < C_MAX_SCRIPT_CALLBACKS; k++) + { + if (g_dglos.g_scriptCallback[k].active == false) + { + memset(&g_dglos.g_scriptCallback[k],0, sizeof(g_dglos.g_scriptCallback[k])); + + g_dglos.g_scriptCallback[k].active = true; + g_dglos.g_scriptCallback[k].min = n1; + g_dglos.g_scriptCallback[k].max = n2; + g_dglos.g_scriptCallback[k].owner = script; + strcpy(g_dglos.g_scriptCallback[k].name, name); + + if (debug_mode) LogMsg("Callback added to %d.", k); + return(k); + } + + } + +#ifdef _DEBUG + LogMsg("Couldn't add callback, all out of space"); +#endif + + return(0); + +} + +int add_sprite(int x1, int y, int brain,int pseq, int pframe ) +{ + + for (int x=1; x < C_MAX_SPRITES_AT_ONCE; x++) + { + if (g_sprite[x].active == false) + { + SAFE_DELETE(g_customSpriteMap[x]); + + memset(&g_sprite[x], 0, sizeof(g_sprite[x])); + + g_sprite[x].active = true; + g_sprite[x].x = x1; + g_sprite[x].y = y; + g_sprite[x].my = 0; + g_sprite[x].mx = 0; + g_sprite[x].speed = 1; + g_sprite[x].brain = brain; + g_sprite[x].frame = 0; + g_sprite[x].pseq = pseq; + g_sprite[x].pframe = pframe; + g_sprite[x].seq = 0; + if (x > g_dglos.last_sprite_created) + g_dglos.last_sprite_created = x; + g_sprite[x].timer = 33; + g_sprite[x].wait = 0; + g_sprite[x].lpx[0] = 0; + g_sprite[x].lpy[0] = 0; + g_sprite[x].moveman = 0; + g_sprite[x].size = 100; + g_sprite[x].que = 0; + g_sprite[x].strength = 0; + g_sprite[x].damage = 0; + g_sprite[x].defense = 0; + g_sprite[x].hard = 1; + + if ( g_customSpriteMap[x] == NULL ) + { + g_customSpriteMap[x] = new std::map; + } + else + { + g_customSpriteMap[x]->clear(); + } + + return(x); + } + + } + + return(0); +} + +LPDIRECTDRAWSURFACE GetSurfaceFromSeq(int seq, int frame = 1) +{ + return g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]; +} + +bool check_sprite_status(int spriteID) +{ + + + check_seq_status(g_sprite[spriteID].pseq, g_sprite[spriteID].pframe); + check_seq_status(g_sprite[spriteID].seq, g_sprite[spriteID].frame); + return true; +} + + +void check_frame_status(int h, int frame) +{ + + if (g_dglos.g_seq[h].active == false) return; + + if (h > 0) + { + // Msg("Smartload: Loading seq %d..", spr[h].seq); + if (GetSurfaceFromSeq(h, frame) == 0) + { + ReloadSequence(h, frame); + } + } +} + +void FreeSequence(int seq) +{ + assert(seq && seq < C_MAX_SEQUENCES); + + if (1) + { + for (int i=0; i < g_dglos.g_seq[seq].m_spaceAllowed; i++) + { + //note, instead of doing frame[1+1] we do frame[1]+1, to really delete whatever + //was loaded, otherwise things get corrupted because of how the SET_FRAME_FRAME + //command allows some frames to be reused. + assert(g_dglos.g_seq[seq].s+1 == g_dglos.g_seq[seq].frame[1]); + //LogMsg("Deleting seq %d, frame %d (%d) (image: %d)", seq, i, g_dglos.g_seq[seq].frame[1]+i, g_dglos.g_picInfo[g_dglos.g_seq[seq].frame[1]+i] ); + SAFE_DELETE(g_pSpriteSurface[g_dglos.g_seq[seq].frame[1] + i]); + } + + } +} + +bool check_pic_status(int picID) +{ + if (picID == 0) return true; + + assert(g_dglos.g_picInfo[picID].m_parentSeq != 0); + + if (g_pSpriteSurface[picID]) return true; + + return check_seq_status(g_dglos.g_picInfo[picID].m_parentSeq); +} + +bool check_seq_status(int seq, int frame) +{ + + if (seq == 0) return true; + if (g_dglos.g_seq[seq].active == false) + { +#ifdef _DEBUG +LogMsg("Seq %d missing?", seq); +#endif + return true; + } + +#ifdef _DEBUG + if (seq == 180) + { + //LogMsg("Woah!"); + } +#endif + if (frame != 0) + { + if (g_pSpriteSurface[g_dglos.g_seq[seq].frame[frame]]) return true; + //load a single frame + return ReloadSequence(seq, frame); + } + + if (seq > 0) if (seq < C_MAX_SEQUENCES) + { + // Msg("Smartload: Loading seq %d..", spr[h].seq); + + for (int i=0; i < g_dglos.g_seq[seq].last; i++) + { + if (g_pSpriteSurface[g_dglos.g_seq[seq].frame[i + 1]] == NULL) + { + if (!ReloadSequence(seq, i+1)) return false; + } + } + } + return true; //no error +} + +void check_base(int base) +{ + /* + for (int i=1; i < 10; i++) + { + if (g_dglos.g_seq[base+i].active == true) check_seq_status(base+i); + } + */ +} + +void check_sprite_status_full(int spriteID) +{ + //same as above but checks for all seq's used by the (base) commands + //is sprite in memory? + //check_seq_status(g_sprite[spriteID].pseq); + check_sprite_status(spriteID); + //if (g_sprite[spriteID].base_walk > -1) check_base(g_sprite[spriteID].base_walk); +} + + +int say_text(char text[200], int h, int script) +{ + int crap2; + //Msg("Creating new sprite with %s connect to %d.",text, h); + if (h == 1000) crap2 = add_sprite(100,100,8,0,0); + else crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,8,0,0); + + if (crap2 == 0) + { + LogMsg("Couldn't say something, out of sprites."); + return(0); + + } + *plast_text = crap2; + strcpy(g_sprite[crap2].text, text); + g_sprite[crap2].kill = strlen(text) * text_timer; + if (g_sprite[crap2].kill < text_min) g_sprite[crap2].kill = text_min; + g_sprite[crap2].damage = -1; + g_sprite[crap2].owner = h; + g_sprite[crap2].hard = 1; + g_sprite[crap2].script = script; + //set X offset for text, using strength var since it's unused + g_sprite[crap2].strength = 75; + //spr[h].x - spr[crap2; + g_sprite[crap2].nohit = 1; + check_seq_status(g_sprite[g_sprite[crap2].owner].seq, g_sprite[g_sprite[crap2].owner].frame); + g_sprite[crap2].defense = ( ((g_dglos.g_picInfo[getpic(g_sprite[crap2].owner)].box.bottom) - g_dglos.g_picInfo[getpic(g_sprite[crap2].owner)].yoffset) + 100); + + g_sprite[crap2].x = g_sprite[g_sprite[crap2].owner].x - g_sprite[crap2].strength; + g_sprite[crap2].y = g_sprite[g_sprite[crap2].owner].y - g_sprite[crap2].defense; + + return(crap2); +} + + +int say_text_xy(char text[200], int mx, int my, int script) +{ + int crap2; + //Msg("Creating new sprite with %s connect to %d.",text, h); + crap2 = add_sprite(mx,my,8,0,0); + + if (crap2 == 0) + { + LogMsg("Couldn't say something, out of sprites."); + return(0); + + } + *plast_text = crap2; + strcpy(g_sprite[crap2].text, text); + g_sprite[crap2].kill = strlen(text) * text_timer; + if (g_sprite[crap2].kill < text_min) g_sprite[crap2].kill = text_min; + g_sprite[crap2].damage = -1; + g_sprite[crap2].nohit = 1; + g_sprite[crap2].owner = 1000; + g_sprite[crap2].hard = 1; + g_sprite[crap2].script = script; + return(crap2); +} + +int does_sprite_have_text(int sprite) +{ + //Msg("getting callback # with %d..", sprite); + for (int k = 1; k <= C_MAX_SPRITES_AT_ONCE; k++) + { + if ( g_sprite[k].active) if (g_sprite[k].owner == sprite) if (g_sprite[k].brain == 8) + { + //Msg("Found it! returning %d.", k); + + return(k); + } + } + return(0); +} + +int var_exists(char name[20], int scope) +{ + + for (int i = 1; i < max_vars; i++) + { + if (g_dglos.g_playerInfo.var[i].active) + { + if (compare(g_dglos.g_playerInfo.var[i].name, name)) + { + + if (g_dglos.g_playerInfo.var[i].scope == scope) //redink1 changed to check recursively... then changed back. Hrm. + { + //Msg("Found match for %s.", name); + return(i); + } + } + } + } + + return(0); +} + +//redink1 added this to make new global functions +void make_function(char file[10], char func[20]) +{ + //See if it already exists + bool exists = false; + int i; + for (i = 0; strlen(g_dglos.g_playerInfo.func[i].func) > 0 && i < 100; i++) + { + if (compare(func, g_dglos.g_playerInfo.func[i].func)) + { + exists = true; + break; + } + } + + if (exists) + { + strncpy(g_dglos.g_playerInfo.func[i].file, file, 10); + } + else + { + strncpy(g_dglos.g_playerInfo.func[0].file, file, 10); + strncpy(g_dglos.g_playerInfo.func[0].func, func, 20); + } +} + +void make_int(char name[80], int value, int scope, int script) +{ + int dupe; + if (strlen(name) > 19) + { + + LogMsg("ERROR: Varname %s is too long in script %s.",name, g_scriptInstance[script]->name); + return; + } + dupe = var_exists(name, scope); + + if (dupe > 0) + { + if (scope != 0) + { +#ifdef _DEBUG + //LogMsg("Local var %s already used in this procedure in script %s.",name, g_scriptInstance[script]->name); +#endif + + g_dglos.g_playerInfo.var[dupe].var = value; + + } else + { +#ifdef _DEBUG + LogMsg("Var %s is already a global, not changing value.",name); +#endif + } + + return; + } + + //make new var + + for (int i = 1; i < max_vars; i++) + { + if (g_dglos.g_playerInfo.var[i].active == false) + { + + g_dglos.g_playerInfo.var[i].active = true; + g_dglos.g_playerInfo.var[i].scope = scope; + strcpy(g_dglos.g_playerInfo.var[i].name, name); + //g("var %s created, used slot %d ", name,i); + g_dglos.g_playerInfo.var[i].var = value; + return; + } + } + + LogMsg("ERROR: Out of var space, all %d used.", max_vars); +} + +int var_equals(char name[20], char newname[20], char math, int script, char rest[200]) +{ + int k; + //redink1 set newret to NULL so debug errors did not appear. + int newret = NULL; // = NULL; + + if (name[0] != '&') + { + LogMsg("ERROR (var equals): Unknown var %s in %s offset %d.",name, g_scriptInstance[script]->name, g_scriptInstance[script]->current); + return(0); + } + + int i = get_var(script, name); + if (i > 0) + { + goto next; + } + + LogMsg("ERROR: (var equals2) Unknown var %s in %s offset %d.",name, g_scriptInstance[script]->name, g_scriptInstance[script]->current); + return(0); + +next: + int newval = 0; + + if (strchr(rest, '(') != NULL) + + { + newret = process_line(script, rest, false); + newval = g_dglos.g_returnint; + goto next2; + } + + if (strchr(newname, ';') != NULL) replace(";", "", newname); + + //redink1 fixed for scope and such + k = get_var(script, newname); + if (k > 0) + { + newval = g_dglos.g_playerInfo.var[k].var; + goto next2; + } + + if (compare(newname, (char*)"¤t_sprite")) + { + newval = g_scriptInstance[script]->sprite; + goto next2; + } + + if (compare(newname, (char*)"¤t_script")) + { + newval = script; + goto next2; + + } + + //v1.08 special variables. + if (compare(newname, (char*)"&return")) + { + newval = g_dglos.g_returnint; + goto next2; + } + + if (compare(newname, (char*)"&arg1")) + { + newval = g_scriptInstance[script]->arg1; + goto next2; + } + + if (compare(newname, (char*)"&arg2")) + { + newval = g_scriptInstance[script]->arg2; + goto next2; + } + + if (compare(newname, (char*)"&arg3")) + { + newval = g_scriptInstance[script]->arg3; + goto next2; + } + + if (compare(newname, (char*)"&arg4")) + { + newval = g_scriptInstance[script]->arg4; + goto next2; + } + + if (compare(newname, (char*)"&arg5")) + { + newval = g_scriptInstance[script]->arg5; + goto next2; + } + + if (compare(newname, (char*)"&arg6")) + { + newval = g_scriptInstance[script]->arg6; + goto next2; + } + + if (compare(newname, (char*)"&arg7")) + { + newval = g_scriptInstance[script]->arg7; + goto next2; + } + + if (compare(newname, (char*)"&arg8")) + { + newval = g_scriptInstance[script]->arg8; + goto next2; + } + + if (compare(newname, (char*)"&arg9")) + { + newval = g_scriptInstance[script]->arg9; + goto next2; + } + + newval = atol(newname); + +next2: + + if (math == '=') + g_dglos.g_playerInfo.var[i].var = newval; + + if (math == '+') + g_dglos.g_playerInfo.var[i].var += newval; + + if (math == '-') + g_dglos.g_playerInfo.var[i].var -= newval; + + if (math == '/') + g_dglos.g_playerInfo.var[i].var = g_dglos.g_playerInfo.var[i].var / newval; + + if (math == '*') + g_dglos.g_playerInfo.var[i].var = g_dglos.g_playerInfo.var[i].var * newval; + + return(newret); +} + +void get_word(char line[300], int word, char *crap) +{ + int cur = 0; + + bool space_mode = false; + char save_word[100]; + save_word[0] = 0; + + for (int k = 0; k < strlen(line); k++) + { + + if (space_mode == true) + { + if (line[k] != ' ') + { + space_mode = false; + strcpy(save_word, ""); + + } + } + + if (space_mode == false) + { + if (line[k] == ' ') + { + cur++; + if (word == cur) goto done; + space_mode = true; + strcpy(save_word, ""); + + goto dooba; + } else + { + strchar(save_word, line[k]); + + } + } + +dooba:; + + } + + if (space_mode == false) + { + + if (cur+1 != word) strcpy(save_word, ""); + } + +done: + + strcpy(crap, save_word); + + //Msg("word %d of %s is %s.", word, line, crap); +} + +int var_figure(char h[200], int script) +{ + char crap[200]; + int ret = 0; + int n1 = 0, n2 = 0; + //Msg("Figuring out %s...", h); + get_word(h, 2, crap); + //Msg("Word two is %s...", crap); + + if (compare(crap, (char*)"")) + { + //one word equation + + if (h[0] == '&') + { + //its a var possibly + decipher_string(h, script); + } + + //Msg("truth is %s", h); + ret = atol(h); + // Msg("returning %d, happy?", ret); + return(ret); + } + + get_word(h, 1, crap); + //Msg("Comparing %s...", crap); + + decipher_string(crap,script); + n1 = atol(crap); + + get_word(h, 3, crap); + replace(")", "", crap); + //Msg("to %s...", crap); + decipher_string(crap,script); + n2 = atol(crap); + + get_word(h, 2, crap); + if (debug_mode) + LogMsg("Compared %d to %d",n1, n2); + + if (compare(crap, (char*)"==")) + { + if (n1 == n2) ret = 1; else ret = 0; + return(ret); + } + + if (compare(crap, (char*)">")) + { + if (n1 > n2) ret = 1; else ret = 0; + return(ret); + } + + if (compare(crap, (char*)"<")) + { + if (n1 < n2) ret = 1; else ret = 0; + return(ret); + } + + if (compare(crap,(char*) "!=")) + { + if (n1 != n2) ret = 1; else ret = 0; + return(ret); + } + + if (compare(crap, (char*)"<=")) + { + if (n1 <= n2) ret = 1; else ret = 0; + return(ret); + } + if (compare(crap, (char*)">=")) + { + if (n1 >= n2) ret = 1; else ret = 0; + return(ret); + } + + return(ret); + +} + +void kill_text_owned_by(int sprite) +{ + for (int i = 1; i < C_MAX_SPRITES_AT_ONCE; i++) + { + if (g_sprite[i].active) + if (g_sprite[i].brain == 8) if (g_sprite[i].owner == sprite) + { + g_sprite[i].active = false; + } + } +} + +bool text_owned_by(int sprite) +{ + for (int i = 1; i < C_MAX_SPRITES_AT_ONCE; i++) + { + if (g_sprite[i].active) + if (g_sprite[i].brain == 8) if (g_sprite[i].owner == sprite) + { + return(true); + } + } + return(false); +} + + +void kill_text_owned_by_safe(int sprite) +{ + for (int i = 1; i < C_MAX_SPRITES_AT_ONCE; i++) + { + if (g_sprite[i].active) + if (g_sprite[i].brain == 8) if (g_sprite[i].owner == sprite) + { + g_sprite[i].active = false; + + if (g_sprite[i].callback != 0) run_script(g_sprite[i].callback); + } + } + +} + +void kill_scripts_owned_by(int sprite) +{ + for (int i = 1; i < C_MAX_SCRIPTS; i++) + { + if (g_scriptInstance[i] != NULL) + { + if (g_scriptInstance[i]->sprite == sprite) + { + kill_script(i); + } + } + } + +} + +void kill_sprite_all (int sprite) +{ + g_sprite[sprite].active = false; + + kill_text_owned_by(sprite); + kill_scripts_owned_by(sprite); +} + + +void kill_returning_stuff( int script) +{ + int i; + for (i = 1; i < C_MAX_SCRIPT_CALLBACKS; i++) + { + if (g_dglos.g_scriptCallback[i].active) if (g_dglos.g_scriptCallback[i].owner == script) + { + //LogMsg("killed a returning callback, ha!"); + g_dglos.g_scriptCallback[i].active = false; + } + } + + + for (i = 1; i <= g_dglos.last_sprite_created; i++) + { + if (g_sprite[i].active) if (g_sprite[i].brain == 8) if (g_sprite[i].callback == script) + { + LogMsg("Killed sprites callback command"); + g_sprite[i].callback = 0; + } + } +} + +bool talk_get(int script) +{ + char line[200], check[200], checker[200]; + int cur = 1; + char *p; + int retnum = 0; + clear_talk(); + g_dglos.g_talkInfo.newy = -5000; + while(1) + { + +redo: + read_next_line(script, line); + strip_beginning_spaces(line); + //Msg("Comparing to %s.", line); + + get_word(line, 1, checker); + + if (compare(checker, (char*)"set_y")) + { + get_word(line, 2, checker); + g_dglos.g_talkInfo.newy = atol(checker); + goto redo; + } + + if (compare(checker, (char*)"set_title_color")) + { + get_word(line, 2, checker); + g_dglos.g_talkInfo.color = atol(checker); + goto redo; + } + + if (compare(line, (char*)"\n")) goto redo; + if (compare(line, (char*)"\\\\")) goto redo; + + + strip_beginning_spaces(line); + //Msg("Comparing to %s.", line); + if (compare(line, (char*)"\n")) goto redo; + if (compare(line, (char*)"\\\\")) goto redo; + +morestuff: + + separate_string(line, 1, '(', check); + strip_beginning_spaces(check); + + if (compare(check, (char*)"title_start")) + { + while(read_next_line(script, line)) + { + strcpy(check, line); + strip_beginning_spaces(line); + get_word(line, 1, checker); + separate_string(line, 1, '(', check); + strip_beginning_spaces(check); + + if (compare(check, (char*)"title_end")) + { + replace((char*)"\n\n\n\n",(char*)"\n \n", g_dglos.g_talkInfo.buffer); + replace((char*)"\n\n",(char*)"\n", g_dglos.g_talkInfo.buffer); + goto redo; + } + + assert("!You better check this.."); + line[strlen(line)] = 0; + //Msg("LINE IS: %s: Like it?",line); + + decipher_string(line, script); + strcat(g_dglos.g_talkInfo.buffer, line); + //talk.buffer[strlen(talk.buffer)-1] = 0; + } + + goto redo; + } + + if (compare(check, (char*)"choice_end")) + { + if (cur-1 == 0) + { + LogMsg("Error: choice() has 0 options in script %s, offset %d.", + g_scriptInstance[script]->name, g_scriptInstance[script]->current); + + return(false); + } + //all done, lets jam + //Msg("found choice_end, leaving!"); + g_dglos.g_talkInfo.last = cur-1; + g_dglos.g_talkInfo.cur = 1; + g_dglos.g_talkInfo.active = true; + g_dglos.g_talkInfo.page = 1; + g_dglos.g_talkInfo.cur_view = 1; + g_dglos.g_talkInfo.script = script; + //kill the punch button if it was pressed, otherwise if you punch and talk to someone it crashes the game. + //this was also in the original dink, amazing nobody saw it? + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON1] = false; + g_dglo.m_dirInput[DINK_INPUT_BUTTON1] = false; + + g_dglo.m_dirInputFinished[DINK_INPUT_BUTTON2] = false; + g_dglo.m_dirInput[DINK_INPUT_BUTTON2] = false; + sjoy.button[1] = false; + sjoy.button[2] = false; + return(true); + + } + + separate_string(line, 1, '\"', check); + strip_beginning_spaces(check); + + //Msg("Check is %s.",check); + + if (strlen(check) > 2) + { + //found conditional statement + if (strchr(check, '(') == NULL) + + { + LogMsg("Error with choice() statement in script %s, offset %d. (%s?)", + g_scriptInstance[script]->name, g_scriptInstance[script]->current, check); + return(false); + } + + separate_string(check, 2, '(', checker); + separate_string(checker, 1, ')', check); + + //Msg("Running %s through var figure..", check); + if (var_figure(check, script) == 0) + { + //LogMsg("Answer is no."); + retnum++; + goto redo; + //said NO to statement + } + //Msg("Answer is yes."); + separate_string(line, 1, ')', check); + + p = &line[strlen(check)+1]; + + strcpy(check, p); + + + strcpy(line, check); + + //Msg("new line is %s, happy?", line); + goto morestuff; + } + + separate_string(line, 2, '\"', check); + strip_beginning_spaces(check); +#ifdef _DEBUG + //LogMsg("Line %d is %s.",cur,check); +#endif + if (strcmp(check, "Quit to Windows") == 0) + { + strcpy(check, "Quit"); + } + + retnum++; + decipher_savegame = retnum; + decipher_string(check, script); + decipher_savegame = 0; + strcpy(g_dglos.g_talkInfo.line[cur], check); + g_dglos.g_talkInfo.line_return[cur] = retnum; + cur++; + } + +} + +bool PlayMidi(const char *sFileName) +{ + //first check for mp3 versions.. + string fName = "sound/"+ToLowerCaseString(sFileName); + StringReplace("\\", "/", fName); + + if (GetFileExtension(fName) == "mid") + { + bool bTryUsingOgg = true; + + if (!g_dglo.m_dmodGameDir.empty() && FileExists(g_dglo.m_dmodGamePathWithDir+fName)) + { + //actually, don't replace with ogg, they probably have their own midi stuff here + bTryUsingOgg = false; + } + + string tempName = ModifyFileExtension(fName, "ogg"); + + if (bTryUsingOgg && !g_dglo.m_dmodGameDir.empty() && FileExists(g_dglo.m_dmodGamePathWithDir+tempName)) + { + + //found it + fName = tempName; + + } else + if (!g_dglo.m_dmodGameDir.empty() && FileExists(g_dglo.m_dmodGamePathWithDir+fName)) + { + + //found it, no changed needed + + + } else + { + //try the base dir too + if (FileExists(g_dglo.m_gamePathWithDir+tempName)) + { + //found it + fName = tempName; + } + } + + } + + g_dglo.m_lastMusicPath = sFileName; + + GetAudioManager()->Play(GetFileLocationString(fName), true, true, false); + LogMsg("Playing music %s", sFileName); + return true; +} + + +void check_midi(void) +{ + + char hold[20]; + + if (!g_dglos.midi_active) return; + if (g_MapInfo.music[*pmap] != 0) + { + + if (g_MapInfo.music[*pmap] == -1) + { + //kill music + LogMsg("Stopped cd"); + StopMidi(); + + } + + if (g_MapInfo.music[*pmap] > 1000) + { + sprintf(hold, "%d.mid",g_MapInfo.music[*pmap]-1000); + + PlayMidi(hold); + } else + { + //there is music associated with this screen + sprintf(hold, "%d.mid",g_MapInfo.music[*pmap]); + PlayMidi(hold); + } + + } + +} + + +//------------------------------------------------------------------ +// +// Function : StopMidi +// +// Purpose : Stops a midi file playing +// +//------------------------------------------------------------------ + +bool StopMidi() +{ + g_dglo.m_lastMusicPath = ""; + LogMsg("Stopping midi"); + GetAudioManager()->StopMusic(); + // Yahoo! + return true; +} + +void get_right(char line[200], char thing[100], char *ret) +{ + char *dumb; + int pos = strcspn(line, thing ); + + if (pos == 0){ strcpy(ret, ""); return; } + + dumb = &ret[pos+1]; + strcpy(ret, dumb); +} + +void int_prepare(char line[256], int script) +{ + int def = 0; + char hold[256]; + strcpy(hold, line); + char name[100]; + char crap[256]; + replace("="," ",line); + strcpy(crap, line); + separate_string(crap, 1,';',line); + get_word(line, 2, name); + + if (name[0] != '&') + { + LogMsg("ERROR: Can't create var %s, should be &%s.", name,name); + return; + } + + + make_int(name, def,script, script); + + strcpy(line, hold); + +} + +int32 change_sprite(int32 h, int32 val, int32 * change) +{ + //Msg("Searching sprite %s with val %d. Cur is %d", h, val, *change); + if (h >= C_MAX_SPRITES_AT_ONCE) + { + LogMsg("Error: Can't use sp_ commands on a sprite after it's connected to sprite 1000, can crash. Ignoring command."); + return 0; + } + + if (h < 1) + { +#ifdef _DEBUG + LogMsg("Error with an SP command - Sprite %d is invalid.", h); +#endif + return(-1); + } + if (g_sprite[h].active == false) return(-1); + if (val != -1) + { + *change = val; + } + + return(*change); +} + +int32 change_sprite(int32 h, int32 val, bool * change) +{ + //Msg("Searching sprite %s with val %d. Cur is %d", h, val, *change); + + if (h < 1) + { + #ifdef _DEBUG + LogMsg("Error with an SP command - Sprite %d is invalid.", h); +#endif + return(-1); + } + if (h >= C_MAX_SPRITES_AT_ONCE || g_sprite[h].active == false) return(-1); + if (val != -1) + { + *change = val; + } + + return(*change); +} + +int change_edit(int h, int val, unsigned short * change) +{ + //Msg("Searching sprite %s with val %d. Cur is %d", h, val, *change); + + if (h > 99) return(-1); + if (h < 1) return(-1); + if (val != -1) + { + *change = val; + } + + return(*change); + +} +int change_edit_char(int h, int val, unsigned char * change) +{ + //Msg("Searching sprite %s with val %d. Cur is %d", h, val, *change); + // Msg("h is %d..",val); + if (h > 99) return(-1); + if (h < 1) return(-1); + if (val != -1) + { + *change = val; + } + + return(*change); + +} + + +int32 change_sprite_noreturn(int32 h, int32 val, int32 * change) +{ + //Msg("Searching sprite %s with val %d. Cur is %d", h, val, *change); + if (h >= C_MAX_SPRITES_AT_ONCE || g_sprite[h].active == false) return(-1); + + { + *change = val; + } + + return(*change); + +} + + +void draw_sprite_game(LPDIRECTDRAWSURFACE lpdest,int h) +{ + if (::g_b_kill_app) return; //don't try, we're quitting + if (g_sprite[h].brain == 8) return; + + if (g_sprite[h].nodraw == 1) return; + rtRect32 dstRect,srcRect; + + int ddrval; + + DDBLTFX ddbltfx; + ddbltfx.dwSize = sizeof( ddbltfx); + ddbltfx.dwFillColor = 0; + + if (getpic(h) < 1) return; + + + + + + if (!check_pic_status(getpic(h))) + { + + LogMsg("Hmm, bad sprite at %d.. you need to setup a way for a pic to load itself", getpic(h)); + return; + } +#ifdef _DEBUG + if (!g_pSpriteSurface[getpic(h)]) + { + int pic = getpic(h); + + assert(!"The hell?"); + } + +#endif +#ifdef _DEBUG + if (g_sprite[h].pseq == 66 && g_sprite[h].pframe == 1) + { + + //LogMsg("Drawing it"); + } +#endif + + + if (get_box(h, &dstRect, &srcRect)) + { + //redink1 error checking for invalid rectangle + if (dstRect.left >= dstRect.right || dstRect.top >= dstRect.bottom) + { + return; + assert(!"Bad rect"); + } + + //check_seq_status(h); + + //redink1 error checking for out-of-bounds clipping + /*if (box_crap.left < 0) + box_crap.left = 0; + if (box_crap.top < box_real.top) + box_crap.top = box_crap.top; + if (box_crap.right > box_real.right) + box_crap.right = box_real.right; + if (box_crap.bottom > box_real.bottom) + box_crap.bottom = box_real.bottom;*/ + + // Msg("Box_crap: %d %d %d %d, Box_real: %d %d %d %d",box_crap.left,box_crap.top, + // box_crap.right, box_crap.bottom,box_real.left,box_real.top, + // box_real.right, box_real.bottom); + + /* + if (g_sprite[h].pseq != 0) + { + if (!check_seq_status(g_sprite[h].pseq)) return; + assert(!"Bad sprite"); + + } +*/ + + /* + if (lpdest->m_pSurf && lpdest->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_RGBA) + { + if (g_dglos.g_picInfo[getpic(h)].pSurface->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_RGBA) + { + + LogMsg("Doing rgba to rgba.."); + } + } + */ + + //check to see if we need a 32 bit buffer for this or not + if (lpdest->m_pSurf && lpdest->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + { + if (g_pSpriteSurface[getpic(h)]->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_RGBA) + { + + + //yep, convert what we've got to 32 bit. We don't lose what we've done so far. + + + assert(lpdest == lpDDSBackGround); + + //convert it to a high color surface on the fly, without losing the data on it + + LPDIRECTDRAWSURFACE pNewSurf = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, true, lpdest->m_pSurf); + LogMsg("Detected high color bmps that need to drawn to the static landscape, converting backbuffers to 32 bit on the fly."); + delete lpDDSBackGround; + + lpdest = lpDDSBackGround = pNewSurf; + if (lpDDSBuffer->m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + { + //this one too + delete lpDDSBuffer; + lpDDSBuffer = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, true); + } + + } + + } + ddrval = lpdest->Blt(&dstRect, g_pSpriteSurface[getpic(h)], + &srcRect , DDBLT_KEYSRC ,&ddbltfx ); + + /* + LogMsg("MainSpriteDraw(): Could not draw sprite %d, pic %d.",h,getpic(h)); + LogMsg("Box_crap: %d %d %d %d, Box_real: %d %d %d %d",box_crap.left,box_crap.top, + box_crap.right, box_crap.bottom,box_real.left,box_real.top, + box_real.right, box_real.bottom); + if (g_sprite[h].pseq != 0) check_seq_status(g_sprite[h].pseq); + */ + } +} + +void changedir( int dir1, int k,int base) +{ + int hspeed; + int speed_hold = g_sprite[k].speed; + if (k > 1) if (g_sprite[k].brain != 9) if (g_sprite[k].brain != 10) + { + + //if (mbase_timing > 20) mbase_timing = 20; + + // Msg(",base_timing is %d", base_timing); + hspeed = g_sprite[k].speed * (g_dglos.base_timing / 4); + if (hspeed > 49) + { +#ifdef _DEBUG + LogMsg("Speed was %d", hspeed); +#endif + g_sprite[k].speed = 49; + } else + g_sprite[k].speed = hspeed; + } + int old_seq = g_sprite[k].seq; + g_sprite[k].dir = dir1; + + if (dir1 == 1) + { + g_sprite[k].mx = (0 - g_sprite[k].speed ) + (g_sprite[k].speed / 3); + g_sprite[k].my = g_sprite[k].speed - (g_sprite[k].speed / 3); + + if (base != -1) + { + g_sprite[k].seq = base + 1; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) + { + g_sprite[k].seq = base + 9; + } + } + + if (old_seq != g_sprite[k].seq) + { + g_sprite[k].frame = 0; + g_sprite[k].delay = 0; + } + } + + if (dir1 == 2) + { + g_sprite[k].mx = 0; + g_sprite[k].my = g_sprite[k].speed; + if (base != -1) + g_sprite[k].seq = base + 2; + + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+3].active) g_sprite[k].seq = base +3; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+1].active) g_sprite[k].seq = base +1; + + if (old_seq != g_sprite[k].seq) + { + g_sprite[k].frame = 0; + g_sprite[k].delay = 0; + } + } + + if (dir1 == 3) + { + g_sprite[k].mx = g_sprite[k].speed - (g_sprite[k].speed / 3); + g_sprite[k].my = g_sprite[k].speed - (g_sprite[k].speed / 3); + if (base != -1) + { + g_sprite[k].seq = base + 3; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) + g_sprite[k].seq = base + 7; + + } + + if (old_seq != g_sprite[k].seq) + { + g_sprite[k].frame = 0; + g_sprite[k].delay = 0; + } + } + + if (dir1 == 4) + { + + //Msg("Changing %d to four..",k); + g_sprite[k].mx = (0 - g_sprite[k].speed); + g_sprite[k].my = 0; + if (base != -1) + g_sprite[k].seq = base + 4; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+7].active) g_sprite[k].seq = base +7; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+1].active) g_sprite[k].seq = base +1; + } + + if (dir1 == 6) + { + g_sprite[k].mx = g_sprite[k].speed; + g_sprite[k].my = 0; + if (base != -1) + g_sprite[k].seq = base + 6; + + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+3].active) g_sprite[k].seq = base +3; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+9].active) g_sprite[k].seq = base +9; + + } + + if (dir1 == 7) + { + g_sprite[k].mx = (0 - g_sprite[k].speed) + (g_sprite[k].speed / 3); + g_sprite[k].my = (0 - g_sprite[k].speed)+ (g_sprite[k].speed / 3); + if (base != -1) + { + g_sprite[k].seq = base + 7; + + + if (g_dglos.g_seq[g_sprite[k].seq].active == false) + { + + g_sprite[k].seq = base + 3; + } + } + + } + if (dir1 == 8) + { + g_sprite[k].mx = 0; + g_sprite[k].my = (0 - g_sprite[k].speed); + if (base != -1) + g_sprite[k].seq = base + 8; + + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+7].active) g_sprite[k].seq = base +7; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) if (g_dglos.g_seq[base+9].active) g_sprite[k].seq = base +9; + + } + + + if (dir1 == 9) + { + g_sprite[k].mx = g_sprite[k].speed- (g_sprite[k].speed / 3); + g_sprite[k].my = (0 - g_sprite[k].speed)+ (g_sprite[k].speed / 3); + if (base != -1) + { + g_sprite[k].seq = base + 9; + if (g_dglos.g_seq[g_sprite[k].seq].active == false) + { + g_sprite[k].seq = base + 1; + } + } + } + + if (old_seq != g_sprite[k].seq) + { + g_sprite[k].frame = 0; + g_sprite[k].delay = 0; + } + + + if (g_dglos.g_seq[g_sprite[k].seq].active == false) + { + //spr[k].mx = 0; + //spr[k].my = 0; + g_sprite[k].seq = old_seq; + } + + //Msg("Leaving with %d..", spr[k].dir); + + //Msg("Changedir: Tried to switch sprite %d to dir %d",k,dir1); + + g_sprite[k].speed = speed_hold; + +} + + +void update_play_changes( void ) +{ + + for (int j = 1; j < 100; j++) + { + if (g_dglos.g_smallMap.sprite[j].active) + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] != 0) + { + //lets make some changes, player has extra info + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 1) + { + g_dglos.g_smallMap.sprite[j].active = 0; + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 2) + { + g_dglos.g_smallMap.sprite[j].type = 1; + g_dglos.g_smallMap.sprite[j].hard = 1; + } + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 3) + { + + // Msg("Changing sprite %d", j); + g_dglos.g_smallMap.sprite[j].type = 0; + g_dglos.g_smallMap.sprite[j].hard = 1; + + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 4) + { + g_dglos.g_smallMap.sprite[j].type = 1; + g_dglos.g_smallMap.sprite[j].hard = 0; + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 5) + { + g_dglos.g_smallMap.sprite[j].type = 0; + g_dglos.g_smallMap.sprite[j].hard = 0; + } + + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 6) + { + g_dglos.g_smallMap.sprite[j].active = 0; + + } + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 7) + { + g_dglos.g_smallMap.sprite[j].active = 0; + + } + if (g_dglos.g_playerInfo.spmap[*pmap].type[j] == 8) + { + g_dglos.g_smallMap.sprite[j].active = 0; + + } + + g_dglos.g_smallMap.sprite[j].seq = g_dglos.g_playerInfo.spmap[*pmap].seq[j]; + g_dglos.g_smallMap.sprite[j].frame = g_dglos.g_playerInfo.spmap[*pmap].frame[j]; + strcpy(g_dglos.g_smallMap.sprite[j].script, ""); + } + } +} + +void update_status_all(void) +{ + bool drawexp = false; + int next = next_raise(); + int script; + if (next != g_dglos.g_guiRaise) + { + g_dglos.g_guiRaise += next / 40; + if (g_dglos.g_guiRaise > next) g_dglos.g_guiRaise = next; + //make noise here + drawexp = true; + SoundPlayEffect( 13,15050, 0,0 ,0); + } + + if (*pexper != g_dglos.g_guiExp) + { + if ( ( g_dglos.g_talkInfo.active == false && g_itemScreenActive == false && g_sprite[1].freeze == 0 ) || g_dglos.g_guiExp + 10 < g_dglos.g_guiRaise ) + { + //update screen experience + g_dglos.g_guiExp += 10; + //make noise here + + if (g_dglos.g_guiExp > *pexper) g_dglos.g_guiExp = *pexper; + drawexp = true; + SoundPlayEffect( 13,29050, 0,0 ,0); + + if (g_dglos.g_guiExp >= g_dglos.g_guiRaise) + { + + *pexper -= next; + g_dglos.g_guiExp = 0; + + script = load_script("lraise", 1, false); + if (locate(script, "raise")) run_script(script); + } + } + } + + if (drawexp) + { + draw_exp(false); + } + + if ( (g_dglos.g_guiLifeMax != *plifemax) || (g_dglos.g_guiLife != *plife) ) + { + if (g_dglos.g_guiLifeMax < *plifemax) g_dglos.g_guiLifeMax++; + if (g_dglos.g_guiLifeMax > *plifemax) g_dglos.g_guiLifeMax--; + if (g_dglos.g_guiLife > *plife) g_dglos.g_guiLife--; + if (g_dglos.g_guiLife < *plife) g_dglos.g_guiLife++; + if (g_dglos.g_guiLife > *plife) g_dglos.g_guiLife--; + if (g_dglos.g_guiLife < *plife) g_dglos.g_guiLife++; + //draw_bar(flifemax, 190); + //draw_bar(flife, 451); + } + + if ( g_dglos.g_guiStrength != *pstrength) + { + if (g_dglos.g_guiStrength < *pstrength) g_dglos.g_guiStrength++; + if (g_dglos.g_guiStrength > *pstrength) g_dglos.g_guiStrength--; + SoundPlayEffect( 22,22050, 0,0 ,0); + draw_strength(false); + } + + if ( g_dglos.g_guiDefense != *pdefense) + { + if (g_dglos.g_guiDefense < *pdefense) g_dglos.g_guiDefense++; + if (g_dglos.g_guiDefense > *pdefense) g_dglos.g_guiDefense--; + SoundPlayEffect( 22,22050, 0,0 ,0); + draw_defense(false); + } + if ( g_dglos.g_guiMagic != *pmagic) + { + if (g_dglos.g_guiMagic < *pmagic) g_dglos.g_guiMagic++; + if (g_dglos.g_guiMagic > *pmagic) g_dglos.g_guiMagic--; + SoundPlayEffect( 22,22050, 0,0 ,0); + draw_magic(false); + } + + if (g_dglos.g_guiGold != *pgold) + { + if (g_dglos.g_guiGold < *pgold) + { + g_dglos.g_guiGold += 20; + if (g_dglos.g_guiGold > *pgold) g_dglos.g_guiGold = *pgold; + } + + if (g_dglos.g_guiGold > *pgold) + { + g_dglos.g_guiGold -= 20; + if (g_dglos.g_guiGold < *pgold) g_dglos.g_guiGold = *pgold; + } + SoundPlayEffect( 14,22050, 0,0 ,0); + draw_gold(false); + } + + if (*pmagic_level < *pmagic_cost) + { + if (g_itemScreenActive == false) + *pmagic_level += *pmagic; + if (*pmagic_level > *pmagic_cost) *pmagic_level = *pmagic_cost; + } + if (*pmagic_cost > 0) if (*pmagic_level > 0) + { + double mnumd = *pmagic_level; + mnumd *= 100; + mnumd /= *pmagic_cost; + int mnum = static_cast(mnumd); + //int mnum = *pmagic_level / (*pmagic_cost / 100); + if (mnum != g_dglos.g_guiLastMagicDraw) + { + draw_mlevel(mnum, false); + //draw_status_all(); + g_dglos.g_guiLastMagicDraw = mnum; + } + } + + g_sprite[1].strength = g_dglos.g_guiStrength; + g_sprite[1].defense = g_dglos.g_guiDefense; + + if (g_dglos.g_guiLife < 1) + { + script = load_script("dinfo", 1000, false); + if (locate(script, "die")) run_script(script); + } +} + +void place_sprites_game(bool bBackgroundOnly ) +{ + int sprite; + + bool bs[C_MAX_SPRITES_AT_ONCE]; + int rank[C_MAX_SPRITES_AT_ONCE]; + int highest_sprite; + + update_play_changes(); + + memset(&bs,0,sizeof(bs)); + memset(&rank,0,sizeof(rank)); + int hs; + + for (int r1 = 1; r1 < 100; r1++) + { + highest_sprite = 20000; //more than it could ever be + rank[r1] = 0; + + for (int h1 = 1; h1 < 100; h1++) + { + if (bs[h1] == false) + { + if (g_dglos.g_smallMap.sprite[h1].active && (!bBackgroundOnly || g_dglos.g_smallMap.sprite[h1].type == 0) ) + { + if (g_dglos.g_smallMap.sprite[h1].que != 0) hs = g_dglos.g_smallMap.sprite[h1].que; else hs = g_dglos.g_smallMap.sprite[h1].y; + if ( hs < highest_sprite ) + { + highest_sprite =hs; + rank[r1] = h1; + } + } + + } + } + if (rank[r1] != 0) + bs[rank[r1]] = true; + } + + int j; + bool bScaledBackgroundSpritesRequired = false; //if true, we do a different, more memory intensive method for the rest of the sprites + + for (int oo =1; rank[oo] > 0; oo++) + { + //Msg("Ok, rank[%d] is %d.",oo,rank[oo]); + j = rank[oo]; + +#ifdef _DEBUG + if (g_dglos.g_smallMap.sprite[j].seq == 66 && g_dglos.g_smallMap.sprite[j].frame == 1) + { + + //LogMsg("Drawing it"); + } +#endif + + + if (g_dglos.g_smallMap.sprite[j].active == true) if ( ( g_dglos.g_smallMap.sprite[j].vision == 0) || (g_dglos.g_smallMap.sprite[j].vision == *pvision)) + { + check_seq_status(g_dglos.g_smallMap.sprite[j].seq, g_dglos.g_smallMap.sprite[j].frame); + + //we have instructions to make a sprite + if ( (g_dglos.g_smallMap.sprite[j].type == 0) || (g_dglos.g_smallMap.sprite[j].type == 2) ) + + { + //make it part of the background (much faster) + sprite = add_sprite_dumb(g_dglos.g_smallMap.sprite[j].x,g_dglos.g_smallMap.sprite[j].y,0, + g_dglos.g_smallMap.sprite[j].seq,g_dglos.g_smallMap.sprite[j].frame, + g_dglos.g_smallMap.sprite[j].size); + //Msg("Background sprite %d has hard of %d..", j, pam.sprite[j].hard); + g_sprite[sprite].hard = g_dglos.g_smallMap.sprite[j].hard; + g_sprite[sprite].sp_index = j; + g_sprite[sprite].alt = g_dglos.g_smallMap.sprite[j].alt; + + check_sprite_status_full(sprite); + if (g_dglos.g_smallMap.sprite[j].type == 0) + { + if (g_dglos.g_smallMap.sprite[j].size != 0 && g_dglos.g_smallMap.sprite[j].size != 100) + { + //it requires scaling, need to do things differently as our low mem fast custom blits won't work with this + bScaledBackgroundSpritesRequired = true; + } + if (bScaledBackgroundSpritesRequired) + { + g_dglo.m_bgSpriteMan.Add(sprite); + + } else + { + draw_sprite_game(lpDDSBackGround,sprite); + + } + } + + + if (g_sprite[sprite].hard == 0) + { + add_hardness(sprite,100+j); + } + + g_sprite[sprite].active = false; + } + + if (g_dglos.g_smallMap.sprite[j].type == 1) + { + //make it a living sprite + + sprite = add_sprite_dumb(g_dglos.g_smallMap.sprite[j].x,g_dglos.g_smallMap.sprite[j].y,0, + g_dglos.g_smallMap.sprite[j].seq,g_dglos.g_smallMap.sprite[j].frame, + g_dglos.g_smallMap.sprite[j].size); + + g_sprite[sprite].hard = g_dglos.g_smallMap.sprite[j].hard; + + //assign addition parms to the new sprite + g_sprite[sprite].sp_index = j; + + g_sprite[sprite].brain = g_dglos.g_smallMap.sprite[j].brain; + g_sprite[sprite].speed = g_dglos.g_smallMap.sprite[j].speed; + g_sprite[sprite].base_walk = g_dglos.g_smallMap.sprite[j].base_walk; + g_sprite[sprite].base_idle = g_dglos.g_smallMap.sprite[j].base_idle; + g_sprite[sprite].base_attack = g_dglos.g_smallMap.sprite[j].base_attack; + g_sprite[sprite].base_hit = g_dglos.g_smallMap.sprite[j].base_hit; + g_sprite[sprite].hard = g_dglos.g_smallMap.sprite[j].hard; + g_sprite[sprite].timer = g_dglos.g_smallMap.sprite[j].timer; + g_sprite[sprite].que = g_dglos.g_smallMap.sprite[j].que; + g_sprite[sprite].sp_index = j; + g_sprite[sprite].alt = g_dglos.g_smallMap.sprite[j].alt; + g_sprite[sprite].base_die = g_dglos.g_smallMap.sprite[j].base_die; + g_sprite[sprite].strength = g_dglos.g_smallMap.sprite[j].strength; + g_sprite[sprite].defense = g_dglos.g_smallMap.sprite[j].defense; + g_sprite[sprite].gold = g_dglos.g_smallMap.sprite[j].gold; + g_sprite[sprite].exp = g_dglos.g_smallMap.sprite[j].exp; + g_sprite[sprite].nohit = g_dglos.g_smallMap.sprite[j].nohit; + g_sprite[sprite].touch_damage = g_dglos.g_smallMap.sprite[j].touch_damage; + g_sprite[sprite].hitpoints = g_dglos.g_smallMap.sprite[j].hitpoints; + g_sprite[sprite].sound = g_dglos.g_smallMap.sprite[j].sound; + check_sprite_status_full(sprite); + if (g_dglos.g_smallMap.sprite[j].prop == 0) if (g_sprite[sprite].sound != 0) + { + //make looping sound +#ifdef _DEBUG + LogMsg("making sound with sprite %d..", sprite); +#endif + SoundPlayEffect( g_sprite[sprite].sound,22050, 0,sprite, 1); + } + + if (g_sprite[sprite].hard == 0) + { + add_hardness(sprite,100+j); + } + + //does it need a script loaded? + + if (strlen(g_dglos.g_smallMap.sprite[j].script) > 1) + { + g_sprite[sprite].script = load_script(g_dglos.g_smallMap.sprite[j].script, sprite, true); + } + + } + //Msg("I just made sprite %d because rank[%d] told me to..",sprite,j); + } + } + +#ifdef _DEBUG + + LogMsg("Using %d background sprites in realdraw mode.", g_dglo.m_bgSpriteMan.GetCount()); +#endif +} + +bool kill_last_sprite(void) +{ + int found; + found = 0; + bool nosetlast = false; + for (int k=1; k < C_MAX_SPRITES_AT_ONCE; k++ ) + + if (g_sprite[k].active) + { + + if (g_sprite[k].live) + { + nosetlast = true; + goto crazy; + + } + + found = k; +crazy:; + + } + if (found > 1) + {g_sprite[found].active = false; + if (nosetlast == false) + g_dglos.last_sprite_created = found -1; + return(true); + } + + //we didn't kill any sprites, only 1 remains + return(false); +} + + +void CopyBitmapToBackBuffer (char *pName) +{ + + int ddrval; + + string fName = pName; + StringReplace("\\", "/", fName); + + fName = GetFileLocationString(fName); + + if (!FileExists(fName)) + { + LogMsg("Error: Can't find bitmap at %s.",fName.c_str()); + return; + } + SAFE_DELETE(lpDDSBuffer); + assert(!lpDDSBuffer); + lpDDSBuffer = LoadBitmapIntoSurface(fName.c_str(), TRANSPARENT_NONE); + + rtRect32 rcRect(0,0,C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y); + + ddrval = lpDDSBack->BltFast( 0, 0, lpDDSBuffer, + &rcRect, DDBLTFAST_NOCOLORKEY); + +} + +void show_bmp( char *pName, int showdot, int reserved, int script) +{ + CopyBitmapToBackBuffer(pName); + + g_dglos.g_bShowingBitmap.active = true; + g_dglos.g_bShowingBitmap.showdot = showdot; + g_dglos.g_bShowingBitmap.script = script; + strncpy(g_dglos.g_lastBitmapShown, pName, C_SHOWN_BITMAP_SIZE-1); + g_abort_this_flip = true; + +} + + +void copy_bmp( char *pName) +{ + int ddrval; + + string fName = pName; + StringReplace("\\", "/", fName); + + fName = GetFileLocationString(fName); + + if (!FileExists(fName)) + { + LogMsg("Error: Can't find bitmap at %s.",fName.c_str()); + return; + } +SAFE_DELETE(lpDDSBuffer); + assert(!lpDDSBuffer); + lpDDSBuffer = LoadBitmapIntoSurface(fName.c_str(), TRANSPARENT_NONE); + + g_abort_this_flip = true; + + rtRect32 rcRect(0,0,C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y); + + ddrval = lpDDSBack->BltFast( 0, 0, lpDDSBuffer, + &rcRect, DDBLTFAST_NOCOLORKEY); + + ddrval = lpDDSBackGround->BltFast( 0, 0, lpDDSBuffer, + &rcRect, DDBLTFAST_NOCOLORKEY); + +} + + +bool playing( int sound) +{ + return false; +} + +int get_pan(int h) +{ + + int pan = 0; + int x1 = 320; + + //uncomment to allow math to be done from Dink's current location + //x1 = spr[1].x; + + if (g_sprite[h].active) + { + if (g_sprite[h].x > x1) pan += (g_sprite[h].x - x1) * 6; + if (x1 > g_sprite[h].x) pan -= (x1 - g_sprite[h].x) * 6; + } + + if (pan > 10000) pan = 10000; + if (pan < -10000) pan = -10000; + + return(pan); +} + + + +int get_vol(int h) +{ + + int pan = 0; + int pan2 = 0; + + if (g_sprite[h].active) + { + if (g_sprite[h].x > g_sprite[1].x) pan -= (g_sprite[h].x - g_sprite[1].x) * 4; + if (g_sprite[1].x > g_sprite[h].x) pan -= (g_sprite[1].x - g_sprite[h].x) * 4; + if (g_sprite[h].y > g_sprite[1].y) pan2 -= (g_sprite[h].y - g_sprite[1].y) * 4; + if (g_sprite[1].y > g_sprite[h].y) pan2 -= (g_sprite[1].y - g_sprite[h].y) * 4; + + //Msg("pan %d, pan2 %d", pan, pan2); + + if (pan2 < pan) pan = pan2; + } + + if (pan > -100) pan = 0; + if (pan < -10000) pan = -10000; + return(pan); +} + +void kill_all_sounds() +{ + for (int i=1; i <= num_soundbanks; i++) + { + soundbank[i].Stop(); + //Msg("REPEAT Sound %d playing.. owner is %d.", i,soundinfo[i].owner); + soundinfo[i].owner = 0; + soundinfo[i].repeat = 0; + soundinfo[i].freq = 0; + soundinfo[i].survive = 0; + + } +} + +void kill_repeat_sounds( void ) +{ + if (!sound_on) return; + + for (int i=1; i <= num_soundbanks; i++) + { + if (soundinfo[i].repeat) if (soundinfo[i].owner == 0) if (soundinfo[i].survive == 0) + { + + soundbank[i].Stop(); + //Msg("REPEAT Sound %d playing.. owner is %d.", i,soundinfo[i].owner); + soundinfo[i].owner = 0; + soundinfo[i].repeat = 0; + } + } +} + +void kill_repeat_sounds_all( void ) +{ + if (!sound_on) return; + + for (int i=1; i <= num_soundbanks; i++) + { + if (soundinfo[i].repeat) if (soundinfo[i].owner == 0) + { + soundbank[i].Stop(); + //Msg("REPEAT Sound %d playing.. owner is %d.", i,soundinfo[i].owner); + soundinfo[i].owner = 0; + soundinfo[i].repeat = 0; + } + } +} + +void update_sound(void) +{ + + if (!sound_on) return; + + g_soundTimer = 0; + + if (! (g_soundTimer < GetBaseApp()->GetGameTick())) + { + //wait before updating + return; + } + + g_soundTimer = GetBaseApp()->GetGameTick()+120; + + for (int i=1; i <= num_soundbanks; i++) + { + if (soundinfo[i].repeat) if (soundinfo[i].owner != 0) + { + + if ( ( g_sprite[soundinfo[i].owner].sound == 0) || ( soundinfo[i].owner == 0) + + || (g_sprite[soundinfo[i].owner].active == false) || soundbank[i].m_audioID == 0) + { + soundbank[i].Stop(); + //Msg("Killed bank %d", i); + //Msg("REPEAT Sound %d playing.. owner is %d.", i,soundinfo[i].owner); + soundinfo[i].owner = 0; + soundinfo[i].repeat = 0; + } else + { + soundbank[i].SetPan(get_pan(soundinfo[i].owner)); + soundbank[i].SetVolume(get_vol(soundinfo[i].owner)); + + } + } + + if (soundbank[i].IsInUse()) + { + { + //Msg("Sound %d playing.. owner is %d.", i,soundinfo[i].owner); + if (soundinfo[i].owner != 0) + { + if (g_sprite[soundinfo[i].owner].active == false) + { + //Msg("Killed bank %d", i); + + soundbank[i].Stop(); + + } else + { + soundbank[i].SetPan(get_pan(soundinfo[i].owner)); + soundbank[i].SetVolume(get_vol(soundinfo[i].owner)); + } + + } + } + } + } + + +} + +int playbank( int sound, int min,int plus, int sound3d, bool repeat, int forceBank = 0 ) +{ + +if (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) +{ + if (repeat) + return 0; //we don't support looping sounds because we can't figure out if they are playing or not, missing an IsPlaying() +} + //Msg("Playing bank %d..", sound); + int i; + + if (forceBank != 0) + { + i = forceBank; + goto madeit; + } + for (i=1; i <= num_soundbanks; i++) + { + + if (!soundbank[i].IsInUse()) + { + goto madeit; + } + } + + return(false); + +madeit: + +soundbank[i].Reset(); + +StringReplace("\\", "/", g_soundInfo[sound].m_fileName); +string soundFilePathAndName = "sound/"+ToLowerCaseString(g_soundInfo[sound].m_fileName); +string fName; + +//hack because android sucks +/* +if ( (GetEmulatedPlatformID() == PLATFORM_ID_ANDROID) || (GetEmulatedPlatformID() == PLATFORM_ID_WEBOS) + || (GetEmulatedPlatformID() == PLATFORM_ID_BBX)) + */ +if (1) +{ + //hack the sound value a bit + + if (sound == 10 && g_soundInfo[sound].m_fileName == "SWORD2.WAV" && min == 22050) + { + GetAudioManager()->Play("dink/sound/sword2_item.wav"); + return 0; + } + + //first try with oggs + + string temp = ModifyFileExtension(soundFilePathAndName, "ogg"); + + temp = GetFileLocationString(temp); + + if (FileExists(temp)) + { + fName = temp; + } else + { + // LogMsg("Can't find %s", GetFileLocationString(temp).c_str()); + fName = GetFileLocationString(soundFilePathAndName); + + } + + +} else +{ + fName = GetFileLocationString(soundFilePathAndName); +} + + + +//before we load it, let's see how big it really is. +int fileSize = GetFileManager()->GetFileSize(fName, false); + +if (fileSize < 1) +{ + LogMsg("Unable to locate sound %s", fName.c_str()); + return 0; +} + + +bool bForceStreaming = false; + +if (fileSize > 1024*1024*2) +{ + //too big, let's stream it + bForceStreaming = true; +} + +soundbank[i].m_audioID = GetAudioManager()->Play(fName, repeat != NULL, false, false, bForceStreaming); +#ifdef _DEBUG + //LogMsg("Got audioid %d when playing %s",soundbank[i].m_audioID, fName.c_str() ); +#endif +if (soundbank[i].m_audioID == 0) return 0; +soundbank[i].m_soundIDThatPlayedUs = sound; + +int freq = RandomRange(min, min+plus); + +if (GetEmulatedPlatformID() != PLATFORM_ID_ANDROID) + GetAudioManager()->SetFrequency(soundbank[i].m_audioID, freq); + +if (sound3d > 0) +{ + soundbank[i].SetPan(get_pan(sound3d)); + soundbank[i].SetVolume(get_vol(sound3d)); +} + +soundinfo[i].owner = sound3d; +soundinfo[i].repeat = repeat; +soundinfo[i].survive = 0; +soundinfo[i].vol = 0; +soundinfo[i].freq = freq; + +return i; + + + +} /* SoundPlayEffect */ + + +int SoundPlayEffect( int sound, int min,int plus , int sound3d, bool repeat) +{ + return playbank(sound, min, plus, sound3d, repeat); +} /* SoundPlayEffect */ + + +int hurt_thing(int h, int damage, int special) +{ + //lets hurt this sprite but good + if (damage < 1) return(0); + int num = damage - g_sprite[h].defense; + + // Msg("num is %d.. defense was %d.of sprite %d", num, spr[h].defense, h); + if (num < 1) num = 0; + + if (num == 0) + { + if ((rand() % 2)+1 == 1) num = 1; + } + + g_sprite[h].damage += num; + return(num); + //draw blood here +} + +void random_blood(int mx, int my, int h) +{ + //if ((rand() % 2) == 1) myseq = 188; else myseq = 187; + //redink1 - customizable blood depending on what sprite we hit!! + int myseq; + int randy; + + if (g_sprite[h].bloodseq > 0 && g_sprite[h].bloodnum > 0) + { + myseq = g_sprite[h].bloodseq; + randy = g_sprite[h].bloodnum; + } + else + { + myseq = 187; + randy = 3; + } + + myseq += (rand() % randy); + + int crap2 = add_sprite(mx,my,5,myseq,1); + g_sprite[crap2].speed = 0; + g_sprite[crap2].base_walk = -1; + g_sprite[crap2].nohit = 1; + g_sprite[crap2].seq = myseq; + if (h > 0) g_sprite[crap2].que = g_sprite[h].y+1; +} + +bool SoundStopEffect( int sound ) +{ + /* + if(!g_soundInfo[sound].sound ) + { + return false; + } + + g_soundInfo[sound].sound->Stop(); + + return true; + */ + + return true; +} /* SoundStopEffect */ + + + +bool InitSound() +{ + + for (int i=1; i < num_soundbanks; i++) + { + soundbank[i].Reset(); + } + return true; +} /* InitSound */ + +void BuildScreenBackground( bool bFullRebuild ) +{ + rtRect32 rcRect; + int pa, cool; + *pvision = 0; + + if (bFullRebuild) + { + while (kill_last_sprite()); + kill_repeat_sounds(); + kill_all_scripts(); + g_dglo.m_bgSpriteMan.Clear(); + } + +restart: + int tileScreenID; + + for (int x=0; x<96; x++) + { + cool = g_dglos.g_smallMap.t[x].num / 128; + pa = g_dglos.g_smallMap.t[x].num - (cool * 128); + rcRect.left = (pa * 50- (pa / 12) * 600); + rcRect.top = (pa / 12) * 50; + rcRect.right = rcRect.left + 50; + rcRect.bottom = rcRect.top + 50; + + tileScreenID = cool+1; + + bool bRequireRebuild; + + if (!LoadTileScreenIfNeeded(tileScreenID, bRequireRebuild)) + { + continue; + } + + if (bRequireRebuild) goto restart; + g_tileScreens[tileScreenID]->UpdateLastUsedTime(); + + lpDDSBackGround->BltFast( (x * 50 - ((x / 12) * 600))+g_gameAreaLeftOffset, (x / 12) * 50, g_tileScreens[tileScreenID], + &rcRect, DDBLTFAST_NOCOLORKEY| DDBLTFAST_WAIT ); + } + + if (bFullRebuild) + { + if (strlen(g_dglos.g_smallMap.script) > 1) + { + int ms = load_script(g_dglos.g_smallMap.script,0, true); + + if (ms > 0) + { + locate(ms, "main"); + g_dglos.no_running_main = true; + run_script(ms); + g_dglos.no_running_main = false; + } + } + } + + + //lets add the sprites hardness to the real hardness, adding its own uniqueness to our collective. + place_sprites_game(!bFullRebuild); + + if (!bFullRebuild) return; //don't mess with the game tick stuff or initscripts + //if script for overall screen, run it + + g_dglos.g_dinkTick = GetBaseApp()->GetGameTick(); + init_scripts(); +} + + + +void fill_back_sprites(void ) +{ + int sprite; + + bool bs[C_MAX_SPRITES_AT_ONCE]; + int rank[C_MAX_SPRITES_AT_ONCE]; + int highest_sprite; + + memset(&bs,0,sizeof(bs)); + int hs; + + for (int r1 = 1; r1 < 100; r1++) + { + + highest_sprite = 20000; //more than it could ever be + rank[r1] = 0; + + for (int h1 = 1; h1 < 100; h1++) + { + if (bs[h1] == false) + { + if (g_dglos.g_smallMap.sprite[h1].active) if (g_dglos.g_smallMap.sprite[h1].type != 1) if (g_dglos.g_smallMap.sprite[h1].hard == 0) + { + if (g_dglos.g_smallMap.sprite[h1].que != 0) hs = g_dglos.g_smallMap.sprite[h1].que; else hs = g_dglos.g_smallMap.sprite[h1].y; + if ( hs < highest_sprite ) + { + highest_sprite =hs; + rank[r1] = h1; + } + } + + } + } + if (rank[r1] != 0) + bs[rank[r1]] = true; + } + + int j; + + for (int oo =1; rank[oo] > 0; oo++) + { + //Msg("Ok, rank[%d] is %d.",oo,rank[oo]); + j = rank[oo]; + + if (g_dglos.g_smallMap.sprite[j].active == true) if ( ( g_dglos.g_smallMap.sprite[j].vision == 0) || (g_dglos.g_smallMap.sprite[j].vision == *pvision)) + { + { + //make it part of the background (much faster) + + sprite = add_sprite_dumb(g_dglos.g_smallMap.sprite[j].x,g_dglos.g_smallMap.sprite[j].y,0, + g_dglos.g_smallMap.sprite[j].seq,g_dglos.g_smallMap.sprite[j].frame, + g_dglos.g_smallMap.sprite[j].size); + g_sprite[sprite].hard = g_dglos.g_smallMap.sprite[j].hard; + g_sprite[sprite].sp_index = j; + g_sprite[sprite].alt = g_dglos.g_smallMap.sprite[j].alt; + check_sprite_status_full(sprite); + if (g_sprite[sprite].hard == 0) + { + /*if (pam.sprite[j].prop == 0) + add_hardness(sprite, 1); else */ add_hardness(sprite,100+j); + + } + g_sprite[sprite].active = false; + } + } + } +} + + +void add_item(char name[10], int mseq, int mframe, bool magic) +{ + if (magic == false) + { + //add reg item + + for (int i = 1; i < 17; i ++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active == false) + { + if (debug_mode) + LogMsg("Weapon/item %s added to inventory.",name); + g_dglos.g_playerInfo.g_itemData[i].seq = mseq; + g_dglos.g_playerInfo.g_itemData[i].frame = mframe; + strcpy(g_dglos.g_playerInfo.g_itemData[i].name, name); + g_dglos.g_playerInfo.g_itemData[i].active = true; + //if (debug_mode) + // LogMsg("wep: Checking seq",name); + + check_seq_status(mseq, mframe); + + + int crap1 = load_script(g_dglos.g_playerInfo.g_itemData[i].name, 1000, false); + + + if (locate(crap1, "PICKUP")) + { + run_script(crap1); + } + + + return; + } + } + + } else + { + //add magic item + for (int i = 1; i < 9; i ++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active == false) + { + if (debug_mode) + LogMsg("Magic %s added to inventory.",name); + g_dglos.g_playerInfo.g_MagicData[i].seq = mseq; + g_dglos.g_playerInfo.g_MagicData[i].frame = mframe; + strcpy(g_dglos.g_playerInfo.g_MagicData[i].name, name); + + g_dglos.g_playerInfo.g_MagicData[i].active = true; + //check_seq_status(mseq, mframe); + int crap = load_script(g_dglos.g_playerInfo.g_MagicData[i].name, 1000, false); + if (locate(crap, "PICKUP")) run_script(crap); + + return; + } + } + } +} + +void fill_screen(int num) +{ + + //assert(!"Seth, fix this"); + + DDBLTFX ddbltfx; + ddbltfx.dwFillColor = num; + lpDDSBackGround->Blt(NULL ,NULL,NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + +/* + + DDBLTFX ddbltfx; + ZeroMemory(&ddbltfx, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof( ddbltfx); + + //redink1 fix for correct fill_screen colors in truecolor mode + if (truecolor) + { + lpDDPal->GetEntries(0,0,256,pe); + ddbltfx.dwFillColor = pe[num].peBlue << wBPos | pe[num].peGreen << wGPos | pe[num].peRed << wRPos; + } + else + ddbltfx.dwFillColor = num; + crap = lpDDSTwo->Blt(NULL ,NULL,NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); +*/ + +} + + +void fill_hard_sprites(void ) +{ + bool bs[C_MAX_SPRITES_AT_ONCE]; + int rank[C_MAX_SPRITES_AT_ONCE]; + int highest_sprite; + int h; + memset(&bs,0,sizeof(bs)); + + //Msg("filling sprite hardness..."); + int max_s = g_dglos.last_sprite_created; + int height; + + for (int r1 = 1; r1 <= max_s; r1++) + { + highest_sprite = 22024; //more than it could ever be + rank[r1] = 0; + for (int h1 = 1; h1 < max_s+1; h1++) + { + if (g_sprite[h1].active) + { + if (bs[h1] == false) + { + //Msg( "Ok, %d is %d", h1,(spr[h1].y + k[spr[h1].pic].yoffset) ); + if (g_sprite[h1].que != 0) height = g_sprite[h1].que; else height = g_sprite[h1].y; + if ( height < highest_sprite ) + { + highest_sprite = height; + rank[r1] = h1; + } + } + } + } + if (rank[r1] != 0) + bs[rank[r1]] = true; + } + + for ( int j = 1; j <= max_s; j++) + { + h = rank[j]; + if (h > 0) + if (g_sprite[h].active) + { + // Msg("proccesing sprite %d", h); + if (g_sprite[h].sp_index != 0) + { + //Msg("has spindex of %d prop is %d",spr[h].sp_index,pam.sprite[spr[h].sp_index].prop); + if (g_dglos.g_smallMap.sprite[g_sprite[h].sp_index].hard == 0) + { + add_hardness(h,100+g_sprite[h].sp_index); + //Msg("added warp hardness for %d", spr[h].sp_index); + } + } else + { + if (g_sprite[h].hard == 0) + { + //Msg("adding a new sprite hardness %d (not from editor)", h); + add_hardness(h, 1); + } + + } + } + } +} + +void LoadGame(int gameSlot) +{ + kill_all_scripts_for_real(); + g_dglos.g_returnint = load_game(gameSlot); + LogMsg("load completed. "); + + *pupdate_status = 1; + draw_status_all(); +} + + +int process_line (int script, char *pLineIn, bool doelse) +{ + char * h, *p; + int i; + char line[200]; + char ev[15][100]; + char temp[255]; + char first[2]; + int sprite = 0; + + if (g_scriptInstance[script]->level < 1) g_scriptInstance[script]->level = 1; + + for (int kk =1; kk < 15; kk++) ev[kk][0] = 0; + + h = pLineIn; + if (h[0] == 0) return(0); + if ( (h[0] == '/') && (h[1] == '/')) + + { + //Msg("It was a comment!"); + goto bad; + } + + + for ( i=1; i <= 14; i++) + { + if (separate_string(h, i,' ',ev[i]) == false) goto pass; + } + +pass: +#ifdef _DEBUG + //LogMsg("first line is %s (second is %s), third is %s", ev[1], ev[2], ev[3]); +#endif + + if (compare(ev[1], (char*)"VOID")) + { + + if (g_scriptInstance[script]->proc_return != 0) + { + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + + //Msg("returning.."); + return(2); + } + //replace("\n","",ev[1]); + if (ev[1][strlen(ev[1]) -1] == ':') if (strlen(ev[2]) < 2) if (strncmp(ev[1],"say",3) != 0) + { + // Msg("Found label %s..",ev[1]); + return(0); //its a label + } + + if (ev[1][0] == '(') + { + //this procedure has been passed a conditional statement finder + //what kind of conditional statement is it? + p = h; + separate_string(h, 2,')',temp); + //Msg("We found %s, woah!", temp); + separate_string(h, 1,')',ev[1]); + + // Msg("Ok, turned h %s to ev1 %s.",h,ev[1]); + p = &p[strlen(ev[1])+1]; + + strip_beginning_spaces(p); + // Msg("does %s have a ( in front?", p); + //Msg("We found %s, woah!", temp); + + //These are used for conditionals?? + if (strchr(temp, '=') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d == %s", g_dglos.g_returnint, temp); + g_dglos.g_returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + + if (strchr(temp, '>') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d > %s", g_dglos.g_returnint, temp); + g_dglos.g_returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + + if (strchr(temp, '<') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d < %s", g_dglos.g_returnint, temp); + g_dglos.g_returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + + /* + if (strchr(temp, '<=') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d <= %s", returnint, temp); + returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + if (strchr(temp, '>=') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d >= %s", returnint, temp); + returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + */ + + if (strchr(temp, '!') != NULL) + { + h = &h[1]; + strip_beginning_spaces(h); + process_line(script, h, false); + replace("==", "", temp); + sprintf(line, "%d != %s", g_dglos.g_returnint, temp); + g_dglos.g_returnint = var_figure(line, script); + strcpy(h, "\n"); + return(0); + } + + if (p[0] == ')') + { + //its a procedure in the if statement!!! + h = &h[1]; + p = &p[1]; + strcpy(line, p); + process_line(script, h, false); + + //8 + LogMsg("Returned %d for the returnint", g_dglos.g_returnint); + h = pLineIn; + strcpy(pLineIn, line); + + // Msg("Returing %s..", s); + return(0); + } else + { + h = &h[1]; + + separate_string(h, 1,')',line); + h = &h[strlen(line)+1]; + g_dglos.g_returnint = var_figure(line, script); + strcpy(pLineIn, h); + + return(0); + } + + strip_beginning_spaces(h); + strip_beginning_spaces(ev[1]); + pLineIn = h; + } else + { + } + + + if (strchr(ev[1], '(') != NULL) + { + //Msg("Has a (, lets change it"); + separate_string(h, 1,'(',ev[1]); + //Msg("Ok, first is now %s",ev[1]); + } + + first[0] = ev[1][0]; + first[1] = 0; +// sprintf(first, "%c",ev[1][0]); + + if (compare(first, "{")) + { + g_scriptInstance[script]->level++; + //Msg("Went up level, now at %d.", rinfo[script]->level); + h = &h[1]; + if (g_scriptInstance[script]->skipnext) + { + g_scriptInstance[script]->skipnext = false; + g_scriptInstance[script]->onlevel = ( g_scriptInstance[script]->level - 1); + //Msg("Skipping until level %d is met..", rinfo[script]->onlevel); + } + goto good; + } + + if (compare(first, "}")) + { + g_scriptInstance[script]->level--; + //Msg("Went down a level, now at %d.", rinfo[script]->level); + h = &h[1]; + + if (g_scriptInstance[script]->onlevel > 0) if (g_scriptInstance[script]->level == g_scriptInstance[script]->onlevel) + { + strip_beginning_spaces(h); + strcpy(pLineIn, h); + return(4); + } + goto good; + } + + if (g_scriptInstance[script]->level < 0) + { + g_scriptInstance[script]->level = 0; + } + + if (compare(ev[1], (char*)"void")) + { + // Msg("Next procedure starting, lets quit"); + strcpy(pLineIn, h); + if (g_scriptInstance[script]->proc_return != 0) + { + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + return(2); + } + + { //used to be an if.. + + + if (g_scriptInstance[script]->onlevel > 0) + { + if (g_scriptInstance[script]->level > g_scriptInstance[script]->onlevel) return(0); + + } + g_scriptInstance[script]->onlevel = 0; + + if (g_scriptInstance[script]->skipnext) + { + //sorry, can't do it, you were told to skip the next thing + g_scriptInstance[script]->skipnext = false; + strcpy(pLineIn, h); + return(3); + } + + //if (debug_mode) Msg("%s",s); + + + if (compare(ev[1], (char*)"void")) + { + LogMsg("ERROR: Missing } in %s, offset %d.", g_scriptInstance[script]->name,g_scriptInstance[script]->current); + strcpy(pLineIn, h); + return(2); + } + + if (compare(ev[1], (char*)"else")) + { + //Msg("Found else!"); + h = &h[strlen(ev[1])]; + + if (!doelse) + { + //they shouldn't run the next thing + g_scriptInstance[script]->skipnext = true; + //Msg("No to else..."); + + } + strcpy(pLineIn, h); + return(1); + + } + + if (compare(ev[1], (char*)"unfreeze")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //Msg("UnFreeze called for %d.", nlist[0]); + if (g_sprite[g_nlist[0]].active) g_sprite[g_nlist[0]].freeze = 0; else + LogMsg("Couldn't unfreeze sprite %d in script %d, it doesn't exist.", g_nlist[0], script); + + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"freeze")) + { + //Msg("Freeze called (%s)", h); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + if (g_sprite[g_nlist[0]].active) g_sprite[g_nlist[0]].freeze = script; else + LogMsg("Couldn't freeze sprite %d in script %d, it doesn't exist.", g_nlist[0], script); + + } + + strcpy(pLineIn, h); + return(0); + } + + + //redink1 added so we can have return values and crap. + if (compare(ev[1], (char*)"return")) + { + + if (debug_mode) LogMsg("Found return; statement"); + + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + process_line(script, h, false); + + if (g_scriptInstance[script]->proc_return != 0) + { + g_dglos.bKeepReturnInt = true; + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + + return(2); + } + + + if (compare(ev[1], (char*)"if")) + { + + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + //LogMsg("running if with string of %s", h); + + process_line(script, h, false); + + //Msg("Result is %d", returnint); + + if (g_dglos.g_returnint != 0) + { + if (debug_mode) LogMsg("If returned true"); + + + } else + { + //don't do it! + g_scriptInstance[script]->skipnext = true; + if (debug_mode) LogMsg("If returned false, skipping next thing"); + } + + //DO STUFF HERE! + strcpy(pLineIn, h); + //g("continuing to run line %s..", h); + return(5); + + } + + if (compare(ev[1], (char*)"sp_dir")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].dir); + + if (g_nlist[1] != -1) changedir(g_sprite[g_nlist[0]].dir, g_nlist[0], g_sprite[g_nlist[0]].base_walk); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[2], "=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[1]; + strip_beginning_spaces(h); + var_equals(ev[1], ev[3], '=', script, h); + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"set_callback_random")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + int cb = add_callback(slist[0],g_nlist[1],g_nlist[2],script); + //got all parms, let do it + g_dglos.g_returnint = cb; + } + + strcpy(pLineIn, h); + return(0); + } + + // redink1 added + if (compare(ev[1], (char*)"callback_kill")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if ( g_nlist[0] >= 0 && g_nlist[0] <= 99) + { + g_dglos.g_scriptCallback[g_nlist[0]].active = false; + } + } + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"set_dink_speed")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p) && g_nlist[0] != 0) + { + g_dglos.dinkspeed = g_nlist[0]; + } + + strcpy(pLineIn, h); + return(0); + } + + //redink1 + if (compare(ev[1], (char*)"set_dink_base_push")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.mDinkBasePush = g_nlist[0]; + } + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"reset_timer")) + { + h = &h[strlen(ev[1])]; + g_dglos.time_start = GetBaseApp()->GetGameTick(); + g_dglos.g_playerInfo.minutes = 0; + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"set_keep_mouse")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.keep_mouse = g_nlist[0]; + + } + + strcpy(pLineIn, h); + return(0); + } + + + + + if (compare(ev[1], (char*)"add_item")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + add_item(slist[0], g_nlist[1], g_nlist[2], false); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"add_exp")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + add_exp(g_nlist[0], g_nlist[1], true); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"add_magic")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + add_item(slist[0], g_nlist[1], g_nlist[2], true); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"kill_this_item")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + kill_cur_item_script(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"kill_this_magic")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + kill_cur_magic_script(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + + + if (compare(ev[1], (char*)"show_bmp")) + { + //LogMsg("showing BMP"); + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_wait_for_button.active = false; + show_bmp(slist[0], g_nlist[1], g_nlist[2], script); + } + + strcpy(pLineIn, h); + return(2); + } + + if (compare(ev[1], (char*)"wait_for_button")) + { + //LogMsg("waiting for button with script %d", script); + h = &h[strlen(ev[1])]; + strcpy(pLineIn, h); + g_dglos.g_wait_for_button.script = script; + g_dglos.g_wait_for_button.active = true; + g_dglos.g_wait_for_button.button = 0; + return(2); + } + + if (compare(ev[1], (char*)"stop_wait_for_button")) + { + g_dglos.g_wait_for_button.active = false; + return(0); + } + + if (compare(ev[1], (char*)"copy_bmp_to_screen")) + { + LogMsg("copying BMP"); + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + copy_bmp(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"say")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + if (g_nlist[1] == 0) + { + LogMsg("Say_stop error: Sprite 0 can talk? Yeah, didn't think so."); + return(0); + } + + if (g_nlist[1] != 1000) + kill_text_owned_by(g_nlist[1]); + decipher_string(slist[0], script); + g_dglos.g_returnint = say_text(slist[0], g_nlist[1], script); + //Msg("Just said %s.", slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"draw_screen")) + { + if (g_dglos.g_gameMode == 1 || g_dglos.g_gameMode == 2) + { + g_dglos.m_bRenderBackgroundOnLoad = true; + } else + { + g_dglos.m_bRenderBackgroundOnLoad = false; + } + + if (g_scriptInstance[script]->sprite == 1000) + { + BuildScreenBackground(); + return(0); + } + BuildScreenBackground(); + return(2); + } + + if (compare(ev[1], (char*)"free_items")) + { + g_dglos.g_returnint = 0; + for (int i = 1; i < 17; i ++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active == false) + { + g_dglos.g_returnint += 1; + } + } + return(0); + } + + + if (compare(ev[1], (char*)"kill_cur_item")) + { + g_dglos.g_returnint = 0; + kill_cur_item(); + return(2); + } + + if (compare(ev[1], (char*)"kill_cur_magic")) + { + g_dglos.g_returnint = 0; + kill_cur_magic(); + return(2); + } + + if (compare(ev[1], (char*)"free_magic")) + { + g_dglos.g_returnint = 0; + + for (int i = 1; i < 9; i ++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active == false) + { + g_dglos.g_returnint += 1; + } + } + return(0); + } + + + + + if (compare(ev[1], (char*)"draw_status")) + { + draw_status_all(); + return(0); + } + + + if (compare(ev[1], (char*)"arm_weapon")) + { + + if (g_dglos.weapon_script != 0) if (locate(g_dglos.weapon_script, "DISARM")) run_script(g_dglos.weapon_script); + g_dglos.weapon_script = load_script(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, 1000, false); + if (locate(g_dglos.weapon_script, "ARM")) run_script(g_dglos.weapon_script); + + + return(0); + } + + if (compare(ev[1], (char*)"arm_magic")) + { + + + if (g_dglos.magic_script != 0) if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + g_dglos.magic_script = load_script(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, 1000, false); + if (locate(g_dglos.magic_script, "ARM")) run_script(g_dglos.magic_script); + + return(0); + } + + + if (compare(ev[1], (char*)"load_screen")) + { + //Msg("Loading map %d..",*pmap); + update_screen_time(); + load_map(g_MapInfo.loc[*pmap]); + + //redink1 fix for correct indicator on mini-map + if (g_MapInfo.indoor[*pmap] == 0) + g_dglos.g_playerInfo.last_map = *pmap; + return(0); + } + + + if (compare(ev[1], (char*)"choice_start")) + { + + kill_text_owned_by(1); + if (talk_get(script)) + { + // Msg("Question gathered successfully."); + return(2); + } + + return(0); + } + + + if (compare(ev[1], (char*)"say_stop")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[1] == 0) + { + LogMsg("Say_stop error: Sprite 0 can talk? Yeah, didn't think so."); + return(0); + } + + kill_text_owned_by(g_nlist[1]); + kill_text_owned_by(1); + kill_returning_stuff(script); + + decipher_string(slist[0], script); + sprite = say_text(slist[0], g_nlist[1], script); + g_dglos.g_returnint = sprite; + g_sprite[sprite].callback = script; + g_dglos.g_playerInfo.last_talk = script; + //Msg("Sprite %d marked callback true.", sprite); + + strcpy(pLineIn, h); + return(2); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"say_stop_npc")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + if (text_owned_by(g_nlist[1])) + { + g_dglos.g_returnint = 0; + return(0); + } + + kill_returning_stuff(script); + decipher_string(slist[0], script); + sprite = say_text(slist[0], g_nlist[1], script); + g_dglos.g_returnint = sprite; + g_sprite[sprite].callback = script; + strcpy(pLineIn, h); + + return(2); + + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"say_stop_xy")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + //LogMsg("Say_stop_xy: Adding %s", slist[0]); + kill_returning_stuff(script); + decipher_string(slist[0], script); + sprite = say_text_xy(slist[0], g_nlist[1], g_nlist[2], script); + g_sprite[sprite].callback = script; + g_sprite[sprite].live = true; + g_dglos.g_playerInfo.last_talk = script; + strcpy(pLineIn, h); + + return(2); + + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"say_xy")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + kill_returning_stuff(script); + decipher_string(slist[0], script); + sprite = say_text_xy(slist[0], g_nlist[1], g_nlist[2], script); + g_dglos.g_returnint = sprite; + strcpy(pLineIn, h); + return(0); + + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"restart_game")) + { + DinkRestartGame(); + + /* + while (kill_last_sprite()); + kill_repeat_sounds_all(); + kill_all_scripts_for_real(); + g_gameMode = 0; + screenlock = 0; + kill_all_vars(); + memset(&g_dglos.g_hitmap, 0, sizeof(g_dglos.g_hitmap)); + for (int u = 1; u <= 10; u++) + g_dglos.g_playerInfo.button[u] = u; + int script = load_script("main", 0, true); + + locate(script, "main"); + run_script(script); + //lets attach our vars to the scripts + attach(); + */ + return(2); + } + + if (compare(ev[1], (char*)"wait")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + // Msg("Wait called for %d.", nlist[0]); + strcpy(pLineIn, h); + kill_returning_stuff(script); + int cb1 = add_callback("",g_nlist[0],0,script); + + return(2); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"preload_seq")) + { + /* + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + check_seq_status(g_nlist[0]); + } + + strcpy(pLineIn, h); + */ + return(0); + } + + if (compare(ev[1], (char*)"script_attach")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_scriptInstance[script]->sprite = g_nlist[0]; + } + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"draw_hard_sprite")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + update_play_changes(); + int l = g_nlist[0]; + rtRect32 mhard; + mhard = g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[l].pseq].frame[g_sprite[l].pframe]].hardbox; + OffsetRect(&mhard, (g_sprite[l].x- 20), g_sprite[l].y); + + fill_hardxy(mhard); + fill_back_sprites(); + fill_hard_sprites(); + + + } + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"move")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,1,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_sprite[g_nlist[0]].move_active = true; + g_sprite[g_nlist[0]].move_dir = g_nlist[1]; + g_sprite[g_nlist[0]].move_num = g_nlist[2]; + g_sprite[g_nlist[0]].move_nohard = g_nlist[3]; + g_sprite[g_nlist[0]].move_script = 0; + if (debug_mode) LogMsg("Moving: Sprite %d, dir %d, num %d", g_nlist[0],g_nlist[1], g_nlist[2]); + + + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"sp_script")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,2,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[0] == 0) + { + LogMsg("Error: sp_script cannot process sprite 0??"); + return(0); + } + kill_scripts_owned_by(g_nlist[0]); + if (!slist[1][0] || load_script(slist[1], g_nlist[0], true) == 0) + { + g_dglos.g_returnint = 0; + return(0); + } + //if (no_running_main == true) LogMsg("Not running %s until later..", g_scriptInstance[g_sprite[g_nlist[0]].script]->name); + + if (g_dglos.no_running_main == false) + locate(g_sprite[g_nlist[0]].script, "MAIN"); + + + int tempreturn = g_sprite[g_nlist[0]].script; + + if (g_dglos.no_running_main == false) + run_script(g_sprite[g_nlist[0]].script); + + + g_dglos.g_returnint = tempreturn; + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"spawn")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + int mysc = load_script(slist[0], 1000, true); + if (mysc == 0) + { + g_dglos.g_returnint = 0; + return(0); + } + locate(mysc, "MAIN"); + int tempreturn = mysc; + run_script(mysc); + g_dglos.g_returnint = tempreturn; + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"run_script_by_number")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,2,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (locate(g_nlist[0], slist[1])) + { + run_script(g_nlist[0]); + } + + } + + strcpy(pLineIn, h); + return(0); + } + + + + if (compare(ev[1], (char*)"draw_hard_map")) + { + // (sprite, direction, until, nohard); + LogMsg("Drawing hard map.."); + update_play_changes(); + fill_whole_hard(); + fill_hard_sprites(); + fill_back_sprites(); + strcpy(pLineIn, h); + return(0); + } + + + + + if (compare(ev[1], (char*)"draw_background")) + { + BuildScreenBackground(false); + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"fade_down")) + { + g_dglos.process_downcycle = true; + g_dglos.process_upcycle = false; + + g_dglos.cycle_clock = g_dglos.g_dinkTick; + + g_dglos.cycle_script = script; + + strcpy(pLineIn, h); + + return(2); + } + + if (compare(ev[1], (char*)"fade_up")) + { + h = &h[strlen(ev[1])]; + g_dglos.process_upcycle = true; + g_dglos.process_downcycle = false; + + g_dglos.cycle_clock = g_dglos.g_dinkTick; + g_dglos.cycle_script = script; + g_dinkFadeAlpha = 1; + strcpy(pLineIn, h); + return(2); + } + + if (compare(ev[1], (char*)"kill_this_task")) + { + if (g_scriptInstance[script]->proc_return != 0) + { + run_script(g_scriptInstance[script]->proc_return); + } + kill_script(script); + return(2); + } + + + if (compare(ev[1], (char*)"kill_game")) + { + LogMsg("Was told to kill game, so doing it like a good boy."); + + g_sprite[1].freeze = 0; + SaveState(g_dglo.m_savePath+"continue_state.dat"); + WriteLastPathSaved(""); + + //kill our state.dat if it existed, not needed now, this can exist if an iphone goes into suspend, but then is resumed + RemoveFile(GetSavePath()+"state.dat", false); + + DinkQuitGame(); + //uncomment below if you want this to actually work + //PostMessage(g_hWndMain, WM_CLOSE, 0, 0); + + return(2); + } + + //redink1 added + if (compare(ev[1], (char*)"loopmidi")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if ( g_nlist[0] > 0 ) + { + g_dglos.mLoopMidi = true; + } + else + { + g_dglos.mLoopMidi = false; + } + } + return(0); + } + + if (compare(ev[1], (char*)"playmidi")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + int regm = atol(slist[0]); + LogMsg("Processing playmidi command."); + if (regm > 1000) + { + + LogMsg("playmidi - cd play command detected."); + PlayMidi((toString(regm-1000)+".mid").c_str()); + + } else + { + PlayMidi(slist[0]); + } + + } + + strcpy(pLineIn, h); + return(0); + } + if (compare(ev[1], (char*)"stopmidi")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + StopMidi(); + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"LOGMSG")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + LogMsg(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"kill_all_sounds")) + { + kill_repeat_sounds_all(); + strcpy(pLineIn, h); + return(0); + + } + + if (compare(ev[1], (char*)"turn_midi_off")) + { + g_dglos.midi_active = false; + strcpy(pLineIn, h); + return(0); + + } + if (compare(ev[1], (char*)"turn_midi_on")) + { + g_dglos.midi_active = true; + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"Playsound")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,1,1,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (sound_on) + g_dglos.g_returnint = SoundPlayEffect(g_nlist[0], g_nlist[1], g_nlist[2], g_nlist[3],g_nlist[4]); + else g_dglos.g_returnint = 0; + + } else + g_dglos.g_returnint = 0; + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"sound_set_survive")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (sound_on) + { + //let's set one sound to survive + if (g_nlist[0] > 0) + soundinfo[g_nlist[0]].survive = g_nlist[1]; + } + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"sound_set_vol")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (sound_on) + { + //let's set one sound to survive + if (g_nlist[0] > 0) + { + soundinfo[g_nlist[0]].vol = g_nlist[1]; + + soundbank[g_nlist[0]].SetVolume(g_nlist[1]); + } + } + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"sound_set_kill")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (sound_on) + { + //let's set one sound to survive + if (g_nlist[0] > 0) + { + soundbank[g_nlist[0]].Stop(); + } + + } + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"save_game")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + save_game(g_nlist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"force_vision")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + *pvision = g_nlist[0]; + g_scriptInstance[script]->sprite = 1000; + fill_whole_hard(); + BuildScreenBackground(); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"fill_screen")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + fill_screen(g_nlist[0]); + g_dglos.m_bRenderBackgroundOnLoad = false; + + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"load_game")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + int gameSlot = g_nlist[0]; + + if (gameSlot == 10) + { + string fName = DinkGetSavePath()+"autosave.dat"; + + bool bSuccess = LoadState(fName, true); + + if (!bSuccess) + { + RemoveFile(fName, false); + GetAudioManager()->Play("audio/buzzer2.wav"); + ShowQuickMessage("Error loading save state. Old version?"); + } else + { + GetAudioManager()->Play("audio/quick_load.wav"); + LoadState(fName, false); + ShowQuickMessage("Game loaded."); + } + + + + } else + { + LoadGame(gameSlot); + + } + return(2); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"game_exist")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[0] == 10) + { + //hack to check for the autosave slot instead + sprintf(temp, "%sautosavedb.dat",(g_dglo.m_savePath).c_str()); + } else + { + sprintf(temp, "%ssave%d.dat",(g_dglo.m_savePath).c_str(), g_nlist[0]); + } + if (FileExists(temp)) g_dglos.g_returnint = 1; else g_dglos.g_returnint = 0; + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"move_stop")) + { + // (sprite, direction, until, nohard); + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,1,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //Msg("Move stop running %d to %d..", nlist[0], nlist[0]); + g_sprite[g_nlist[0]].move_active = true; + g_sprite[g_nlist[0]].move_dir = g_nlist[1]; + g_sprite[g_nlist[0]].move_num = g_nlist[2]; + g_sprite[g_nlist[0]].move_nohard = g_nlist[3]; + g_sprite[g_nlist[0]].move_script = script; + strcpy(pLineIn, h); + if (debug_mode) LogMsg("Move_stop: Sprite %d, dir %d, num %d", g_nlist[0],g_nlist[1], g_nlist[2]); + return(2); + + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"load_sound")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (sound_on) + { +#ifdef _DEBUG + LogMsg("getting %s..",slist[0]); +#endif + CreateBufferFromWaveFile(slist[0],g_nlist[1]); + } + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"debug")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + decipher_string(slist[0], script); + LogMsg(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"goto")) + { + //LogMsg("Goto %s", ev[2]); + locate_goto(ev[2], script); + return(0); + } + + //redink1 added for global functions + if (compare(ev[1], (char*)"make_global_function")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,2,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + make_function(slist[0], slist[1]); + //Msg(slist[0]); + } + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"make_global_int")) + { + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + make_int(slist[0], g_nlist[1],0, script); + //Msg(slist[0]); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"int")) + { + + int_prepare(h, script); + + //Msg(slist[0]); + + h = &h[strlen(ev[1])]; + + //Msg("Int is studying %s..", h); + if (strchr(h, '=') != NULL) + { + strip_beginning_spaces(h); + //Msg("Found =...continuing equation"); + strcpy(pLineIn, h); + return(4); + } + + return(0); + + } + + if (compare(ev[1], (char*)"busy")) + { + + h = &h[strlen(ev[1])]; + // Msg("Running busy, h is %s", h); + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[0] == 0) LogMsg("ERROR: Busy cannot get info on sprite 0 in %s.",g_scriptInstance[script]->name); + else + { + + g_dglos.g_returnint = does_sprite_have_text(g_nlist[0]); + + LogMsg("Busy: Return int is %d and %d. Nlist got %d.", g_dglos.g_returnint,does_sprite_have_text(g_nlist[0]), g_nlist[0]); + + } + + } else LogMsg("Failed getting parms for Busy()"); + + strcpy(pLineIn, h); + return(0); + } + + //redink1 added + if (compare(ev[1], (char*)"sp_freeze")) + { + h = &h[strlen(ev[1])]; + // Msg("Running busy, h is %s", h); + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + // Set the value + if ( g_nlist[1] == 0 ) + { + g_sprite[g_nlist[0]].freeze = 0; + } + else if ( g_nlist[1] == 1 ) + { + g_sprite[g_nlist[0]].freeze = script; + } + + // Return the value + if ( g_sprite[g_nlist[0]].freeze > 0 ) + { + g_dglos.g_returnint = 1; + } + else + { + g_dglos.g_returnint = 0; + } + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"inside_box")) + { + + h = &h[strlen(ev[1])]; + //LogMsg("Running pigs with h", h); + int32 p[20] = {1,1,1,1,1,1,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + rtRect32 myrect(g_nlist[2], g_nlist[3], g_nlist[4], g_nlist[5]); + g_dglos.g_returnint = inside_box(g_nlist[0], g_nlist[1], myrect); + + if (debug_mode) + LogMsg("Inbox is int is %d and %d. Nlist got %d.", g_dglos.g_returnint, g_nlist[0], g_nlist[1]); + + + + } else LogMsg("Failed getting parms for inside_box"); + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"random")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = (rand() % g_nlist[0])+g_nlist[1]; + } else LogMsg("Failed getting parms for Random()"); + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"get_version")) + { + h = &h[strlen(ev[1])]; + g_dglos.g_returnint = C_DINK_VERSION; + strcpy(pLineIn, h); + return(0); + } + if (compare(ev[1], (char*)"get_client_version")) + { + h = &h[strlen(ev[1])]; + g_dglos.g_returnint = GetApp()->GetVersion()*100; + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"get_platform")) + { + //h = &h[strlen(ev[1])]; + g_dglos.g_returnint = GetEmulatedPlatformID(); + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"SHOW_POPUP")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + LogMsg("Showing %s in %d..",slist[0], g_nlist[1]); + + Entity *pBG = GetEntityRoot()->GetEntityByName("GameMenu"); + assert(pBG); + if (!pBG) return 0; + VariantList vList(pBG, string(slist[0])); + GetMessageManager()->CallEntityFunction(pBG, g_nlist[1], "ShowQuickTip", &vList); + } + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], (char*)"initfont")) + { + LogMsg("Ignoring Initfont command"); + return(0); + } + + if (compare(ev[1], (char*)"get_truecolor")) + { + //h = &h[strlen(ev[1])]; + if (g_dglo.m_dmodGameDir == "lyna/") return 0; + + g_dglos.g_returnint = 1; + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"get_burn")) + { + h = &h[strlen(ev[1])]; + g_dglos.g_returnint = 0; + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"set_mode")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_gameMode = g_nlist[0]; + g_dglos.g_returnint = g_dglos.g_gameMode; + //if (g_dglos.g_gameMode == ) + } else LogMsg("Failed to set mode"); + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"kill_shadow")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + for (int jj = 1; jj <= g_dglos.last_sprite_created; jj++) + { + if (g_sprite[jj].brain == 15) if (g_sprite[jj].brain_parm == g_nlist[0]) + { + + g_sprite[jj].active = 0; + } + + + } + } + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"create_sprite")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,1,1,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_dglos.g_returnint = add_sprite_dumb(g_nlist[0],g_nlist[1],g_nlist[2], + g_nlist[3],g_nlist[4], + 100); + + return(0); + } + g_dglos.g_returnint = 0; + return(0); + } + + + + if (compare(ev[1], (char*)"sp")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + for (int ii = 1; ii <= g_dglos.last_sprite_created; ii++) + { + + if (g_sprite[ii].sp_index == g_nlist[0]) + { + + if (debug_mode) LogMsg("Sp returned %d.", ii); + g_dglos.g_returnint = ii; + return(0); + } + + } + if (g_dglos.last_sprite_created == 1) + { + LogMsg("warning - you can't call SP() from a screen-ref, no sprites have been created yet."); + } + + } + g_dglos.g_returnint = 0; + return(0); + } + + + if (compare(ev[1], (char*)"is_script_attached")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + + g_dglos.g_returnint = g_sprite[g_nlist[0]].script; + + } + return(0); + } + + + + if (compare(ev[1], (char*)"sp_speed")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].speed); + + if (g_nlist[1] != -1) changedir(g_sprite[g_nlist[0]].dir, g_nlist[0], g_sprite[g_nlist[0]].base_walk); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_range")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].range); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_nocontrol")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].nocontrol); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_nodraw")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].nodraw); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_picfreeze")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].picfreeze); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + + if (compare(ev[1], (char*)"get_sprite_with_this_brain")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + if ( (g_sprite[i].brain == g_nlist[0]) && (i != g_nlist[1]) ) if + (g_sprite[i].active == 1) + { + //LogMsg("Ok, sprite with brain %d is %d", g_nlist[0], i); + g_dglos.g_returnint = i; + return(0); + } + + } + } + //LogMsg("Ok, sprite with brain %d is 0", g_nlist[0], i); + + g_dglos.g_returnint = 0; + return(0); + } + + //redink1 added this to make Paul Pliska's life more fulfilling + if (compare(ev[1], (char*)"get_next_sprite_with_this_brain")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + for (int i = g_nlist[2]; i <= g_dglos.last_sprite_created; i++) + { + if ( (g_sprite[i].brain == g_nlist[0]) && (i != g_nlist[1]) ) if + (g_sprite[i].active == 1) + { + //LogMsg("Ok, sprite with brain %d is %d", g_nlist[0], i); + g_dglos.g_returnint = i; + return(0); + } + + } + } + //LogMsg("Ok, sprite with brain %d is 0", g_nlist[0], i); + + g_dglos.g_returnint = 0; + return(0); + } + + + if (compare(ev[1], (char*)"get_rand_sprite_with_this_brain")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + int cter = 0; + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + if ( (g_sprite[i].brain == g_nlist[0]) && (i != g_nlist[1]) ) if + (g_sprite[i].active == 1) + { + cter++; + + } + + } + + if (cter == 0) + { + LogMsg("Get rand brain can't find any brains with %d.",g_nlist[0]); + g_dglos.g_returnint = 0; + return(0); + } + + int mypick = (rand() % cter)+1; + cter = 0; + for (int ii = 1; ii <= g_dglos.last_sprite_created; ii++) + { + if ( (g_sprite[ii].brain == g_nlist[0]) && (ii != g_nlist[1]) ) if + (g_sprite[ii].active == 1) + { + cter++; + if (cter == mypick) + { + g_dglos.g_returnint = ii; + return(0); + } + } + + } + + + } + + + g_dglos.g_returnint = 0; + return(0); + } + + + + if (compare(ev[1], (char*)"sp_sound")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].sound); + + if (g_nlist[1] > 0) + { + SoundPlayEffect( g_sprite[g_nlist[0]].sound,22050, 0,g_nlist[0], 1); + + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_attack_wait")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1]+g_dglos.g_dinkTick, &g_sprite[g_nlist[0]].attack_wait); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_active")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].active); + + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_disabled")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].disabled); + + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_size")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].size); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"activate_bow")) + { + + g_sprite[1].seq = 0; + g_sprite[1].pseq = 100+g_sprite[1].dir; + g_sprite[1].pframe = 1; + g_dglos.g_bowStatus.active = true; + g_dglos.g_bowStatus.script = script; + g_dglos.g_bowStatus.hitme = false; + g_dglos.g_bowStatus.time = 0; + return(2); + } + + if (compare(ev[1], (char*)"get_last_bow_power")) + { + g_dglos.g_returnint = g_dglos.g_bowStatus.last_power; + return(0); + } + + if (compare(ev[1], (char*)"sp_que")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].que); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_gold")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].gold); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_base_walk")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].base_walk); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_target")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].target); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"stopcd")) + { + + LogMsg("Stopped cd"); + + return(0); + } + + + if (compare(ev[1], (char*)"sp_base_hit")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].base_hit); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_base_attack")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].base_attack); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_base_idle")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].base_idle); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if ( (compare(ev[1], (char*)"sp_base_die")) || (compare(ev[1], (char*)"sp_base_death")) ) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].base_die); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"disable_all_sprites")) + { + for (int jj = 1; jj < g_dglos.last_sprite_created; jj++) + if (g_sprite[jj].active) g_sprite[jj].disabled = true; + return(0); + } + if (compare(ev[1], (char*)"enable_all_sprites")) + { + for (int jj = 1; jj < g_dglos.last_sprite_created; jj++) + if (g_sprite[jj].active) g_sprite[jj].disabled = false; + return(0); + } + + + if (compare(ev[1], (char*)"sp_pseq")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].pseq); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_pframe")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].pframe); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_seq")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].seq); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"editor_type")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //Msg("Setting editor_type.."); + g_dglos.g_returnint = change_edit_char(g_nlist[0], g_nlist[1], &g_dglos.g_playerInfo.spmap[*pmap].type[g_nlist[0]]); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"editor_seq")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_edit(g_nlist[0], g_nlist[1], &g_dglos.g_playerInfo.spmap[*pmap].seq[g_nlist[0]]); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"editor_frame")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_edit_char(g_nlist[0], g_nlist[1], &g_dglos.g_playerInfo.spmap[*pmap].frame[g_nlist[0]]); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + + if (compare(ev[1], (char*)"sp_editor_num")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = g_sprite[g_nlist[0]].sp_index; + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_brain")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].brain); + if (g_nlist[1] == 13) + { + //a mouse brain was set... + g_dglo.SetViewOverride(DinkGlobals::VIEW_FULL); + + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_exp")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].exp); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"set_button")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + + g_dglos.g_playerInfo.button[g_nlist[0]] = g_nlist[1]; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_reverse")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].reverse); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_noclip")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].noclip); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_touch_damage")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].touch_damage); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_brain_parm")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].brain_parm); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"sp_brain_parm2")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].brain_parm2); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_follow")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].follow); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"set_smooth_follow")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if ( g_nlist[0] == 0 ) + { + g_dglos.smooth_follow = false; + } + else if ( g_nlist[0] == 1 ) + { + g_dglos.smooth_follow = true; + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_frame")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].frame); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_frame_delay")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].frame_delay); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"hurt")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //redink1 fix for freeze if hurt value is less than 0 + if (g_nlist[1] < 0) + return(0); + if (hurt_thing(g_nlist[0], g_nlist[1], 0) > 0) + random_blood(g_sprite[g_nlist[0]].x, g_sprite[g_nlist[0]].y-40, g_nlist[0]); + if (g_sprite[g_nlist[0]].nohit != 1) + if (g_sprite[g_nlist[0]].script != 0) + + if (locate(g_sprite[g_nlist[0]].script, "HIT")) + { + + if (g_scriptInstance[script]->sprite != 1000) + { + *penemy_sprite = g_scriptInstance[script]->sprite; + //redink1 addition of missle_source stuff + *pmissle_source = g_scriptInstance[script]->sprite; + } + + kill_returning_stuff(g_sprite[g_nlist[0]].script); + run_script(g_sprite[g_nlist[0]].script); + } + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_hard")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].hard); + if (g_sprite[g_nlist[0]].sp_index != 0) if (g_nlist[1] != -1) + { + + g_dglos.g_smallMap.sprite[g_sprite[g_nlist[0]].sp_index].hard = g_dglos.g_returnint; + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_move_nohard")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].move_nohard); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"sp_flying")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].flying); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + + + if (compare(ev[1], (char*)"sp_kill_wait")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_sprite[g_nlist[0]].wait = 0; + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + if (compare(ev[1], (char*)"sp_kill")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[0] < C_MAX_SPRITES_AT_ONCE) //SETH this fixes crash when killing milder + { + g_sprite[g_nlist[0]].kill = g_nlist[1]; + return(0); + } else + { + LogMsg("Aborting crash in sp_kill"); + } + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"screenlock")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if ( g_nlist[0] == 0 || g_nlist[0] == 1 ) + { + g_dglos.screenlock = g_nlist[0]; + } + } + //redink1 - set screenlock() to return the screenlock value + g_dglos.g_returnint = g_dglos.screenlock; + return(0); + } + + if (compare(ev[1], (char*)"stop_entire_game")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_stopEntireGame = g_nlist[0]; + + + /* + rtRect32 rcRect(0,0,C_DINK_SCREENSIZE_X,C_DINK_SCREENSIZE_Y); + int ddrval; + ddrval = lpDDSBackGround->BltFast( 0, 0, lpDDSBack, + &rcRect, DDBLTFAST_NOCOLORKEY); + */ + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"dink_can_walk_off_screen")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.walk_off_screen = g_nlist[0]; + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"push_active")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_pushingEnabled = g_nlist[0]; + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_x")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].x); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"count_item")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + for (int i = 1; i < 17; i++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active) + { + if (compare(g_dglos.g_playerInfo.g_itemData[i].name, slist[0])) g_dglos.g_returnint++; + } + + } + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"count_magic")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + for (int i = 1; i < 9; i++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active) + { + if (compare(g_dglos.g_playerInfo.g_MagicData[i].name, slist[0])) g_dglos.g_returnint++; + } + + } + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_mx")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].mx); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_move_x")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].mx); + return(0); + } + return(0); + } + + if (compare(ev[1], (char*)"sp_my")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].my); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_move_y")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite_noreturn(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].my); + return(0); + } + return(0); + } + + if (compare(ev[1], (char*)"scripts_used")) + { + h = &h[strlen(ev[1])]; + int m = 0; + for (int i = 1; i < C_MAX_SCRIPTS; i++) + if (g_scriptInstance[i] != NULL) m++; + g_dglos.g_returnint = m; +#ifdef _DEBUG +LogMsg("%d scripts used", g_dglos.g_returnint); +#endif + return(0); + } + + if (compare(ev[1], (char*)"sp_hitpoints")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].hitpoints); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_attack_hit_sound")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].attack_hit_sound); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_attack_hit_sound_speed")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].attack_hit_sound_speed); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_strength")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].strength); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_defense")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].defense); + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"init")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + figure_out(slist[0], 0); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_distance")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].distance); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_nohit")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].nohit); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"sp_notouch")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].notouch); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + if (compare(ev[1], (char*)"compare_weapon")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + if (*pcur_weapon == 0) + { + return(0); + } + + if (compare(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, slist[0])) + { + g_dglos.g_returnint = 1; + + } + return(0); + } + return(0); + } + + + if (compare(ev[1], (char*)"compare_magic")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + if (*pcur_magic == 0) + { + return(0); + } + + //redink1 fix so compare_magic works! + if (compare(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, slist[0])) + { + g_dglos.g_returnint = 1; + + } + return(0); + } + return(0); + } + + + if (compare(ev[1], (char*)"compare_sprite_script")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,2,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + + if (g_nlist[0] == 0) + { + LogMsg("Error: Can't compare sprite script for sprite 0!??!?!"); + return(0); + } + if (g_sprite[g_nlist[0]].active) + { + + if (g_sprite[g_nlist[0]].script == 0) + { + LogMsg("Compare sprite script says: Sprite %d has no script.",g_nlist[0]); + return(0); + } + if (compare(slist[1], g_scriptInstance[g_sprite[g_nlist[0]].script]->name)) + { + g_dglos.g_returnint = 1; + return(0); + } + + } else + { + LogMsg("Can't compare sprite script, sprite not active."); + } + return(0); + } + + return(0); + } + + if (compare(ev[1], (char*)"sp_y")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].y); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"sp_timing")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].timer); + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[1], (char*)"return;")) + { + if (debug_mode) LogMsg("Found return; statement"); + + if (g_scriptInstance[script]->proc_return != 0) + { + g_dglos.bKeepReturnInt = true; + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + return(2); + } + + + //redink1 - sets font color + if (compare(ev[1], (char*)"set_font_color")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,1,1,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (g_nlist[0] >= 1 && g_nlist[0] <= 15 && + g_nlist[1] >= 0 && g_nlist[1] <= 255 && + g_nlist[2] >= 0 && g_nlist[2] <= 255 && + g_nlist[3] >= 0 && g_nlist[3] <= 255) + { + g_dglos.font_colors[g_nlist[0]].red = g_nlist[1]; + g_dglos.font_colors[g_nlist[0]].green = g_nlist[2]; + g_dglos.font_colors[g_nlist[0]].blue = g_nlist[3]; + } + } + + strcpy(pLineIn, h); + return(0); + } + + //redink1 - clears the editor information, useful for save games and such + if (compare(ev[1], (char*)"clear_editor_info")) + { + h = &h[strlen(ev[1])]; + for (int i = 0; i < 769; i++) + { + for (int j = 0; j < 100; j++) + { + g_dglos.g_playerInfo.spmap[i].seq[j] = 0; + g_dglos.g_playerInfo.spmap[i].frame[j] = 0; + g_dglos.g_playerInfo.spmap[i].type[j] = 0; + g_dglos.g_playerInfo.spmap[i].last_time = 0; + } + } + g_dglos.g_returnint = 1; + return(0); + } + + //redink1 - returns the number of variables used + if (compare(ev[1], (char*)"var_used")) + { + h = &h[strlen(ev[1])]; + int m = 0; + for (int i = 1; i < max_vars; i++) + if (g_dglos.g_playerInfo.var[i].active == true) + m++; + g_dglos.g_returnint = m; + return(0); + } + + //redink1 added this function to load a new map/dink.dat + if (compare(ev[1], (char*)"load_map")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,2,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + strcpy(g_dglos.current_map,slist[0]); + strcpy(g_dglos.current_dat,slist[1]); + load_info(); + } + + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function to load a pallete from any bmp + if (compare(ev[1], (char*)"load_palette")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + assert(!"We don't support this"); + } + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[1], "load_tile")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + assert(!"Unsupported"); + LogMsg("Command load_tile unsupported"); + } + + strcpy(pLineIn, h); + return(0); + } + + + //redink1 added this function to change the save game 'info' + if (compare(ev[1], (char*)"set_save_game_info")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + strcpy(g_dglos.save_game_info,slist[0]); + } + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function to show the item screen + if (compare(ev[1], (char*)"show_inventory")) + { + h = &h[strlen(ev[1])]; + g_itemScreenActive = true; + if (!IsLargeScreen()) + { + g_dglo.SetViewOverride(DinkGlobals::VIEW_ZOOMED); + } + + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function,, and took it away. + /*if (compare(ev[1], (char*)"get_compatibility")) + { + returnint = 0; + + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + if (compare(slist[0],"get_compatibility")) + { + if (nlist[1] <= 1) + { + returnint = 1; + } + } + } + strcpy(s, h); + return(0); + }*/ + + //redink1 added this function + if (compare(ev[1], (char*)"get_time_game")) + { + h = &h[strlen(ev[1])]; + + + g_dglos.g_returnint = (GetBaseApp()->GetGameTick()-g_dglos.time_start) / (1000*60); + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"get_time_real")) + { + h = &h[strlen(ev[1])]; + + h = &h[strlen(ev[1])]; + char mytime[5]; + time_t ct; + struct tm *time_now; + time(&ct); + time_now = localtime(&ct); + strftime(mytime,5,"%M",time_now); + g_dglos.g_returnint = atoi(mytime); + strftime(mytime,5,"%H",time_now); + g_dglos.g_returnint += 60*atoi(mytime); + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"get_date_year")) + { + h = &h[strlen(ev[1])]; + char mytime[5]; + time_t ct; + struct tm *time_now; + time(&ct); + time_now = localtime(&ct); + strftime(mytime,5,"%Y",time_now); + g_dglos.g_returnint = atoi(mytime); + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"get_date_month")) + { + h = &h[strlen(ev[1])]; + char mytime[5]; + time_t ct; + struct tm *time_now; + time(&ct); + time_now = localtime(&ct); + strftime(mytime,5,"%m",time_now); + g_dglos.g_returnint = atoi(mytime); + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"get_date_day")) + { + h = &h[strlen(ev[1])]; + char mytime[5]; + time_t ct; + struct tm *time_now; + time(&ct); + time_now = localtime(&ct); + strftime(mytime,5,"%d",time_now); + g_dglos.g_returnint = atoi(mytime); + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"math_abs")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = abs(g_nlist[0]); + } + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + /*if (compare(ev[1], (char*)"math_sin")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + returnint = sin((double)nlist[0]); + } + strcpy(s, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"math_cos")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + returnint = cos((double)nlist[0]); + } + strcpy(s, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"math_tan")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + returnint = tan((double)nlist[0]); + } + strcpy(s, h); + return(0); + }*/ + + //redink1 added this function + if (compare(ev[1], (char*)"math_sqrt")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = sqrt((double)abs(g_nlist[0])); + } + strcpy(pLineIn, h); + return(0); + } + + //redink1 added this function + if (compare(ev[1], (char*)"math_mod")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = (g_nlist[0] % g_nlist[1]); + } + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[1], (char*)"breakpoint")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {0,0,0,0,0,0,0,0,0,0}; + assert(!"Breakpoint!"); + return(0); + } + //redink1 + if (compare(ev[1], (char*)"sp_custom")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,1,1,0,0,0,0,0,0,0}; + if ( get_parms(ev[1], script, h, p) && g_sprite[g_nlist[1]].active == true ) + { + if ( g_nlist[1] < 1 || g_sprite[g_nlist[1]].active == false ) + { + g_dglos.g_returnint = -1; + } + else + { + // If key doesn't exist, create it. + if ( g_customSpriteMap[g_nlist[1]]->find( slist[0] ) == g_customSpriteMap[g_nlist[1]]->end() ) + { + g_customSpriteMap[g_nlist[1]]->insert( std::make_pair( slist[0], 0 ) ); + } + + // Set the value + if ( g_nlist[2] != -1 ) + { + g_customSpriteMap[g_nlist[1]]->erase( slist[0] ); + g_customSpriteMap[g_nlist[1]]->insert( std::make_pair( slist[0], g_nlist[2] ) ); + } + + g_dglos.g_returnint = g_customSpriteMap[g_nlist[1]]->find( slist[0] )->second; + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 + if (compare(ev[1], (char*)"sp_blood_seq")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].bloodseq); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].bloodseq; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 + if (compare(ev[1], (char*)"sp_blood_num")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].bloodnum); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].bloodseq; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 added to get index of specified item + if (compare(ev[1], (char*)"get_item")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + for (int i = 1; i < 17; i++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active) + { + if (compare(g_dglos.g_playerInfo.g_itemData[i].name, slist[0])) + { + g_dglos.g_returnint = i; + break; + } + } + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 added to get index of specified magic spell + if (compare(ev[1], (char*)"get_magic")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,0,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + g_dglos.g_returnint = 0; + for (int i = 1; i < 9; i++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active) + { + if (compare(g_dglos.g_playerInfo.g_MagicData[i].name, slist[0])) + { + g_dglos.g_returnint = i; + break; + } + } + } + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 clip stuff + if (compare(ev[1], (char*)"sp_clip_left")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].alt.left); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].alt.left; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 clip stuff + if (compare(ev[1], (char*)"sp_clip_top")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].alt.top); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].alt.top; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 clip stuff + if (compare(ev[1], (char*)"sp_clip_right")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].alt.right); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].alt.right; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 clip stuff + if (compare(ev[1], (char*)"sp_clip_bottom")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + change_sprite(g_nlist[0], g_nlist[1], &g_sprite[g_nlist[0]].alt.bottom); + + g_dglos.g_returnint = g_sprite[g_nlist[0]].alt.bottom; + + return(0); + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 added so developers can change or see what tile is at any given position + if (compare(ev[1], (char*)"map_tile")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //Yeah... they can only modify valid tiles + if (g_nlist[0] > 0 && g_nlist[0] <= 96) + { + //Only change the value if it is greater than 0... + if (g_nlist[1] > 0) + { + g_dglos.g_smallMap.t[g_nlist[0]-1].num = g_nlist[1]; + } + g_dglos.g_returnint = g_dglos.g_smallMap.t[g_nlist[0]-1].num; + return(0); + } + } + g_dglos.g_returnint = -1; + return(0); + } + + //redink1 added so a developer can retrieve/modify a hard tile + if (compare(ev[1], (char*)"map_hard_tile")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {1,1,0,0,0,0,0,0,0,0}; + if (get_parms(ev[1], script, h, p)) + { + //Yeah... they can only modify valid tiles + if (g_nlist[0] > 0 && g_nlist[0] <= 96) + { + //Only change the value if it is greater than 0... + if (g_nlist[1] > 0) + { + g_dglos.g_smallMap.t[g_nlist[0]-1].althard = g_nlist[1]; + } + g_dglos.g_returnint = g_dglos.g_smallMap.t[g_nlist[0]-1].althard; + return(0); + } + } + g_dglos.g_returnint = -1; + return(0); + } + + + if (compare(ev[2], "+=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[2]; + strip_beginning_spaces(h); + var_equals(ev[1], ev[3], '+', script, h); + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[2], "*=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[2]; + strip_beginning_spaces(h); + var_equals(ev[1], ev[3], '*', script, h); + strcpy(pLineIn, h); + return(0); + } + + + + if (compare(ev[2], "-=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[2]; + strip_beginning_spaces(h); + + var_equals(ev[1], ev[3], '-', script, h); + + strcpy(pLineIn, h); + return(0); + } + + + if (compare(ev[2], "/") || compare(ev[2], "/=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[1]; + strip_beginning_spaces(h); + + var_equals(ev[1], ev[3], '/', script, h); + + strcpy(pLineIn, h); + return(0); + } + + if (compare(ev[2], "*") || compare(ev[2], "*=")) + { + h = &h[strlen(ev[1])]; + strip_beginning_spaces(h); + h = &h[1]; + strip_beginning_spaces(h); + + var_equals(ev[1], ev[3], '*', script, h); + + strcpy(pLineIn, h); + return(0); + } + if (compare(ev[1], (char*)"external")) + { + h = &h[strlen(ev[1])]; + int32 p[20] = {2,2,1,1,1,1,1,1,1,1}; + memset(slist, 0, 10 * 200); + get_parms(ev[1], script, h, p); + if (slist[0][0] && slist[1][0]) + { + int myscript1 = load_script(slist[0],g_scriptInstance[script]->sprite, false); + if (myscript1 == 0) + { + LogMsg("Error: Couldn't find %s.c (for procedure %s)", slist[0], slist[1]); + return(0); + } + g_scriptInstance[myscript1]->arg1 = g_nlist[2]; + g_scriptInstance[myscript1]->arg2 = g_nlist[3]; + g_scriptInstance[myscript1]->arg3 = g_nlist[4]; + g_scriptInstance[myscript1]->arg4 = g_nlist[5]; + g_scriptInstance[myscript1]->arg5 = g_nlist[6]; + g_scriptInstance[myscript1]->arg6 = g_nlist[7]; + g_scriptInstance[myscript1]->arg7 = g_nlist[8]; + g_scriptInstance[myscript1]->arg8 = g_nlist[9]; + if (locate( myscript1, slist[1])) + { + g_scriptInstance[myscript1]->proc_return = script; + run_script(myscript1); + + return(2); + } else + { + LogMsg("Error: Couldn't find procedure %s in %s.", slist[1], slist[0]); + kill_script(myscript1); + } + } + strcpy(pLineIn, h); + return(0); + } + + + if (strchr(h, '(') != NULL) + { + + //lets attempt to run a procedure + + int myscript = load_script(g_scriptInstance[script]->name, g_scriptInstance[script]->sprite, false); + + h = &h[strlen(ev[1])]; + + int32 p[20] = {1,1,1,1,1,1,1,1,1,1}; + get_parms(ev[1], script, h, p); + + if (locate( myscript, ev[1])) + { + g_scriptInstance[myscript]->arg1 = g_nlist[0]; + g_scriptInstance[myscript]->arg2 = g_nlist[1]; + g_scriptInstance[myscript]->arg3 = g_nlist[2]; + g_scriptInstance[myscript]->arg4 = g_nlist[3]; + g_scriptInstance[myscript]->arg5 = g_nlist[4]; + g_scriptInstance[myscript]->arg6 = g_nlist[5]; + g_scriptInstance[myscript]->arg7 = g_nlist[6]; + g_scriptInstance[myscript]->arg8 = g_nlist[7]; + g_scriptInstance[myscript]->arg9 = g_nlist[8]; + + g_scriptInstance[myscript]->proc_return = script; + run_script(myscript); + return(2); + } else + { + for (int i = 0; strlen(g_dglos.g_playerInfo.func[i].func) > 0 && i < 100; i++) + { + if (compare(g_dglos.g_playerInfo.func[i].func, ev[1])) + { + myscript = load_script(g_dglos.g_playerInfo.func[i].file, g_scriptInstance[script]->sprite, false); + g_scriptInstance[myscript]->arg1 = g_nlist[0]; + g_scriptInstance[myscript]->arg2 = g_nlist[1]; + g_scriptInstance[myscript]->arg3 = g_nlist[2]; + g_scriptInstance[myscript]->arg4 = g_nlist[3]; + g_scriptInstance[myscript]->arg5 = g_nlist[4]; + g_scriptInstance[myscript]->arg6 = g_nlist[5]; + g_scriptInstance[myscript]->arg7 = g_nlist[6]; + g_scriptInstance[myscript]->arg8 = g_nlist[7]; + g_scriptInstance[myscript]->arg9 = g_nlist[8]; + if (locate(myscript, ev[1])) + { + g_scriptInstance[myscript]->proc_return = script; + run_script(myscript); + return(2); + } + break; + } + } + LogMsg("ERROR: Procedure void %s( void ); not found in script %s. (word 2 was %s) ", line, + ev[2], g_scriptInstance[myscript]->name); + kill_script(myscript); + } + + return(0); + + } + + LogMsg("MERROR: \"%s\" unknown in %s, offset %d.",ev[1], g_scriptInstance[script]->name,g_scriptInstance[script]->current); + + } + +bad: + strcpy(pLineIn, h); + return(0); + +good: + strcpy(pLineIn, h); + //s = h + //Msg("ok, continuing with running %s..",s); + return(1); +} + + +void run_script (int script) +{ + int result; + char line[200]; + if (g_dglos.bKeepReturnInt) + { + g_dglos.bKeepReturnInt = false; + } + else + { + g_dglos.g_returnint = 0; + } + returnstring[0] = 0; + if (g_scriptInstance[script] != NULL) + { + if (debug_mode) + LogMsg("Script %s is entered at offset %d.", g_scriptInstance[script]->name, g_scriptInstance[script]->current); + } else + { + LogMsg("Error: Tried to run a script that doesn't exist in memory. Nice work."); + } + + while(read_next_line(script, line)) + { + while(1) + { + + if (ScriptEOF(script)) + { + if (g_scriptInstance[script]->proc_return != 0) + { + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + return; + } + + strip_beginning_spaces(line); + if (compare(line, "\n")) break; + + + result = process_line(script,line, false); + if (result == 3) + { +redo: + if (!read_next_line(script, line)) + { + //we've reached the end of the script + return; + } +crappa: + strip_beginning_spaces(line); + if (compare(line, "\n")) goto redo; + if (compare(line, "\\\\")) goto redo; + // Msg("processing %s knowing we are going to skip it...", line); + result = process_line(script,line, true); + } + + if (result == 5) goto crappa; + + if (result == 3) + { + + goto redo; + } + + if (result == 2) + { + if (debug_mode) LogMsg("giving script the boot"); + //quit script + return; + } + if (result == 0) break; + + if (result == 4) + { + // Msg("Was sent %s, length %d", line, strlen(line)); + + if (strlen(line) < 2) + { +redo2: + if (!read_next_line(script, line)) + { + //script is actualyl empty + break; + } + strip_beginning_spaces(line); + //Msg("Comparing to %s.", line); + if (compare(line, "\n")) goto redo2; + if (compare(line, "\\\\")) goto redo2; + } + result = process_line(script,line, true); + } + + + if (result == 2) + { + if (debug_mode) LogMsg("giving script the boot"); + //quit script + return; + } + if (result == 0) break; + } + } + + if (g_scriptInstance[script] != NULL) + { + if (g_scriptInstance[script]->proc_return != 0) + { + run_script(g_scriptInstance[script]->proc_return); + kill_script(script); + } + } +} + + +void process_callbacks(void) +{ + uint32 thist = (int)GetBaseApp()->GetGameTick(); + + for (int i = 1; i < C_MAX_SCRIPTS; i++) + { + if (g_scriptInstance[i] != NULL) + { + if (g_scriptInstance[i]->sprite > 0) if (g_scriptInstance[i]->sprite != 1000) if (g_sprite[g_scriptInstance[i]->sprite].active == false) + { + //kill this script, owner is dead + //if (debug_mode) + LogMsg("Killing script Set%s, owner sprite %d is dead.",g_scriptInstance[i]->name, g_scriptInstance[i]->sprite); + kill_script(i); + } + + } + } + + + for (int k = 1; k < C_MAX_SCRIPT_CALLBACKS; k++) + { + if (g_dglos.g_scriptCallback[k].active) + { + + if (g_dglos.g_scriptCallback[k].owner > 0) if (g_scriptInstance[g_dglos.g_scriptCallback[k].owner] == NULL) + { + //kill this process, it's owner sprite is 'effin dead. + if (debug_mode) LogMsg("Killed callback %s because script %d is dead.", + k, g_dglos.g_scriptCallback[k].owner); + g_dglos.g_scriptCallback[k].active = false; + + } else + { + + if (g_dglos.g_scriptCallback[k].timer == 0) + { + //set timer + + if (g_dglos.g_scriptCallback[k].max > 0) + g_dglos.g_scriptCallback[k].timer = thist + (rand() % g_dglos.g_scriptCallback[k].max)+g_dglos.g_scriptCallback[k].min; + else g_dglos.g_scriptCallback[k].timer = thist + g_dglos.g_scriptCallback[k].min; + + } else + { + + if (g_dglos.g_scriptCallback[k].timer < thist) + { + g_dglos.g_scriptCallback[k].timer = 0; + //g_dglos.g_scriptCallback[k].active = false; //SETH Adding this fixes one prob, but breaks others? + if (compare(g_dglos.g_scriptCallback[k].name, "")) + { + //callback defined no proc name, so lets assume they want to start the script where it + //left off + //kill this callback + g_dglos.g_scriptCallback[k].active = false; + run_script(g_dglos.g_scriptCallback[k].owner); + if (debug_mode) LogMsg("Called script %d with callback %d.", g_dglos.g_scriptCallback[k].owner, k); + + } else + { + + if (debug_mode) LogMsg("Called proc %s with callback %d.", g_dglos.g_scriptCallback[k].name, k); + + //callback defined a proc name + if (locate(g_dglos.g_scriptCallback[k].owner,g_dglos.g_scriptCallback[k].name)) + { + + //found proc, lets run it + run_script(g_dglos.g_scriptCallback[k].owner); + + } + + } + + } + + } + } + } + } + +} + + +void init_scripts(void) +{ + for (int k = 1; k < C_MAX_SCRIPTS; k++) + { + if (g_scriptInstance[k] != NULL && g_scriptInstance[k]->sprite != 0 && g_scriptInstance[k]->sprite < 300 && g_sprite[g_scriptInstance[k]->sprite].active ) + { + if (locate(k,"main")) + { + if (debug_mode) LogMsg("Screendraw: running main of script %s..", g_scriptInstance[k]->name); + run_script(k); + } + } + } + +} + +//redink1 added for font colors +void init_font_colors(void) +{ + //Light Magenta + g_dglos.font_colors[1].red = 255; + g_dglos.font_colors[1].green = 198; + g_dglos.font_colors[1].blue = 255; + + //Dark Green + g_dglos.font_colors[2].red = 131; + g_dglos.font_colors[2].green = 181; + g_dglos.font_colors[2].blue = 74; + + //Bold Cyan + g_dglos.font_colors[3].red = 99; + g_dglos.font_colors[3].green = 242; + g_dglos.font_colors[3].blue = 247; + + //Orange + g_dglos.font_colors[4].red = 255; + g_dglos.font_colors[4].green = 156; + g_dglos.font_colors[4].blue = 74; + + //Magenta + g_dglos.font_colors[5].red = 222; + g_dglos.font_colors[5].green = 173; + g_dglos.font_colors[5].blue = 255; + + //Brown Orange + g_dglos.font_colors[6].red = 244; + g_dglos.font_colors[6].green = 188; + g_dglos.font_colors[6].blue = 73; + + //Light Gray + g_dglos.font_colors[7].red = 173; + g_dglos.font_colors[7].green = 173; + g_dglos.font_colors[7].blue = 173; + + //Dark Gray + g_dglos.font_colors[8].red = 85; + g_dglos.font_colors[8].green = 85; + g_dglos.font_colors[8].blue = 85; + + //Sky Blue + g_dglos.font_colors[9].red = 148; + g_dglos.font_colors[9].green = 198; + g_dglos.font_colors[9].blue = 255; + + //Bright Green + g_dglos.font_colors[10].red = 0; + g_dglos.font_colors[10].green = 255; + g_dglos.font_colors[10].blue = 0; + + //Yellow + g_dglos.font_colors[11].red = 255; + g_dglos.font_colors[11].green = 255; + g_dglos.font_colors[11].blue = 2; + + //Yellow + g_dglos.font_colors[12].red = 255; + g_dglos.font_colors[12].green = 255; + g_dglos.font_colors[12].blue = 2; + + //Hot Pink + g_dglos.font_colors[13].red = 255; + g_dglos.font_colors[13].green = 132; + g_dglos.font_colors[13].blue = 132; + + //Yellow + g_dglos.font_colors[14].red = 255; + g_dglos.font_colors[14].green = 255; + g_dglos.font_colors[14].blue = 2; + + //White + g_dglos.font_colors[15].red = 255; + g_dglos.font_colors[15].green = 255; + g_dglos.font_colors[15].blue = 255; +} + +void text_draw(int h) +{ + + char crap[200]; + char *cr; + rtRect32 rcRect; + int color = 15; + + int maxX = 620; + int minX = 0; + + if (g_dglo.m_curView == DinkGlobals::VIEW_ZOOMED) + { + //maxX = 600; + minX = 20; + } + if (g_sprite[h].damage == -1) + { + //redink1 fix for : and '%deee bugs? + strcpy(crap, g_sprite[h].text); + //sprintf(crap, "%s", spr[h].text); + cr = &crap[0]; + color = 14; + while( cr[0] == '`') + { + //color code at top + if (cr[1] == '#') color = 13; + if (cr[1] == '1') color = 1; + if (cr[1] == '2') color = 2; + if (cr[1] == '3') color = 3; + if (cr[1] == '5') color = 5; + if (cr[1] == '6') color = 6; + if (cr[1] == '7') color = 7; + if (cr[1] == '8') color = 8; + if (cr[1] == '9') color = 9; + if (cr[1] == '0') color = 10; + if (cr[1] == '$') color = 14; + if (cr[1] == '%') color = 15; + //redink1 support for additional colors + if (cr[1] == '@') color = 12; + if (cr[1] == '!') color = 11; + + if (cr[1] == '4') color = 4; + cr = &cr[2]; + } + + //Msg("Final is %s.",cr); + if (g_sprite[h].owner == 1000) + { + rcRect = rtRect32 (g_sprite[h].x,g_sprite[h].y,g_sprite[h].x+620,g_sprite[h].y+400); + } else + { + + rcRect = rtRect32 (g_sprite[h].x,g_sprite[h].y,g_sprite[h].x+150,g_sprite[h].y+150); + + + if (g_sprite[h].x+150 > maxX) + OffsetRect(&rcRect, ((g_sprite[h].x+150)-maxX) - (((g_sprite[h].x+150)-maxX) * 2), 0); + + + if (rcRect.left < minX && rcRect.left >= 0) + { + OffsetRect(&rcRect, minX - rcRect.left, 0); + } + } + + } else + { + + sprintf(crap, "%d", g_sprite[h].damage); + cr = &crap[0]; + if (g_sprite[h].brain_parm == 5000) color = 14; + + + if (g_sprite[h].y < minX) g_sprite[h].y = minX; + rcRect = rtRect32 (g_sprite[h].x,g_sprite[h].y,g_sprite[h].x+50 ,g_sprite[h].y+50); + } + + +/* + if (g_dglos.bFadedDown || g_dglos.process_downcycle) + color = 15; + */ + + uint32 rgbColor = MAKE_RGBA(g_dglos.font_colors[color].red, g_dglos.font_colors[color].green, g_dglos.font_colors[color].blue, 255); + + uint32 bgColor = MAKE_RGBA(0,0,0,100); + + rtRect rTemp(rcRect); + + // SetTextColor(hdc,RGB(8,14,21)); + if (g_sprite[h].owner == 1200) + { + + + + GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, cr, false, false, rgbColor, g_dglo.m_fontSize, false, bgColor); + } else + { + if ( (cr[0] == ' ' && cr[1] == 0) || (cr[0] == ' ' && cr[1] == ' ' && cr[2] == 0) || (cr[0] == ' ' && cr[1] == ' ' && cr[2] == ' ' && cr[3] == 0) ) + { + //skip it, it's just blank, otherwise it will draw the bg which looks dumb + } else + { + GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, cr, true, false, rgbColor, g_dglo.m_fontSize, false , bgColor); + } + } + + OffsetRect(&rTemp,0,1); + +} + +void get_last_sprite(void) +{ + + for (int i = C_MAX_SPRITES_AT_ONCE - 1; i > 2; i--) + { + + if (g_sprite[i].active) + { + g_dglos.last_sprite_created = i; + // Msg("last sprite created is %d.", i); + return; + } + } +} + +bool DestroySound( void ) +{ +/* + uint32 idxKill; + + for( idxKill = 0; idxKill < max_sounds; idxKill++ ) + { + SoundDestroyEffect( idxKill ); + } + + return true; + */ + return true; + +} /* DestroySound */ + +/* +* SoundDestroyEffect +* +* Frees up resources associated with a sound effect +*/ +bool SoundDestroyEffect( int sound ) +{ +/* + if(g_soundInfo[sound].sound) + { + delete g_soundInfo[sound].sound; + g_soundInfo[sound].sound = NULL; + } + return true; +*/ + + return true; +} + +#ifdef C_DINK_KEYBOARD_INPUT + +short GetKeyboard(int key) +{ + // returns 0 if the key has been depressed, else returns 1 and sets key to code recd. + return (GetAsyncKeyState(key) & 0x8000); +} + +BOOL keypressed( void ) +{ + for (int x=0; x<256; x++) + { + if (GetKeyboard(x) > 0) + { + return(TRUE); + } + } + return(FALSE); +} + +#endif + +void check_joystick(void) +{ + + for (int e2=1; e2 <=10; e2++) + { + sjoy.joybit[e2] = false; + } + + sjoy.right = false; + sjoy.left = false; + sjoy.up = false; + sjoy.down = false; + + sjoy.rightd = false; + sjoy.leftd = false; + sjoy.upd = false; + sjoy.downd = false; + + for (int i=0; i < 7; i++) + { + if (g_dglo.m_dirInput[DINK_INPUT_BUTTON1+i]) sjoy.joybit[1+i] = true; + } + + for (int x5=1; x5 <=10; x5++) sjoy.button[x5] = false; + + for (int x=1; x <=10; x++) + { + if (sjoy.joybit[x]) + { + if (sjoy.letgo[x] == true) + { + sjoy.button[x] = true; + sjoy.letgo[x] = false; + } + } + } + + if (g_dglo.m_dirInput[DINK_INPUT_LEFT]) sjoy.left = true; + if (g_dglo.m_dirInput[DINK_INPUT_RIGHT]) sjoy.right = true; + if (g_dglo.m_dirInput[DINK_INPUT_UP]) sjoy.up = true; + if (g_dglo.m_dirInput[DINK_INPUT_DOWN]) sjoy.down = true; + + + + for (int x2=1; x2 <=10; x2++) + { + if (sjoy.joybit[x2]) sjoy.letgo[x2] = false; else sjoy.letgo[x2] = true; + } + + if (sjoy.right) if (sjoy.rightold == true) + { + sjoy.rightd = true; + sjoy.rightold = false; + } + + if (sjoy.right) sjoy.rightold = false; else sjoy.rightold = true; + + + if (sjoy.left) if (sjoy.leftold == true) + { + sjoy.leftd = true; + sjoy.leftold = false; + } + + if (sjoy.left) sjoy.leftold = false; else sjoy.leftold = true; + + + if (sjoy.up) if (sjoy.upold == true) + { + sjoy.upd = true; + sjoy.upold = false; + } + + if (sjoy.up) sjoy.upold = false; else sjoy.upold = true; + + + if (sjoy.down) if (sjoy.downold == true) + { + sjoy.downd = true; + sjoy.downold = false; + } + + if (sjoy.down) sjoy.downold = false; else sjoy.downold = true; + + + if (g_dglos.g_wait_for_button.active) + { + + //check for dirs + + if (sjoy.rightd) g_dglos.g_wait_for_button.button = 16; + if (sjoy.leftd) g_dglos.g_wait_for_button.button = 14; + if (sjoy.upd) g_dglos.g_wait_for_button.button = 18; + if (sjoy.downd) g_dglos.g_wait_for_button.button = 12; + + sjoy.rightd = false; + sjoy.downd = false; + sjoy.upd = false; + sjoy.leftd = false; + + //check buttons + for (int ll=1; ll <= 10; ll++) + { + if (sjoy.button[ll]) + { + //button was pressed + g_dglos.g_wait_for_button.button = ll; + + } + sjoy.button[ll] = false; + + } + + if (g_dglos.g_wait_for_button.button != 0) + { + *presult = g_dglos.g_wait_for_button.button; + g_dglos.g_wait_for_button.active = false; + run_script(g_dglos.g_wait_for_button.script); + } + + } + for (int i=0; i < DINK_INPUT_COUNT; i++) + { + if (g_dglo.m_dirInputFinished[i]) + { + g_dglo.m_dirInput[i] = false; + g_dglo.m_dirInputFinished[i] = false; + + } + } + + +} + + +// ********* CHECK TO SEE IF THIS CORD IS ON A HARD SPOT ********* +bool not_in_this_base(int seq, int base) +{ + int realbase = (seq / 10) * 10; + + if (realbase != base) + { + return(true); + } else + { + return(false); + } +} + +bool in_this_base(int seq, int base) +{ + + int realbase = (seq / 10) * 10; + if (realbase == base) + { + // Msg("TRUE - Ok, realbase is %d, compared to the base, which is %d.", realbase, base); + return(true); + } + else + { + // Msg("FALSE - Ok, realbase is %d, compared to the base, which is %d.", realbase, base); + return(false); + } +} + + +void automove (int j) +{ + char kindx,kindy; + int speedx = 0; + int speedy = 0; + + if (g_sprite[j].mx != 0) + { + if (g_sprite[j].mx < 0) + kindx = '-'; else kindx = '+'; + if (kindx == '-') speedx = (g_sprite[j].mx - (g_sprite[j].mx * 2)); else + speedx = g_sprite[j].mx; + } else kindx = '0'; + + if (g_sprite[j].my != 0) + { + if (g_sprite[j].my < 0) + kindy = '-'; else kindy = '+'; + if (kindy == '-') speedy = (g_sprite[j].my - (g_sprite[j].my * 2)); else + speedy = g_sprite[j].my; + + } else kindy = '0'; + + int speed = speedx; + if (speedy > speedx) speed = speedy; + if (speed > 0) + move(j,speed,kindx,kindy); + //move(j, 1, '+','+'); + +} + + +int autoreverse(int j) +{ + //Msg("reversing die %d",spr[j].dir); + int r = ((rand() % 2)+1); + if ( (g_sprite[j].dir == 1) || (g_sprite[j].dir == 2) ) + { + if (r == 1) + return(8); + if (r == 2) + return(6); + + } + + if ( (g_sprite[j].dir == 3) || (g_sprite[j].dir == 6) ) + { + if (r == 1) + return(2); + if (r == 2) + + return(4); + + } + + if ( (g_sprite[j].dir == 9) || (g_sprite[j].dir == 8) ) + { + if (r == 1) + return(2); + if (r == 2) + + return(6); + + + } + + if ( (g_sprite[j].dir == 7) || (g_sprite[j].dir == 4) ) + { + if (r == 1) + return(8); + if (r == 2) + return(6); + + } + + return(0); +} + + +int autoreverse_diag(int j) +{ + if (g_sprite[j].dir == 0) g_sprite[j].dir = 7; + int r = ((rand() % 2)+1); + + if ( (g_sprite[j].dir == 1) || (g_sprite[j].dir == 3) ) + { + + if (r == 1) + return(9); + if (r == 2) + return(7); + } + + if ( (g_sprite[j].dir == 3) || (g_sprite[j].dir == 6) ) + { + if (r == 1) + return(7); + if (r == 2) + return(1); + + } + + if ( (g_sprite[j].dir == 9) || (g_sprite[j].dir == 8) ) + { + if (r == 1) + return(1); + if (r == 2) + return(7); + } + + if ( (g_sprite[j].dir == 7) || (g_sprite[j].dir == 4) ) + { + if (r == 1) + return(3); + if (r == 2) + return(9); + + } + +#ifdef _DEBUG + LogMsg("Auto Reverse Diag was sent a dir %d sprite, base %d walk.",g_sprite[j].dir, g_sprite[j].base_walk); +#endif + return(0); +} + +void draw_damage(int h) +{ + + int crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,8,0,0); + + g_sprite[crap2].y -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].yoffset; + g_sprite[crap2].x -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].xoffset; + g_sprite[crap2].y -= g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].box.bottom / 3; + g_sprite[crap2].x += g_dglos.g_picInfo[g_dglos.g_seq[g_sprite[h].pseq].frame[g_sprite[h].pframe]].box.right / 5; + + g_sprite[crap2].speed = 1; + g_sprite[crap2].hard = 1; + g_sprite[crap2].brain_parm = h; + g_sprite[crap2].my = -1; + g_sprite[crap2].kill = 1000; + g_sprite[crap2].dir = 8; + g_sprite[crap2].damage = g_sprite[h].damage; +} + + +void add_kill_sprite(int h) +{ + if ( (g_sprite[h].dir > 9) || (g_sprite[h].dir < 1) ) + { + LogMsg("Error: Changing sprites dir from %d (!?) to 3.", g_sprite[h].dir); + g_sprite[h].dir = 3; + } + + int dir = g_sprite[h].dir; + int base = g_sprite[h].base_die; + + //Msg("Base die is %d", base); + if (base == -1) + { + + if (g_dglos.g_seq[g_sprite[h].base_walk+5].active != 0) + { + add_exp(g_sprite[h].exp, h); + + int crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,5,g_sprite[h].base_walk +5,1); + g_sprite[crap2].speed = 0; + g_sprite[crap2].seq = g_sprite[h].base_walk + 5; + //redink1 added this so corpses are the same size + g_sprite[crap2].size = g_sprite[h].size; + return; + } else + { + dir = 0; + base = 164; + } + } + + + if (g_dglos.g_seq[base+dir].active == false) + { + + if (dir == 1) dir = 9; + else if (dir == 3) dir = 7; + else if (dir == 7) dir = 3; + else if (dir == 9) dir = 1; + + else if (dir == 4) dir = 6; + else if (dir == 6) dir = 4; + else if (dir == 8) dir = 2; + else if (dir == 2) dir = 8; + } + + if (g_dglos.g_seq[base+dir].active == false) + { + LogMsg("Can't make a death sprite for dir %d!", base+dir); + } + + int crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,5,base +dir,1); + g_sprite[crap2].speed = 0; + g_sprite[crap2].base_walk = 0; + g_sprite[crap2].seq = base + dir; + + if (base == 164) g_sprite[crap2].brain = 7; + + g_sprite[crap2].size = g_sprite[h].size; + + add_exp(g_sprite[h].exp, h); +} + +void done_moving(int h) +{ + g_sprite[h].move_active = false; + g_sprite[h].move_nohard = false; + + if (g_sprite[h].move_script > 0) + { + // Msg("mover running script %d..", spr[h].move_script); + run_script(g_sprite[h].move_script); + } +} + +int get_distance_and_dir(int h, int h1, int *dir) +{ + if ( g_dglos.smooth_follow ) + { + unsigned int x_diff( abs( g_sprite[h].x - g_sprite[h1].x ) ); + unsigned int y_diff( abs( g_sprite[h].y - g_sprite[h1].y ) ); + if ( g_sprite[h].x < g_sprite[h1].x ) + { + if ( g_sprite[h].y < g_sprite[h1].y ) + { + // 6, 3, 2 + if ( y_diff * 4 < x_diff ) + { + *dir = 6; + } + else if ( x_diff * 4 < y_diff ) + { + *dir = 2; + } + else + { + *dir = 3; + } + } + else if ( g_sprite[h].y > g_sprite[h1].y ) + { + // 4, 9, 8 + if ( y_diff * 4 < x_diff ) + { + *dir = 6; + } + else if ( x_diff * 4 < y_diff ) + { + *dir = 8; + } + else + { + *dir = 9; + } + } + else + { + *dir = 6; + } + } + else if ( g_sprite[h].x > g_sprite[h1].x ) + { + if ( g_sprite[h].y < g_sprite[h1].y ) + { + // 4, 1, 2 + if ( y_diff * 4 < x_diff ) + { + *dir = 4; + } + else if ( x_diff * 4 < y_diff ) + { + *dir = 2; + } + else + { + *dir = 1; + } + } + else if ( g_sprite[h].y > g_sprite[h1].y ) + { + // 4, 7, 8 + if ( y_diff * 4 < x_diff ) + { + *dir = 4; + } + else if ( x_diff * 4 < y_diff ) + { + *dir = 8; + } + else + { + *dir = 7; + } + } + else + { + *dir = 4; + } + } + else + { + if ( g_sprite[h].y < g_sprite[h1].y ) + { + *dir = 2; + } + else if ( g_sprite[h].y > g_sprite[h1].y ) + { + *dir = 8; + } + } + return max( x_diff, y_diff ); + } + + int distancex = 5000; + int distancey = 5000; + int dirx = *dir; + int diry = *dir; + if (g_sprite[h].x > g_sprite[h1].x) if ((g_sprite[h].x - g_sprite[h1].x) < distancex) + { + distancex = (g_sprite[h].x - g_sprite[h1].x); + dirx = 4; + } + + if (g_sprite[h].x <= g_sprite[h1].x) if ((g_sprite[h1].x - g_sprite[h].x) < distancex) + { + distancex = (g_sprite[h1].x - g_sprite[h].x); + dirx = 6; + } + if (g_sprite[h].y > g_sprite[h1].y) if ((g_sprite[h].y - g_sprite[h1].y) < distancey) + { + distancey = (g_sprite[h].y - g_sprite[h1].y); + diry = 8; + + } + if (g_sprite[h].y <= g_sprite[h1].y) if ((g_sprite[h1].y - g_sprite[h].y) < distancey) + { + distancey = (g_sprite[h1].y - g_sprite[h].y); + diry = 2; + } + if (distancex > distancey) + { + + *dir = dirx; + return(distancex); + } + else + { + *dir = diry; + return(distancey); + } + + +} + +void process_follow(int h) +{ + int hx, hy; + + if (g_sprite[h].follow > 299) + { + LogMsg("ERROR: Sprite %d cannot 'follow' sprite %d??",h,g_sprite[h].follow); + return; + } + + if (g_sprite[g_sprite[h].follow].active == false) + { + LogMsg("Killing follow"); + g_sprite[h].follow = 0; + return; + } + + hx = g_sprite[g_sprite[h].follow].x; + hy = g_sprite[g_sprite[h].follow].y; + + int dir; + int distance = get_distance_and_dir(h, g_sprite[h].follow, &dir); + + if (distance < 40) return; + + changedir(dir,h,g_sprite[h].base_walk); + automove(h); + + +} + + +void process_target(int h) +{ + int hx, hy; + + if (g_sprite[h].target > 299) + { + LogMsg("ERROR: Sprite %d cannot 'target' sprite %d??",h,g_sprite[h].follow); + return; + } + + if (g_sprite[g_sprite[h].target].active == false) + { + LogMsg("Killing target"); + g_sprite[h].target = 0; + return; + } + + hx = g_sprite[g_sprite[h].target].x; + hy = g_sprite[g_sprite[h].target].y; + + int dir; + int distance = get_distance_and_dir(h, g_sprite[h].target, &dir); + + if (distance < g_sprite[h].distance) return; + + changedir(dir,h,g_sprite[h].base_walk); + + automove(h); + + +} + + +bool check_for_kill_script(int i) +{ + + + if (g_sprite[i].script > 0) + { + //if ( (spr[i].brain == 0) | (spr[i].brain == 5) | (spr[i].brain == 6) | (spr[i].brain == 7)) + + if (locate(g_sprite[i].script, "DIE")) run_script(g_sprite[i].script); + + return(true); + } + + return(false); +} + +bool check_for_duck_script(int i) +{ + if (g_sprite[i].script > 0) + { + //if ( (spr[i].brain == 0) | (spr[i].brain == 5) | (spr[i].brain == 6) | (spr[i].brain == 7)) + + if (locate(g_sprite[i].script, "DUCKDIE")) run_script(g_sprite[i].script); + + return(true); + } + + return(false); +} + +void process_move(int h) +{ + // Msg("Proccesing sprite %d, dir %d (script is %d)", h, spr[h].dir, spr[h].move_script); + if ((g_sprite[h].move_dir == 4) | (g_sprite[h].move_dir == 1) | (g_sprite[h].move_dir == 7) ) + { + if (g_sprite[h].x <= g_sprite[h].move_num) + { + //done moving + done_moving(h); + return; + } + changedir(g_sprite[h].move_dir,h,g_sprite[h].base_walk); + automove(h); + } + + if ( (g_sprite[h].move_dir == 6) | (g_sprite[h].move_dir == 9) | (g_sprite[h].move_dir == 3)) + { + if (g_sprite[h].x >= g_sprite[h].move_num) + { + //done moving + done_moving(h); + return; + } + changedir(g_sprite[h].move_dir,h,g_sprite[h].base_walk); + automove(h); + } + + + if (g_sprite[h].move_dir == 2) + { + if (g_sprite[h].y >= g_sprite[h].move_num) + { + //done moving + done_moving(h); + return; + } + changedir(g_sprite[h].move_dir,h,g_sprite[h].base_walk); + automove(h); + } + + + if (g_sprite[h].move_dir == 8) + { + if (g_sprite[h].y <= g_sprite[h].move_num) + { + //done moving + done_moving(h); + return; + } + changedir(g_sprite[h].move_dir,h,g_sprite[h].base_walk); + automove(h); + } +} + +void duck_brain(int h) +{ + int hold; + + if ( (g_sprite[h].damage > 0) && (in_this_base(g_sprite[h].pseq, 110) ) ) + { + check_for_duck_script(h); + + //hit a dead duck + int crap2 = add_sprite(g_sprite[h].x,g_sprite[h].y,7,164,1); + g_sprite[crap2].speed = 0; + g_sprite[crap2].base_walk = 0; + g_sprite[crap2].seq = 164; + draw_damage(h); + g_sprite[h].damage = 0; + add_exp(g_sprite[h].exp, h); + + kill_sprite_all(h); + return; + } + + if ( (g_sprite[h].damage > 0) && (in_this_base(g_sprite[h].pseq, g_sprite[h].base_walk) ) ) + { + + draw_damage(h); + add_exp(g_sprite[h].exp, h); + g_sprite[h].damage = 0; + + //lets kill the duck here, ha. + check_for_kill_script(h); + g_sprite[h].follow = 0; + int crap = add_sprite(g_sprite[h].x,g_sprite[h].y,5,1,1); + g_sprite[crap].speed = 0; + g_sprite[crap].base_walk = 0; + g_sprite[crap].size = g_sprite[h].size; + g_sprite[crap].speed = ((rand() % 3)+1); + + + g_sprite[h].base_walk = 110; + g_sprite[h].speed = 1; + g_sprite[h].timer = 0; + g_sprite[h].wait = 0; + g_sprite[h].frame = 0; + + if (g_sprite[h].dir == 0) g_sprite[h].dir = 1; + if (g_sprite[h].dir == 4) g_sprite[h].dir = 7; + if (g_sprite[h].dir == 6) g_sprite[h].dir = 3; + + changedir(g_sprite[h].dir,h,g_sprite[h].base_walk); + g_sprite[crap].dir = g_sprite[h].dir; + g_sprite[crap].base_walk = 120; + changedir(g_sprite[crap].dir,crap,g_sprite[crap].base_walk); + automove(h); + return; + } + + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].freeze) + { + return; + } + + + if (g_sprite[h].follow > 0) + { + process_follow(h); + return; + } + + if (g_sprite[h].base_walk == 110) + { + if ( (rand() % 100)+1 == 1) + random_blood(g_sprite[h].x, g_sprite[h].y-18, h); + goto walk; + } + + if (g_sprite[h].seq == 0 ) + { + if (((rand() % 12)+1) == 1 ) + { + hold = ((rand() % 9)+1); + if ((hold != 2) && (hold != 8) && (hold != 5)) + { + //Msg("random dir change started.. %d", hold); + changedir(hold,h,g_sprite[h].base_walk); + } + else + { + int junk = g_sprite[h].size; + + if (junk >= 100) + junk = 18000 - (junk * 50); + + if (junk < 100) + junk = 16000 + (junk * 100); + + SoundPlayEffect( 1,junk, 800,h ,0); + g_sprite[h].mx = 0; + g_sprite[h].my = 0; + g_sprite[h].wait = g_dglos.g_dinkTick + (rand() % 300)+200; + } + + return; + } + + if ((g_sprite[h].mx != 0) || (g_sprite[h].my != 0)) + { + g_sprite[h].seq = g_sprite[h].seq_orig; + + } + } + + +walk: + if (g_sprite[h].y > C_DINK_ORIGINAL_GAME_AREA_Y) + { + changedir(9,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x > g_gameAreaRightBarStartX-30) + { + changedir(7,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].y < 10) + { + changedir(1,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x < 30) + { + changedir(3,h,g_sprite[h].base_walk); + } + + // Msg("Duck dir is %d, seq is %d.", spr[h].dir, spr[h].seq); + automove(h); + + if (check_if_move_is_legal(h) != 0) + + { + if (g_sprite[h].dir != 0) + changedir(autoreverse_diag(h),h,g_sprite[h].base_walk); + } + +} + +// end duck_brain + +void change_dir_to_diag( int32 *dir) +{ + + if (*dir == 8) *dir = 7; + if (*dir == 4) *dir = 1; + if (*dir == 2) *dir = 3; + if (*dir == 6) *dir = 9; + +} + +void pill_brain(int h) +{ + int hold; + + if (g_sprite[h].damage > 0) + { + //got hit + + if (g_sprite[h].hitpoints > 0) + { + draw_damage(h); + if (g_sprite[h].damage > g_sprite[h].hitpoints) g_sprite[h].damage = g_sprite[h].hitpoints; + g_sprite[h].hitpoints -= g_sprite[h].damage; + + if (g_sprite[h].hitpoints < 1) + { + //they killed it + check_for_kill_script(h); + + if (g_sprite[h].brain == 9) + { + if (g_sprite[h].dir == 0) g_sprite[h].dir = 3; + change_dir_to_diag(&g_sprite[h].dir); + add_kill_sprite(h); + g_sprite[h].active = false; + } + return; + + } + } + g_sprite[h].damage = 0; + } + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].freeze) return; + + if (g_sprite[h].follow > 0) + { + process_follow(h); + } + + if (g_sprite[h].target != 0) + { + + if (in_this_base(g_sprite[h].seq, g_sprite[h].base_attack)) + { + //still attacking + return; + } + + int dir; + if (g_sprite[h].distance == 0) g_sprite[h].distance = 5; + int distance = get_distance_and_dir(h, g_sprite[h].target, &dir); + + if (distance < g_sprite[h].distance) if (g_sprite[h].attack_wait < g_dglos.g_dinkTick) + { + // Msg("base attack is %d.",spr[h].base_attack); + if (g_sprite[h].base_attack != -1) + { + int attackdir; + bool old_smooth_follow = g_dglos.smooth_follow; + g_dglos.smooth_follow = false; + get_distance_and_dir(h, g_sprite[h].target, &attackdir); + g_dglos.smooth_follow = old_smooth_follow; + //Msg("attacking with %d..", spr[h].base_attack+dir); + + g_sprite[h].dir = attackdir; + + g_sprite[h].seq = g_sprite[h].base_attack+g_sprite[h].dir; + g_sprite[h].frame = 0; + + if (g_sprite[h].script != 0) + { + if (locate(g_sprite[h].script, "ATTACK")) run_script(g_sprite[h].script); + } else + g_sprite[h].move_wait = g_dglos.g_dinkTick + ((rand() % 300)+10);; + return; + + } + + } + + if (g_sprite[h].move_wait < g_dglos.g_dinkTick) + { + process_target(h); + g_sprite[h].move_wait = g_dglos.g_dinkTick + 200; + + } + else + { + goto walk_normal; + } + + return; + } + +walk_normal: + + if (g_sprite[h].base_walk != -1) + { + if ( g_sprite[h].seq == 0) goto recal; + } + + if (( g_sprite[h].seq == 0) && (g_sprite[h].move_wait < g_dglos.g_dinkTick)) + { +recal: + if (((rand() % 12)+1) == 1 ) + { + hold = ((rand() % 9)+1); + if ( (hold != 4) && (hold != 6) && (hold != 2) && (hold != 8) && (hold != 5)) + { + changedir(hold,h,g_sprite[h].base_walk); + g_sprite[h].move_wait = g_dglos.g_dinkTick +((rand() % 2000)+200); + } + + } else + { + //keep going the same way + if (in_this_base(g_sprite[h].seq_orig, g_sprite[h].base_attack)) goto recal; + g_sprite[h].seq = g_sprite[h].seq_orig; + if (g_sprite[h].seq_orig == 0) goto recal; + } + } + + if (g_sprite[h].y > (C_DINK_ORIGINAL_GAME_AREA_Y - 15)) + + { + changedir(9,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x > (g_gameAreaRightBarStartX - 15)) + + { + changedir(1,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].y < 18) + { + changedir(1,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x < 18) + { + changedir(3,h,g_sprite[h].base_walk); + } + + automove(h); + + if (check_if_move_is_legal(h) != 0) + { + g_sprite[h].move_wait = g_dglos.g_dinkTick + 400; + changedir(autoreverse_diag(h),h,g_sprite[h].base_walk); + } + +} + +void find_action(int h) +{ + g_sprite[h].action = (rand() % 2)+1; + + if (g_sprite[h].action == 1) + { + //sit and think + g_sprite[h].move_wait = g_dglos.g_dinkTick +((rand() % 3000)+400); + if (g_sprite[h].base_walk != -1) + { + int dir = (rand() % 4)+1; + + g_sprite[h].pframe = 1; + if (dir == 1) g_sprite[h].pseq = g_sprite[h].base_walk+1; + if (dir == 2) g_sprite[h].pseq = g_sprite[h].base_walk+3; + if (dir == 3) g_sprite[h].pseq = g_sprite[h].base_walk+7; + if (dir == 4) g_sprite[h].pseq = g_sprite[h].base_walk+9; + } + + return; + } + + if (g_sprite[h].action == 2) + { + //move + g_sprite[h].move_wait = g_dglos.g_dinkTick +((rand() % 3000)+500); + int dir = (rand() % 4)+1; + g_sprite[h].pframe = 1; + if (dir == 1) changedir(1,h,g_sprite[h].base_walk); + if (dir == 2) changedir(3,h,g_sprite[h].base_walk); + if (dir == 3) changedir(7,h,g_sprite[h].base_walk); + if (dir == 4) changedir(9,h,g_sprite[h].base_walk); + return; + } + + + LogMsg("Internal error: Brain 16, unknown action."); +} + +void people_brain(int h) +{ + if (g_sprite[h].damage > 0) + { + //got hit + + if (g_sprite[h].hitpoints > 0) + { + draw_damage(h); + if (g_sprite[h].damage > g_sprite[h].hitpoints) g_sprite[h].damage = g_sprite[h].hitpoints; + g_sprite[h].hitpoints -= g_sprite[h].damage; + + if (g_sprite[h].hitpoints < 1) + { + //they killed it + check_for_kill_script(h); + + if (g_sprite[h].brain == 16) + { + if (g_sprite[h].dir == 0) g_sprite[h].dir = 3; + g_sprite[h].brain = 0; + change_dir_to_diag(&g_sprite[h].dir); + add_kill_sprite(h); + g_sprite[h].active = false; + } + return; + + } + } + g_sprite[h].damage = 0; + + } + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].freeze) return; + + if (g_sprite[h].follow > 0) + { + process_follow(h); + return; + } + + if ((g_sprite[h].move_wait < g_dglos.g_dinkTick) && (g_sprite[h].seq == 0)) + { + g_sprite[h].action = 0; + } + + if (g_sprite[h].action == 0) find_action(h); + + if (g_sprite[h].action != 2) + { + g_sprite[h].seq = 0; + return; + + } + if (g_sprite[h].seq_orig != 0) + if (g_sprite[h].seq == 0) g_sprite[h].seq = g_sprite[h].seq_orig; + + + if (g_sprite[h].y > C_DINK_ORIGINAL_GAME_AREA_Y) + { + + if ( ((rand() % 2)+1) == 1) + changedir(9,h,g_sprite[h].base_walk); + else changedir(7,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x > g_gameAreaRightBarStartX) + + { + if ( ((rand() % 2)+1) == 1) + changedir(1,h,g_sprite[h].base_walk); + else changedir(7,h,g_sprite[h].base_walk); + + } + + if (g_sprite[h].y < 20) + { + if ( ((rand() % 2)+1) == 1) + changedir(1,h,g_sprite[h].base_walk); + else changedir(3,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x < 30) + { + if ( ((rand() % 2)+1) == 1) + changedir(3,h,g_sprite[h].base_walk); + else changedir(9,h,g_sprite[h].base_walk); + } + + automove(h); + + if (check_if_move_is_legal(h) != 0) + { + if ((rand() % 3) == 2) + { + changedir(autoreverse_diag(h),h,g_sprite[h].base_walk); + + } else + { + g_sprite[h].move_wait = 0; + g_sprite[h].pframe = 1; + g_sprite[h].seq = 0; + } + } +} + + +void no_brain(int h) +{ + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].freeze) return; + + if (g_sprite[h].follow > 0) + { + process_follow(h); + return; + } +} + + +void shadow_brain(int h) +{ + if (g_sprite[g_sprite[h].brain_parm].active == false) + { + g_sprite[h].active = false; + return; + } + + g_sprite[h].x = g_sprite[g_sprite[h].brain_parm].x; + g_sprite[h].y = g_sprite[g_sprite[h].brain_parm].y; + g_sprite[h].size = g_sprite[g_sprite[h].brain_parm].size; + + if (g_sprite[h].seq == 0) if (g_sprite[h].seq_orig != 0) g_sprite[h].seq = g_sprite[h].seq_orig; +} + + +void dragon_brain(int h) +{ + int hold; + + + if (g_sprite[h].damage > 0) + { + //got hit + if (g_sprite[h].hitpoints > 0) + { + draw_damage(h); + if (g_sprite[h].damage > g_sprite[h].hitpoints) g_sprite[h].damage = g_sprite[h].hitpoints; + g_sprite[h].hitpoints -= g_sprite[h].damage; + + if (g_sprite[h].hitpoints < 1) + { + //they killed it + + check_for_kill_script(h); + if (g_sprite[h].brain == 10) + { + add_kill_sprite(h); + g_sprite[h].active = false; + } + + return; + + } + } + g_sprite[h].damage = 0; + } + + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + + if (g_sprite[h].freeze) return; + + + if (g_sprite[h].follow > 0) + { + process_follow(h); + return; + } + + if (g_sprite[h].target != 0) + if (g_sprite[h].attack_wait < g_dglos.g_dinkTick) + { + if (g_sprite[h].script != 0) + { + + if (locate(g_sprite[h].script, "ATTACK")) run_script(g_sprite[h].script); + } + } + + if (g_sprite[h].seq == 0) + { +recal: + if (((rand() % 12)+1) == 1 ) + { + hold = ((rand() % 9)+1); + if ( (hold != 1) && (hold != 3) && (hold != 7) && (hold != 9) && (hold != 5)) + { + changedir(hold,h,g_sprite[h].base_walk); + + } + + } else + { + //keep going the same way + g_sprite[h].seq = g_sprite[h].seq_orig; + if (g_sprite[h].seq_orig == 0) goto recal; + } + + } + + + if (g_sprite[h].y > C_DINK_ORIGINAL_GAME_AREA_Y) + + { + changedir(8,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x > C_DINK_SCREENSIZE_X) + { + changedir(4,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].y < 0) + { + changedir(2,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x < 0) + { + changedir(6,h,g_sprite[h].base_walk); + } + + automove(h); + + if (check_if_move_is_legal(h) != 0) + + { + + int mydir = autoreverse(h); + + // Msg("Real dir now is %d, autoresver changed to %d.",spr[h].dir, mydir); + + changedir(mydir,h,g_sprite[h].base_walk); + +#ifdef _DEBUG + LogMsg("real dir changed to %d",g_sprite[h].dir); +#endif + } + +} + + +void pig_brain(int h) +{ + int hold; + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if ( (g_sprite[h].damage > 0) ) + { + + draw_damage(h); + g_sprite[h].hitpoints -= g_sprite[h].damage; + g_sprite[h].damage = 0; + if (g_sprite[h].hitpoints < 1) + { + add_exp(g_sprite[h].exp, h); + g_sprite[h].damage = 0; + //lets kill the duck here, ha. + check_for_kill_script(h); + g_sprite[h].speed = 0; + g_sprite[h].base_walk = -1; + g_sprite[h].seq = 164; + g_sprite[h].brain = 7; + } + + return; + } + + if (g_sprite[h].freeze) return; + + if (g_sprite[h].seq == 0 ) + { + + if (((rand() % 12)+1) == 1 ) + { + hold = ((rand() % 9)+1); + + if ( (hold != 4) && (hold != 6) && (hold != 2) && (hold != 8) && (hold != 5)) + { + changedir(hold,h,g_sprite[h].base_walk); + + } + else + { + int junk = g_sprite[h].size; + + if (junk >= 100) + junk = 18000 - (junk * 50); + + if (junk < 100) + junk = 16000 + (junk * 100); + + + hold = ((rand() % 4)+1); + + if (!playing(g_sprite[h].last_sound)) g_sprite[h].last_sound = 0; + + if (g_sprite[h].last_sound == 0) + { + + + if (hold == 1) + g_sprite[h].last_sound = SoundPlayEffect( 2,junk, 800 ,h,0); + if (hold == 2) + g_sprite[h].last_sound = SoundPlayEffect( 3,junk, 800,h ,0); + if (hold == 3) + g_sprite[h].last_sound = SoundPlayEffect( 4,junk, 800 ,h,0); + if (hold == 4) + g_sprite[h].last_sound = SoundPlayEffect( 5,junk, 800,h,0 ); + + } + + g_sprite[h].mx = 0; + g_sprite[h].my = 0; + g_sprite[h].wait = g_dglos.g_dinkTick + (rand() % 300)+200; + + } + + } + else + { + + if ((g_sprite[h].mx != 0) || (g_sprite[h].my != 0)) + + { + g_sprite[h].seq = g_sprite[h].seq_orig; + + } + + } + } + + + if (g_sprite[h].y > (C_DINK_ORIGINAL_GAME_AREA_Y-g_dglos.g_picInfo[getpic(h)].box.bottom / 4)) + { + changedir(9,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x > (C_DINK_SCREENSIZE_X-g_dglos.g_picInfo[getpic(h)].box.right-10)) + { + changedir(1,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].y < 10) + { + changedir(1,h,g_sprite[h].base_walk); + } + + if (g_sprite[h].x < 10) + { + changedir(3,h,g_sprite[h].base_walk); + } + + automove(h); + + if (check_if_move_is_legal(h) != 0) + + { + changedir(autoreverse_diag(h),h,g_sprite[h].base_walk); + } + +} +// end duck_brain + + + + +int check_if_move_is_legal(int u) + +{ + //redink1 removed so move_nohard is active for all movements, not just active moves. + //if (spr[u].move_active) + if (g_sprite[u].move_nohard == 1) + return(0); + if (u == 1) if (in_this_base(g_sprite[u].seq, g_dglos.mDinkBasePush)) return(0); + + if (u == 1) if (!no_cheat) if (debug_mode) return(0); + int hardness = 0; + if (g_sprite[u].moveman > 0) + { + for (int i=1; i <= g_sprite[u].moveman; i++) + { + hardness = get_hard(u,g_sprite[u].lpx[i]-20 , g_sprite[u].lpy[i]); + if (hardness == 2) if (g_sprite[u].flying) + { + g_sprite[u].moveman = 0; + // redink1 changed so flying works properly + return(0); + } + + if (hardness > 0) + { + g_sprite[u].x = g_sprite[u].lpx[i-1]; + g_sprite[u].y = g_sprite[u].lpy[i-1]; + g_sprite[u].moveman = 0; + + if (g_dglos.g_pushingEnabled) + if (u == 1) if (hardness != 2) if (g_dglos.g_playerInfo.push_active == false) + { + if ( (g_sprite[u].dir == 2) | (g_sprite[u].dir == 4) | (g_sprite[u].dir == 6) | (g_sprite[u].dir == 8) ) + { + //he (dink) is definatly pushing on something + g_dglos.g_playerInfo.push_active = true; + g_dglos.g_playerInfo.push_dir = g_sprite[u].dir; + g_dglos.g_playerInfo.push_timer = g_dglos.g_dinkTick; + + } + } else + { + if (g_dglos.g_playerInfo.push_dir != g_sprite[1].dir) g_dglos.g_playerInfo.push_active = false; + } + return(hardness); + } + } + } + + + if (u == 1) g_dglos.g_playerInfo.push_active = false; + return(0); +} + + + +void move(int u, int amount, char kind, char kindy) +{ + int mx = 0; + int my = 0; + bool clearx; + bool cleary; + clearx = false; + cleary = false; + + for (int i=1; i <= amount; i++) + { + g_sprite[u].moveman++; + if (mx >= g_sprite[u].mx) clearx = true; + if (my >= g_sprite[u].my) clearx = true; + + if ((clearx) && (cleary)) + { + mx = 0; + my = 0; + clearx = false; + cleary = false; + } + + if (kind == '+') + { + if (mx < g_sprite[u].mx) + g_sprite[u].x++; + mx++; + + } + if (kind == '-') + { + + + if (mx < (g_sprite[u].mx - (g_sprite[u].mx * 2))) + g_sprite[u].x--; + mx++; + } + + if (kindy == '+') + { + + if (my < g_sprite[u].my) + g_sprite[u].y++; + my++; + } + if (kindy == '-') + { + + if (my < (g_sprite[u].my - (g_sprite[u].my * 2))) + g_sprite[u].y--; + my++; + } + + g_sprite[u].lpx[g_sprite[u].moveman] = g_sprite[u].x; + g_sprite[u].lpy[g_sprite[u].moveman] = g_sprite[u].y; + } +} + +void bounce_brain(int h) +{ + if (g_sprite[h].y > (C_DINK_ORIGINAL_GAME_AREA_Y-g_dglos.g_picInfo[getpic(h)].box.bottom)) + { + g_sprite[h].my -= (g_sprite[h].my * 2); + } + + if (g_sprite[h].x > (C_DINK_SCREENSIZE_X-g_dglos.g_picInfo[getpic(h)].box.right)) + { + g_sprite[h].mx -= (g_sprite[h].mx * 2); + } + + if (g_sprite[h].y < 0) + { + g_sprite[h].my -= (g_sprite[h].my * 2); + } + + + if (g_sprite[h].x < 0) + { + g_sprite[h].mx -= (g_sprite[h].mx * 2); + } + + + g_sprite[h].x += g_sprite[h].mx; + g_sprite[h].y += g_sprite[h].my; +} +//end bounce brain + +void CheckTransitionSurface() +{ + if (!g_transitionSurf.IsLoaded()) + { + g_transitionSurf.SetUsesAlpha(false); + g_transitionSurf.InitBlankSurface(GetPrimaryGLX(), GetPrimaryGLY()); + g_transitionSurf.SetSmoothing(false); + g_transitionSurf.SetBlendingMode(SurfaceAnim::BLENDING_PREMULTIPLIED_ALPHA); + } +} + +void UpdateFrameWithoutTransitionAndThinking() +{ + SetOrthoRenderSize(g_dglo.m_orthoRenderRect.right, g_dglo.m_orthoRenderRect.GetHeight(), -g_dglo.m_orthoRenderRect.left, -g_dglo.m_orthoRenderRect.top); + + GetBaseApp()->SetGameTickPause(true); //don't let logic actually happen in here + + rtRect32 rcRect; + + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = C_DINK_SCREENSIZE_X; + rcRect.bottom = C_DINK_SCREENSIZE_Y; + + //Blit from Two, which holds the base scene. + + lpDDSBack->BltFast( 0, 0, lpDDSBackGround, &rcRect, DDBLTFAST_NOCOLORKEY); + g_dglo.m_bgSpriteMan.Render(lpDDSBack); //blit sprites that have been shoved into the bg, too slow to actually add them, so we fake it until the screen is rebuilt + + + //render sprites + + int h= 0; + + for (int j = 1; j < C_MAX_SPRITES_AT_ONCE; j++) + { + if (g_dglos.plane_process) + h = g_spriteRank[j]; else h = j; + //Msg( "Ok, rank %d is %d", j,h); + + if (h > 0) + { + ThinkSprite(h, g_bTransitionActive || g_dglos.g_stopEntireGame == 1); + } + } + + GetBaseApp()->SetGameTickPause(false); + + RemoveOrthoRenderSize(); + +} + + +void StartScreenScrollTransition(int direction) +{ + + //this is where we grab a screenshot of the current pic before scrolling to the next screen + rtRect32 rcRect; + + if (no_transition) + { + //g_bInitiateScreenMove = true; + return; + } + + CheckTransitionSurface(); + //remember this for later + + //remove the aspect ratio hack + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + UpdateFrameWithoutTransitionAndThinking(); + g_transitionSurf.CopyFromScreen(); + + ApplyAspectRatioGLMatrix(); + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED) + { + //clear background if needed + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + } + //redraw it the correct way, otherwise we can see a flash + UpdateFrameWithoutTransitionAndThinking(); + + + + g_bInitiateScreenMove = true; + g_bTransitionActive = true; + g_dglo.m_transitionTimer = 0; + + //look at your numpad.., that's the dir we're going + + //here we're set an offset needed for where we START FROM for the animation. When the anim is done, this will be applied 0% + switch(direction) + { + case 4: + g_dglo.m_transitionOffsetNative = CL_Vec2f((int32)-g_dglo.m_nativeGameArea.GetWidth(), 0); + g_dglo.m_transitionOffset = CL_Vec2f((int32)-g_dglo.m_gameArea.GetWidth(), 0); + break; + + case 6: + g_dglo.m_transitionOffsetNative = CL_Vec2f((int32)g_dglo.m_nativeGameArea.GetWidth(), 0); + g_dglo.m_transitionOffset = CL_Vec2f((int32)g_dglo.m_gameArea.GetWidth(), 0); + break; + case 8: + g_dglo.m_transitionOffsetNative = CL_Vec2f(0, -g_dglo.m_nativeGameArea.GetHeight()); + g_dglo.m_transitionOffset = CL_Vec2f(0, -g_dglo.m_gameArea.GetHeight()); + break; + case 2: + g_dglo.m_transitionOffsetNative = CL_Vec2f(0, (int32)g_dglo.m_nativeGameArea.GetHeight()); + g_dglo.m_transitionOffset = CL_Vec2f(0, (int32)g_dglo.m_gameArea.GetHeight()); + break; + + default: + assert(!"er"); + } +} + + +void ProcessTransition(void) +{ + if (!g_bTransitionActive) return; + + g_dglo.m_transitionProgress = float(GetBaseApp()->GetGameTick()-g_dglo.m_transitionTimer) / C_DINK_SCREEN_TRANSITION_TIME_MS; + + if (g_dglo.m_transitionTimer == 0) + { + g_dglo.m_transitionProgress = 0; + } + + float inverseProg = 1.0f - g_dglo.m_transitionProgress; + + if (g_dglo.m_transitionProgress >= 1) + { + g_bTransitionActive = false; + g_bInitiateScreenMove = 0; + g_dglo.m_transitionOffset = CL_Vec2f(0,0); + g_dglo.m_transitionTimer = 0; + } + + //float offsetX = 0.5f; + + float fTemp = inverseProg; + //fTemp = 1.0f; + glTranslatef((g_dglo.m_transitionOffset.x*fTemp),(g_dglo.m_transitionOffset.y*fTemp), 0); + //LogMsg("Trans: %.2f", g_dglo.m_transitionProgress); + //glScalef(G_TRANSITION_SCALE_TRICK,G_TRANSITION_SCALE_TRICK,1); + +} + +void EndProcessTransition() +{ + if (!g_bTransitionActive) return; + float inverseProg = 1.0f - g_dglo.m_transitionProgress; + //glScalef(1/G_TRANSITION_SCALE_TRICK,1/G_TRANSITION_SCALE_TRICK,1); + + glTranslatef((-g_dglo.m_transitionOffset.x*inverseProg), (- ( (g_dglo.m_transitionOffset.y*inverseProg))), 0); + +}; + +void BlitSecondTransitionScreen() +{ + + if (g_bTransitionActive) + { + CheckTransitionSurface(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + float offsetX = g_dglo.m_centeringOffset.x*(1 - ((float)GetFakePrimaryScreenSizeX() / (float)C_DINK_SCREENSIZE_X)); + float offsetY = g_dglo.m_centeringOffset.y*(1 - ((float)GetFakePrimaryScreenSizeY() / (float)C_DINK_SCREENSIZE_Y)); + //for some reason, after doing the aspect ratio scale trick, I need to also move it over a bit for this second blit to line up + //glTranslatef(offsetX, + + //Let me write a long explanation of why these numbers are used. It's be... sorry, uhh.. phone call + glTranslatef(-offsetX, -offsetY, 0); + + rtRectf dstRect = g_dglo.m_nativeGameArea; + rtRectf dstOffset = rtRectf(0.5f,0.5f,-0.5f,-0.5f); + + /* + + //old code for when we manually rotated the screen, these days we let iOS do it, it's not a horrible performance penalty anymore + + + if (GetPrimaryGLX() < GetPrimaryGLY() && GetEmulatedPlatformID() != PLATFORM_ID_WINDOWS) + { + + swap(dstRect.left, dstRect.top); + swap(dstRect.right, dstRect.bottom); + rtRectf srcRect = ConvertFakeScreenRectToReal(dstRect); + + //CHECK the fakescreen stuff.. + if (GetOrientation() == ORIENTATION_LANDSCAPE_LEFT) + { + glTranslatef((-g_dglo.m_transitionOffsetNative.x*g_dglo.m_transitionProgress), (g_dglo.m_nativeGameArea.GetHeight()-g_dglo.m_transitionOffsetNative.y*g_dglo.m_transitionProgress),0); + glRotatef(-90, 0, 0, 1); + srcRect.AdjustPosition(GetScreenSizeYf()-g_dglo.m_nativeGameArea.GetHeight(), 0); + g_transitionSurf.BlitEx(dstRect, srcRect); + + } else + { + glTranslatef( ( ( g_dglo.m_nativeGameArea.left*2+g_dglo.m_nativeGameArea.GetWidth())-g_dglo.m_transitionOffsetNative.x*g_dglo.m_transitionProgress), + ( (g_dglo.m_nativeGameArea.top) -g_dglo.m_transitionOffsetNative.y*g_dglo.m_transitionProgress ),0); + glRotatef(90, 0, 0, 1); + g_transitionSurf.BlitEx(dstRect, srcRect); + } + + + } else + \*/ + { + dstRect.AdjustPosition( ( -g_dglo.m_transitionOffsetNative.x*g_dglo.m_transitionProgress), + ( -g_dglo.m_transitionOffsetNative.y*g_dglo.m_transitionProgress)); + + //dstRect.AdjustPosition(-g_dglo.m_centeringOffset.x*g_dglo.m_transitionProgress, -g_dglo.m_centeringOffset.y*g_dglo.m_transitionProgress); + rtRectf srcRect = ConvertFakeScreenRectToReal(g_dglo.m_nativeGameArea); + // LogMsg("Dest rect: %s",PrintRect(dstRect)); + g_transitionSurf.BlitEx(dstRect, srcRect); + } + + //g_globalBatcher.Flush(); + + if (!g_onePixelSurf.IsLoaded()) + { + g_onePixelSurf.InitBlankSurface(1, 1); + g_onePixelSurf.FillColor(glColorBytes(255, 255, 255, 255)); + } + + if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED) + { + static uint32 blackBarsColor = MAKE_RGBA(0, 0, 0, 255); + + g_onePixelSurf.BlitScaled(g_dglo.m_nativeGameArea.left, 0, CL_Vec2f(5000, 5000), ALIGNMENT_RIGHT_CENTER, blackBarsColor); + g_onePixelSurf.BlitScaled(g_dglo.m_nativeGameArea.right, 0, CL_Vec2f(5000, 5000), ALIGNMENT_LEFT_CENTER, blackBarsColor); + + g_onePixelSurf.BlitScaled(0, g_dglo.m_nativeGameArea.top, CL_Vec2f(5000, 5000), ALIGNMENT_DOWN_CENTER, blackBarsColor); + g_onePixelSurf.BlitScaled(0, g_dglo.m_nativeGameArea.bottom, CL_Vec2f(5000, 5000), ALIGNMENT_UPPER_CENTER, blackBarsColor); + + } + //s.Blit(0, 0); + //g_globalBatcher.Flush(); + + glPopMatrix( ); + + //well, at this point we're done except there is garbage on the area outside the playfield if we're letterboxed so aspect ratio is right. This could have all been + //avoided with a render to surface but I think this will be faster + } + + +} + +void did_player_cross_screen(bool bCheckWithoutMoving, int playerID) +{ +bool move_gonna = false; + + if (g_dglos.walk_off_screen == 1) return; + //DO MATH TO SEE IF THEY HAVE CROSSED THE SCREEN, IF SO LOAD NEW ONE + if ((g_sprite[playerID].x) < g_gameAreaLeftOffset) + { + if ((g_MapInfo.loc[*pmap-1] > 0) && (g_dglos.screenlock == 0) ) + { + //move one map to the left + if (bCheckWithoutMoving) + { + move_gonna = true; + return; + } + update_screen_time(); + StartScreenScrollTransition(4); + *pmap -= 1; + load_map(g_MapInfo.loc[*pmap]); + if (g_MapInfo.indoor[*pmap] == 0) g_dglos.g_playerInfo.last_map = *pmap; + + BuildScreenBackground(); + g_sprite[playerID].x = 619; + g_sprite[playerID].y = g_sprite[playerID].lpy[0]; + goto b1end; + } else + { + g_sprite[playerID].x = g_gameAreaLeftOffset; + } + } + + if ((g_sprite[playerID].x) > 619) + { + if ((g_MapInfo.loc[*pmap+1] > 0) && (g_dglos.screenlock == 0) ) + { + //move one map to the right + if (bCheckWithoutMoving) + { + move_gonna = true; + return; + } + + update_screen_time(); + StartScreenScrollTransition(6); + *pmap += 1; + load_map(g_MapInfo.loc[*pmap]); + if (g_MapInfo.indoor[*pmap] == 0) g_dglos.g_playerInfo.last_map = *pmap; + + BuildScreenBackground(); + g_sprite[playerID].x = g_gameAreaLeftOffset; + g_sprite[playerID].y = g_sprite[playerID].lpy[0]; + goto b1end; + } else + { + g_sprite[playerID].x = 619; + } + } + + if (g_sprite[playerID].y < 0) + { + if ((g_MapInfo.loc[*pmap-32] > 0) && (g_dglos.screenlock == 0) ) + { + //move one map up + if (bCheckWithoutMoving) + { + move_gonna = true; + return; + } + update_screen_time(); + StartScreenScrollTransition(8); + *pmap -= 32; + load_map(g_MapInfo.loc[*pmap]); + if (g_MapInfo.indoor[*pmap] == 0) g_dglos.g_playerInfo.last_map = *pmap; + + g_sprite[playerID].x = g_sprite[playerID].lpx[0]; + BuildScreenBackground(); + g_sprite[playerID].y = 399; + + goto b1end; + } else + { + g_sprite[playerID].y = 0; + } + } + + if ( (g_sprite[playerID].y > 399 ) ) + { + if ( (g_MapInfo.loc[*pmap+32] > 0) && (g_dglos.screenlock == 0) ) + { + //move one map down + if (bCheckWithoutMoving) + { + move_gonna = true; + return; + } + update_screen_time(); + StartScreenScrollTransition(2); + *pmap += 32; + load_map(g_MapInfo.loc[*pmap]); + if (g_MapInfo.indoor[*pmap] == 0) g_dglos.g_playerInfo.last_map = *pmap; + + BuildScreenBackground(); + g_sprite[playerID].y = 0; + + g_sprite[playerID].x = g_sprite[playerID].lpx[0]; + + goto b1end; + } else + { + g_sprite[playerID].y = 399; + } + } + +b1end:; +} + +bool run_through_tag_list_talk(int h) +{ + rtRect32 box; + int amount, amounty; + + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + + if (g_sprite[i].active) if (i != h) if (g_sprite[i].brain != 8) + { + box = g_dglos.g_picInfo[getpic(i)].hardbox; + OffsetRect(&box, g_sprite[i].x, g_sprite[i].y); + InflateRect(&box, 10,10); + + amount = 50; + amounty = 35; + if (g_sprite[h].dir == 6) + { + box.left -= amount; + } + + if (g_sprite[h].dir == 4) + { + box.right += amount; + } + + if (g_sprite[h].dir == 2) + { + box.top -= amounty; + } + + if (g_sprite[h].dir == 8) + { + box.bottom += amounty; + } + + // draw_box(box, 33); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + //Msg("Talking to sprite %d", i); + if (g_sprite[i].script > 0) + { + //Msg("trying to find TALK in script %d", spr[i].script); + if (locate(g_sprite[i].script, "TALK")) + { + kill_returning_stuff(g_sprite[i].script); + run_script(g_sprite[i].script); + return(true); + } + } + } + } + } + + return(false); +} + +void make_missile(int x1, int y1, int dir, int speed, int seq, int frame, int strength) +{ + int crap = add_sprite(x1,y1,11,seq,frame); + g_sprite[crap].speed = speed; + g_sprite[crap].seq = seq; + g_sprite[crap].timer = 0; + g_sprite[crap].strength = strength; + g_sprite[crap].flying = true; + changedir(dir, crap, 430); +} + +void missile_brain( int h, bool repeat) +{ + rtRect32 box; + automove(h); + + *pmissle_source = h; + int hard = check_if_move_is_legal(h); + if (repeat) if (g_sprite[h].seq == 0) g_sprite[h].seq = g_sprite[h].seq_orig; + g_sprite[1].hitpoints = *plife; + + if (hard > 0) if (hard != 2) + { + //lets check to see if they hit a sprites hardness + if (hard > 100) + { + for (int ii = 1; ii < g_dglos.last_sprite_created; ii++) + { + if (g_sprite[ii].sp_index == hard-100) + { + if (g_sprite[ii].script > 0) + { + *pmissile_target = 1; + *penemy_sprite = 1; + + if (locate(g_sprite[ii].script, "HIT")) + { + kill_returning_stuff(g_sprite[ii].script); + run_script(g_sprite[ii].script); + } + } + + if (g_sprite[h].script > 0) + { + *pmissile_target = ii; + *penemy_sprite = 1; + if (locate(g_sprite[h].script, "DAMAGE")) + { + kill_returning_stuff(g_sprite[h].script); + run_script(g_sprite[h].script); + } + } else + { + if (g_sprite[h].attack_hit_sound == 0) + { + SoundPlayEffect( 9,22050, 0 ,0,0); + } else + { + SoundPlayEffect( g_sprite[h].attack_hit_sound,g_sprite[h].attack_hit_sound_speed, 0 ,0,0); + } + g_sprite[h].active = 0; + } + + //run missile end + return; + } + } + } + + //run missile end + + if (g_sprite[h].script > 0) + { + *pmissile_target = 0; + if (locate(g_sprite[h].script, "DAMAGE")) run_script(g_sprite[h].script); + } else + { + if (g_sprite[h].attack_hit_sound == 0) + { + SoundPlayEffect( 9,22050, 0 ,0,0); + } else + { + SoundPlayEffect( g_sprite[h].attack_hit_sound,g_sprite[h].attack_hit_sound_speed, 0 ,0,0); + } + + g_sprite[h].active = 0; + return; + } + } + + if (g_sprite[h].x > 1000) g_sprite[h].active = false; + if (g_sprite[h].y > 700) g_sprite[h].active = false; + if (g_sprite[h].y < -500) g_sprite[h].active = false; + if (g_sprite[h].x < -500) g_sprite[h].active = false; + + //did we hit anything that can die? + + for (int j = 1; j <= g_dglos.last_sprite_created; j++) + { + if (g_sprite[j].active) if (h != j) if (g_sprite[j].nohit != 1) if (g_sprite[j].notouch == false) + if (g_sprite[h].brain_parm != j) if (g_sprite[h].brain_parm2!= j) //if (spr[j].brain != 15) if + //(spr[j].brain != 11) + { + box = g_dglos.g_picInfo[getpic(j)].hardbox; + OffsetRect(&box, g_sprite[j].x, g_sprite[j].y); + + if (g_sprite[h].range != 0) + InflateRect(&box, g_sprite[h].range,g_sprite[h].range); + + if (debug_mode) draw_box(box, 33); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + g_sprite[j].notouch = true; + g_sprite[j].notouch_timer = g_dglos.g_dinkTick+100; + g_sprite[j].target = 1; + *penemy_sprite = 1; + //change later to reflect REAL target + if (g_sprite[h].script > 0) + { + + *pmissile_target = j; + if (locate(g_sprite[h].script, "DAMAGE")) run_script(g_sprite[h].script); + } else + { + + if (g_sprite[h].attack_hit_sound == 0) + { + SoundPlayEffect( 9,22050, 0 ,0,0); + } else + { + SoundPlayEffect( g_sprite[h].attack_hit_sound,g_sprite[h].attack_hit_sound_speed, 0 ,0,0); + } + } + + if ( g_sprite[j].hitpoints > 0) if (g_sprite[h].strength != 0) + { + int hit = 0; + if (g_sprite[h].strength == 1) hit = g_sprite[h].strength - g_sprite[j].defense; else + + hit = (g_sprite[h].strength / 2) + ((rand() % (g_sprite[h].strength / 2))+1) + - g_sprite[j].defense; + + if (hit < 0) hit = 0; + + + g_sprite[j].damage += hit; + if (hit > 0) + { + random_blood(g_sprite[j].x, g_sprite[j].y-40, j); + } + g_sprite[j].last_hit = 1; + //Msg("Damage done is %d..", spr[j].damage); + } + + if (g_sprite[j].script > 0) + { + //CHANGED did = h + *pmissile_target = 1; + + if (locate(g_sprite[j].script, "HIT")) + { + kill_returning_stuff(g_sprite[j].script); + run_script(g_sprite[j].script); + } + } + } + } + } + +} + + +void missile_brain_expire(int h) +{ + missile_brain(h, false); + if (g_sprite[h].seq == 0) g_sprite[h].active = 0; +} + +void run_through_mouse_list(int h, bool special) +{ + rtRect32 box; + + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + + if (g_sprite[i].active) if (i != h) if + ((g_sprite[i].touch_damage != 0) ) + { + + if (g_sprite[i].touch_damage != -1) if (g_sprite[h].notouch) return; + box = g_dglos.g_picInfo[getpic(i)].hardbox; + OffsetRect(&box, g_sprite[i].x, g_sprite[i].y); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + + if ((g_sprite[i].touch_damage == -1) && (g_sprite[i].script != 0)) + { + LogMsg("running %d's script..",g_sprite[i].script); + if (locate(g_sprite[i].script, "CLICK")) run_script(g_sprite[i].script); + } + else + { + if (g_sprite[i].touch_damage == -1) + { + LogMsg("Sprites touch damage is set to -1 but there is no script set!"); + } else + { + //lets hurt the guy + } + } + + if (special) return; + } + } + + } + + if (special) SoundPlayEffect(19, 22050, 0, 0,0); + +} + + +void mouse_brain(int h) +{ + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + int diag = 0; + + if (sjoy.right) diag++; + if (sjoy.left) diag++; + if (sjoy.down) diag++; + if (sjoy.up) diag++; + + //*********************************PROCESS MOVEMENT + + if (diag == 1) + { + + if (sjoy.right) + { + move(h,g_sprite[h].speed,'+','0'); + changedir(6,h,g_sprite[h].base_walk); + } + + if (sjoy.left) + { + move(h,g_sprite[h].speed,'-','0'); + changedir(4,h,g_sprite[h].base_walk); + } + + if (sjoy.down) + { + move(h,g_sprite[h].speed,'0','+'); + changedir(2,h,g_sprite[h].base_walk); + } + + if (sjoy.up) + { + move(h,g_sprite[h].speed,'0','-'); + changedir(8,h,g_sprite[h].base_walk); + } + + } + // ***************** DIAGONAL!!!! + + if (diag > 1) + { + + if ( (sjoy.up) && (sjoy.left) ) + { + changedir(7,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'-','-'); + } + + if ( (sjoy.down) && (sjoy.left)) + { + changedir(1,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'-','+'); + } + + if ( (sjoy.down) && (sjoy.right)) + { + changedir(3,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'+','+'); + } + + + if ( (sjoy.up) && (sjoy.right)) + { + changedir(9,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'+','-'); + } + } + + if ( (sjoy.button[1] == true)) + { + LogMsg("running through mouse list.."); + run_through_mouse_list(h, true); + sjoy.button[1] = false; + } + +} + +void process_bow( int h) +{ + int timetowait = 100; + + if (g_dglos.g_bowStatus.wait < g_dglos.g_dinkTick) + { + if (sjoy.right) g_sprite[h].dir = 6; + if (sjoy.left) g_sprite[h].dir = 4; + if (sjoy.up) g_sprite[h].dir = 8; + if (sjoy.down) g_sprite[h].dir = 2; + } + + if (sjoy.right) if (sjoy.up) + { + g_sprite[h].dir = 9; + g_dglos.g_bowStatus.wait = g_dglos.g_dinkTick + timetowait; + } + if (sjoy.left) if (sjoy.up) + { + g_sprite[h].dir = 7; + g_dglos.g_bowStatus.wait = g_dglos.g_dinkTick + timetowait; + } + if (sjoy.right) if (sjoy.down) + { + g_sprite[h].dir = 3; + g_dglos.g_bowStatus.wait = g_dglos.g_dinkTick + timetowait; + + } + if (sjoy.left) if (sjoy.down) + { + g_sprite[h].dir = 1; + g_dglos.g_bowStatus.wait = g_dglos.g_dinkTick + timetowait; + + } + g_sprite[h].pseq = 100+g_sprite[h].dir; + + if (g_dglos.g_bowStatus.pull_wait < g_dglos.g_dinkTick) + { + g_dglos.g_bowStatus.pull_wait = g_dglos.g_dinkTick + 10; + if (g_dglos.g_bowStatus.hitme) g_dglos.g_bowStatus.time += 7; + if (g_dglos.g_bowStatus.time > 500) g_dglos.g_bowStatus.time = 500; + + float progress = (float(g_dglos.g_bowStatus.time)/500); //was +1 + + g_sprite[h].pframe = (float(4)*progress)+1; +#ifdef _DEBUG + //LogMsg("sprite %d's pframe is now %d", h, g_sprite[h].pframe); +#endif + + } + + if (sjoy.letgo[1]) + { + g_dglos.g_bowStatus.active = false; + g_dglos.g_bowStatus.last_power = g_dglos.g_bowStatus.time; + run_script(g_dglos.g_bowStatus.script); + return; + } + +} + +bool DinkIsWaitingForSkippableDialog() +{ + return (g_sprite[1].active && g_sprite[1].brain == 1 && g_sprite[1].freeze && !g_dglos.g_talkInfo.active); +} + +bool DinkSkipDialogLine() +{ + bool bSkipped = false; + + for (int jj = 1; jj <= g_dglos.last_sprite_created; jj++) + { + + //Msg("Checking %d, brain %d, script %d, my freeze is %d",jj, spr[jj].brain, spr[jj].script, spr[h].freeze); + if (g_sprite[jj].brain == 8) if (g_sprite[jj].script == g_dglos.g_playerInfo.last_talk) + { + //this sprite owns its freeze + + g_sprite[jj].kill_timer = 1; + + //force the message to be over + bSkipped = true; + } + } + + return bSkipped; +} + +bool DinkCanRunScriptNow() +{ + if (GetDinkGameMode() != DINK_GAME_MODE_NORMAL) return false; + + if (!g_sprite[1].active) return false; + + if (g_sprite[1].move_active) return false; + + if (g_sprite[1].nocontrol) return false; + + if (g_sprite[1].freeze) return false; + + if (GetDinkSubGameMode() == DINK_SUB_GAME_MODE_DIALOG) return false; + if (GetDinkSubGameMode() == DINK_SUB_GAME_MODE_SHOWING_BMP) return false; + + if (g_bTransitionActive) return false; + return true; +} + +bool DinkLoadPlayerScript(const string fileName) +{ + int mycrap = load_script(fileName.c_str(), 1, false, true); + if (locate(mycrap, (char*)"MAIN")) + { + run_script(mycrap); + return true; + } + + return false; +} + +void human_brain(int h) +{ + int diag; + int crap; + bool bad; + + if (g_dglos.g_gameMode == 0) goto b1end; + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].damage > 0) + { + draw_damage(h); + + *plife -= g_sprite[h].damage; + + g_sprite[h].damage = 0; + if (*plife < 0) *plife = 0; + + int hurt = (rand() % 2)+1; + + if (hurt == 1) SoundPlayEffect( 15,25050, 2000 ,0,0); + if (hurt == 2) SoundPlayEffect( 16,25050, 2000 ,0,0); + + //draw blood + } + + + if (g_dglos.g_playerInfo.push_active) + { + + if (g_dglos.g_playerInfo.push_dir == 2) if (!sjoy.down) + { + g_sprite[h].nocontrol = false; + g_dglos.g_playerInfo.push_active = false; + } + + if (g_dglos.g_playerInfo.push_dir == 4) if (!sjoy.left) + { + g_sprite[h].nocontrol = false; + g_dglos.g_playerInfo.push_active = false; + } + if (g_dglos.g_playerInfo.push_dir == 6) if (!sjoy.right) + { + g_sprite[h].nocontrol = false; + g_dglos.g_playerInfo.push_active = false; + } + + if (g_dglos.g_playerInfo.push_dir == 8) if (!sjoy.up) + { + g_sprite[h].nocontrol = false; + g_dglos.g_playerInfo.push_active = false; + } + } + + if (g_sprite[h].nocontrol) return; + + if (g_dglos.g_talkInfo.active) goto freeze; + + + if ( g_sprite[h].freeze) + { + //they are frozen + + if ( (sjoy.button[2] == true) || (sjoy.key[32])) + { + //they hit the talk button while frozen, lets hurry up the process + + DinkSkipDialogLine(); + } + goto freeze; + } + //****************************** KEYS THAT CAN BE PRESSED AT ANY TIME ************** + + if (g_dglos.g_bowStatus.active) + { + //bow is active!! + process_bow(h); + return; + } + + if (g_dglos.g_playerInfo.push_active) if (g_dglos.g_playerInfo.push_timer + 600 < g_dglos.g_dinkTick) + { + g_sprite[h].seq = g_dglos.mDinkBasePush+g_sprite[h].dir; + g_sprite[h].frame = 1; + g_sprite[h].nocontrol = true; + //play.push_active = false; + run_through_tag_list_push(h); + return; + } + + if ( (sjoy.button[2] == true) ) + { + if (!run_through_tag_list_talk(h)) + { + //redink1 addition of 'not talking to anything' script + + int sc = load_script("DNOTALK", 0, false, true); + if (sc != 0 && locate(sc,"MAIN")) + { + run_script(sc); + } + else + + { + kill_text_owned_by(h); + int randy = (rand() % 6)+1; + + if (randy == 1) say_text((char*)"`$I don't see anything here.",h,0); + if (randy == 2) say_text((char*)"`$Huh?",h,0); + if (randy == 3) say_text((char*)"`$I'm fairly sure I can't talk to or use that.",h,0); + if (randy == 4) say_text((char*)"`$What?",h,0); + if (randy == 5) say_text((char*)"`$I'm bored.",h,0); + if (randy == 6) say_text((char*)"`$Not much happening here.",h,0); + } + } + } + + if ( (sjoy.button[1] == true) && (g_dglos.weapon_script != 0) && (!sjoy.button[2] == true)) + { + + if (g_sprite[h].base_hit > 0) + { + if (locate(g_dglos.weapon_script, "USE")) run_script(g_dglos.weapon_script); + + goto b1end; + } + } + +#ifdef C_DINK_KEYBOARD_INPUT + //added AGAIN 10-19-99 + //Let's check keys for getting hit + + /* + int x5; + if (g_bHasFocus) + { + + if (g_dglos.but_timer < g_dglos.g_dinkTick) + { + for (x5=29; x5<255; x5++) + { + if (x5 == 32) x5++; + if (x5 == 54) x5++; + if (x5 == 55) x5++; + if (x5 == 37) x5++; + if (x5 == 38) x5++; + if (x5 == 39) x5++; + if (x5 == 40) x5++; + if (x5 == 77) x5++; + + char msg[32]; + + if (GetKeyboard(x5)) + { + sprintf(msg, "key-%d",x5); + g_dglos.but_timer = g_dglos.g_dinkTick+200; + + + if (DinkLoadPlayerScript(msg)) + { + goto b1end; + } + } + } + } + } + */ +#endif + + + if ( sjoy.button[6] == true ) + { + int mycrap = load_script("BUTTON6", 1, false, true); //map + if (locate(mycrap, (char*)"MAIN")) run_script(mycrap); + goto b1end; + } + + if ( sjoy.button[7] == true ) + { + int mycrap = load_script("BUTTON7", 1, false, true); + if (locate(mycrap, (char*)"MAIN")) run_script(mycrap); + goto b1end; + } + + if ( sjoy.button[8] == true ) + { + int mycrap = load_script("BUTTON8", 1, false, true); + if (locate(mycrap, (char*)"MAIN")) run_script(mycrap); + goto b1end; + } + + if ( sjoy.button[9] == true ) + { + int mycrap = load_script("BUTTON9", 1, false, true); + if (locate(mycrap, (char*)"MAIN")) run_script(mycrap); + goto b1end; + } + + if ( sjoy.button[10] == true ) + { + int mycrap = load_script("BUTTON10", 1, false, true); + if (locate(mycrap, (char*)"MAIN")) run_script(mycrap); + goto b1end; + } + + if (g_dglos.magic_script != 0) if (sjoy.joybit[3]) goto shootm; + if ( (sjoy.button[3] == true) ) + { + if (g_dglos.magic_script == 0) + { + //redink1 addition of 'no magic' script + + int sc = load_script("DNOMAGIC", 0, false, true); + if (sc != 0 && locate(sc,"MAIN")) + { + run_script(sc); + } + else + + { + int randy = (rand() % 6)+1; + kill_text_owned_by(h); + + if (randy == 1) say_text((char*)"`$I don't know any magic.",h,0); + if (randy == 2) say_text((char*)"`$I'm no wizard!",h,0); + if (randy == 3) say_text((char*)"`$I need to learn magic before trying this.",h,0); + if (randy == 4) say_text((char*)"`$I'm gesturing wildly to no avail!",h,0); //redink1 removed an extra space + if (randy == 5) say_text((char*)"`$Nothing happened.",h,0); + if (randy == 6) say_text((char*)"`$Hocus pocus!",h,0); + } + + goto b1end; + } + + //player pressed 1 + //lets magiced something +shootm: + if (*pmagic_level >= *pmagic_cost) + { + if (locate(g_dglos.magic_script, "USE")) run_script(g_dglos.magic_script); + + goto b1end; + } + } + + if (sjoy.button[4]) + { + //redink1 addition of 'enter key/inventory' script + int sc = load_script("BUTTON4", 0, false, true); + if (sc != 0) { + if (locate(sc,"MAIN")) { + run_script(sc); + return; + } + } + + g_itemScreenActive = true; + if (!IsLargeScreen() || IsIphone4Size) + { + g_dglo.SetViewOverride(DinkGlobals::VIEW_ZOOMED); + } + SoundPlayEffect(18, 22050,0,0,0); + return; + } + +#if defined(C_DINK_KEYBOARD_INPUT) && defined(_DEBUG) + + if ( GetKeyboard(50) ) + { + if (g_bHasFocus) + { + + //player pressed 2 + //lets add a duck with brain 2 + + crap = add_sprite(g_sprite[h].x-20,g_sprite[h].y-50,3,26,1); + g_sprite[crap].speed = 1; + g_sprite[crap].base_walk = 20; + g_sprite[crap].exp = 11; + g_sprite[crap].hitpoints = 5; + } + } +#endif + + if ( (sjoy.button[5] == true) ) + { + + if (!g_dglos.g_bShowingBitmap.active) if (!g_dglos.g_bowStatus.active) if (!g_dglos.g_talkInfo.active) + { + int sc = load_script("ESCAPE", 1000, false); + if (sc != 0) if (locate(sc,"MAIN")) run_script(sc); + return; + } + } + + if (g_sprite[h].skip > 0) + + if (g_sprite[h].skip <= g_sprite[h].skiptimer) + { + g_sprite[h].skiptimer = 0; + goto b1end; + } + + diag = 0; + if (sjoy.right) diag++; + if (sjoy.left) diag++; + if (sjoy.down) diag++; + if (sjoy.up) diag++; + + //*********************************PROCESS MOVEMENT + + if (diag == 1) + { + + if (sjoy.right) + { + move(h,g_sprite[h].speed,'+','0'); + changedir(6,h,g_sprite[h].base_walk); + } + + if (sjoy.left) + { + move(h,g_sprite[h].speed,'-','0'); + changedir(4,h,g_sprite[h].base_walk); + } + + if (sjoy.down) + { + move(h,g_sprite[h].speed,'0','+'); + changedir(2,h,g_sprite[h].base_walk); + } + + + if (sjoy.up) + { + move(h,g_sprite[h].speed,'0','-'); + changedir(8,h,g_sprite[h].base_walk); + } + + } + // ***************** DIAGONAL!!!! + + + if (diag > 1) if (diag < 3) + { + + if ( (sjoy.up) && (sjoy.left) ) + { + changedir(7,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'-','-'); + + } + + if ( (sjoy.down) && (sjoy.left)) + { + changedir(1,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'-','+'); + + } + + if ( (sjoy.down) && (sjoy.right)) + { + changedir(3,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'+','+'); + } + + + if ( (sjoy.up) && (sjoy.right)) + { + changedir(9,h,g_sprite[h].base_walk); + move(h,g_sprite[h].speed - (g_sprite[h].speed / 3),'+','-'); + } + + } + + bad = false; + if (sjoy.right) bad = true; + if (sjoy.left) bad = true; + if (sjoy.up) bad = true; + if (sjoy.down) bad = true; + + if (bad) + { + if (g_sprite[h].idle) + { + g_sprite[h].frame = 1; + g_sprite[h].idle = false; + } + goto badboy; + } + + + if (not_in_this_base(g_sprite[h].seq, g_sprite[h].base_idle)) //uncomment to allow walk anim to end before idle anim to start + { +freeze: + if (g_sprite[h].dir == 1) g_sprite[h].dir = 2; + if (g_sprite[h].dir == 3) g_sprite[h].dir = 2; + if (g_sprite[h].dir == 7) g_sprite[h].dir = 8; + if (g_sprite[h].dir == 9) g_sprite[h].dir = 8; + + if (g_sprite[h].base_idle != 0) changedir(g_sprite[h].dir,h,g_sprite[h].base_idle); + g_sprite[h].idle = true; + } +badboy: + +b1end:; + +check_sprite_status(h); + + if ( (g_sprite[h].dir == 2) | (g_sprite[h].dir == 4) | (g_sprite[h].dir == 6) | (g_sprite[h].dir == 8)) goto smoothend; + crap = check_if_move_is_legal(h); + if (crap != 0) + { + if (g_dglos.g_smallMap.sprite[crap-100].prop != 0) g_dglos.flub_mode = crap; + + //hit something, can we move around it? + + + if( (g_sprite[h].seq == g_sprite[h].base_walk + 4) | + (g_sprite[h].seq == g_sprite[h].base_walk + 6) ) + { + int hardm = get_hard_play(h, g_sprite[h].x, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].y -= 1; + } + } + + if( (g_sprite[h].seq == g_sprite[h].base_walk + 8) | + (g_sprite[h].seq == g_sprite[h].base_walk + 2) ) + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y); + if (hardm == 0) + { + g_sprite[h].x -= 1; + } + } + + if (g_sprite[h].seq == g_sprite[h].base_walk + 9) + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y); + if (hardm == 0) + { + g_sprite[h].x += 1; + + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y+1); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y += 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y+2); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y += 2; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].y -= 1; + + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y -= 1; + } + + } + } + } + } + } + + if (g_sprite[h].seq == g_sprite[h].base_walk + 7) + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y); + if (hardm == 0) + { + g_sprite[h].x -= 1; + + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y+1); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y += 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y+2); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y += 2; + } else + { + + int hardm = get_hard_play(h, g_sprite[h].x, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].y -= 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y -= 1; + } + } + } + } + } + } + + if (g_sprite[h].seq == g_sprite[h].base_walk + 1) + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y); + if (hardm == 0) + { + g_sprite[h].x -= 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y -= 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y-2); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y -= 2; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x, g_sprite[h].y+1); + if (hardm == 0) + { + + g_sprite[h].y += 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y+1); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y += 1; + } + + } + + } + + } + } + + } + + if (g_sprite[h].seq == g_sprite[h].base_walk + 3) + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y); + if (hardm == 0) + { + g_sprite[h].x += 1; + + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y-1); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y -= 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x+1, g_sprite[h].y-2); + if (hardm == 0) + { + g_sprite[h].x += 1; + g_sprite[h].y -= 2; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x, g_sprite[h].y+1); + if (hardm == 0) + { + + g_sprite[h].y += 1; + } else + { + int hardm = get_hard_play(h, g_sprite[h].x-1, g_sprite[h].y+1); + if (hardm == 0) + { + g_sprite[h].x -= 1; + g_sprite[h].y += 1; + } + + } + + } + + } + + + } + + } + } + + +smoothend:; +} + + + +int find_sprite(int block) +{ + + for (int k = 1; k <= g_dglos.last_sprite_created; k++) + { + if (g_sprite[k].sp_index == block) + { + return(k); + } + } + return(0); +} + +int special_block(int block, int h) +{ + if (g_dglos.g_smallMap.sprite[block].prop == 1) + { + //they touched a warp + + if (g_dglos.g_smallMap.sprite[block].sound == 0) + SoundPlayEffect( 7,12000, 0 , 0,0); else + SoundPlayEffect( g_dglos.g_smallMap.sprite[block].sound,22050, 0 , 0,0); + + if (g_dglos.g_smallMap.sprite[block].parm_seq != 0) + { + //we'll also play an animation here + + int sprite = find_sprite(block); + if (sprite > 0) + { + g_sprite[sprite].seq = g_dglos.g_smallMap.sprite[block].parm_seq; + g_dglos.process_warp = block; + } + return(1); + } + g_dglos.process_warp = block; + + return(1); //redraw screen with fade + } + return(0); +} + +void down_cycle() +{ + //redink1 truecolor fadedown... + g_dglos.process_downcycle = true; + + float alpha = float(g_dglos.g_dinkTick - g_dglos.cycle_clock)/ (float)C_DINK_FADE_TIME_MS; + ForceRange(alpha, 0, 1); + g_dinkFadeAlpha = alpha; + +// LogMsg("Alpha is %.2f", alpha); +} + +void up_cycle(void) +{ + //redink1 added this for true-color fade support + g_dglos.process_upcycle = true; + + float alpha = float(g_dglos.g_dinkTick - g_dglos.cycle_clock)/ (float)C_DINK_FADE_TIME_MS; + ForceRange(alpha, 0, 1); + g_dinkFadeAlpha = 1-alpha; + + + // LogMsg("Alpha is %.2f", alpha); +} + +void draw_box(rtRect32 box, int color) +{ + + DrawRect(box); + //DDBLTFX ddbltfx; + + + //ddbltfx.dwSize = sizeof(ddbltfx); + //ddbltfx.dwFillColor = color; + //ddrval = lpDDSBack->Blt(&box ,NULL, NULL, DDBLT_COLORFILL| DDBLT_WAIT, &ddbltfx); +} + +//redink1 and Invertigo fix for windowed/high color mode +void flip_it(void) +{ + + //redink1 fix for true-color transition + //The idea is to apply the fade to the backbuffer right before the main flip/blt. + if (g_dglos.process_downcycle || g_dglos.process_upcycle || g_dglos.bFadedDown) + { + + //Make sure we're not 'stuck'... i.e. fade down when already black, or fade up when not black + if (g_dglos.process_downcycle && g_dglos.bFadedDown || g_dglos.process_upcycle && !g_dglos.bFadedDown) + { + if (g_dglos.process_downcycle) + g_dglos.process_downcycle = false; + if (g_dglos.process_upcycle) + { + g_dglos.process_upcycle = false; + if ( g_dglos.mSwapped ) + { + + g_dglos.mSwapped = false; + } + } + + if (g_dglos.cycle_script != 0) + { + int junk = g_dglos.cycle_script; + g_dglos.cycle_script = 0; + run_script(junk); + } + } + + if ( g_dglos.process_downcycle || g_dglos.bFadedDown || g_dglos.process_upcycle ) + { + //just tell them the fade is complete for now + + if ( g_dglos.process_downcycle == true ) + { + + if (g_dglos.g_dinkTick > g_dglos.cycle_clock+C_DINK_FADE_TIME_MS) + { + g_dglos.bFadedDown = true; + } + + } + else if ( g_dglos.process_upcycle == true ) + { + if (g_dglos.g_dinkTick > g_dglos.cycle_clock+C_DINK_FADE_TIME_MS) + { + g_dglos.bFadedDown = false; + } + + } + } + } +} + +void run_through_tag_list(int h, int strength) +{ + rtRect32 box; + int amount, amounty; + + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + if (g_sprite[i].active) if (i != h) if + (! ( (g_sprite[i].nohit == 1) && (g_sprite[i].script == 0)) ) + { + box = g_dglos.g_picInfo[getpic(i)].hardbox; + OffsetRect(&box, g_sprite[i].x, g_sprite[i].y); + box.right += 5; + box.left -= 5; + box.top -= 5; + box.bottom += 10; + if (g_sprite[h].range == 0) + amount = 28; else amount = g_sprite[h].range; + + if (g_sprite[h].range == 0) + amounty = 36; else amounty = (g_sprite[h].range + (g_sprite[h].range / 6)); + + int range_amount = g_sprite[h].range / 8; + + if (g_sprite[h].dir == 6) + { + box.top -= 10; + box.bottom += 10; + if (g_sprite[h].range != 0) box.top -= range_amount; + if (g_sprite[h].range != 0) box.bottom += range_amount; + box.left -= amount; + } + + if (g_sprite[h].dir == 4) + { + box.right += amount; + + box.top -= 10; + box.bottom += 10; + if (g_sprite[h].range != 0) box.top -= range_amount; + if (g_sprite[h].range != 0) box.bottom += range_amount; + } + + if (g_sprite[h].dir == 2) + { + box.right += 10; + box.left -= 10; + box.top -= amounty; + + if (g_sprite[h].range != 0) box.right += range_amount; + if (g_sprite[h].range != 0) box.left -= range_amount; + } + + if (g_sprite[h].dir == 8) + { + box.right += 10; + box.left -= 10; + box.bottom += amounty; + + if (g_sprite[h].range != 0) box.right += range_amount; + if (g_sprite[h].range != 0) box.right -= range_amount; + } + + if (debug_mode) draw_box(box, 33); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + //redink1 addition for fixing missle_source problems + *pmissle_source = h; + if (g_sprite[i].nohit == 1) + { + if (g_sprite[i].script > 0) + { + //if ( (spr[i].brain == 0) | (spr[i].brain == 5) | (spr[i].brain == 6) | (spr[i].brain == 7)) + *penemy_sprite = h; + + if ( (g_sprite[i].base_attack != -1) || (g_sprite[i].touch_damage > 0)) + g_sprite[i].target = h; + + if (locate(g_sprite[i].script, "HIT")) + { + kill_returning_stuff(g_sprite[i].script); + run_script(g_sprite[i].script); + } + } + + } else + { + //hit this personb/thing + if (g_sprite[h].attack_hit_sound == 0) + { + SoundPlayEffect( 9,22050, 0 ,0,0); + } else + { + SoundPlayEffect( g_sprite[h].attack_hit_sound,g_sprite[h].attack_hit_sound_speed, 0 ,0,0); + } + if ( (g_sprite[i].base_attack != -1) || (g_sprite[i].touch_damage > 0)) + g_sprite[i].target = h; + if (g_sprite[h].strength == 0) + { + + } else + { + if ( (g_sprite[i].hitpoints > 0) || (i == 1) ) + { + + g_sprite[i].last_hit = h; + if ( hurt_thing(i, (g_sprite[h].strength / 2) + ((rand() % ((g_sprite[h].strength+1) / 2))+1), 0) > 0) + random_blood(g_sprite[i].x, g_sprite[i].y-40, i); //redink1 + } + + } + if (g_sprite[i].script > 0) + { + //if ( (spr[i].brain == 0) | (spr[i].brain == 5) | (spr[i].brain == 6) | (spr[i].brain == 7)) + g_sprite[i].last_hit = h; + *penemy_sprite = h; + if ( (g_sprite[i].base_attack != -1) || (g_sprite[i].touch_damage > 0)) + g_sprite[i].target = h; + + if (locate(g_sprite[i].script, "HIT")) + { + kill_returning_stuff(g_sprite[i].script); + run_script(g_sprite[i].script); + } + + } + + } + + } + + } + + } + +} + + + +void run_through_tag_list_push(int h) +{ + rtRect32 box; + + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + if (g_sprite[i].active) if (i != h) if + ((g_sprite[i].script != 0) ) + { + + box = g_dglos.g_picInfo[getpic(i)].hardbox; + OffsetRect(&box, g_sprite[i].x, g_sprite[i].y); + + //InflateRect(&box, 10,10); + + box.right += 2; + box.left -= 2; + box.top -= 2; + box.bottom += 2; + //draw_box(box, 33); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + if (locate(g_sprite[i].script, "PUSH")) run_script(g_sprite[i].script); + } + } + } +} + +void run_through_touch_damage_list(int h) +{ + rtRect32 box; + + for (int i = 1; i <= g_dglos.last_sprite_created; i++) + { + if (g_sprite[i].active) if (i != h) if + ((g_sprite[i].touch_damage != 0) ) + { + + if (g_sprite[i].touch_damage != -1) if (g_sprite[h].notouch) return; + box = g_dglos.g_picInfo[getpic(i)].hardbox; + OffsetRect(&box, g_sprite[i].x, g_sprite[i].y); + + //InflateRect(&box, 10,10); + + box.right += 2; + box.left -= 2; + box.top -= 2; + box.bottom += 2; + if (debug_mode) + draw_box(box, 33); + + if (inside_box(g_sprite[h].x, g_sprite[h].y, box)) + { + + if ((g_sprite[i].touch_damage == -1) && (g_sprite[i].script != 0)) + { + if (locate(g_sprite[i].script, "TOUCH")) run_script(g_sprite[i].script); + } else + { + if (g_sprite[i].touch_damage == -1) + { + LogMsg("Sprites touch damage is set to -1 but there is no script set!"); + } else + { + //lets hurt the guy + + g_sprite[h].notouch = true; + g_sprite[h].notouch_timer = g_dglos.g_dinkTick+400; + g_sprite[h].last_hit = i; + if (g_sprite[i].script != 0) + if (locate(g_sprite[i].script, "TOUCH")) run_script(g_sprite[i].script); + if (hurt_thing(h, g_sprite[i].touch_damage, 0) > 0) + random_blood(g_sprite[h].x, g_sprite[h].y-40, h); + } + } + + } + } + } +} + + +void process_warp_man(void) +{ + rtRect32 box_crap; + DDBLTFX ddbltfx; + + int sprite = find_sprite(g_dglos.process_warp); + + if (sprite == 0 || g_sprite[sprite].seq == 0) + { + g_dglos.process_count++; + + if (g_dglos.process_count == 1) + { + g_dglos.cycle_clock = g_dglos.g_dinkTick; + + //redink1 Limit palette cycles for true color mode + down_cycle(); + } + + if (g_dglos.process_downcycle == false) //redink1 more limits for fade down stuff + { + ddbltfx.dwSize = sizeof(ddbltfx); + + ddbltfx.dwFillColor = 0; + box_crap = rtRect32 (0,0,C_DINK_SCREENSIZE_X,C_DINK_SCREENSIZE_Y); + + //int ddrval = lpDDSBack->Blt(&box_crap ,NULL, NULL, DDBLT_COLORFILL| DDBLT_WAIT, &ddbltfx); + + flip_it(); + + g_dglos.process_count = 0; + int block = g_dglos.process_warp; + update_screen_time(); + g_sprite[1].x = g_dglos.g_smallMap.sprite[block].warp_x; + g_sprite[1].y = g_dglos.g_smallMap.sprite[block].warp_y; + *pmap = g_dglos.g_smallMap.sprite[block].warp_map; + + //redink1 change so map indicator is correct on warp. + if (g_MapInfo.indoor[g_dglos.g_smallMap.sprite[block].warp_map] == 0) + g_dglos.g_playerInfo.last_map = g_dglos.g_smallMap.sprite[block].warp_map; + + load_map(g_MapInfo.loc[g_dglos.g_smallMap.sprite[block].warp_map]); + + BuildScreenBackground(); + + g_dglos.cycle_clock = g_dglos.g_dinkTick; + g_dinkFadeAlpha = 1; + g_dglos.process_upcycle = true; + g_dglos.process_warp = 0; + } + + } else + { + g_dglos.process_count = 0; + } + +} + +void one_time_brain(int h) +{ + + //goes once then draws last frame to background + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].follow > 0) + { + process_follow(h); + } + + + if (g_sprite[h].seq == 0) + { + + g_dglo.m_bgSpriteMan.Add(h); + //draw_sprite_game(lpDDSTwo,h); + g_sprite[h].active = false; + return; + } + + changedir(g_sprite[h].dir,h,-1); + automove(h); + +} + +void one_time_brain_for_real(int h) +{ + + if (g_sprite[h].move_active) + { + process_move(h); + } + + if (g_sprite[h].follow > 0) + { + process_follow(h); + } + + if (g_sprite[h].seq == 0) + { + g_sprite[h].active = false; + return; + } + + if (g_sprite[h].dir > 0) + { + changedir(g_sprite[h].dir,h,-1); + automove(h); + } +} + +void scale_brain(int h) +{ + if (g_sprite[h].size == g_sprite[h].brain_parm) + { + g_sprite[h].active = false; + return; + } + + int num = 5 * (g_dglos.base_timing / 4); + + if (g_sprite[h].size > g_sprite[h].brain_parm) + { + if (g_sprite[h].size - num < g_sprite[h].brain_parm) num = g_sprite[h].size - g_sprite[h].brain_parm; + g_sprite[h].size -= num; + } + + if (g_sprite[h].size < g_sprite[h].brain_parm) + { + if (g_sprite[h].size + num > g_sprite[h].brain_parm) num = g_sprite[h].brain_parm - g_sprite[h].size; + g_sprite[h].size += num; + } + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].dir > 0) + { + changedir(g_sprite[h].dir,h,-1); + automove(h); + } +} + +void repeat_brain(int h) +{ + + if (g_sprite[h].move_active) + { + process_move(h); + } + + if (g_sprite[h].seq_orig == 0) if (g_sprite[h].sp_index != 0) + { + g_sprite[h].seq_orig = g_dglos.g_smallMap.sprite[g_sprite[h].sp_index].seq; + g_sprite[h].frame = g_dglos.g_smallMap.sprite[g_sprite[h].sp_index].frame; + g_sprite[h].wait = 0; + } + + if (g_sprite[h].seq == 0) g_sprite[h].seq = g_sprite[h].seq_orig; + +} + + +void text_brain(int h) +{ + + if ( (g_sprite[h].damage == -1) && (g_sprite[h].owner != 1000)) + { + + if (g_sprite[g_sprite[h].owner].active == false) + { + //msg("Killing text brain %d, because owner %d is dead.",h, spr[h].owner); + g_sprite[h].active = false; + return; + } + + //give this text the cords from it's owner sprite + g_sprite[h].x = g_sprite[g_sprite[h].owner].x - g_sprite[h].strength; + + + g_sprite[h].y = g_sprite[g_sprite[h].owner].y - g_sprite[h].defense; + + if (g_sprite[h].x < 1) g_sprite[h].x = 1; + + if (g_sprite[h].y < 1) g_sprite[h].y = 1; + + + } else + { + //Msg("automoving %d.. ", h); + + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + automove(h); + } + +} + + +void process_talk() +{ + + int px = 48, py = 44; + + int sx = 184; + int sy = 94, sy_hold, sy_ho; + int spacing = 12; + int curxl = 126; + int curxr = 462; + int curyr = 200; + int curyl = 200; + + int y_last = 0, y_hold = 0, y_ho = 0; + rtRect32 rcRect; + int i; + int x_depth = 335; + if (g_dglos.g_talkInfo.newy != -5000) + sy = g_dglos.g_talkInfo.newy; + + sy_hold = sy; + sy_ho = sy; + int ddrval; + + int fake_page; + + if (check_seq_status(30)) + { + + + + ddrval = lpDDSBack->BltFast( px, py, g_pSpriteSurface[g_dglos.g_seq[30].frame[2]], + &g_dglos.g_picInfo[g_dglos.g_seq[30].frame[2]].box , DDBLTFAST_SRCCOLORKEY ); + + + ddrval = lpDDSBack->BltFast( px+169, py+42, g_pSpriteSurface[g_dglos.g_seq[30].frame[3]], + &g_dglos.g_picInfo[g_dglos.g_seq[30].frame[3]].box , DDBLTFAST_SRCCOLORKEY ); + + ddrval = lpDDSBack->BltFast( px+169+180, py+1, g_pSpriteSurface[g_dglos.g_seq[30].frame[4]], + &g_dglos.g_picInfo[g_dglos.g_seq[30].frame[4]].box , DDBLTFAST_SRCCOLORKEY ); + + } + + int talk_hold = g_dglos.g_talkInfo.cur; +// if (sjoy.rightd) g_dglos.g_talkInfo.cur++; +// if (sjoy.leftd) g_dglos.g_talkInfo.cur--; + + if (sjoy.downd) g_dglos.g_talkInfo.cur++; + if (sjoy.upd) g_dglos.g_talkInfo.cur--; + + + if (g_dglos.g_playerInfo.mouse > 20) + { + g_dglos.g_talkInfo.cur++; + g_dglos.g_playerInfo.mouse = 0; + } + + if (g_dglos.g_playerInfo.mouse < -20) + { + g_dglos.g_talkInfo.cur--; + g_dglos.g_playerInfo.mouse = 0; + } + + if (talk_hold != g_dglos.g_talkInfo.cur) + { + if (g_dglos.g_talkInfo.cur >= g_dglos.g_talkInfo.cur_view) if (g_dglos.g_talkInfo.cur <= g_dglos.g_talkInfo.cur_view_end) + SoundPlayEffect(11, 22050,0,0,0); + } +uint32 rgbColor = MAKE_RGBA(255,255,255,255); + + if (strlen(g_dglos.g_talkInfo.buffer) > 0) + { + + rcRect = rtRect32 (sx,94,463,400); + if (g_dglos.g_talkInfo.newy != -5000) rcRect.bottom = g_dglos.g_talkInfo.newy+15; + + int color = 15; + + // SetTextColor(hdc,RGB(8,14,21)); + //DrawText(hdc,talk.buffer,strlen(talk.buffer),&rcRect,DT_VCENTER | DT_CENTER | DT_WORDBREAK); + + if (g_dglos.g_talkInfo.color >= 1 && g_dglos.g_talkInfo.color <= 15) + { + color = g_dglos.g_talkInfo.color; + } + + rgbColor = MAKE_RGBA(g_dglos.font_colors[color].red, g_dglos.font_colors[color].green, g_dglos.font_colors[color].blue, 255); + + // OffsetRect(&rcRect, 1, 1); + //DrawText(hdc,talk.buffer,strlen(talk.buffer),&rcRect,DT_VCENTER | DT_CENTER | DT_WORDBREAK); + + rtRect rTemp(rcRect); + + GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, g_dglos.g_talkInfo.buffer, true, false, rgbColor, g_dglo.m_fontSize) ; + // SetTextColor(hdc,RGB(8,14,21)); + } + + //tabulate distance needed by text, LORDII experience helped here + + for (i = g_dglos.g_talkInfo.cur_view; i < g_dglos.g_talkInfo.last; i++) + { + rcRect = rtRect32 (sx,y_hold,463,x_depth+100); + rtRect rTemp(rcRect); + + y_hold = (int)GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, g_dglos.g_talkInfo.line[i], true, false, rgbColor, g_dglo.m_fontSize, true).y; + sy_hold += y_hold; + + //Msg("Sy_hold = %d (%d)", sy_hold,i); + + if (sy_hold > x_depth) + { + + g_dglos.g_talkInfo.cur_view_end = i-1; + //Msg("Sy is over, sp cur_view is %d ", talk.cur_view_end); + goto death; + } + } + + g_dglos.g_talkInfo.cur_view_end = i; + + if (g_dglos.g_talkInfo.cur_view == 1) if (g_dglos.g_talkInfo.cur_view_end == g_dglos.g_talkInfo.last) + { + + //Msg("Small enough to fit on one screen, lets center it!"); + sy += ( (x_depth - sy_hold) / 2) - 20; + + } +death: + + + if (g_dglos.g_talkInfo.cur > g_dglos.g_talkInfo.last) + { + SoundPlayEffect(11, 22050,0,0,0); + + g_dglos.g_talkInfo.cur = 1; + + } + if (g_dglos.g_talkInfo.cur < 1) + { + SoundPlayEffect(11, 22050,0,0,0); + + g_dglos.g_talkInfo.cur = g_dglos.g_talkInfo.last; + } + + //Msg("Talkcur is %d, talk cur view is %d", talk.cur, talk.cur_view); + //total options too large for page, lets scroll + + + if (g_dglos.g_talkInfo.cur > g_dglos.g_talkInfo.cur_view_end) + { + // Msg("advancing page: talkcur is %d, changing cur_view to same", talk.cur, talk.cur_view); + g_dglos.g_talkInfo.cur_view = g_dglos.g_talkInfo.cur; + g_dglos.g_talkInfo.page ++; + + // Msg("Page advanced to %d. (cur_end is %d, cur is %d)", talk.page,talk.cur_view_end, talk.cur); + goto fin; + } + + if (g_dglos.g_talkInfo.cur < g_dglos.g_talkInfo.cur_view) + { + // Msg("Turning back the clock from page %d..", talk.page); + + g_dglos.g_talkInfo.cur_view = 1; + // talk.cur = 1; + + g_dglos.g_talkInfo.page--; + LogMsg("Page backed to %d.", g_dglos.g_talkInfo.page); + fake_page = 1; + for (i = 1; i < g_dglos.g_talkInfo.last; i++) + { + rcRect = rtRect32 (sx,sy_ho,463,x_depth); + rtRect rTemp = rtRect(rcRect); + + y_ho += (int)GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, g_dglos.g_talkInfo.line[i], true, false, rgbColor, g_dglo.m_fontSize, true).y; + //y_ho = DrawText(hdc,talk.line[i],lstrlen(talk.line[i]),&rcRect,DT_CALCRECT | DT_CENTER | DT_WORDBREAK); + sy_ho += y_ho; + //Msg("adding y_yo %d.. (on %d)", y_ho,i); + if (sy_ho > x_depth) + { + /*if (fake_page == talk.page) + { + goto fin; + } + */ + fake_page++; + sy_ho = sy+ y_ho; + //Msg("Does fake page (%d) match desired page (%d) %d", fake_page, talk.page, i); + } + if (fake_page == g_dglos.g_talkInfo.page) + { + g_dglos.g_talkInfo.cur_view = i; + g_dglos.g_talkInfo.cur_view_end = g_dglos.g_talkInfo.cur; + //Msg("Going to fin with end being %d, and.cur being %d. View is %d.", + // talk.cur_view_end, talk.cur, talk.cur_view); + goto fin; + } + // Msg("Second: Sy is over, sp cur_view is %d", talk.cur_view_end); + } + + g_dglos.g_talkInfo.cur_view_end = i; + } + + //Msg("talk last is %d. cur_view_end is %d, Cur is %d", talk.last, talk.cur_view_end, talk.cur); + + for ( i = g_dglos.g_talkInfo.cur_view; i <= g_dglos.g_talkInfo.cur_view_end; i++) + { + //lets figure out where to draw this line + + rcRect = rtRect32 (sx,sy,463,x_depth+100); + rtRect rTemp=rtRect(rcRect); + + if (i == g_dglos.g_talkInfo.cur) + { + curyl = sy-4; + curyr = sy-4; + // SetTextColor(hdc,RGB(255,255,255)); + rgbColor = MAKE_RGBA(255,255,255,255); + } + else + rgbColor = MAKE_RGBA(255,255,2,255); + + + y_last = (int)GetApp()->GetFont(FONT_SMALL)->DrawWrapped(rTemp, g_dglos.g_talkInfo.line[i], true, false, rgbColor, g_dglo.m_fontSize).y; + sy += y_last; + } + +fin: + + if (g_dglos.g_talkInfo.timer < g_dglos.g_dinkTick) + { + g_dglos.g_talkInfo.curf++; + g_dglos.g_talkInfo.timer = g_dglos.g_dinkTick+100; + } + + if (g_dglos.g_talkInfo.curf == 0) g_dglos.g_talkInfo.curf = 1; + if (g_dglos.g_talkInfo.curf > 7) g_dglos.g_talkInfo.curf = 1; + + + if (check_seq_status(456) && check_seq_status(457)) + { + ddrval = lpDDSBack->BltFast( curxl, curyl, g_pSpriteSurface[g_dglos.g_seq[456].frame[g_dglos.g_talkInfo.curf]], + &g_dglos.g_picInfo[g_dglos.g_seq[456].frame[g_dglos.g_talkInfo.curf]].box , DDBLTFAST_SRCCOLORKEY ); + + ddrval = lpDDSBack->BltFast( curxr, curyr, g_pSpriteSurface[g_dglos.g_seq[457].frame[g_dglos.g_talkInfo.curf]], + &g_dglos.g_picInfo[g_dglos.g_seq[456].frame[g_dglos.g_talkInfo.curf]].box , DDBLTFAST_SRCCOLORKEY ); + } + + if (GetBaseApp()->GetGameTickPause()) return; + + if ( (sjoy.button[1]) || (sjoy.button[2])) + { + g_dglos.g_talkInfo.active = false; + *presult = g_dglos.g_talkInfo.line_return[g_dglos.g_talkInfo.cur]; + SoundPlayEffect(17, 22050,0,0,0); + + if (g_dglos.g_talkInfo.script != 0) + { + //we need to continue a script + run_script(g_dglos.g_talkInfo.script); + } + } +} + +CL_Vec2f NativeToDinkCoords(CL_Vec2f vPos) +{ + return CL_Vec2f( g_dglo.m_orthoRenderRect.left+ vPos.x * g_dglo.m_orthoRenderRect.GetWidth()/GetScreenSizeXf(), vPos.y *g_dglo.m_orthoRenderRect.GetHeight()/GetScreenSizeYf()); +} + + +void DinkSetCursorPosition(CL_Vec2f vPos) +{ + + if (g_sprite[1].active) if (g_sprite[1].brain == 13) + { + g_sprite[1].x = vPos.x; + g_sprite[1].y = vPos.y; + } +} + +void UpdateCursorPosition(int dx, int dy) +{ + /* + * Pick up any leftover fuzz from last time. This is important + * when scaling down mouse motions. Otherwise, the user can + * drag to the right extremely slow for the length of the table + * and not get anywhere. + */ + if (g_sprite[1].active) if (g_sprite[1].brain == 13) + { + g_sprite[1].x += dx; + g_sprite[1].y += dy; + /* Clip the cursor to our client area */ + + if (g_sprite[1].x > C_DINK_SCREENSIZE_X) g_sprite[1].x = C_DINK_SCREENSIZE_X; + if (g_sprite[1].y > C_DINK_SCREENSIZE_Y) g_sprite[1].y = C_DINK_SCREENSIZE_Y; + if (g_sprite[1].x < 0) g_sprite[1].x = 0; + if (g_sprite[1].y < 0) g_sprite[1].y = 0; + } + + /* + if (g_gameMode == 1) + { + g_dglos.g_playerInfo.mouse += dy; + //Msg("play mousey is now %d", play.mouse); + } + */ +} + +void Scrawl_OnMouseInput(void) +{ + /* + if (g_lastMouseClick) + { + mouse1 = true; + g_lastMouseClick = false; + } + + if (g_lastMouseX != 0 || g_lastMouseY != 0) + { + g_lastMouseX = 0; + g_lastMouseY = 0; + } + + */ + + UpdateCursorPosition(0, 0); + +} + +void button_brain(int h ) +{ + rtRect32 box; + if (g_sprite[h].move_active) + { + process_move(h); + return; + } + + if (g_sprite[h].script == 0) return; + + box = g_dglos.g_picInfo[getpic(h)].hardbox; + OffsetRect(&box, g_sprite[h].x, g_sprite[h].y); + + if (g_sprite[h].brain_parm == 0) + { + if (inside_box(g_sprite[1].x, g_sprite[1].y, box)) + { + g_sprite[h].brain_parm = 1; + + if (locate(g_sprite[h].script, "BUTTONON")) + { + run_script(g_sprite[h].script); + return; + } + } + } + else + { + if (!inside_box(g_sprite[1].x, g_sprite[1].y, box)) + { + g_sprite[h].brain_parm = 0; + + if (locate(g_sprite[h].script, "BUTTONOFF")) + { + run_script(g_sprite[h].script); + return; + } + } + } +} + +CL_Rect GetItemRectFromIndex(int num, bool magic) +{ + int mx = 20; + int my = 0; + + int vert = 0; + + if (magic == false) + { + mx = 260; + my = 83; + + vert = ((num-1) / 4); + mx += (((num-1) - (vert * 4)) * (18 + 65)); + my += (vert * (20 + 55)); + } else + { + mx = 45; + my = 83; + + vert = ((num-1) / 2); + mx += (((num-1) - (vert * 2)) * (18 + 65)); + my += (vert * (20 + 55)); + } + + return CL_Rect(mx, my, mx+65, my+55); +} + +const int C_DINK_MAX_ITEMS = 16; +const int C_DINK_MAX_MAGICS = 8; + +void SetCurInventoryPositionIndex(int itemIndex, bool bIsMagic) +{ + + g_dglos.g_playerInfo.item_magic = bIsMagic; + g_dglos.g_playerInfo.curitem = itemIndex; +} + +bool DinkSetInventoryPosition(CL_Vec2f vPos) +{ + + if (g_itemScreenActive) + { + + for (int i = 1; i < C_DINK_MAX_MAGICS+1; i++) + { + if (GetItemRectFromIndex(i, true).contains(vPos)) + { + SetCurInventoryPositionIndex(i, true); + return true; + } + } + + for (int i = 1; i < C_DINK_MAX_ITEMS+1; i++) + { + if (GetItemRectFromIndex(i, false).contains(vPos)) + { + SetCurInventoryPositionIndex(i, false); + return true; + } + } + + } + + return false; //invalid +} + + +void draw_item(int num, bool magic, int mseq, int mframe) +{ + CL_Rectf r = GetItemRectFromIndex(num, magic); + + check_seq_status(mseq); + + if (g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]] == NULL) + { + + if (!magic) + { + LogMsg("Whups, item %d seq %d frame %d not loaded, killed it", + num, mseq, mframe); + g_dglos.g_playerInfo.g_itemData[num].active = false; + } else + { + LogMsg("Whups, magic %d seq %d frame %d not loaded, killed it", + num, mseq, mframe); + g_dglos.g_playerInfo.g_MagicData[num].active = false; + + } + + return; + } + + + int ddrval = lpDDSBack->BltFast( r.left, r.top, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box, DDBLTFAST_SRCCOLORKEY); + +} + +void process_item( void ) +{ + + rtRect32 rcRect; + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = C_DINK_SCREENSIZE_X; + rcRect.bottom = C_DINK_SCREENSIZE_Y; + int hor, virt; + int ddrval; + ddrval = lpDDSBack->BltFast( 0, 0, lpDDSBackGround, &rcRect, DDBLTFAST_NOCOLORKEY); + + if (!check_seq_status(423)) return; + + //lets blit the main screen over it + + ddrval = lpDDSBack->BltFast( 20, 0, g_pSpriteSurface[g_dglos.g_seq[423].frame[1]], &g_dglos.g_picInfo[g_dglos.g_seq[423].frame[1]].box, DDBLTFAST_SRCCOLORKEY); + + //draw all currently owned items; magic + int i; + + for (i = 1; i < C_DINK_MAX_MAGICS+1; i++) + { + if (g_dglos.g_playerInfo.g_MagicData[i].active) draw_item(i, true, g_dglos.g_playerInfo.g_MagicData[i].seq,g_dglos.g_playerInfo.g_MagicData[i].frame); + } + + //draw all currently owned items; normal + for ( i = 1; i < C_DINK_MAX_ITEMS+1; i++) + { + if (g_dglos.g_playerInfo.g_itemData[i].active) draw_item(i, false, g_dglos.g_playerInfo.g_itemData[i].seq,g_dglos.g_playerInfo.g_itemData[i].frame); + + } + + //draw selection box around armed weapon + if (*pcur_weapon != 0) if (g_dglos.g_playerInfo.g_itemData[*pcur_weapon].active) + draw_item(*pcur_weapon, false, 423, 4); + + + //draw selection box around armed magic + if (*pcur_magic != 0) if (g_dglos.g_playerInfo.g_itemData[*pcur_magic].active) + draw_item(*pcur_magic, true, 423, 5); + + + //draw the selector around it, alternating from 2 to 3 + if (g_dglos.g_playerInfo.curitem < 1) g_dglos.g_playerInfo.curitem = 1; + + + if (g_dglos.g_dinkTick > g_dglos.item_timer) + { + if (g_dglos.item_pic == 2) g_dglos.item_pic = 3; else g_dglos.item_pic = 2; + g_dglos.item_timer = g_dglos.g_dinkTick + 400; + + } + + draw_item(g_dglos.g_playerInfo.curitem, g_dglos.g_playerInfo.item_magic, 423, g_dglos.item_pic); + + if (!g_dglos.g_playerInfo.item_magic) + { + + + hor = (g_dglos.g_playerInfo.curitem - (((g_dglos.g_playerInfo.curitem-1) / 4) * 4)); + virt = ((g_dglos.g_playerInfo.curitem-1) / 4); + + //choosing weapon/item + + if (sjoy.button[1]|| sjoy.button[4]) + { + if (g_dglos.g_playerInfo.g_itemData[g_dglos.g_playerInfo.curitem].active) + { + //arm weapon + SoundPlayEffect(18, 42050,0,0,0); + if (*pcur_weapon != 0) + { + //disarm old weapon + if (locate(g_dglos.weapon_script, "DISARM")) run_script(g_dglos.weapon_script); + } + //load weapons script + *pcur_weapon = g_dglos.g_playerInfo.curitem; + g_dglos.weapon_script = load_script(g_dglos.g_playerInfo.g_itemData[*pcur_weapon].name, 1000, false); + if (locate(g_dglos.weapon_script, "ARM")) run_script(g_dglos.weapon_script); + if (locate(g_dglos.weapon_script, "ARMMOVIE")) run_script(g_dglos.weapon_script); + + draw_status_all(); + } else + { + //can't arm nothing, play sound + } + } else + if (sjoy.rightd) + { + if (hor < 4) g_dglos.g_playerInfo.curitem++; + SoundPlayEffect(11, 22050,0,0,0); + } else + if (sjoy.leftd) + { + if (hor > 1) + { + g_dglos.g_playerInfo.curitem--; + SoundPlayEffect(11, 22050,0,0,0); + + } + else + { + SoundPlayEffect(11, 22050,0,0,0); + + g_dglos.g_playerInfo.item_magic = true; + g_dglos.g_playerInfo.curitem = (virt * 2) + 2; + //switch to magic mode + } + } else + + + if (sjoy.downd) + { + if (virt < 3) + { + g_dglos.g_playerInfo.curitem += 4; + SoundPlayEffect(11, 22050,0,0,0); + + } + } else + + if (sjoy.upd) + { + if (virt > 0) + { + g_dglos.g_playerInfo.curitem -= 4; + SoundPlayEffect(11, 22050,0,0,0); + + } + } + } else + + { + hor = (g_dglos.g_playerInfo.curitem - (((g_dglos.g_playerInfo.curitem-1) / 2) * 2)); + virt = ((g_dglos.g_playerInfo.curitem-1) / 2); + + if (sjoy.button[1]|| sjoy.button[4]) + { + if (g_dglos.g_playerInfo.g_MagicData[g_dglos.g_playerInfo.curitem].active) + { + //arm magic + SoundPlayEffect(18, 42050,0,0,0); + if (*pcur_magic != 0) + { + //disarm old weapon + if (locate(g_dglos.magic_script, "DISARM")) run_script(g_dglos.magic_script); + } + //load magics script + *pcur_magic = g_dglos.g_playerInfo.curitem; + g_dglos.magic_script = load_script(g_dglos.g_playerInfo.g_MagicData[*pcur_magic].name, 1000, false); + if (locate(g_dglos.magic_script, "ARM")) run_script(g_dglos.magic_script); + if (locate(g_dglos.magic_script, "ARMMOVIE")) run_script(g_dglos.magic_script); + draw_status_all(); + } else + { + //can't arm nothing, play sound + } + } + + if (sjoy.rightd) + { + if (hor < 2) + { + g_dglos.g_playerInfo.curitem++; + SoundPlayEffect(11, 22050,0,0,0); + + } + else + { + g_dglos.g_playerInfo.item_magic = false; + g_dglos.g_playerInfo.curitem = (virt * 4) +1; + SoundPlayEffect(11, 22050,0,0,0); + + } + } else + if (sjoy.leftd) + { + if (hor > 1) + { + g_dglos.g_playerInfo.curitem--; + SoundPlayEffect(11, 22050,0,0,0); + + } + } else + + if (sjoy.downd) + { + if (virt < 3) + { + g_dglos.g_playerInfo.curitem += 2; + SoundPlayEffect(11, 22050,0,0,0); + + } + } else + + if (sjoy.upd) + { + if (virt > 0) + { + g_dglos.g_playerInfo.curitem -= 2; + SoundPlayEffect(11, 22050,0,0,0); + } + } + } + + if (g_dglos.g_talkInfo.active) + { + assert(!"People use this?") ; + process_talk(); + } + + //g_dglo.SetViewOverride(DinkGlobals::VIEW_ZOOMED); + + //a special process callbacks for just stuff that was created in this mode? + // process_callbacks_special(); + flip_it(); + + if (sjoy.button[1] || sjoy.button[4]) + { + SoundPlayEffect(17, 22050,0,0,0); + g_itemScreenActive = false; + g_dglo.SetViewOverride(DinkGlobals::VIEW_NONE); + } +} + +void process_animated_tiles( void ) +{ + rtRect32 rcRect; + int cool; + int flip; + int pa; + + //process water tiles + + if (water_timer < g_dglos.g_dinkTick) + { + + water_timer = g_dglos.g_dinkTick + ((rand() % 2000)); + + flip = ((rand() % 2)+1); + + int tileScreenID; + + for (int x=0; x<96; x++) + { + //redink1 fix for first broken water tile + if (g_dglos.g_smallMap.t[x].num >= 896) if (g_dglos.g_smallMap.t[x].num < (896+128)) + { + + cool = g_dglos.g_smallMap.t[x].num / 128; + pa = g_dglos.g_smallMap.t[x].num - (cool * 128); + rcRect.left = (pa * 50- (pa / 12) * 600); + rcRect.top = (pa / 12) * 50; + rcRect.right = rcRect.left + 50; + rcRect.bottom = rcRect.top + 50; + + tileScreenID = cool+flip; + bool bRequireRebuild; + + LoadTileScreenIfNeeded(tileScreenID, bRequireRebuild); + g_tileScreens[tileScreenID]->UpdateLastUsedTime(); + + lpDDSBackGround->BltFast( (x * 50 - ((x / 12) * 600))+g_gameAreaLeftOffset, (x / 12) * 50, g_tileScreens[tileScreenID], + &rcRect, DDBLTFAST_NOCOLORKEY| DDBLTFAST_WAIT ); + + } + } + + } + + //end of water processing + + if (fire_forward) fire_flip++; + if (!fire_forward) fire_flip--; + + if (fire_flip < 1) + { + fire_flip = 5; + fire_forward = false; + } + + int tileScreenID; + + for (int x=0; x<96; x++) + { + //redink1 fix for first broken fire tile + if (g_dglos.g_smallMap.t[x].num >= 2304) if (g_dglos.g_smallMap.t[x].num < (2304+128)) + { + + cool = g_dglos.g_smallMap.t[x].num / 128; + pa = g_dglos.g_smallMap.t[x].num - (cool * 128); + rcRect.left = (pa * 50- (pa / 12) * 600); + rcRect.top = (pa / 12) * 50; + rcRect.right = rcRect.left + 50; + rcRect.bottom = rcRect.top + 50; + + tileScreenID = cool+fire_flip; + bool bRequireRebuild; + + LoadTileScreenIfNeeded(tileScreenID, bRequireRebuild); + g_tileScreens[tileScreenID]->UpdateLastUsedTime(); + + lpDDSBackGround->BltFast( (x * 50 - ((x / 12) * 600))+g_gameAreaLeftOffset, (x / 12) * 50, g_tileScreens[tileScreenID], + &rcRect, DDBLTFAST_NOCOLORKEY| DDBLTFAST_WAIT ); + + + } + } +} + +void ThinkShowBmp() +{ + if ( (sjoy.button[1]) + || (sjoy.button[2]) + || (sjoy.button[3]) + || (sjoy.button[4]) + || (sjoy.button[5]) + || (sjoy.button[6]) + ) + { + g_dglos.g_bShowingBitmap.active = false; + if (g_dglos.g_bShowingBitmap.script != 0) + run_script(g_dglos.g_bShowingBitmap.script); + g_dglos.g_bShowingBitmap.stime = g_dglos.g_dinkTick+2000; + g_dglos.but_timer = g_dglos.g_dinkTick + 200; + + int sprite = say_text_xy("", 1, 440, 0); + g_sprite[sprite].noclip = 1; + } +} +void process_show_bmp( void ) +{ + rtRect32 rcRect(0,0,C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y); + + lpDDSBack->BltFast( 0, 0, lpDDSBuffer, &rcRect, DDBLTFAST_NOCOLORKEY); + + if (g_dglos.g_bShowingBitmap.showdot) + { + //let's display a nice dot to mark where they are on the map + int x = g_dglos.g_playerInfo.last_map - 1; + int mseq = 165; + + if (check_seq_status(mseq)) + { + g_dglos.g_bShowingBitmap.picframe++; + if (g_dglos.g_bShowingBitmap.picframe > g_dglos.g_seq[mseq].last) g_dglos.g_bShowingBitmap.picframe = 1; + int mframe = g_dglos.g_bShowingBitmap.picframe; + lpDDSBack->BltFast( (x % 32) * 20, (x / 32) * 20, g_pSpriteSurface[g_dglos.g_seq[mseq].frame[mframe]], + &g_dglos.g_picInfo[g_dglos.g_seq[mseq].frame[mframe]].box, DDBLTFAST_SRCCOLORKEY| DDBLTFAST_WAIT ); + } + + + } + +} + +void drawscreenlock( void ) +{ + DrawRect(g_dglo.m_gameArea, MAKE_RGBA( (255-80)+ 80*(SinToZeroToOneRange(SinGamePulseByMS(1000))),0,0,255)); + //TODO draw screenlock + if (check_seq_status(423, 9)) + { + + lpDDSBack->BltFast(0, 0, g_pSpriteSurface[g_dglos.g_seq[423].frame[9]], + &g_dglos.g_picInfo[g_dglos.g_seq[423].frame[9]].box , DDBLTFAST_NOCOLORKEY ); + } + + if (check_seq_status(423, 10)) + { + + //draw the screenlock icon + lpDDSBack->BltFast(620, 0, g_pSpriteSurface[g_dglos.g_seq[423].frame[10]], + &g_dglos.g_picInfo[g_dglos.g_seq[423].frame[10]].box , DDBLTFAST_NOCOLORKEY ); + } + +} + + + +void ThinkSprite(int h, bool get_frame) +{ + + if (g_sprite[h].active) + { + int move_result = 0; + + if (GetBaseApp()->GetGameTickPause()) + { + goto past; + } + + g_sprite[h].moveman = 0; //init thing that keeps track of moving path + g_sprite[h].lpx[0] = g_sprite[h].x; + g_sprite[h].lpy[0] = g_sprite[h].y; //last known legal cords + + g_sprite[h].skiptimer++; + //inc delay, used by "skip" by all sprites +// box_crap = g_dglos.g_picInfo[getpic(h)].box; + + if (g_sprite[h].kill > 0) + { + if (g_sprite[h].kill_timer == 0) g_sprite[h].kill_timer = g_dglos.g_dinkTick; + if (g_sprite[h].kill_timer + g_sprite[h].kill < g_dglos.g_dinkTick) + { + + g_sprite[h].active = false; + // Msg("Killing sprite %d.", h); + + get_last_sprite(); + if (g_sprite[h].callback > 0) + { + // Msg("Callback running script %d.", spr[h].script); + run_script(g_sprite[h].callback); + } + } + } + + if (g_sprite[h].timer > 0) + { + if (g_dglos.g_dinkTick > g_sprite[h].wait) + { + g_sprite[h].wait = g_dglos.g_dinkTick + g_sprite[h].timer; + }else + { + goto animate; + } + } + + //brains - predefined bahavior patterns available to any sprite + + if (g_sprite[h].notouch) if (g_dglos.g_dinkTick > g_sprite[h].notouch_timer) g_sprite[h].notouch = false; + if (get_frame == false) + { + if ( (g_sprite[h].brain == 1)/* || (spr[h].brain == 9) || (spr[h].brain == 3) */ ) + { + + run_through_touch_damage_list(h); + } + + if (g_sprite[h].brain == 1) + { + if (g_dglos.process_warp == 0) + human_brain(h); + } + + if (g_sprite[h].brain == 2) bounce_brain(h); + if (g_sprite[h].brain == 0) no_brain(h); + if (g_sprite[h].brain == 3) duck_brain(h); + if (g_sprite[h].brain == 4) pig_brain(h); + if (g_sprite[h].brain == 5) one_time_brain(h); + if (g_sprite[h].brain == 6) repeat_brain(h); + if (g_sprite[h].brain == 7) one_time_brain_for_real(h); + if (g_sprite[h].brain == 8) text_brain(h); + if (g_sprite[h].brain == 9) pill_brain(h); + if (g_sprite[h].brain == 10) dragon_brain(h); + if (g_sprite[h].brain == 11) missile_brain(h, true); + if (g_sprite[h].brain == 12) scale_brain(h); + if (g_sprite[h].brain == 13) mouse_brain(h); + if (g_sprite[h].brain == 14) button_brain(h); + if (g_sprite[h].brain == 15) shadow_brain(h); + if (g_sprite[h].brain == 16) people_brain(h); + if (g_sprite[h].brain == 17) missile_brain_expire(h); + } else + { + goto past; + } + if (::g_b_kill_app) return; + + +animate: + + + if (g_sprite[h].brain != 13) + { + move_result = check_if_move_is_legal(h); + } + + if (g_dglos.flub_mode != -500) + { +#ifdef _DEBUG + LogMsg("move result is %d", g_dglos.flub_mode); +#endif + move_result = g_dglos.flub_mode; + g_dglos.flub_mode = -500; + } + + if (g_sprite[h].brain == 1) if (move_result > 100) + { + if (g_dglos.g_smallMap.sprite[move_result-100].prop == 1) + special_block(move_result - 100, h); + } + + if (g_sprite[h].reverse) + { + //reverse instructions + if (g_sprite[h].seq > 0) + { + if (g_sprite[h].frame < 1) + { + // new anim + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_dglos.g_seq[g_sprite[h].seq].last; + g_sprite[h].frame = g_dglos.g_seq[g_sprite[h].seq].last; + if (g_sprite[h].frame_delay != 0) g_sprite[h].delay = (g_dglos.g_dinkTick+ g_sprite[h].frame_delay); else + g_sprite[h].delay = (g_dglos.g_dinkTick + g_dglos.g_seq[g_sprite[h].seq].delay[g_dglos.g_seq[g_sprite[h].seq].last]); + } else + { + // not new anim + + //is it time? + + if (g_dglos.g_dinkTick > g_sprite[h].delay) + { + g_sprite[h].frame--; + + if (g_sprite[h].frame_delay != 0) g_sprite[h].delay = (g_dglos.g_dinkTick + g_sprite[h].frame_delay); else + + g_sprite[h].delay = (g_dglos.g_dinkTick + g_dglos.g_seq[g_sprite[h].seq].delay[g_sprite[h].frame]); + + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_sprite[h].frame; + + + if (g_dglos.g_seq[g_sprite[h].seq].frame[g_sprite[h].frame] < 2) + { + + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_sprite[h].frame+1; + + g_sprite[h].frame = 0; + g_sprite[h].seq_orig = g_sprite[h].seq; + g_sprite[h].seq = 0; + g_sprite[h].nocontrol = false; + + + if (h == 1) if (in_this_base(g_sprite[h].seq_orig,g_dglos.mDinkBasePush)) + { + g_dglos.g_playerInfo.push_active = false; + if (g_dglos.g_playerInfo.push_dir == 2) if (sjoy.down) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 4) if (sjoy.left) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 6) if (sjoy.right) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 8) if (sjoy.up) g_dglos.g_playerInfo.push_active = true; + goto past; + } + } + if (g_sprite[h].seq > 0) if (g_dglos.g_seq[g_sprite[h].seq].special[g_sprite[h].frame] == 1) + { + //this sprite can damage others right now! + //lets run through the list and tag sprites who were hit with their damage + + run_through_tag_list(h, g_sprite[h].strength); + } + } + } + } + + + } else + { + + if (g_sprite[h].seq > 0) if (g_sprite[h].picfreeze == 0) + { + if (g_sprite[h].frame < 1) + { + // new anim + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = 1; + g_sprite[h].frame = 1; + if (g_sprite[h].frame_delay != 0) g_sprite[h].delay = g_dglos.g_dinkTick + g_sprite[h].frame_delay; else + + g_sprite[h].delay = (g_dglos.g_dinkTick + g_dglos.g_seq[g_sprite[h].seq].delay[1]); + } else + { + // not new anim + + //is it time? + + if (g_dglos.g_dinkTick > g_sprite[h].delay) + { + g_sprite[h].frame++; + if (g_sprite[h].frame_delay != 0) g_sprite[h].delay = g_dglos.g_dinkTick + g_sprite[h].frame_delay; else + + g_sprite[h].delay = (g_dglos.g_dinkTick + g_dglos.g_seq[g_sprite[h].seq].delay[g_sprite[h].frame]); + + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_sprite[h].frame; + + if (g_dglos.g_seq[g_sprite[h].seq].frame[g_sprite[h].frame] == -1) + { + g_sprite[h].frame = 1; + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_sprite[h].frame; + if (g_sprite[h].frame_delay != 0) g_sprite[h].delay = g_dglos.g_dinkTick + g_sprite[h].frame_delay; else + + g_sprite[h].delay = (g_dglos.g_dinkTick + g_dglos.g_seq[g_sprite[h].seq].delay[g_sprite[h].frame]); + } + + //if (g_sprite[h].frame == g_dglos.g_seqData[g_sprite[h].seq].last+1) + + if (g_dglos.g_seq[g_sprite[h].seq].frame[g_sprite[h].frame] < 1) + { + + g_sprite[h].pseq = g_sprite[h].seq; + g_sprite[h].pframe = g_sprite[h].frame-1; + + g_sprite[h].frame = 0; + g_sprite[h].seq_orig = g_sprite[h].seq; + g_sprite[h].seq = 0; + g_sprite[h].nocontrol = false; + + + if (h == 1) if (in_this_base(g_sprite[h].seq_orig,g_dglos.mDinkBasePush)) + { + + g_dglos.g_playerInfo.push_active = false; + if (g_dglos.g_playerInfo.push_dir == 2) if (sjoy.down) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 4) if (sjoy.left) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 6) if (sjoy.right) g_dglos.g_playerInfo.push_active = true; + if (g_dglos.g_playerInfo.push_dir == 8) if (sjoy.up) g_dglos.g_playerInfo.push_active = true; + goto past; + } + } + if (g_sprite[h].seq > 0) if (g_dglos.g_seq[g_sprite[h].seq].special[g_sprite[h].frame] == 1) + { + //this sprite can damage others right now! + //lets run through the list and tag sprites who were hit with their damage + run_through_tag_list(h, g_sprite[h].strength); + } + } + } + } + } + + + if (g_sprite[h].active && g_sprite[h].brain == 1) + { + did_player_cross_screen(true, h); + } + +past: + + check_sprite_status(h); + draw_sprite_game(lpDDSBack,h); + + + } +} + +void SetupFirstScript() +{ + //memset(&g_sprite[1], 0, sizeof(g_sprite[1])); + + + g_sprite[1].speed = 3; + + g_sprite[1].timer = 0; + g_sprite[1].brain = 1; + g_sprite[1].hard = 1; + g_sprite[1].pseq = 2; + g_sprite[1].pframe = 1; + g_sprite[1].seq = 2; + g_sprite[1].dir = 2; + g_sprite[1].damage = 0; + g_sprite[1].strength = 10; + g_sprite[1].defense = 0; + g_sprite[1].skip = 0; + g_sprite[1].alt.Clear(); + g_sprite[1].base_idle = 10; + g_sprite[1].base_walk = -1; + g_sprite[1].size = 100; + g_sprite[1].base_hit = 100; + g_sprite[1].active = true; + + + if (!g_dglo.m_dmodGameDir.empty()) + { + + int crap2 = add_sprite(0,450,8,0,0); + + g_sprite[crap2].hard = 1; + g_sprite[crap2].noclip = 1; + strcpy(g_sprite[crap2].text, g_dglos.dversion_string); + + g_sprite[crap2].damage = -1; + g_sprite[crap2].owner = 1000; + } + + + int scr = load_script("START",1000, true); + if (locate(scr, "MAIN") == false) + { + LogMsg("Error: Can't locate MAIN in script START!"); + } + run_script(scr); + + if (!g_dglo.m_dmodGameDir.empty()) + { + g_dglos.g_gameMode = 1; + } + +} + +void DrawDinkText(int max_s, int32 *rank) +{ + int h; + + for (int j = 1; j < max_s+1; j++) + { + if (g_dglos.plane_process) + h = rank[j]; else h = j; + if (h > 0) + if (g_sprite[h].active) + { + if (g_sprite[h].brain == 8) + { + //LogMsg("Drawing text %d..", h); + text_draw(h); + } + } + } + +} + +void updateFrame() +{ + if (!lpDDSBack || g_dglo.m_curLoadState != FINISHED_LOADING) return; + bool bRenderDinkText = true; + g_dinkFadeAlpha = 0; + if (g_dglos.bFadedDown) g_dinkFadeAlpha = 1; + +#ifdef _DEBUG + + int cur = 0; + for (int i=0; i < C_MAX_SPRITES_AT_ONCE; i++) + { + + if (g_sprite[i].active) cur = i; + } + assert(cur <= g_dglos.last_sprite_created); + + //LogMsg("Script: %d, callbacks: %d", GetScriptsActive(), GetCallbacksActive()); + //check_seq_status(18); + //check_seq_status(102); + //check_seq_status(104); + + //FreeSequence(); + +#endif + + + bool bSpeedUp = false; + + +if (IsDesktop()) +{ + + +#ifdef WIN32 + + //skip the slow ass transition if TAB is held, useful for testing + /* + if (GetAsyncKeyState(9)) + { + bSpeedUp = true; + } + */ +#endif +/* + if (GetAsyncKeyState(VK_F1)) + { + SaveStateWithExtra(); + } + + if (GetAsyncKeyState(VK_F8)) + { + string fName = DinkGetSavePath()+"quicksave.dat"; + + if (FileExists(fName)) + { + LoadStateWithExtra(); + } else + { + ShowQuickMessage("No state to load yet."); + } + + } +*/ +} +#ifdef _DEBUG +/* + if (GetAsyncKeyState('C')) + { + LogMsg("Writing and loading state"); + + SaveState(GetSavePath()+"state.dat"); + LoadState(GetSavePath()+"state.dat", false); + //DinkUnloadGraphicsCache(); + + } +*/ + + #endif + + + if (DinkGetSpeedUpMode()) + { + bSpeedUp = true; + } + + if (bSpeedUp) + { + if (!GetApp()->GetGameTickPause()) + { + GetApp()->SetGameTick(GetApp()->GetGameTick()+GetApp()->GetDeltaTick()*5); + } + } + byte state[256]; + rtRect32 rcRect; + bool bCaptureScreen = false; + int h,j; + + bool bs[C_MAX_SPRITES_AT_ONCE]; + int highest_sprite; + + g_abort_this_flip = false; + + ProcessGraphicGarbageCollection(); + //620 + SetOrthoRenderSize(g_dglo.m_orthoRenderRect.right, g_dglo.m_orthoRenderRect.GetHeight(), -g_dglo.m_orthoRenderRect.left, -g_dglo.m_orthoRenderRect.top); + if (5 > 9) + { + trigger_start: + g_bInitiateScreenMove = false; + bCaptureScreen = true; + } + + check_joystick(); + +#ifdef C_DINK_KEYBOARD_INPUT + + +if (GetApp()->GetCheatsEnabled()) +{ + if ( (GetKeyboard(68)) && (GetKeyboard(18)) ) + { + if (g_DebugKeyTimer < GetApp()->GetGameTick()) + { + g_DebugKeyTimer = GetApp()->GetGameTick()+500; + + if (debug_mode) + { + debug_mode = false; + LogMsg("Debug mode off"); + } + else + { + debug_mode = true; + LogMsg("Debug mode on"); + } + + } + } +} + + +#endif + + if (g_dglos.g_gameMode == 1) + { + Scrawl_OnMouseInput(); + } else + { + if (g_dglos.keep_mouse) + { + if ((g_dglos.g_talkInfo.active) || (g_sprite[1].brain == 13)) + Scrawl_OnMouseInput(); + } + } + + + + +#ifdef _WIN32 + static int LastWindowsTimer = 0; + +if (!bSpeedUp) +{ + +//Sleep(50); + + while (GetTickCount() <= LastWindowsTimer) + { + Sleep(0); + } + +} +LastWindowsTimer = GetTickCount(); +#else + + /* + static uint32 lastTick = 0; + + + if (!GetBaseApp()->GetGameTickPause()) + { + while (GetSystemTimeTick()-lastTick < 33) + { + + } + } + + lastTick = GetSystemTimeTick(); + */ +#endif + + g_dglos.lastTickCount = g_dglos.g_dinkTick; + g_dglos.g_dinkTick = GetBaseApp()->GetGameTick(); + + + int fps_final = g_dglos.g_dinkTick - g_dglos.lastTickCount; + + //redink1 changed to 12-12 from 10-15... maybe work better on faster computers? + if (fps_final < 12) fps_final = 12; + if (fps_final > 68) fps_final = 68; + + g_dglos.base_timing = fps_final / 3; + if (g_dglos.base_timing < 4) g_dglos.base_timing = 4; + + int junk3; + + //redink1 added these changes to set Dink's speed correctly, even on fast machines. + + if (g_dglos.dinkspeed <= 0) + junk3 = 0; + else if (g_dglos.dinkspeed == 1) + junk3 = 12; + else if (g_dglos.dinkspeed == 2) + junk3 = 6; + else if (g_dglos.dinkspeed == 3) + junk3 = 3; + else + junk3 = 1; + + junk3 *= (g_dglos.base_timing / 4); + + g_sprite[1].speed = junk3; + + if (g_dglos.g_bShowingBitmap.active) + { + //grab main loop and divert it to show a bmp instead + + process_show_bmp(); + ThinkShowBmp(); + bRenderDinkText = false; + goto flip; + } + + g_dglos.mbase_count++; + + if (g_dglos.g_dinkTick > g_dglos.g_DinkUpdateTimerMS+100) + { + g_dglos.mbase_timing = (g_dglos.mbase_count / 100); + g_dglos.g_DinkUpdateTimerMS = g_dglos.g_dinkTick; + if (g_dglos.g_bowStatus.active) g_dglos.g_bowStatus.hitme = true; + if (*pupdate_status == 1) update_status_all(); + + update_sound(); + //TODO Animated tiles + if (IsDesktop()) + { + //TODO: Maybe mobile can handle this now? + process_animated_tiles(); + } + } + + state[1] = 0; + + //figure out frame rate + + + if (g_itemScreenActive) + { + process_item(); + bRenderDinkText = false; + + if (!g_dglo.m_curView == DinkGlobals::VIEW_ZOOMED) + { + BlitGUIOverlay(); + } + + goto flip; + } + + ProcessTransition(); + + if (g_dglos.process_upcycle) + { + up_cycle(); + } + if (g_dglos.process_warp > 0) process_warp_man(); + if (g_dglos.process_downcycle) + { + down_cycle(); + } + + int max_s; + + if (g_dglos.plane_process) + { + memset(&bs,0,sizeof(bs)); + max_s = g_dglos.last_sprite_created; + + int height; + + for (int r1 = 1; r1 < max_s+1; r1++) + { + highest_sprite = 22024; //more than it could ever be + + g_spriteRank[r1] = 0; + + for (int h1 = 1; h1 < max_s+1; h1++) + { + if (g_sprite[h1].active) if (g_sprite[h1].disabled == false) + { + if (bs[h1] == false) + { + //Msg( "Ok, %d is %d", h1,(spr[h1].y + k[spr[h1].pic].yoffset) ); + if (g_sprite[h1].que != 0) height = g_sprite[h1].que; else height = g_sprite[h1].y; + if ( height < highest_sprite ) + { + highest_sprite = height; + g_spriteRank[r1] = h1; + } + } + } + } + + if (g_spriteRank[r1] != 0) + bs[g_spriteRank[r1]] = true; + } + + } else + { + //not processing planes + max_s = C_MAX_SPRITES_AT_ONCE; + } + + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = C_DINK_SCREENSIZE_X; + rcRect.bottom = C_DINK_SCREENSIZE_Y; + + //Blit from Two, which holds the base scene. + + lpDDSBack->BltFast( 0, 0, lpDDSBackGround, &rcRect, DDBLTFAST_NOCOLORKEY); + g_dglo.m_bgSpriteMan.Render(lpDDSBack); //blit sprites that have been shoved into the bg, too slow to actually add them, so we fake it until the screen is rebuilt + + if (!g_bTransitionActive) + { + BlitGUIOverlay(); + } + + for ( j = 1; j < max_s+1; j++) + { + if (g_dglos.plane_process) + h = g_spriteRank[j]; else h = j; + //Msg( "Ok, rank %d is %d", j,h); + + if (h > 0) + { + ThinkSprite(h, g_bTransitionActive || g_dglos.g_stopEntireGame == 1); + } + } + + EndProcessTransition(); + + if (g_dglos.g_stopEntireGame == 1) + { + if (g_dglos.g_talkInfo.active) + { + process_talk(); + } + else + { + g_dglos.g_stopEntireGame = 0; + //BuildScreenBackground(false); + draw_status_all(); + + } + bRenderDinkText = false; + goto flip; + + } + + if (g_bTransitionActive) + { + //don't actually think or process game stuff + bRenderDinkText = false; + goto flip; + } + + if ( (sjoy.joybit[7] == true) ) + { + //space is pressed, lets draw the hitmap, why not? + if (!no_cheat) DrawCollision(); + } + + if (g_dglos.g_gameMode == 2) + { + g_dglos.g_gameMode = 3; + load_map(g_MapInfo.loc[*pmap]); + BuildScreenBackground(); + g_dglos.g_guiLife = *plife; + + if (g_dglos.keep_mouse == 0) + { + //kill the mouse here? + g_dglo.UnSetViewOverride(); + } + } + + if (g_sprite[1].active) if (g_sprite[1].brain == 1) did_player_cross_screen(false, 1); + + if (g_bInitiateScreenMove) + { + goto trigger_start; + } + + if (g_dglos.screenlock == 1) + { +#ifdef _DEBUG + if (debug_mode) + { + g_dglos.screenlock = 0; + } +#endif + drawscreenlock(); + } + + if (!GetBaseApp()->GetGameTickPause()) + { + if (g_dglos.g_talkInfo.active) process_talk(); + process_callbacks(); + } + +flip: + + if (g_dinkFadeAlpha *255 > 1) + { + //g_dglo.m_gameArea.bottom++; //hack to fix a little glitchy line + + if (IsDrawingDinkStatusBar()) + { + DrawFilledRect(g_dglo.m_gameArea, MAKE_RGBA(0,0,0,g_dinkFadeAlpha* 255)); + } else + { + DrawFilledRect(g_dglo.m_orthoRenderRect, MAKE_RGBA(0,0,0,g_dinkFadeAlpha* 255)); + + } + + //g_dglo.m_gameArea.bottom--; + } + + if (::g_b_kill_app) return; + if (!g_abort_this_flip) + { + flip_it(); + } + + if (bRenderDinkText) + DrawDinkText(max_s, g_spriteRank); + + RemoveOrthoRenderSize(); + if (turn_on_plane) g_dglos.plane_process = true; + + BlitSecondTransitionScreen(); + + + if (g_bTransitionActive) + { + SetOrthoRenderSize(C_DINK_SCREENSIZE_X, g_dglo.m_orthoRenderRect.GetHeight(), 0, -g_dglo.m_orthoRenderRect.top); + BlitGUIOverlay(); + RemoveOrthoRenderSize(); + } + + + if (bCaptureScreen) + { + //reset the timer because we probably just wasted a bunch loading crap + g_dglo.m_transitionTimer = GetBaseApp()->GetGameTick(); + } + + if (!GetBaseApp()->GetGameTickPause()) + { + UpdateControlsGUIIfNeeded(); + } + +} + + +void load_batch(int linesToProcess, float &percentOut) +{ + + static int iLineCount = 0; + + if (!g_dglo.m_iniScanner.IsLoaded()) + { + //first pass, open the file + iLineCount = 0; + if (!g_dglo.m_iniScanner.LoadFile(GetFileLocationString("dink.ini"), false)) + { + LogMsg("dink.ini not found."); + assert(0); + return; + } + + g_sprite[1].x = 200; + g_sprite[1].y = 300; + } + + for (int i=0; i < linesToProcess; i++) + { + + pre_figure_out(g_dglo.m_iniScanner.GetLine(iLineCount).c_str(), 0, true); + iLineCount++; + if (iLineCount == g_dglo.m_iniScanner.m_lines.size()) + { + + for (int b=0; b < g_dglo.m_iniScanner.m_lines.size(); b++) + { + pre_figure_out(g_dglo.m_iniScanner.GetLine(b).c_str(), 0, false); + } + + program_idata(); + + percentOut = 1; + g_dglo.m_iniScanner.Kill(); + return; + } + + ProcessGraphicGarbageCollection(); + + } + + //we'll need to come back do the rest + percentOut = float(iLineCount) / float(g_dglo.m_iniScanner.m_lines.size()); +} + +void SetDinkGameState(eDinkGameState state) +{ + g_dinkGameState = state; +} + +eDinkGameState GetDinkGameState() +{ + return g_dinkGameState; +} + +void SetDefaultVars(bool bFullClear) +{ + ResetDinkTimers(); + + g_dglo.m_lastActiveView = g_dglo.VIEW_NONE; + g_dglo.UnSetViewOverride(); + g_dglo.m_lastGameMode = DINK_GAME_MODE_NONE; + g_dglo.m_lastSubGameMode = DINK_SUB_GAME_MODE_NONE; + g_dglo.m_bFullKeyboardActive = false; + + g_dglo.m_bWaitingForSkippableConversation = false; + g_dglos.g_DinkUpdateTimerMS =0; + + memset(g_dglo.m_dirInput, 0, sizeof(DINK_INPUT_COUNT*sizeof(bool))); + memset(g_dglo.m_dirInputFinished, 0, sizeof(DINK_INPUT_COUNT*sizeof(bool))); + clear_talk(); + + no_transition = false; + g_abort_this_flip = false; + g_dglos.screenlock = 0; + sound_on = true; + g_dglos.g_pushingEnabled = 1; + turn_on_plane = false; + g_dglos.item_pic = 2; + + fire_forward = 0; + g_dglos.g_stopEntireGame = 0; + g_bInitiateScreenMove = false; + g_bTransitionActive = false; + debug_mode = false; +#ifdef _DEBUG +//debug_mode = true; //script debugging mode +#endif + g_dglos.flub_mode = -500; + g_dglos.last_sprite_created = 1; + decipher_savegame = 0; + g_dglos.bFadedDown = false; + g_dglos.smooth_follow = false; + g_dglos.mSwapped = false; + g_dglos.mLoopMidi = false; + g_dglos.mDinkBasePush = 310; + g_dglos.walk_off_screen = 0; + g_dglos.keep_mouse = 0; + g_dglos.show_dot = false; + g_dglos.plane_process = true; + g_dglos.weapon_script = 0; + g_dglos.magic_script = 0; + g_dglos.last_sprite_created; + g_dglos.no_running_main = false; + g_dglos.process_warp = 0; + g_dglos.process_upcycle = false; + g_dglos.process_downcycle = false; + g_dglos.cycle_clock = 0; + g_dglos.cycle_script = 0; + g_dglos.but_timer = 0; + g_dglo.m_bgSpriteMan.Clear(); + + no_cheat = !GetApp()->GetCheatsEnabled(); + g_itemScreenActive = false; + g_dglos.midi_active = true; + last_saved_game = 0; + g_b_kill_app = false; //if true, will close app as soon as the message pump is + g_dglos.dinkspeed = 3; + + memset(&g_dglos.g_bShowingBitmap, 0, sizeof(ShowingBitmapInfo)); + memset(&g_dglos.g_bowStatus, 0, sizeof(attackinfo_struct)); + + g_dglos.g_returnint = 0; + g_dglos.bKeepReturnInt = false; + g_dglos.process_count = 0; + + if (bFullClear) + { + g_dglo.m_curLoadState = 0; + g_dglo.m_bSpeedUpMode = false; + g_dglos.m_bRenderBackgroundOnLoad = false; + + memset(g_dglos.m_bufferForExpansion, 0, sizeof(g_dglos.m_bufferForExpansion)); + memset(g_dglos.g_picInfo, 0, sizeof(pic_info)*C_MAX_SPRITES); + //memset(g_id, '\0', sizeof(idata) * max_idata); + memset(g_dglos.g_seq, 0, sizeof(sequence) * C_MAX_SEQUENCES); + kill_all_vars(); //it zero's out the player struct + strcpy(g_dglos.current_map, "map.dat"); + strcpy(g_dglos.current_dat,"dink.dat"); + memset(&short_play, 0, sizeof(player_short_info)); + + //redink1 code for version change + strcpy(g_dglos.dversion_string, "v1.10"); + strcpy(g_dglos.save_game_info, "Level &level"); + g_dglos.g_curPicIndex = 1; + //GetBaseApp()->SetGameTick(0); //can cause problems .. don't do it here + g_dglos.time_start = GetBaseApp()->GetGameTick(); + g_dglos.g_playerInfo.minutes = 0; + } +} + +//in some cases, we include DMOD's with the app, but they are static and can't be changed +string GetDMODStaticRootPath() +{ + if (GetPlatformID() == PLATFORM_ID_IOS) + { + return GetBaseAppPath()+"dmods/"; + } + + return ""; //unused + +} + +string GetDMODRootPath() +{ + +#if defined(WIN32) || defined(PLATFORM_HTML5) + + string dmodpath = "dmods/"; + + vector parms = GetBaseApp()->GetCommandLineParms(); + + for (int i=0; i < parms.size(); i++) + { + if (parms[i] == "-dmodpath") + { + if (parms.size() > i+1) + { + dmodpath = ""; + for (int n=i+1; n < parms.size(); n++) + { + dmodpath +=parms[n]; + if (n < parms.size()-1) + { + dmodpath += " "; + } + } + StringReplace("\\", "/", dmodpath); + if (dmodpath[dmodpath.size()-1] != '/') dmodpath += '/'; //need a trailing slash + + } else + { + LogMsg("-dmodpath used wrong"); + } + } + + } + + return dmodpath; +#endif + + if (GetPlatformID() == PLATFORM_ID_WEBOS) + { + return "dmods/"; + } + return GetAppCachePath(); +} + +void InitDinkPaths(string gamePath, string gameDir, string dmodGameDir) +{ + + string dmodPath; + if (!dmodGameDir.empty()) + { + dmodPath = RemoveTrailingBackslash(GetPathFromString(dmodGameDir)); + dmodPath += "/"; //fixing problem with multiple slashes showing up on some OS's and am too lazy to "realyl" fix it or even correct that typo I just made + + dmodGameDir = RemoveTrailingBackslash (GetFileNameFromString(dmodGameDir)); + + if (dmodPath == dmodGameDir) + { + //it's the old format that doesn't include the full path too, guess + dmodPath = GetDMODRootPath(); + dmodPath = RemoveTrailingBackslash(dmodPath); + } + + } + StringReplace("/", "", dmodGameDir); + StringReplace("\\", "", dmodGameDir); + g_dglo.m_gamePath = gamePath; + g_dglo.m_gameDir = gameDir+"/"; + g_dglo.m_gamePathWithDir = g_dglo.m_gamePath + g_dglo.m_gameDir; + + if (dmodGameDir.empty()) + { + g_dglo.m_savePath = GetSavePath()+g_dglo.m_gameDir; + g_dglo.m_dmodGamePathWithDir.clear(); + g_dglo.m_dmodGameDir.clear(); + } else + { + g_dglo.m_dmodGameDir = dmodGameDir+"/"; + g_dglo.m_savePath = GetDMODRootPath()+g_dglo.m_dmodGameDir; + g_dglo.m_dmodGamePathWithDir = dmodPath+g_dglo.m_dmodGameDir; + } +} + +bool InitDinkEngine() +{ + OneTimeDinkInit(); + finiObjects(); + SetDefaultVars(true); + g_dglo.SetView(DinkGlobals::VIEW_FULL); + g_b_kill_app = false; + +#ifdef C_DINK_KEYBOARD_INPUT + while (keypressed()); //clear keyboard buffer +#endif + + return true; + +} + +//call this repeately until progress == 1 +bool LoadGameChunk(int gameIDToLoad, float &progressOut) +{ + + switch(g_dglo.m_curLoadState) + { + + case 0: + progressOut = 0.05f; + + if (!InitializeVideoSystem()) + { + return false; + } + + //redink1 init for color depth information + + assert(!lpDDSBackGround); + + //init back buffer at 8 bit, if highcolor is needed later it will auto convert + lpDDSBackGround = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, false); + fill_screen(0); //fill background with blank to start things off + lpDDSBuffer = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL); + + + + if (!lpDDSBuffer ) return false; + + //blit_background(); + + sound_on = InitSound(); + + break; + + case 1: + progressOut = 0.1f; + LogMsg("loading tilescreens..."); + + /* + for (int h=1; h < C_TILE_SCREEN_COUNT; h++) + { + if (!LoadTileScreenIfNeeded(h)) return false; + } +*/ + LogMsg("Done with tilescreens..."); + break; + + case 2: + { + //this one is going to get called a lot... + + progressOut = 0.2f; + //LogMsg("loading batch..."); + float percent = 0; + load_batch(20, percent); + + //get the progress meter to update within the range of this chunk type + progressOut += .5 * percent; + + if (percent != 1) + { + //call this one again next time + return true; + } + } + + break; + + case 3: + progressOut = 0.7f; + LogMsg("done loading batch"); + if (!load_hard()) return false; + break; + + //Activate dink, but don't really turn him on + g_sprite[1].timer = 33; + + //copy from player info + g_sprite[1].x = g_dglos.g_playerInfo.x; + g_sprite[1].y = g_dglos.g_playerInfo.y; + +// ** SETUP ** + g_dglos.last_sprite_created = 1; + g_dglos.g_gameMode = 0; + case 4: + progressOut = 0.75; + load_info(); + + break; + + case 5: +progressOut = 0.8f; +#ifdef C_DINK_KEYBOARD_INPUT + //clear keyboard buffer + for (int x=0; x<256; x++) + { + GetKeyboard(x); + } +#endif + + for (int u = 1; u <= 10; u++) + g_dglos.g_playerInfo.button[u] = u; + + for (int x1=1; x1 <= 10; x1++) + { + sjoy.letgo[x1] = true; + } + + init_font_colors(); + //lets run our init script + int script; + break; + + case 6: + StopMidi(); + + progressOut = 0.9f; + script = load_script("main", 0, true); + locate(script, "main"); + run_script(script); + attach(); + + break; + case 7: + progressOut = 0.97f; + //first time init + SetupFirstScript(); + //to load a game.. + // script = load_script("instant_load", 1000, true); + + if (gameIDToLoad == 0) + { + if (g_dglo.m_dmodGameDir.empty()) + { + //to start from scatch + script = load_script("newgame", 1000, true); + locate(script, "main"); + run_script(script); + } + + } else + { + if (!load_game(gameIDToLoad)) + { + LogError("Couldn't load save game"); + } + } + + break; + + case 8: + progressOut = 1; + g_dglo.m_curLoadState = FINISHED_LOADING-1; + break; + + default: + + assert(!"oops"); + + } + + g_dglo.m_curLoadState++; + return true; +} + +void DinkGlobals::SetView( eView view ) +{ + if (m_viewOverride != VIEW_NONE) + { + view = m_viewOverride; + } else + { + m_curView = view; + } + switch (view) + { + case VIEW_ZOOMED: + if (GetFakePrimaryScreenSizeX() != 0) + { +// g_dglo.m_nativeGameArea = rtRectf(0,0,GetPrimaryGLX(),GetPrimaryGLY()); + g_dglo.m_nativeGameArea = rtRectf(0,0,GetScreenSizeX(),GetScreenSizeY()); + } else + { + g_dglo.m_nativeGameArea = rtRectf(0,0,GetScreenSizeX(),GetScreenSizeY()); + } + + g_dglo.m_gameArea = rtRect32 (20, 0, 620, 400); + g_dglo.m_orthoRenderRect = rtRect32 (20, 0, 620, 400); + break; + + case VIEW_FULL_WITHOUT_EDGES: + g_dglo.m_nativeGameArea = rtRectf(0,0,480,267); + g_dglo.m_gameArea = rtRect32 (20, 0, 620, 400); + g_dglo.m_orthoRenderRect = rtRect32 (20, 0, 620, 480); + break; + + case VIEW_FULL: + { + g_dglo.m_gameArea = rtRect32 (20, 0, 620, 400); + + float aspect = (float(C_DINK_SCREENSIZE_X)/GetScreenSizeXf()); + float aspectY = (float(C_DINK_SCREENSIZE_Y)/GetScreenSizeYf()); + + g_dglo.m_nativeGameArea = rtRectf(float(g_dglo.m_gameArea.left)/ aspect,0,float(g_dglo.m_gameArea.right)/aspect,float(g_dglo.m_gameArea.bottom)/aspectY); + g_dglo.m_orthoRenderRect = rtRect32 (0, 0, 640, 480); + + +#ifdef _DEBUG + LogMsg("Rect %s AspectX: %.4f, Aspect Y: %.4f", PrintRect(g_dglo.m_nativeGameArea).c_str(), aspect, aspectY); +#endif + } + + break; + + default: + + assert(!"Unhandled view"); + + } + + + g_dglo.m_fontSize = 1.24; + + if (IsIPADSize || IsDesktop()) + { + //the screens are big enough here were we can keep the text smaller, comparable to the original Dink + g_dglo.m_fontSize = 0.88f; + } + + + if (IsLargeScreen()) + { + g_dglo.m_fontSize = 0.88f; + g_dglo.m_fontSize *= (C_DINK_SCREENSIZE_X/GetScreenSizeXf()); + } + +} + +void DinkGlobals::SetViewOverride( eView view ) +{ + m_viewOverride = view; + SetView(m_curView); +} + +void DinkGlobals::UnSetViewOverride() +{ + m_viewOverride = VIEW_NONE; + SetView(m_curView); +} + +void DinkGlobals::ToggleView() +{ + + if (g_bTransitionActive) return; //now is a bad time.. + + if (m_curView == VIEW_FULL) + { + SetView(VIEW_ZOOMED); + } else if (m_curView == VIEW_ZOOMED) + { + SetView(VIEW_FULL); + } else + { + assert(!"huh?"); + } +} + + +void DinkUnloadGraphicsCache() +{ + GetAudioManager()->KillCachedSounds(false, true, 0, 1, false); + + DinkUnloadUnusedGraphicsByUsageTime(100); //unload anything not used in the last second + +#ifdef _WIN32 + /* + if (GetKeyboard(18)) + { + for (int i=1; i < C_MAX_SEQUENCES; i++) + { + FreeSequence(i); + } + } + */ +#endif +} + + +//to help with debugging something.. +bool IsCorruptedSeq(int seq) +{ + return false; + + if (g_dglos.g_seq[seq].frame[1] != 0) + { + if (g_pSpriteSurface[g_dglos.g_seq[seq].frame[1]]) + { + //the first deal has something in it. But do they all? + + for (int g=0; g < g_dglos.g_seq[seq].last; g++) + { + if (!g_pSpriteSurface[g_dglos.g_seq[seq].frame[1] + g]) + { + LogMsg("bad.."); + } + } + + + } + } + + + //looks blank + + return false; +} + +//send in 1000*60 and all images not used in the last one minute will be destroyed + +void DinkUnloadUnusedGraphicsByUsageTime(unsigned int timeMS) +{ + + const unsigned int tickMS = GetBaseApp()->GetGameTick(); + unsigned int mostRecentUsageTick = 0; + + for (int i=1; i < C_MAX_SEQUENCES; i++) + { + for (int g=0; g < g_dglos.g_seq[i].last; g++) + { + //assert(g_dglos.g_picInfo[g_dglos.g_seq[i].frame[1]+g].pSurface); + if (g_pSpriteSurface[g_dglos.g_seq[i].frame[1] + g]) + { + if (g_pSpriteSurface[g_dglos.g_seq[i].frame[1] + g]->m_gameTickOfLastUse+timeMS <= tickMS) + { + SAFE_DELETE(g_pSpriteSurface[g_dglos.g_seq[i].frame[1] + g]); + } + } + } + } + + for (int i=1; i < C_TILE_SCREEN_COUNT; i++) + { + if (g_tileScreens[i]) + { + if (g_tileScreens[i]->m_gameTickOfLastUse + timeMS <= tickMS) + { + SAFE_DELETE(g_tileScreens[i]); + } + } + } +} + +void ProcessGraphicGarbageCollection() +{ + //unload images that haven't been used in a while. If we accidentally unload the wrong one, or all of them, no harm done, the engine + //will reload them as needed. + + /* + if (GetBaseApp()->GetTexMemUsed() < 1024*1024*13) return; + + static uint32 garbageTimer = 0; + + if (garbageTimer < GetBaseApp()->GetGameTick()) + { + + garbageTimer = GetBaseApp()->GetGameTick()+5000; + } else + { + return; + } + + LogMsg("Garbage collection.."); + DinkUnloadUnusedGraphicsByUsageTime(1000*120); + + */ + if (GetBaseApp()->GetMemUsed() > C_DINK_MEM_MAX_ALLOWED || GetBaseApp()->GetTexMemUsed() > C_DINK_TEX_MEM_MAX_ALLOWED) + { + DinkUnloadUnusedGraphicsByUsageTime(1000*5); + GetAudioManager()->KillCachedSounds(false, true, 5000, 1,false); + if (GetBaseApp()->GetMemUsed() > C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP || GetBaseApp()->GetTexMemUsed() > C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP) + { + //still having problems.. let's go deeper + DinkUnloadUnusedGraphicsByUsageTime(1000*3); + + if (GetBaseApp()->GetMemUsed() > C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP || GetBaseApp()->GetTexMemUsed() > C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP) + { + //still having problems.. let's go deeper + DinkUnloadUnusedGraphicsByUsageTime(1000*1); + + if (GetBaseApp()->GetMemUsed() > C_DINK_MEM_CACHE_MAX_ALLOWED_AFTER_A_DUMP || GetBaseApp()->GetTexMemUsed() > C_DINK_TEX_MEM_MAX_ALLOWED_AFTER_A_DUMP) + { + //still having problems.. let's go deeper + DinkUnloadUnusedGraphicsByUsageTime(0); + //GetAudioManager()->KillCachedSounds(false, false, 5000, 1, true); + } + } + + } + } +} + +eDinkGameMode GetDinkGameMode() +{ + + if (g_itemScreenActive) return DINK_GAME_MODE_INVENTORY; + if (g_dglos.g_gameMode == 1 || g_sprite[1].brain == 13) return DINK_GAME_MODE_MOUSE; + if (g_dglos.g_gameMode == 2) return DINK_GAME_MODE_NORMAL; //loading a map I guess + if (g_dglos.g_gameMode == 3) return DINK_GAME_MODE_NORMAL; + if (g_dglos.g_gameMode == 0) return DINK_GAME_MODE_NORMAL; //uhh.. dink died? + + assert(!"Unknown mode"); + + return DINK_GAME_MODE_NORMAL; +} + +bool IsDrawingDinkStatusBar() +{ + return *pupdate_status != 0; +} + +eDinkSubGameMode GetDinkSubGameMode() +{ + if (g_dglos.g_bShowingBitmap.active) return DINK_SUB_GAME_MODE_SHOWING_BMP; + if (g_dglos.g_talkInfo.active) return DINK_SUB_GAME_MODE_DIALOG; + + //default + return DINK_SUB_GAME_MODE_NONE; +} + + +bool SaveHeader(FILE *fp) +{ + SaveToFile(SAVE_FORMAT_VERSION, fp); + SaveToFile(g_dglo.m_dmodGamePathWithDir, fp); + SaveToFile(g_dglo.m_gameDir, fp); + + SaveToFile((uint32)GetApp()->GetGameTick(), fp); + return true; +} + +bool LoadHeader(FILE *fp) +{ + float version; + LoadFromFile(version, fp); + if (version < SAVE_FORMAT_VERSION) + { + LogMsg("Save state from newer version?!"); + return false; + } + + LoadFromFile(g_dglo.m_dmodGameDir, fp); + LoadFromFile(g_dglo.m_gameDir, fp); + + uint32 gameTime; + LoadFromFile(gameTime, fp); + GetApp()->SetGameTick(gameTime); + + + //let's initialize our data based on this + InitDinkPaths(GetBaseAppPath(), RemoveTrailingBackslash(g_dglo.m_gameDir), RemoveTrailingBackslash(g_dglo.m_dmodGameDir)); + return true; +} + +bool SaveSoundState(FILE *fp) +{ + if (!GetAudioManager()->IsPlaying(GetAudioManager()->GetLastMusicID())) + { + g_dglo.m_lastMusicPath = ""; + } + + + SaveToFile(g_dglo.m_lastMusicPath, fp); + if (g_dglo.m_lastMusicPath.empty()) + { + SaveToFile(uint32(0), fp); + } else + { + SaveToFile(GetAudioManager()->GetPos(GetAudioManager()->GetLastMusicID()), fp); + } + + fwrite(&soundinfo, 1, sizeof(soundstruct)*(num_soundbanks+1), fp); + + for (int i=0; i < max_sounds; i++) + { + SaveToFile(g_soundInfo[i].m_fileName, fp); + } + + for (int i=1; i < num_soundbanks; i++) + { + if (soundbank[i].IsInUse()) + { + if (soundinfo[i].repeat) + { + SaveToFile(i, fp); + SaveToFile(soundinfo[i].owner, fp); + SaveToFile(soundinfo[i].survive, fp); + SaveToFile(soundinfo[i].repeat, fp); + SaveToFile(soundinfo[i].vol, fp); + SaveToFile(soundinfo[i].freq, fp); + SaveToFile(soundbank[i].m_soundIDThatPlayedUs, fp); + } + } + } + + //signal that we're done + SaveToFile((int32)0, fp); + return true; +} + +bool LoadSoundState(FILE *fp) +{ + + LoadFromFile(g_dglo.m_lastMusicPath, fp); + + uint32 pos; + LoadFromFile(pos, fp); + + if (!g_dglo.m_lastMusicPath.empty()) + { + PlayMidi(g_dglo.m_lastMusicPath.c_str()); + GetAudioManager()->SetPos(GetAudioManager()->GetLastMusicID(), pos); + } + + fread(&soundinfo, 1, sizeof(soundstruct)*(num_soundbanks+1), fp); + for (int i=0; i < max_sounds; i++) + { + LoadFromFile(g_soundInfo[i].m_fileName, fp); + } + + int32 bankNum; + + while(1) + { + LoadFromFile(bankNum, fp); + if (bankNum == 0) break; + + int32 owner; + LoadFromFile(owner, fp); + int32 survive; + LoadFromFile(survive, fp); + int32 repeat; + LoadFromFile(repeat, fp); + int32 vol; + LoadFromFile(vol, fp); + int32 freq; + LoadFromFile(freq, fp); + + int32 soundID; + LoadFromFile(soundID, fp); + + playbank(soundID, freq, 0, owner, repeat, bankNum); + soundinfo[bankNum].survive = survive; + } + + return true; +} + +bool SaveScriptState(FILE *fp) +{ + //first save the actual script data + + for (int32 i = 1; i < C_MAX_SCRIPTS; i++) + { + if (g_scriptInstance[i]) + { + SaveToFile(i, fp); + fwrite(g_scriptInstance[i], 1, sizeof(refinfo), fp); + //now write the actual script + fwrite(g_scriptBuffer[i], 1, g_scriptInstance[i]->end, fp); + } + } + + SaveToFile((int32)0, fp); //signal end + return true; +} + +bool SaveSpriteState(FILE *fp) +{ + for (int32 i=0; i < C_MAX_SPRITES_AT_ONCE; i++) + { + + if (g_customSpriteMap[i] != 0) + { + g_sprite[i].m_containsSpriteMapData = 1; //signal we have additional sprite data + } + else + { + g_sprite[i].m_containsSpriteMapData = 0; + } + + fwrite(&g_sprite[i], sizeof(SpriteStruct), 1, fp); + + if (g_customSpriteMap[i] != 0) + { + int32 count = g_customSpriteMap[i]->size(); + + SaveToFile(count, fp); //let them know how many are coming + + std::map::iterator itor = g_customSpriteMap[i]->begin(); + + while (itor != g_customSpriteMap[i]->end()) + { + SaveToFile((*itor).first, fp); + SaveToFile((*itor).second, fp); + itor++; + } + + } + } + + return true; //success +} + +bool LoadSpriteState(FILE *fp) +{ + for (int i=0; i < C_MAX_SPRITES_AT_ONCE; i++) + { + SAFE_DELETE(g_customSpriteMap[i]); + + fread(&g_sprite[i], sizeof(SpriteStruct), 1, fp); + + if (g_sprite[i].m_containsSpriteMapData != 0) + { + int sizeofBool = sizeof(bool); + + int32 count; + LoadFromFile(count, fp); + + g_customSpriteMap[i] = new std::map; + + for (int propCount = 0; propCount < count; propCount++) + { + string st; + int32 value; + LoadFromFile(st, fp); + LoadFromFile(value, fp); + //insert it + (*g_customSpriteMap[i])[st] = value; + } + } + } + + return true; //success +} + +bool LoadScriptState(FILE *fp) +{ + + while (1) + { + int32 scriptID; + LoadFromFile(scriptID, fp); + if (scriptID == 0) break; //all done + + //load this script data + assert(!g_scriptInstance[scriptID]); + g_scriptInstance[scriptID] = (refinfo*) malloc(sizeof(refinfo)); + fread(g_scriptInstance[scriptID], 1, sizeof(refinfo), fp); + assert(!g_scriptBuffer[scriptID]); + g_scriptBuffer[scriptID] = new char[g_scriptInstance[scriptID]->end+1]; + g_scriptBuffer[scriptID][g_scriptInstance[scriptID]->end] = 0; + fread(g_scriptBuffer[scriptID], 1,g_scriptInstance[scriptID]->end, fp); + } + + return true; +} + + +bool SaveState(string const &path) +{ + LogMsg("Saving %s", path.c_str()); + CreateDirectoryRecursively(g_dglo.m_savePath, g_dglo.m_gameDir); + + FILE *fp = fopen(path.c_str(), "wb"); + + + //why unload crap when you're saving?! + //DinkUnloadUnusedGraphicsByUsageTime(0); + + if (!fp) + { + LogMsg("Error saving state"); + return false; + } + + bool bOk = true; + + bOk = SaveHeader(fp); + + if (bOk) + { + int dinkGloSize = sizeof(DinkGlobalsStatic); + fwrite(&dinkGloSize, 1, sizeof(int), fp); + + fwrite(&g_dglos, 1, dinkGloSize, fp); + } + + if (bOk) + { + bOk = SaveScriptState(fp); + } + + if (bOk) + { + bOk = SaveSpriteState(fp); + bOk = SaveSoundState(fp); + } + + fclose(fp); + return bOk; //success +} + + +bool LoadState(string const &path, bool bLoadPathsOnly) +{ + LogMsg("Loading %s", path.c_str()); + FILE *fp = fopen(path.c_str(), "rb"); + + if (!fp) + { + LogMsg("Unable to load state, file not found"); + return false; + } + + if (bLoadPathsOnly) + { + + float version; + LoadFromFile(version, fp); + if (version < SAVE_FORMAT_VERSION) + { + LogMsg("Save state from newer version?!"); + fclose(fp); + return false; + } + fclose(fp); + return true; + } + + StopMidi(); + DinkUnloadUnusedGraphicsByUsageTime(0); + KillScriptAccelerators(); + kill_all_sounds(); + kill_all_scripts_for_real(); + ResetDinkTimers(); + g_dglo.m_bgSpriteMan.Clear(); + g_dglo.UnSetViewOverride(); + + bool bOk = LoadHeader(fp); + + + if (bOk) + { + //keep loading + int dinkGloStaticSize = 0; + fread(&dinkGloStaticSize, 1, sizeof(int32), fp); + memset(&g_dglos, 0, sizeof(DinkGlobalsStatic)); + fread(&g_dglos, 1, dinkGloStaticSize, fp); + + + //kill the bad pointers to the graphics + for (int i=0; i < C_MAX_SPRITES; i++) + { + g_pSpriteSurface[i] = NULL; + } + + load_hard(); + load_info(); + + } + + if (bOk) + { + bOk = LoadScriptState(fp); + } + if (bOk) + { + bOk = LoadSpriteState(fp); + bOk = LoadSoundState(fp); + } + + fclose(fp); + if (!attach()) + { + return false; + } + + if ( g_dglos.g_gameMode > 2 || g_dglos.m_bRenderBackgroundOnLoad) + { + BuildScreenBackground(false); + } + + if (g_dglos.g_bShowingBitmap.active) + { + CopyBitmapToBackBuffer(g_dglos.g_lastBitmapShown); + } + + return bOk; //success +} + +void DinkModStrength(int mod) +{ + *pstrength += mod; + GetAudioManager()->Play("dink/sound/secret.wav"); +} + +void DinkModDefense(int mod) +{ + *pdefense += mod; + GetAudioManager()->Play("dink/sound/secret.wav"); +} + +void DinkModMagic(int mod) +{ + *pmagic+= mod; + GetAudioManager()->Play("dink/sound/secret.wav"); +} + +void DinkModLifeMax(int mod) +{ + *plifemax += mod; + *plife += mod; + GetAudioManager()->Play("dink/sound/secret.wav"); +} + +void DinkFillLife() +{ + *plife = *plifemax; +} + +void DinkModGold(int mod) +{ + *pgold += mod; + GetAudioManager()->Play("dink/sound/secret.wav"); +} + +Surface* DinkGetMagicIconImage() +{ + if (*pcur_magic == 0) return NULL; + item_struct *pItem = &g_dglos.g_playerInfo.g_MagicData[*pcur_magic]; + int picID = g_dglos.g_seq[pItem->seq].frame[pItem->frame]; + if (picID == 0) return NULL; + check_pic_status(picID); + + return g_pSpriteSurface[picID]->GetGLSuface(); +} + + +Surface* DinkGetWeaponIconImage() +{ + if (*pcur_weapon == 0) return NULL; + item_struct *pItem = &g_dglos.g_playerInfo.g_itemData[*pcur_weapon]; + int picID = g_dglos.g_seq[pItem->seq].frame[pItem->frame]; + if (picID == 0) return NULL; + + check_pic_status(picID); + return g_pSpriteSurface[picID]->GetGLSuface(); +} + +float DinkGetMagicChargePercent() +{ + if (*pmagic_cost > 0 && *pmagic_level > 0) + { + return float(*pmagic_level) / float(*pmagic_cost); + + + } + + return 0; + +} + +float DinkGetHealthPercent() +{ + if (*plifemax > 0) + { + return float(*plife)/ float(*plifemax); + } + return 0; +} +bool DinkIsDoingScreenTransition() +{ + return g_bTransitionActive; +} + +string DinkGetSavePath() +{ + return g_dglo.m_savePath; +} + +void DinkAddBow() +{ + add_item("item-b2", 438, 12, false); +} + +bool DinkGetSpeedUpMode() +{ + return g_dglo.m_bSpeedUpMode; +} + +void DinkSetSpeedUpMode(bool bSpeedup) +{ + g_dglo.m_bSpeedUpMode = bSpeedup; +} + + +void SaveStateWithExtra() +{ + if (!lpDDSBack || g_dglo.m_curLoadState != FINISHED_LOADING) return; + + LogMsg("Saving state"); + GetAudioManager()->Play("audio/quick_save.wav"); + SaveState(DinkGetSavePath()+"quicksave.dat"); + ShowQuickMessage("State saved."); +}; + +void SaveAutoSave() +{ + + + LogMsg("Saving autosave"); + //GetAudioManager()->Play("audio/quick_save.wav"); + SaveState(DinkGetSavePath()+"autosave.dat"); + + + //add extra info because I don't want to change the save format + uint32 minutes = ( GetBaseApp()->GetGameTick()-g_dglos.time_start) / (1000*60); + + VariantDB db; + db.GetVar("minutes")->Set(minutes); + db.GetVar("description")->Set("Level "+toString(*plevel)); + +#ifdef _DEBUG + LogMsg("Saving autosave to %s", (DinkGetSavePath()+"autosavedb.dat").c_str()); +#endif + db.Save(DinkGetSavePath()+"autosavedb.dat", false); + + ShowQuickMessage("(Auto-saved)"); +}; + +void LoadStateWithExtra() +{ + if (!lpDDSBack || g_dglo.m_curLoadState != FINISHED_LOADING) return; + + //LogMsg("Loading state"); + string fName = DinkGetSavePath()+"quicksave.dat"; + GetAudioManager()->Play("audio/quick_load.wav"); + LoadState(fName, false); + ShowQuickMessage("State loaded."); + +}; + +//note, you must glPopMatrix(); yourself if you use this... + +void ApplyAspectRatioGLMatrix() +{ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + + if (g_dglo.m_aspectRatioModX == 1.0f && g_dglo.m_aspectRatioModY == 1.0f) + { + //not actually using this + g_dglo.m_centeringOffset = CL_Vec3f(0,0,0); + return; + } + + //float offsetX = ((float)GetPrimaryGLX() - (float)C_DINK_SCREENSIZE_X) / 2; + + glScalef(g_dglo.m_aspectRatioModX, g_dglo.m_aspectRatioModY, 1); + + CL_Mat4f mat; + glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0]); + + //OPTIMIZE - All this can be cached... maybe done in RecomputeAspectRatio() + + mat.inverse(); + + CL_Vec3f vTotal = mat.get_transformed_point(CL_Vec3f(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, 0)); + CL_Vec3f vDinkSize = mat.get_transformed_point(CL_Vec3f(C_DINK_SCREENSIZE_X*g_dglo.m_aspectRatioModX, C_DINK_SCREENSIZE_Y *g_dglo.m_aspectRatioModY, 0)); + + //CL_Vec3f vScreenToWorldPixelMod; + + //vScreenToWorldPixelModvTotal.x / vDinkSize + + g_dglo.m_centeringOffset = (vTotal - vDinkSize)/2.0f; + + glTranslatef(g_dglo.m_centeringOffset.x, g_dglo.m_centeringOffset.y, 0); + + //glGetFloatv(GL_PROJECTION_MATRIX, &Matrix); + + + +} + +void RecomputeAspectRatio() +{ + bool bStretchToFit = GetApp()->GetVar("check_stretch")->GetUINT32() != 0; + + if (bStretchToFit || g_dglo.GetActiveView() == DinkGlobals::VIEW_ZOOMED) + { + g_dglo.m_aspectRatioModX = 1.0f; + g_dglo.m_aspectRatioModY = 1.0f; + + } + else + { + float aspect_r = (float)GetPrimaryGLX() / (float)GetPrimaryGLY(); // aspect ratio + + const float correctAspectRatio = (float)C_DINK_SCREENSIZE_X / (float)C_DINK_SCREENSIZE_Y; + + /* + if (GetFakePrimaryScreenSizeX() != 0) + { + //more reliable way to get the aspect ratio + aspect_r=(float)GetFakePrimaryScreenSizeX()/(float)GetFakePrimaryScreenSizeY(); // aspect ratio + } + */ + + float aspectChange = correctAspectRatio / aspect_r; + + + if (aspectChange < 1.0f) + { + //width too big, but leave Y where it is + g_dglo.m_aspectRatioModX = aspectChange; + g_dglo.m_aspectRatioModY = 1.0f; + + } + else + { + //opposite problem, leave width where it is, but scale Y + g_dglo.m_aspectRatioModX = 1.0f; + g_dglo.m_aspectRatioModY = aspect_r / correctAspectRatio; + } + + } +} + +void DinkReInitSurfacesAfterVideoChange() +{ + if (GetDinkGameState() == DINK_GAME_STATE_PLAYING) + { + g_transitionSurf.HardKill(); + //CheckTransitionSurface(); + SAFE_DELETE(lpDDSBackGround); + lpDDSBackGround = InitOffscreenSurface(C_DINK_SCREENSIZE_X, C_DINK_SCREENSIZE_Y, IDirectDrawSurface::MODE_SHADOW_GL, false); + + g_onePixelSurf.HardKill(); + } + + RecomputeAspectRatio(); +} + +void DinkOnForeground() +{ + if (GetDinkGameState() == DINK_GAME_STATE_PLAYING) + { + + bool bForceReinit = false; + +#ifdef WINAPI + //force reinit on windows even if using iphone or android mode + bForceReinit = true; +#endif + + + if (IsDesktop() || GetEmulatedPlatformID() == PLATFORM_ID_ANDROID || bForceReinit) //xoom needs this too after a suspend/resume from hitting the power button + { + LogMsg("Forcing surface unloads via DinkOnForeground"); + DinkReInitSurfacesAfterVideoChange(); + } + + //reinit any lost surfaces that we need to + if ( g_dglos.g_gameMode > 2 || g_dglos.m_bRenderBackgroundOnLoad) + { + BuildScreenBackground(false); + } + + if (g_dglos.g_bShowingBitmap.active) + { + CopyBitmapToBackBuffer(g_dglos.g_lastBitmapShown); + } + } + +} + +void WriteLastPathSaved(string dmodDir) +{ + GetApp()->GetShared()->GetVar("last_saved_path")->Set(dmodDir); +} + +string ReadLastPathSaved() +{ + return GetApp()->GetShared()->GetVar("last_saved_path")->GetString(); +} diff --git a/source/dink/dink.h b/source/dink/dink.h new file mode 100644 index 0000000..7caaa02 --- /dev/null +++ b/source/dink/dink.h @@ -0,0 +1,762 @@ +#ifndef dink_h__ +#define dink_h__ + +#include "App.h" + +#define DSBSTATUS_PLAYING 0x00000001 +#define DSBSTATUS_BUFFERLOST 0x00000002 +#define DSBSTATUS_LOOPING 0x00000004 +#define DSBSTATUS_LOCHARDWARE 0x00000008 +#define DSBSTATUS_LOCSOFTWARE 0x00000010 +#define DSBSTATUS_TERMINATED 0x00000020 +#include "misc_util.h" +#include "video_gl.h" +#include "util/TextScanner.h" +bool InitDinkEngine(); +bool LoadGameChunk(int gameIDToLoad, float &progressOut); //0 for new game +void updateFrame(); +void finiObjects(); +struct SpriteStruct; + +//finished loading is used with g_dglo.m_curLoadState to fake the loader out +#define FINISHED_LOADING 100 + + + +enum eDinkInput +{ + DINK_INPUT_UP, + DINK_INPUT_RIGHT, + DINK_INPUT_DOWN, + DINK_INPUT_LEFT, + DINK_INPUT_BUTTON1, //punch + DINK_INPUT_BUTTON2, //talk + DINK_INPUT_BUTTON3, + DINK_INPUT_BUTTON4, + DINK_INPUT_BUTTON5, //escape + DINK_INPUT_BUTTON6, //map + DINK_INPUT_BUTTON7, + + DINK_INPUT_COUNT +}; + +enum eDinkGameMode +{ + DINK_GAME_MODE_NONE, + DINK_GAME_MODE_MOUSE, + DINK_GAME_MODE_NORMAL, + DINK_GAME_MODE_INVENTORY, +}; + +enum eDinkSubGameMode +{ + DINK_SUB_GAME_MODE_NONE, + DINK_SUB_GAME_MODE_NORMAL, + DINK_SUB_GAME_MODE_SHOWING_BMP, + DINK_SUB_GAME_MODE_DIALOG +}; + +struct BackgroundSprite +{ + rtRect32 dstRect; + rtRect32 srcRect; + int32 pic; +}; + +class BackgroundSpriteManager +{ +public: + + void Clear(); + void Add(int spriteID); + void Render(LPDIRECTDRAWSURFACE lpdest); + int GetCount() {return m_sprites.size();} +private: + + deque m_sprites; +}; + +class DinkGlobals +{ +public: + + enum eView + { + VIEW_ZOOMED, + VIEW_FULL_WITHOUT_EDGES, + VIEW_FULL, //all 640X480 of it, used in the title screen parts + VIEW_ONE_TO_ONE, + VIEW_NONE, + VIEW_COUNT + }; + + DinkGlobals() + { + memset(m_dirInput, 0, sizeof(DINK_INPUT_COUNT*sizeof(bool))); + memset(m_dirInputFinished, 0, sizeof(DINK_INPUT_COUNT*sizeof(bool))); + m_curLoadState = 0; + m_bFullKeyboardActive = false; + m_bLastFullKeyboardActive = false; + m_bSpeedUpMode = false; + m_bUsingDinkPak = false; + m_aspectRatioModX = 1.0f; //not the aspect ratio, the change to the aspect ratio so it's the correct aspect ratio. I know, it makes no sense + m_aspectRatioModY = 1.0f; + + } + + void SetView(eView view); + void ToggleView(); + void SetViewOverride(eView view); //don't allow anyone to change it + void UnSetViewOverride(); + eView GetActiveView() {if (m_viewOverride != VIEW_NONE) return m_viewOverride; return m_curView;} + bool m_dirInput[DINK_INPUT_COUNT]; + bool m_dirInputFinished[DINK_INPUT_COUNT]; //allows us to handle button up/down events on the same frame without losing + //data + string m_lastMusicPath; + string m_gamePath; //where the dink dir is located + string m_gamePathWithDir; //same as above but with /dink tagged on + string m_gameDir; //"dink/" + string m_dmodGamePathWithDir; + string m_dmodGameDir; + string m_savePath; //where the save games are + float m_fontSize; + rtRectf m_nativeGameArea; + rtRect32 m_gameArea; + rtRect32 m_orthoRenderRect; //control which part of Dink's 640X480 get drawn to the screen and at what scale + unsigned int m_transitionTimer; + float m_transitionProgress; + CL_Vec2f m_transitionOffset; + CL_Vec2f m_transitionOffsetNative; //same thing in actual screen pixels + eView m_curView; + eView m_viewOverride; + bool m_bWaitingForSkippableConversation; + //handle the loading process + int m_curLoadState; + TextScanner m_iniScanner; + eDinkGameMode m_lastGameMode; + eDinkSubGameMode m_lastSubGameMode; + eView m_lastActiveView; + bool m_lastIsUpdatingDinkStatusBar; + bool m_bFullKeyboardActive; + bool m_bLastFullKeyboardActive; + bool m_bSpeedUpMode; + + BackgroundSpriteManager m_bgSpriteMan; + bool m_bUsingDinkPak; + float m_aspectRatioModX; + float m_aspectRatioModY; + CL_Vec3f m_centeringOffset; +}; +//#define KYLES_CRAZY_VERSION + +#ifdef KYLES_CRAZY_VERSION +const int C_MAX_SEQUENCES = 9999; //Max # of sprite animations +const int C_MAX_SPRITES = 19999; +const int C_MAX_SPRITES_AT_ONCE = 500; +const int C_MAX_SCRIPT_CALLBACKS = 300; +const int max_vars = 5000; + +#define C_MAX_SPRITE_FRAMES 99 +#define C_SPRITE_MAX_FILENAME_SIZE 64 +const int C_MAX_SCRIPTS = 400; + +#else +const int32 C_MAX_SEQUENCES = 1300; //Max # of sprite animations +const int32 C_MAX_SPRITES = 6000; +const int32 C_MAX_SPRITES_AT_ONCE = 300; +const int32 C_MAX_SCRIPT_CALLBACKS = 100; +const int32 max_vars = 250; + +#define C_MAX_SPRITE_FRAMES 51 +#define C_SPRITE_MAX_FILENAME_SIZE 64 +const int32 C_MAX_SCRIPTS = 200; + + +#endif + + +struct sequence +{ + int16 frame[C_MAX_SPRITE_FRAMES]; + int16 delay[C_MAX_SPRITE_FRAMES]; + unsigned char special[C_MAX_SPRITE_FRAMES]; + + byte active; + short m_xoffset, m_yoffset; + rtRect32 m_hardbox; + eTransparencyType m_transType; + byte m_bLeftAlign; + byte m_speed; + char m_fileName[C_SPRITE_MAX_FILENAME_SIZE]; + short x,y; + short s; + byte last; + byte m_spaceAllowed; + byte m_bFrameSetUsed; + byte m_bIsAnim; +}; + +const int32 C_DINK_SCREENSIZE_X = 640; +const int32 C_DINK_SCREENSIZE_Y = 480; +const int32 C_DINK_VERSION = 109; +const int32 num_soundbanks = 20; +const int32 max_idata = 1000; +const int32 max_sounds = 100; +const int32 text_timer = 77; +const int32 text_min = 2700; + + +const int32 max_game = 20; +const int32 C_TILE_SCREEN_COUNT = 41+1; + +const int32 g_gameAreaRightBarStartX = 620; +const int32 g_gameAreaLeftOffset = 20; +const int32 C_DINK_ORIGINAL_GAME_AREA_Y = 400; //redink1's fix for the 'no sprites on pixel line above status bar' bug + + +eDinkGameMode GetDinkGameMode(); +eDinkSubGameMode GetDinkSubGameMode(); + +struct font_color +{ + int32 red; + int32 green; + int32 blue; +}; + +struct ShowingBitmapInfo +{ + bool active; + bool showdot; + int32 reserved; + int32 script; + int32 stime; + int32 picframe; +}; + +struct wait_for_button +{ + int32 script; + int32 button; + bool active; +}; + + +struct talk_struct +{ + char line[21][101]; + int32 line_return[21]; + char buffer[3000]; + int32 cur; + int32 last; + bool active; + int32 cur_view; + int32 cur_view_end; + int32 page; + int32 script; + int32 offset; + int32 newy; + int32 color; + int32 curf; + int32 timer; +}; + +struct mydata +{ + unsigned char type[100]; + unsigned short seq[100]; + unsigned char frame[100]; + int32 last_time; +}; + +struct varman +{ + int32 var; + char name[20]; + int32 scope; + bool active; +}; + + +struct item_struct +{ + bool active; + char name[10]; + int32 seq; + int32 frame; +}; + +struct player_info_tile +{ + char file[50]; +}; + +struct global_function +{ + char file[10]; + char func[20]; +}; + +struct player_info +{ + int32 version; + char gameinfo[196]; + int32 minutes; + int32 x,y,die, size, defense, dir, pframe, pseq, seq, frame, strength, base_walk, base_idle, base_hit,que; + + item_struct g_MagicData[9]; //1 index based, man I was dumb(er) back then + item_struct g_itemData[17]; + + int32 curitem, unused; + int32 counter; + bool idle; + mydata spmap[769]; + int32 button[10]; + varman var[max_vars]; + bool push_active; + int32 push_dir; + uint32 push_timer; + int32 last_talk; + int32 mouse; + bool item_magic; + int32 last_map; + int32 crap; + int32 buff[95]; + uint32 dbuff[20]; + int32 lbuff[10]; + + //redink1... use wasted space for storing file location of map.dat, dink.dat, palette, and tiles + char mapdat[50]; + char dinkdat[50]; + char palette[50]; + player_info_tile tile[42]; + global_function func[100]; + uint32 m_gameTime; + char cbuff[746]; +}; + +struct attackinfo_struct +{ + int32 time; + bool active; + int32 script; + bool hitme; + int32 last_power; + int32 wait; + int32 pull_wait; +}; + +struct player_short_info +{ + int32 version; + char gameinfo[196]; + int32 minutes; +}; + +struct refinfo +{ + char name[10]; + int32 location; + int32 current; + int32 level; + int32 end; + int32 sprite; //if more than 0, it was spawned and is owned by a sprite, if 1000 doesn't die + bool skipnext; + int32 onlevel; + int32 proc_return; + int32 arg1; + int32 arg2; + int32 arg3; + int32 arg4; + int32 arg5; + int32 arg6; + int32 arg7; + int32 arg8; + int32 arg9; +}; + +struct call_back +{ + int32 owner; + bool active; + int32 type; + char name[20]; + int32 offset; + int32 min, max; + int32 lifespan; + uint32 timer; +}; + +struct SpriteStruct +{ + int32 x,moveman; + int32 y; + int32 mx,my; + int32 lpx[C_MAX_SPRITE_FRAMES],lpy[C_MAX_SPRITE_FRAMES]; + int32 speed; + int32 brain; + int32 seq_orig,dir; + int32 seq; + int32 frame; + uint32 delay; + int32 pseq; + int32 pframe; + + bool active; + int32 attrib; + uint32 wait; + int32 timer; + int32 skip; + int32 skiptimer; + int32 size; + int32 que; + int32 base_walk; + int32 base_idle; + int32 base_attack; + + int32 base_hit; + int32 last_sound; + int32 hard; + rtRect32 alt; + int32 althard; + int32 sp_index; + bool nocontrol; + int32 idle; + int32 strength; + int32 damage; + int32 defense; + int32 hitpoints; + int32 exp; + int32 gold; + int32 base_die; + int32 kill; + int32 kill_timer; + int32 script_num; + char text[200]; + int32 owner; + int32 script; + int32 sound; + int32 callback; + int32 freeze; + bool move_active; + int32 move_script; + int32 move_dir; + int32 move_num; + bool move_nohard; + int32 follow; + int32 nohit; + bool notouch; + uint32 notouch_timer; + bool flying; + int32 touch_damage; + int32 brain_parm; + int32 brain_parm2; + bool noclip; + bool reverse; + bool disabled; + int32 target; + int32 attack_wait; + int32 move_wait; + int32 distance; + int32 last_hit; + bool live; + int32 range; + int32 attack_hit_sound; + int32 attack_hit_sound_speed; + int32 action; + int32 nodraw; + int32 frame_delay; + int32 picfreeze; + //redink1 + int32 bloodseq; + int32 bloodnum; + int32 m_containsSpriteMapData; //1 if yes, 0 if no (the save/load function adds data here if needed) +}; + +extern std::map* g_customSpriteMap[C_MAX_SPRITES_AT_ONCE]; + +struct seth_joy +{ + bool joybit[17]; //is button held down? + bool letgo[17]; //copy of old above + bool button[17]; //has button been pressed recently? + bool key[256]; + bool kletgo[256]; + bool realkey[256]; + bool right,left,up,down; + bool rightd,leftd,upd,downd; + bool rightold,leftold,upold,downold; + +}; + + +//sub struct for hardness map + +struct mega_y +{ + byte y[401]; +}; + +//struct for hardness map + +struct hit_map +{ + mega_y x[601]; +}; + +//sub struct for tile hardness + +#define C_DINK_TILE_SIZE_IN_PIXELS 50 +struct block_y +{ + byte y[C_DINK_TILE_SIZE_IN_PIXELS+1]; //the +1 is because I did everything 1 index based. Yeah, I was an idiot. +}; + +struct ts_block +{ + block_y x[C_DINK_TILE_SIZE_IN_PIXELS+1]; + bool used; + int32 hold; +}; + +//struct for hardness info, INDEX controls which hardness each block has. 800 max +//types available. +struct hardness +{ + ts_block tile[800]; + int32 index[8000]; +}; + +struct map_info +{ + char name[20]; + int32 loc[769]; + int32 music[769]; + int32 indoor[769]; + int32 v[40]; + char s[80]; + char buffer[2000]; + +}; + +struct tile +{ + int32 num, property, althard, more2; + byte more3,more4; + int32 buff[15]; +}; + +struct sprite_placement +{ + int32 x,y,seq,frame, type,size; + bool active; + int32 rotation, special,brain; + char script[13]; + char hit[13]; + char die[13]; + char talk[13]; + int32 speed, base_walk,base_idle,base_attack,base_hit,timer,que; + int32 hard; + rtRect32 alt; + int32 prop; + int32 warp_map; + int32 warp_x; + int32 warp_y; + int32 parm_seq; + int32 base_die, gold, hitpoints, strength, defense,exp, sound, vision, nohit, touch_damage; + int32 buff[5]; +}; + +struct small_map +{ + char name[20]; + tile t[97]; + int32 v[40]; + char s[80]; + sprite_placement sprite[101]; + + char script[13]; + char random[13]; + char load[13]; + char buffer[1000]; +}; + + +struct pic_info +{ + int32 m_filler; //used to store a pointer here, was moved out of the struct as it's saved/loaded in a raw way that depended on 32 bit pointers + rtRect32 box,hardbox; + int16 yoffset; + int16 xoffset; + int16 m_parentSeq; + byte m_bCustomSettingsApplied; +}; + +extern LPDIRECTDRAWSURFACE g_pSpriteSurface[C_MAX_SPRITES]; + +struct seth_sound +{ + string m_fileName; +}; + +struct soundstruct +{ + bool repeat; + int32 owner; + int32 survive; + int32 vol; + int32 freq; //what speed it was played at +}; + +class SoundBankDummy +{ +public: + SoundBankDummy() + { + m_audioID = AUDIO_HANDLE_BLANK; + } + + void Stop() {GetAudioManager()->Stop(m_audioID); m_audioID = 0; m_soundIDThatPlayedUs = 0;}; + void SetPan(float f) {GetAudioManager()->SetPan(m_audioID,f/1700);}; + void SetVolume(float f){GetAudioManager()->SetVol(m_audioID, (1800+f) / 1800);}; + bool IsInUse() {if (m_audioID == 0) return false; return GetAudioManager()->IsPlaying(m_audioID);} + void Reset() + { + if (m_audioID) + { + GetAudioManager()->Stop(m_audioID); + m_audioID = AUDIO_HANDLE_BLANK; + } + } + AudioHandle m_audioID; + int32 m_soundIDThatPlayedUs; +}; + +#define C_SHOWN_BITMAP_SIZE 128 + +struct DinkGlobalsStatic +{ + sequence g_seq[C_MAX_SEQUENCES]; + pic_info g_picInfo[C_MAX_SPRITES]; // Sprite data + + ShowingBitmapInfo g_bShowingBitmap; + wait_for_button g_wait_for_button; + attackinfo_struct g_bowStatus; + small_map g_smallMap; + player_info g_playerInfo; + + talk_struct g_talkInfo; + hit_map g_hitmap; + + int32 but_timer; + int32 dinkspeed; + + + uint32 time_start; + uint32 g_DinkUpdateTimerMS; + uint32 mDinkBasePush; + int32 walk_off_screen; + int32 keep_mouse; + int32 last_sprite_created; + int32 g_curPicIndex; //we actually need this set before finiObjects is called + int32 cur_map,cur_tile; + uint32 g_dinkTick,lastTickCount; + char current_map[50]; + char current_dat[50]; + char dversion_string[6]; + char save_game_info[200]; + font_color font_colors[16]; + int32 g_stopEntireGame; + int32 g_pushingEnabled; + bool no_running_main; + int32 process_count; + int32 show_dot; + int32 plane_process; + int32 base_timing; + int32 weapon_script; + int32 magic_script; + int32 g_gameMode; + bool midi_active; + bool mLoopMidi; + int32 flub_mode; + int32 process_warp; + bool process_upcycle; + bool process_downcycle; + uint32 cycle_clock; + int32 cycle_script; + bool bFadedDown; + bool smooth_follow; + bool mSwapped; + int32 item_timer; + int32 item_pic; + int32 mbase_count; + int32 mbase_timing; + call_back g_scriptCallback[C_MAX_SCRIPT_CALLBACKS]; + int32 g_guiLife, g_guiExp, g_guiStrength, g_guiDefense, g_guiGold, g_guiMagic, g_guiMagicLevel, g_guiLifeMax, g_guiRaise, g_guiLastMagicDraw; + int32 g_returnint; + bool bKeepReturnInt; + int32 screenlock; + + bool m_bRenderBackgroundOnLoad; + + + char g_lastBitmapShown[C_SHOWN_BITMAP_SIZE]; + char m_bufferForExpansion[4968]; +}; + + + +enum eDinkGameState +{ + //helps us to know when to automatically save the game + DINK_GAME_STATE_NOT_PLAYING, + DINK_GAME_STATE_PLAYING +}; +extern DinkGlobals g_dglo; +extern DinkGlobalsStatic g_dglos; //static data, made to write/read from disk + +bool load_game_small(int num, char * line, int *mytime); +void InitDinkPaths(string gamePath, string gameDir, string dmodGameDir); +void DinkUnloadGraphicsCache(); +void ProcessGraphicGarbageCollection(); +string GetDMODRootPath(); //where dmods are stored +bool DinkIsWaitingForSkippableDialog(); +bool DinkSkipDialogLine(); //returns true if a line was actually skipped +void DinkSetCursorPosition(CL_Vec2f vPos); +CL_Vec2f NativeToDinkCoords(CL_Vec2f vPos); +bool IsDrawingDinkStatusBar(); +bool DinkSetInventoryPosition(CL_Vec2f vPos); //returns true if an item was actually set +bool DinkCanRunScriptNow(); +bool DinkLoadPlayerScript(const string fileName); +void DinkUnloadUnusedGraphicsByUsageTime(unsigned int timeMS); + +bool LoadState(string const &path, bool bLoadPathsOnly); +bool SaveState(string const &path); +eDinkGameState GetDinkGameState(); +void SetDinkGameState(eDinkGameState state); +void DinkModStrength(int mod); +void DinkModDefense(int mod); +void DinkModMagic(int mod); +void DinkModLifeMax(int mod); +void DinkFillLife(); +void DinkModGold(int mod); +Surface* DinkGetMagicIconImage(); +Surface* DinkGetWeaponIconImage(); +float DinkGetMagicChargePercent(); +float DinkGetHealthPercent(); +bool DinkIsDoingScreenTransition(); +string DinkGetSavePath(); +void DinkAddBow(); +bool DinkGetSpeedUpMode(); +void DinkSetSpeedUpMode(bool bSpeedup); +void SaveStateWithExtra(); +void LoadStateWithExtra(); +void SaveAutoSave(); +void DinkOnForeground(); +string GetDMODStaticRootPath(); +void DinkReInitSurfacesAfterVideoChange(); +void WriteLastPathSaved(string dmodDir); +string ReadLastPathSaved(); +//is the DMOD dir if applicable + +#endif // dink_h__ \ No newline at end of file diff --git a/source/dink/dinkvar.h b/source/dink/dinkvar.h new file mode 100644 index 0000000..ecf59d3 --- /dev/null +++ b/source/dink/dinkvar.h @@ -0,0 +1,8 @@ + +#ifndef __DINKVAR +#define __DINKVAR + + +#endif + + diff --git a/source/dink/misc_util.cpp b/source/dink/misc_util.cpp new file mode 100644 index 0000000..63cafa8 --- /dev/null +++ b/source/dink/misc_util.cpp @@ -0,0 +1,355 @@ +#include "PlatformPrecomp.h" +#include "misc_util.h" +#include "util/MiscUtils.h" +void strchar(char *string, char ch) +/* This acts in the same way as strcat except it combines a string and +a single character, updating the null at the end. */ +{ + int last; + last=strlen(string); + string[last]=ch; + string[last+1]=0; +} + + +void dink_decompress( unsigned char *in, char * destBuf ) +{ + + const int stackSize = 2*1024; + unsigned char stack[stackSize], pair[128][2]; + int c, top = 0; + memset(stack, 0, stackSize); + memset(pair, 0, 128*2); + + int outputSize = 0; + + c = *in; in++; + + if (c > 127) + { + //read optional pair count and pair table + int readCount = (c-128)*2; + memcpy(&pair,in, readCount ); + in += readCount; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c); + } + // putc(c,out); + + for (;;) + { + + /* Pop byte from stack or read byte from file */ + if (top) + c = stack[--top]; + else + { + if ((c = *in) == 0) break; + in++; + } + + /* Push pair on stack or output byte to file */ + if (c > 127) + { + if (top >= stackSize ) + { +#ifdef _DEBUG + LogMsg("Malformed .d file, can't read it. Would overwrite random memory on the old Dink versions."); + LogMsg("Decompressed to %d bytes", outputSize); +#endif + destBuf[outputSize] = 0; + return; + } + stack[top++] = pair[c-128][1]; + stack[top++] = pair[c-128][0]; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c);// putc(c,out); + outputSize++; + } + } + + destBuf[outputSize] = 0; +#ifdef _DEBUG +//LogMsg("Decompressed to %d bytes", outputSize); +#endif +} + +//this legacy code is very stupid, but I'll leave it for now, it works, whatever +void decompress_nocomp (byte *in, char destBuf[]) +{ + const int stackSize = 2*1024; + unsigned char stack[stackSize], pair[128][2]; + + memset(stack, 0, stackSize); + int c, top = 0; + + int outputSize = 0; + + c = *in; in++; + + if (0) + { + //read optional pair count and pair table + int readCount = (c-128)*2; + memcpy(&pair,in, readCount ); + in += readCount; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c); + } + // putc(c,out); + + for (;;) + { + + /* Pop byte from stack or read byte from file */ + if (top) + c = stack[--top]; + else + { + if ((c = *in) == 0) break; + in++; + } + + /* Push pair on stack or output byte to file */ + if (0) + { + if (top >= stackSize ) + { +#ifdef _DEBUG + LogMsg("Malformed .c file, can't read it. Would overwrite random memory on the old Dink versions."); + destBuf[outputSize] = 0; +#endif + return; + } + stack[top++] = pair[c-128][1]; + stack[top++] = pair[c-128][0]; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c);// putc(c,out); + outputSize++; + } + } + + destBuf[outputSize] = 0; +#ifdef _DEBUG + //LogMsg("Decompressed to %d bytes", outputSize); +#endif +} + + +/* + + +void decompress (FILE *in, char destBuf[]) +{ +const int stackSize = 512*1024; +unsigned char stack[stackSize], pair[128][2]; +int c, top = 0; + +int outputSize = 0; + + +if ((c = getc(in)) > 127) +fread(pair,2,c-128,in); +else +{ + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c); +} +// putc(c,out); + +for (;;) { + + + if (top) + c = stack[--top]; + else if ((c = getc(in)) == EOF) + break; + + + if (c > 127) + { + if (top >= stackSize ) + { + LogMsg("Malformed .d file, can't read it. Would overwrite random memory on the old Dink versions."); + destBuf[outputSize] = 0; + return; + } + stack[top++] = pair[c-128][1]; + stack[top++] = pair[c-128][0]; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c);// putc(c,out); + outputSize++; + } +} + +destBuf[outputSize] = 0; +#ifdef _DEBUG +//LogMsg("Decompressed to %d bytes", outputSize); +#endif +} + + +void decompress_nocomp (FILE *in, char destBuf[]) +{ + //let's do it, only this time decompile OUR style + + unsigned char stack[16], pair[128][2]; + short c, top = 0; + + if ((c = getc(in)) > 255) + fread(pair,2,c-128,in); + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c); + } + // putc(c,out); + + for (;;) { + + if (top) + c = stack[--top]; + else if ((c = getc(in)) == EOF) + break; + + if (c > 255) { + stack[top++] = pair[c-128][1]; + stack[top++] = pair[c-128][0]; + } + else + { + if (c == '\r') c = '\n'; + if (c == 9) c = ' '; + + strchar(destBuf,c);// putc(c,out); + } + } +} + +*/ + +void replace(const char *this1, char *that, char *line) +{ + + char hold[500]; + char thisup[200],lineup[500]; + int u,i; + int checker; + +start: + + strcpy(hold,""); + strcpy(lineup,line); + strcpy(thisup,this1); + ToUpperCase(lineup); + ToUpperCase(thisup); + if (strstr(lineup,thisup) == NULL) return; + checker = -1; + strcpy(hold,""); + for (u = 0; u < strlen(line); u++) + { + if (checker > -1) + { + if (toupper(line[u]) == toupper(this1[checker])) + { + if (checker+1 == strlen(this1)) + { +doit: + u = u - strlen(this1); + u++; + for (i = 0; i < u; i++) hold[i] = line[i]; + for (i = 0; i < strlen(that); i++) hold[(u)+i]=that[i]; + hold[strlen(that)+u] = 0; + for (i = 0; i < (strlen(line)-u)-strlen(this1); i++) + { + hold[(u+strlen(that))+i] = line[(u+strlen(this1))+i]; + } + hold[(strlen(line)-strlen(this1))+strlen(that)] = 0; + strcpy(line,hold); + goto start; + } + checker++; + } else { checker = -1; } + } + if( checker == -1) + { + if (toupper(line[u]) == toupper(this1[0])) + { + checker = 1; + if (strlen(this1) == 1) goto doit; + } + } + } +} + +bool separate_string (const char str[255], int num, char liney, char *return1) +{ + int l; + int k; + l = 1; + strcpy(return1 ,""); + + for (k = 0; k <= strlen(str); k++) + { + + if (str[k] == liney) + { + l++; + if (l == num+1) + goto done; + + if (k < strlen(str)) strcpy(return1,""); + } + if (str[k] != liney) + sprintf(return1, "%s%c",return1 ,str[k]); + } + if (l < num) strcpy(return1,""); + + replace("\n","",return1); //Take the /n off it. + +/* + char s[2]; + s[0] = 9; //tab + s[1] = 0; //null + replace(s,"",return1); //Take the /n off it. +*/ + return(false); + +done: + + if (l < num) strcpy(return1,""); + + replace("\n","",return1); //Take the /n off it. + + //Msg("Took %s and turned it to %s.",str, return1); + return(true); +} diff --git a/source/dink/misc_util.h b/source/dink/misc_util.h new file mode 100644 index 0000000..2ea4792 --- /dev/null +++ b/source/dink/misc_util.h @@ -0,0 +1,18 @@ +#ifndef misc_util_h__ +#define misc_util_h__ + +#include "PlatformSetup.h" + +void getdir(char final[]); + +void dink_decompress (unsigned char *in, char * destBuf); +void decompress_nocomp (byte *in, char destBuf[]); +#ifndef SAFE_RELEASE + #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#endif +void strchar(char *string, char ch) /* This acts in the same way as strcat except it combines a string and a single character, updating the null at the end. */; +bool separate_string (const char str[255], int num, char liney, char *return1); +void replace(const char *this1, char *that, char *line); +char * lmon(int money, char *dest); +void reverse(char *st); +#endif // misc_util_h__ \ No newline at end of file diff --git a/source/dink/resource.h b/source/dink/resource.h new file mode 100644 index 0000000..696ad61 --- /dev/null +++ b/source/dink/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dink.rc +// +#define IDI_ICON1 120 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 122 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/source/dink/update_frame.cpp b/source/dink/update_frame.cpp new file mode 100644 index 0000000..e69de29 diff --git a/source/video_gl.cpp b/source/video_gl.cpp new file mode 100644 index 0000000..8c0926a --- /dev/null +++ b/source/video_gl.cpp @@ -0,0 +1,375 @@ +#include "PlatformPrecomp.h" +#include "video_gl.h" +#include "dink/misc_util.h" +#include +#include "Renderer/SoftSurface.h" +#include "App.h" + +LPDIRECTDRAWSURFACE lpDDSBack = NULL; // DirectDraw back surface +SoftSurface g_palette; + +extern LPDIRECTDRAWSURFACE lpDDSBackGround; + +bool InitializeVideoSystem() +{ + assert(!lpDDSBack); + lpDDSBack = InitOffscreenSurface(640, 480, IDirectDrawSurface::MODE_PRIMARY_GL); + + g_palette.Init(8,8, SoftSurface::SURFACE_PALETTE_8BIT); + g_palette.SetPaletteFromBMP("dink/tiles/palette.bmp", SoftSurface::COLOR_KEY_NONE); + + return true; +} + +void KillVideoEngine() +{ + SAFE_DELETE(lpDDSBack); +} + +void dderror(int hErr){}; + +IDirectDrawSurface * LoadBitmapIntoSurface(const char *pName, eTransparencyType trans, IDirectDrawSurface::eMode mode, byte *pMem) +{ + + IDirectDrawSurface * pSurf; + pSurf = new IDirectDrawSurface; + pSurf->m_mode = mode; + pSurf->m_pSurf = new SoftSurface; + + if (pMem) + { +#ifdef _DEBUG + //LogMsg("loading DDRAW bmp from mem"); +#endif + //if this is set, ignore the filename + pSurf->m_pSurf->LoadFileFromMemory(pMem, SoftSurface::eColorKeyType(trans)); + } else + { +#ifdef _DEBUG + //LogMsg("loading DDRAW bmp from file"); +#endif + pSurf->m_pSurf->LoadFile(pName, SoftSurface::eColorKeyType(trans), false); + } + + //LogMsg("loaded bitmap"); + + switch( mode) + { + case IDirectDrawSurface::MODE_SHADOW_GL: + + + break; + } + + return pSurf; +} + +void GetSizeOfSurface(IDirectDrawSurface *pdds, int *pX, int *pY) +{ + + if (pdds->m_pSurf) + { + *pX = pdds->m_pSurf->GetWidth(); + *pY = pdds->m_pSurf->GetHeight(); + return; + } else + { + assert(!"Bad surface"); + return; + } +} + +IDirectDrawSurface * InitOffscreenSurface(int x, int y, IDirectDrawSurface::eMode mode, bool bHiColor, SoftSurface *pSurfaceToCopyFrom) +{ + IDirectDrawSurface *pdds; + pdds = new IDirectDrawSurface; + pdds->m_mode = mode; + + switch (mode) + { + case IDirectDrawSurface::MODE_NORMAL: + case IDirectDrawSurface::MODE_SHADOW_GL: + + + pdds->m_pSurf = new SoftSurface; + if (bHiColor) + { + pdds->m_pSurf->Init(x,y, SoftSurface::SURFACE_RGBA); + pdds->m_pSurf->SetHasPremultipliedAlpha(true); + } else + { + pdds->m_pSurf->Init(x,y, SoftSurface::SURFACE_PALETTE_8BIT); + pdds->m_pSurf->SetPaletteFromBMP("dink/tiles/palette.bmp", SoftSurface::COLOR_KEY_NONE); + } + + if (pSurfaceToCopyFrom) + { + pdds->m_pSurf->Blit(0,0,pSurfaceToCopyFrom); + + } + if (mode == IDirectDrawSurface::MODE_SHADOW_GL) + { + pdds->m_pGLSurf = new Surface; + + if (GetApp()->GetVar("smoothing")->GetUINT32()) + { + pdds->m_pGLSurf->SetTextureType(Surface::TYPE_GUI); + + } else + { + pdds->m_pGLSurf->SetTextureType(Surface::TYPE_NO_SMOOTHING); + } + + pdds->m_pGLSurf->InitBlankSurface(x,y); + } + + break; + + case IDirectDrawSurface::MODE_PRIMARY_GL: + + break; + } + + return pdds; +} + + +IDirectDrawSurface::IDirectDrawSurface() +{ + m_pSurf = NULL; + m_mode = MODE_NORMAL; + m_pGLSurf = NULL; + m_gameTickOfLastUse = 0; +} + +IDirectDrawSurface::~IDirectDrawSurface() +{ + SAFE_DELETE(m_pSurf); + SAFE_DELETE(m_pGLSurf); +} + +glColorBytes RGBA_TO_GLCOLOR(const unsigned int color) +{ + return glColorBytes(GET_RED(color), GET_GREEN(color), GET_BLUE(color), GET_ALPHA(color)); +} + +unsigned int GLCOLOR_TO_RGBA(const glColorBytes glColor) +{ + return MAKE_RGBA(glColor.r, glColor.g, glColor.b, glColor.a); +} + +Surface * IDirectDrawSurface::GetGLSuface() +{ + assert(m_mode == MODE_SHADOW_GL && "We're only using this for item icons, and they always would be gl shadowed!"); + + UpdateShadowSurface(); + return m_pGLSurf; +} + +int IDirectDrawSurface::Blt( rtRect32 *pDestRect, IDirectDrawSurface * pSrcSurf, rtRect32 *pSrcRect, uint32 flags, DDBLTFX *pFX ) +{ + if (pSrcSurf) + { + pSrcSurf->UpdateLastUsedTime(); + } + + switch (m_mode) + { + + case MODE_SHADOW_GL: + case MODE_NORMAL: + if (flags & DDBLT_COLORFILL) + { + assert(pFX); + assert(pDestRect == NULL && "Well, we only support modifying the entire screen"); + m_pSurf->FillColor(g_palette.GetPalette()[pFX->dwFillColor]); + return DD_OK; + } + if (pSrcSurf && pSrcSurf->m_pSurf && pSrcSurf->m_pSurf->GetSurfaceType() != SoftSurface::SURFACE_NONE) + { + //assert(!"Dumbass alert"); + m_pSurf->Blit(pDestRect->left, pDestRect->top, pSrcSurf->m_pSurf, pSrcRect->left, pSrcRect->top, pSrcRect->right-pSrcRect->left, pSrcRect->bottom-pSrcRect->top); + } + + break; + + case MODE_PRIMARY_GL: + { + if (flags & DDBLT_COLORFILL) + { + + assert(pFX); + DrawRect(*pDestRect, GLCOLOR_TO_RGBA(g_palette.GetPalette()[pFX->dwFillColor])); + return DD_OK; + } + + if (!pSrcSurf) + { + assert(!"huh?!"); + return DD_OK; + } + if (pSrcSurf->m_mode == MODE_SHADOW_GL) + { + //blit from a GL surface instead + pSrcSurf->UpdateShadowSurface(); + pSrcSurf->m_pGLSurf->BlitEx(rtRectf(*pDestRect) + rtRectf(0,0, 0.5f, 0.5f), rtRectf(*pSrcRect)); + break; + } + + SoftSurface s; + s.Init(pSrcRect->GetWidth(), pSrcRect->GetHeight(), SoftSurface::SURFACE_RGBA); + + //s.FillColor(glColorBytes(0,0,0,0)); + + s.Blit(0,0, pSrcSurf->m_pSurf, pSrcRect->left,pSrcRect->top, pSrcRect->GetWidth(), pSrcRect->GetHeight()); + if (pSrcSurf->m_pSurf->GetUsesAlpha()) + { + s.SetUsesAlpha(true); + } + + g_globalBatcher.BlitRawImage(pDestRect->left,pDestRect->top, s); + } + + break; + + } + return DD_OK; +} + +void IDirectDrawSurface::UpdateShadowSurface() +{ + assert(m_mode == MODE_SHADOW_GL && "Don't call this on other modes!"); + assert(m_pSurf); + + if (m_pSurf->GetModified()) + { + //init the surface if needed + if (!m_pGLSurf) + { + m_pGLSurf = new Surface; + if (GetApp()->GetVar("smoothing")->GetUINT32()) + { + m_pGLSurf->SetTextureType(Surface::TYPE_GUI); + } else + { + m_pGLSurf->SetTextureType(Surface::TYPE_NO_SMOOTHING); + } + + + m_pGLSurf->InitBlankSurface(m_pSurf->GetWidth(),m_pSurf->GetHeight()); + } + + + if (m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_PALETTE_8BIT) + { + SoftSurface s; + s.Init(m_pSurf->GetWidth(), m_pSurf->GetHeight(), SoftSurface::SURFACE_RGBA); + s.FillColor(glColorBytes(0,0,0,0)); + s.Blit(0,0, m_pSurf); + s.FlipY(); + + + + //put it on the GL surface + m_pGLSurf->UpdateSurfaceRect(rtRect(0,0, s.GetWidth(), s.GetHeight()), s.GetPixelData()); + m_pGLSurf->SetUsesAlpha(m_pSurf->GetUsesAlpha()); + + if (s.GetHasPremultipliedAlpha()) + { + m_pGLSurf->SetBlendingMode(Surface::BLENDING_PREMULTIPLIED_ALPHA); + } + + + // if (m_pSurf) m_pSurf->SetModified(false); //WARNING: Seth changed on 8/21/2017, seems like this fixes issue with constantly re-initting surfaces + + + // SAFE_FREE(m_pSurf); + } + else + { + assert(m_pSurf); + assert(m_pGLSurf); + assert(m_pSurf->GetSurfaceType() == SoftSurface::SURFACE_RGBA); + //m_pSurf->FillColor(glColorBytes(0,0,0,0)); + if (m_pSurf->GetPixelData()) + { + m_pSurf->FlipY(); + m_pGLSurf->UpdateSurfaceRect(rtRect(0,0, m_pSurf->GetWidth(), m_pSurf->GetHeight()), m_pSurf->GetPixelData(), true); + m_pSurf->FlipY(); + m_pGLSurf->SetUsesAlpha(m_pSurf->GetUsesAlpha()); + + if (m_pSurf->GetHasPremultipliedAlpha()) + { + m_pGLSurf->SetBlendingMode(Surface::BLENDING_PREMULTIPLIED_ALPHA); + } + + } + + } + + if (m_pSurf) m_pSurf->SetModified(false); + + //assert(m_pGLSurf->GetBlendingMode() == Surface::BLENDING_PREMULTIPLIED_ALPHA); + } +} + +int IDirectDrawSurface::BltFast( int x, int y, IDirectDrawSurface *pSrcSurf, rtRect32 *pSrcRect, uint32 dwTrans ) +{ + + if (pSrcSurf) + { + pSrcSurf->UpdateLastUsedTime(); + } + + switch (m_mode) + { + case MODE_SHADOW_GL: + case MODE_NORMAL: + + if (pSrcSurf->m_mode == MODE_PRIMARY_GL) + { + //we need to copy from what is already on the screen + m_pSurf->BlitFromScreen(x, y, pSrcRect->left, pSrcRect->top, pSrcRect->GetWidth(), pSrcRect->GetHeight()); + //m_pSurf->Blit(x, y, lpDDSBackGround->m_pSurf, pSrcRect->left, pSrcRect->top, pSrcRect->GetWidth(), pSrcRect->GetHeight()); + m_pSurf->SetUsesAlpha(false); + } else + { + m_pSurf->Blit(x, y, pSrcSurf->m_pSurf, pSrcRect->left, pSrcRect->top, pSrcRect->GetWidth(), pSrcRect->GetHeight()); + } + break; + + case MODE_PRIMARY_GL: + + if (!pSrcSurf) + { + assert(!"Shit!"); + return DD_OK; + } + + if (pSrcSurf->m_mode == MODE_SHADOW_GL) + { + //blit from a GL surface instead + pSrcSurf->UpdateShadowSurface(); + pSrcSurf->m_pGLSurf->BlitEx(rtRectf(x, y, x+pSrcRect->GetWidth(), y +pSrcRect->GetHeight())+ rtRectf(0,0, 0.5f, 0.5f), rtRectf(*pSrcRect)); + break; + } + + SoftSurface s; + s.Init(pSrcRect->GetWidth(), pSrcRect->GetHeight(), SoftSurface::SURFACE_RGBA); + s.Blit(0,0, pSrcSurf->m_pSurf, pSrcRect->left,pSrcRect->top, pSrcRect->GetWidth(), pSrcRect->GetHeight()); + + if (pSrcSurf->m_pSurf->GetUsesAlpha()) + { + s.SetUsesAlpha(true); + } + g_globalBatcher.BlitRawImage(x,y, s); + break; + + } + return DD_OK; +} + +void IDirectDrawSurface::UpdateLastUsedTime() +{ + m_gameTickOfLastUse = GetBaseApp()->GetGameTick(); +} \ No newline at end of file diff --git a/source/video_gl.h b/source/video_gl.h new file mode 100644 index 0000000..9babdbf --- /dev/null +++ b/source/video_gl.h @@ -0,0 +1,114 @@ +#ifndef video_dx_h__ +#define video_dx_h__ + +#include "PlatformSetup.h" +#include "math/rtRect.h" + +class SoftSurface; +class Surface; + +typedef struct _DDCOLORKEY +{ + uint32 dwColorSpaceLowValue; // low boundary of color space that is to + // be treated as Color Key, inclusive + uint32 dwColorSpaceHighValue; // high boundary of color space that is + // to be treated as Color Key, inclusive +} DDCOLORKEY; + +typedef struct _DDBLTFX +{ + uint32 dwSize; // size of structure + uint32 dwDDFX; // FX operations + uint32 dwROP; // Win32 raster operations + uint32 dwDDROP; // Raster operations new for DirectDraw + uint32 dwRotationAngle; // Rotation angle for blt + uint32 dwZBufferOpCode; // ZBuffer compares + uint32 dwZBufferLow; // Low limit of Z buffer + uint32 dwZBufferHigh; // High limit of Z buffer + uint32 dwZBufferBaseDest; // Destination base value + uint32 dwZDestConstBitDepth; // Bit depth used to specify Z constant for destination + + DDCOLORKEY ddckDestColorkey; // DestColorkey override + DDCOLORKEY ddckSrcColorkey; // SrcColorkey override + + uint32 dwFillColor; // color in RGB or Palettized + uint32 dwFillDepth; // depth value for z-buffer + uint32 dwFillPixel; // pixel value for RGBA or RGBZ + +} DDBLTFX; + +typedef DDBLTFX * LPDDBLTFX; + +enum eTransparencyType +{ + TRANSPARENT_NONE, + TRANSPARENT_BLACK, + TRANSPARENT_WHITE, + TRANSPARENT_MAGENTA + +}; + +//blt flags +#define DDBLT_KEYSRC 0x00008000l +#define DDBLT_COLORFILL 0x00000400l +#define DDBLT_WAIT 0x01000000l + + +#define DD_OK 0L +#define DD_FALSE 1L +/**************************************************************************** +* +* BLTFAST FLAGS +* +****************************************************************************/ + +#define DDBLTFAST_NOCOLORKEY 0x00000000 +#define DDBLTFAST_SRCCOLORKEY 0x00000001 +#define DDBLTFAST_DESTCOLORKEY 0x00000002 +#define DDBLTFAST_WAIT 0x00000010 +#define DDBLTFAST_DONOTWAIT + + +//my fake DD wrapper that really uses GL under the hood +class IDirectDrawSurface +{ +public: + + enum eMode + { + MODE_NORMAL, //8 bit image only + MODE_PRIMARY_GL, //just a dummy surface, blitting to it goes straight to the screen + MODE_SHADOW_GL //keep an 8 bit version but cache a HW GL surface as well + }; + + IDirectDrawSurface(); + ~IDirectDrawSurface(); + + int Blt(rtRect32 *pDestRect, IDirectDrawSurface * pSrcSurf, rtRect32 *pSrcRect, uint32 flags, DDBLTFX *pFX); + int BltFast(int x, int y, IDirectDrawSurface *pSrcSurf, rtRect32 *pSrcRect, uint32 dwTrans);; + void UpdateLastUsedTime(); + void UpdateShadowSurface(); + Surface * GetGLSuface(); //update it and send back a valid surface if possible + + Surface *m_pGLSurf; + eMode m_mode; + SoftSurface *m_pSurf; + int m_gameTickOfLastUse; + + +}; + +typedef class IDirectDrawSurface *LPDIRECTDRAWSURFACE; + +IDirectDrawSurface * InitOffscreenSurface(int x, int y, IDirectDrawSurface::eMode mode = IDirectDrawSurface::MODE_NORMAL, bool bHiColor = false, SoftSurface * pSurfaceToCopyFrom = NULL); + +extern LPDIRECTDRAWSURFACE lpDDSBack; + +void dderror(int hErr); +bool InitializeVideoSystem(); +void KillVideoEngine(); +void GetSizeOfSurface(IDirectDrawSurface *pdds, int *pX, int *pY); + +IDirectDrawSurface * LoadBitmapIntoSurface(const char *pName, eTransparencyType trans= TRANSPARENT_NONE, IDirectDrawSurface::eMode mode = IDirectDrawSurface::MODE_SHADOW_GL, byte *pMem = NULL); + +#endif // video_dx_h__ \ No newline at end of file diff --git a/windows_vs2017/iPhoneRTDink.sln b/windows_vs2017/iPhoneRTDink.sln new file mode 100644 index 0000000..5957764 --- /dev/null +++ b/windows_vs2017/iPhoneRTDink.sln @@ -0,0 +1,59 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winRTDink", "winRTDink.vcxproj", "{AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Common Debug|Win32 = Common Debug|Win32 + Common Debug|x64 = Common Debug|x64 + Common Release|Win32 = Common Release|Win32 + Common Release|x64 = Common Release|x64 + Debug GL|Win32 = Debug GL|Win32 + Debug GL|x64 = Debug GL|x64 + Debug WebOS|Win32 = Debug WebOS|Win32 + Debug WebOS|x64 = Debug WebOS|x64 + Flash GLES Debug Test|Win32 = Flash GLES Debug Test|Win32 + Flash GLES Debug Test|x64 = Flash GLES Debug Test|x64 + Release GL AkikoBox|Win32 = Release GL AkikoBox|Win32 + Release GL AkikoBox|x64 = Release GL AkikoBox|x64 + Release GL|Win32 = Release GL|Win32 + Release GL|x64 = Release GL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Debug|Win32.ActiveCfg = Common Debug|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Debug|Win32.Build.0 = Common Debug|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Debug|x64.ActiveCfg = Common Debug|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Debug|x64.Build.0 = Common Debug|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Debug|x64.Build.2 = Release GL WinDir|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Release|Win32.ActiveCfg = Common Release|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Release|Win32.Build.0 = Common Release|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Release|x64.ActiveCfg = Common Release|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Common Release|x64.Build.0 = Common Release|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug GL|Win32.ActiveCfg = Debug GL|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug GL|Win32.Build.0 = Debug GL|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug GL|x64.ActiveCfg = Debug GL|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug GL|x64.Build.0 = Debug GL|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug WebOS|Win32.ActiveCfg = Debug WebOS|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug WebOS|Win32.Build.0 = Debug WebOS|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug WebOS|x64.ActiveCfg = Debug WebOS|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Debug WebOS|x64.Build.0 = Debug WebOS|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Flash GLES Debug Test|Win32.ActiveCfg = Debug WebOS|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Flash GLES Debug Test|Win32.Build.0 = Debug WebOS|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Flash GLES Debug Test|x64.ActiveCfg = Common Release|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Flash GLES Debug Test|x64.Build.0 = Common Release|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL AkikoBox|Win32.ActiveCfg = Release GL AkikoBox|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL AkikoBox|Win32.Build.0 = Release GL AkikoBox|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL AkikoBox|x64.ActiveCfg = Release GL AkikoBox|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL AkikoBox|x64.Build.0 = Release GL AkikoBox|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL|Win32.ActiveCfg = Release GL|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL|Win32.Build.0 = Release GL|Win32 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL|x64.ActiveCfg = Release GL|x64 + {AD1D1337-0F3F-4AC5-B9EE-EE151B0193FE}.Release GL|x64.Build.0 = Release GL|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/windows_vs2017/resource.h b/windows_vs2017/resource.h new file mode 100644 index 0000000..6129c75 --- /dev/null +++ b/windows_vs2017/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by winRTDink.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows_vs2017/winRTDink.aps b/windows_vs2017/winRTDink.aps new file mode 100644 index 0000000..12a3f27 Binary files /dev/null and b/windows_vs2017/winRTDink.aps differ diff --git a/windows_vs2017/winRTDink.rc b/windows_vs2017/winRTDink.rc new file mode 100644 index 0000000..eb47905 --- /dev/null +++ b/windows_vs2017/winRTDink.rc @@ -0,0 +1,69 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "..\\script\\win_installer\\dink.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/windows_vs2017/winRTDink.vcproj b/windows_vs2017/winRTDink.vcproj new file mode 100644 index 0000000..ffbbb61 --- /dev/null +++ b/windows_vs2017/winRTDink.vcproj @@ -0,0 +1,8301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +