From d08b4d13b944907e64346294edebe358598d71f0 Mon Sep 17 00:00:00 2001 From: Flugente Date: Sun, 11 Dec 2016 12:43:41 +0000 Subject: [PATCH] New feature: Minigames are interactive actions that happen in a dedicated screen. For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&goto=347722&#msg_347722 GameDir >= r2350 is required. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8346 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameVersion.cpp | 18 +- Screens.cpp | 2 + Strategic/LuaInitNPCs.cpp | 45 +- Tactical/Handle Items.cpp | 15 +- Tactical/Handle Items.h | 1 + Tactical/Interface Cursors.cpp | 3 + Tactical/Interface Cursors.h | 3 + Tactical/MiniGame.h | 34 + Tactical/Minigame.cpp | 1288 ++++++++++++++++++++++ Tactical/Points.cpp | 3 + Tactical/Soldier Control.cpp | 10 + Tactical/Tactical_VS2005.vcproj | 8 + Tactical/Tactical_VS2008.vcproj | 8 + Tactical/Tactical_VS2010.vcxproj | 6 +- Tactical/Tactical_VS2010.vcxproj.filters | 10 +- Tactical/Tactical_VS2013.vcxproj | 2 + Tactical/Tactical_VS2013.vcxproj.filters | 6 + Tactical/UI Cursors.cpp | 2 + Utils/Cursors.cpp | 20 +- Utils/Cursors.h | 5 + Utils/_ChineseText.cpp | 1 + Utils/_DutchText.cpp | 1 + Utils/_EnglishText.cpp | 1 + Utils/_FrenchText.cpp | 1 + Utils/_GermanText.cpp | 5 +- Utils/_ItalianText.cpp | 1 + Utils/_PolishText.cpp | 1 + Utils/_RussianText.cpp | 1 + jascreens.h | 5 + screenids.h | 1 + 30 files changed, 1478 insertions(+), 29 deletions(-) create mode 100644 Tactical/MiniGame.h create mode 100644 Tactical/Minigame.cpp diff --git a/GameVersion.cpp b/GameVersion.cpp index 5a3b420f..f47a102e 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -15,9 +15,9 @@ #ifdef JA2EDITOR #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8345 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8345 (Development Build)" }; #endif // ------------------------------ @@ -27,11 +27,11 @@ //DEBUG BUILD VERSION #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8345 (Development Build)" }; #elif defined (JA113DEMO) - CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8345 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8345 (Development Build)" }; #endif #elif defined CRIPPLED_VERSION @@ -46,16 +46,16 @@ //RELEASE BUILD VERSION #ifdef JA2UB - CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8345 (Development Build)" }; #elif defined (JA113DEMO) - CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8345 (Development Build)" }; #else - CHAR16 zVersionLabel[256] = { L"Release v1.13.8340 (Development Build)" }; + CHAR16 zVersionLabel[256] = { L"Release v1.13.8345 (Development Build)" }; #endif #endif -CHAR8 czVersionNumber[16] = { "Build 16.11.16" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 16.12.11" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; // SAVE_GAME_VERSION is defined in header, change it there diff --git a/Screens.cpp b/Screens.cpp index bede75ef..b1c1b7c6 100644 --- a/Screens.cpp +++ b/Screens.cpp @@ -69,6 +69,8 @@ Screens GameScreens[MAX_SCREENS] = { MPChatScreenInit, MPChatScreenHandle, MPChatScreenShutdown }, // OJW - 20090314 { MPConnectScreenInit, MPConnectScreenHandle, MPConnectScreenShutdown }, // OJW - 20090422 + { MiniGameScreenInit, MiniGameScreenHandle, MiniGameScreenShutdown }, // added by Flugente + #ifdef JA2BETAVERSION { AIViewerScreenInit, AIViewerScreenHandle, AIViewerScreenShutdown }, #endif diff --git a/Strategic/LuaInitNPCs.cpp b/Strategic/LuaInitNPCs.cpp index 8abc097a..c6df63c4 100644 --- a/Strategic/LuaInitNPCs.cpp +++ b/Strategic/LuaInitNPCs.cpp @@ -74,6 +74,8 @@ extern "C" { #include "Encrypted File.h" #include "BriefingRoom_Data.h" +#include "MiniGame.h" // added by Flugente + extern UINT8 gubWaitingForAllMercsToExitCode; //-------------------------- UB ------------------------------ @@ -864,6 +866,9 @@ static int l_NumNonPlayerTeamInSector( lua_State *L ); static int l_SetSamSiteHackStatus( lua_State *L ); static int l_GetSamSiteHackStatus( lua_State *L ); +static int l_SetMiniGameType( lua_State *L ); +static int l_SoldierSpendMoney( lua_State *L ); + using namespace std; UINT16 idProfil; @@ -1736,6 +1741,9 @@ void IniFunction(lua_State *L, BOOLEAN bQuests ) lua_register( L, "NumNonPlayerTeamInSector", l_NumNonPlayerTeamInSector ); lua_register( L, "SetSamSiteHackStatus", l_SetSamSiteHackStatus ); lua_register( L, "GetSamSiteHackStatus", l_GetSamSiteHackStatus ); + + lua_register( L, "SetMiniGameType", l_SetMiniGameType ); + lua_register( L, "SoldierSpendMoney", l_SoldierSpendMoney ); } #ifdef NEWMUSIC BOOLEAN LetLuaMusicControl(UINT8 Init) @@ -10582,16 +10590,12 @@ static int l_SetPendingNewScreenSEXSCREEN (lua_State *L) static int l_SetPendingNewScreen (lua_State *L) { - UINT8 n = lua_gettop(L); - - UINT8 scr = 0; - int i = 0; - for (i= 1; i<=n; i++ ) + if ( lua_gettop( L ) >= 1 ) { - if (i == 1 ) scr = lua_tointeger(L,i); - } + UINT32 scr = lua_tointeger( L, 1 ); - SetPendingNewScreen( scr ); + SetPendingNewScreen( scr ); + } return 0; } @@ -13331,3 +13335,28 @@ static int l_GetSamSiteHackStatus( lua_State *L ) return 1; } + +static int l_SetMiniGameType( lua_State *L ) +{ + if ( lua_gettop( L ) >= 1 ) + { + UINT32 usMiniGame = lua_tointeger( L, 1 ); + + SetNextGame( usMiniGame ); + } + + return 0; +} + +static int l_SoldierSpendMoney( lua_State *L ) +{ + if ( lua_gettop( L ) >= 2 ) + { + UINT8 usId = lua_tointeger( L, 1 ); + UINT32 amount = lua_tointeger( L, 2 ); + + lua_pushinteger( L, SpendMoney( MercPtrs[usId], amount ) ); + } + + return 1; +} diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index aba785b2..1ccb3538 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -8916,14 +8916,15 @@ void DoInteractiveActionDefaultResult( INT32 sGridNo, UINT8 ubID, BOOLEAN aSucce } } } - } - - if ( !aSuccess ) - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[7], pSoldier->GetName( ) ); + } } break; - + case INTERACTIVE_STRUCTURE_MINIGAME: + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[9] ); + } + break; default: break; @@ -8963,5 +8964,9 @@ BOOLEAN SpendMoney( SOLDIERTYPE *pSoldier, UINT32 aAmount ) aAmount = 0; } + // warning if we don't have enough money + if ( aAmount > 0 ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szInteractiveActionText[7], pSoldier->GetName( ) ); + return (aAmount == 0); } diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h index 8a45e3b3..71aa4fa6 100644 --- a/Tactical/Handle Items.h +++ b/Tactical/Handle Items.h @@ -130,6 +130,7 @@ typedef enum INTERACTIVE_STRUCTURE_READFILE, INTERACTIVE_STRUCTURE_WATERTAP, INTERACTIVE_STRUCTURE_SODAMACHINE, + INTERACTIVE_STRUCTURE_MINIGAME, INTERACTIVE_STRUCTURE_TYPE_MAX, } INTERACTIVE_STRUCTURE_TYPE; diff --git a/Tactical/Interface Cursors.cpp b/Tactical/Interface Cursors.cpp index 665f4a50..99b2c808 100644 --- a/Tactical/Interface Cursors.cpp +++ b/Tactical/Interface Cursors.cpp @@ -230,6 +230,9 @@ UICursor gUICursors[ NUM_UI_CURSORS ] = SODAMACHINE_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_SODAMACHINE, 0, SODAMACHINE_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_SODAMACHINE_RED, 0, + MINIGAME_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_MINIGAME, 0, + MINIGAME_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_MINIGAME_RED, 0, + }; diff --git a/Tactical/Interface Cursors.h b/Tactical/Interface Cursors.h index f8fb9b89..553b8db7 100644 --- a/Tactical/Interface Cursors.h +++ b/Tactical/Interface Cursors.h @@ -207,6 +207,9 @@ typedef enum SODAMACHINE_GREY_UICURSOR, SODAMACHINE_RED_UICURSOR, + MINIGAME_GREY_UICURSOR, + MINIGAME_RED_UICURSOR, + NUM_UI_CURSORS } UICursorDefines; diff --git a/Tactical/MiniGame.h b/Tactical/MiniGame.h new file mode 100644 index 00000000..da79ca4b --- /dev/null +++ b/Tactical/MiniGame.h @@ -0,0 +1,34 @@ +#ifndef __MINIGAME_H +#define __MINIGAME_H + +/** +* @file +* @author Flugente (bears-pit.com) +*/ + +// Flugente: lets create a few minigames +enum +{ + MINIGAME_FIRST = 0, + TETRIS = MINIGAME_FIRST, +}; + +// enums of gamestates +enum +{ + MINIGAME_STARTSCREEN = 0, + MINIGAME_GAME, + MINIGAME_GAMEOVER, + MINIGAME_PAUSE, +}; + +void SetNextGame( UINT32 ausGame, UINT32 ausGameState = MINIGAME_STARTSCREEN ); + +UINT32 MiniGameScreenInit( void ); +UINT32 MiniGameScreenHandle( void ); +UINT32 MiniGameScreenShutdown( void ); + +void MiniGame_Init_Tetris(); +UINT32 MiniGame_Handle_Tetris(); + +#endif //__MINIGAME_H \ No newline at end of file diff --git a/Tactical/Minigame.cpp b/Tactical/Minigame.cpp new file mode 100644 index 00000000..99bf4ca9 --- /dev/null +++ b/Tactical/Minigame.cpp @@ -0,0 +1,1288 @@ +/** +* @file +* @author Flugente (bears-pit.com) +*/ + +#include "builddefines.h" +#include +#include +#include "sgp.h" +#include "gameloop.h" +#include "MiniGame.h" +#include "WCheck.h" +#include "Utilities.h" +#include "WordWrap.h" +#include "Cursors.h" +#include "Line.h" +#include "Insurance Text.h" +#include "Encrypted File.h" +#include "Text.h" +#include "Multi Language Graphic Utils.h" +#include "random.h" +#include "Interface.h" +#include "DropDown.h" +#include "finances.h" +#include "Game Clock.h" +#include "GameVersion.h" +#include "GameSettings.h" +#include "message.h" +#include "Game Event Hook.h" +#include "Overhead.h" +#include "Sound Control.h" +#include "himage.h" +#include "vobject.h" +#include "vobject_blitters.h" +#include "wcheck.h" +#include "input.h" +#include "font.h" +#include "timer.h" +#include "mousesystem.h" +#include +#include +#include "Timer Control.h" +#include "Sys Globals.h" +#include "interface.h" +#include "utilities.h" +#include "render dirty.h" +#include "cursor control.h" +#include "utilities.h" +#include "english.h" +#include "WordWrap.h" +#include "gamescreen.h" + +// remember the previous screen +UINT32 guiMiniGamePreviousScreen = GAME_SCREEN; + +int gMiniGame = MINIGAME_FIRST; +int gMiniGameState = MINIGAME_STARTSCREEN; +BOOLEAN gMiniGameIsInit = FALSE; + +void SetNextGame( UINT32 ausGame, UINT32 ausGameState ) +{ + gMiniGame = ausGame; + gMiniGameState = ausGameState; + + guiMiniGamePreviousScreen = guiCurrentScreen; +} + +void MiniGameDataInit() +{ + if ( !gMiniGameIsInit ) + { + switch ( gMiniGame ) + { + case TETRIS: + MiniGame_Init_Tetris( ); + break; + + default: + break; + } + + gMiniGameIsInit = TRUE; + } +} + +BOOLEAN MiniGameExit() +{ + gMiniGameIsInit = FALSE; + + gMiniGame = MINIGAME_FIRST; + gMiniGameState = MINIGAME_STARTSCREEN; + + SetPendingNewScreen( GAME_SCREEN ); + + FadeInGameScreen(); + + HandleTacticalUI( ); + + return GAME_SCREEN; +} + +UINT32 MiniGameScreenInit( void ) +{ + return TRUE; +} + +UINT32 MiniGameScreenHandle( void ) +{ + if ( gfKeyState[ESC] ) + { + return MiniGameExit(); + } + + // init game data if not already done so + MiniGameDataInit(); + + switch ( gMiniGame ) + { + case TETRIS: + return MiniGame_Handle_Tetris( ); + break; + + default: + break; + } + + return MINIGAME_SCREEN; +} + +UINT32 MiniGameScreenShutdown( void ) +{ + return TRUE; +} + +////////////////////////////////////////////// TETRIS ////////////////////////////////////////////// +// This defines what tiles a block can belong to +enum +{ + TETRISBLOCKTYPE_NONE = 0, // empty block + TETRISBLOCKTYPE_L, + TETRISBLOCKTYPE_L_INVERTED, + TETRISBLOCKTYPE_T, + TETRISBLOCKTYPE_SQUARE, + TETRISBLOCKTYPE_LONG, + TETRISBLOCKTYPE_Z, + TETRISBLOCKTYPE_Z_INVERTED, + TETRISBLOCKTYPE_CONFLICT, // we spawned a new tile into an existing tile. If this happens the game will end + + TETRISBLOCKTYPE_MAX +}; + +typedef struct +{ + BOOLEAN resting; + BOOLEAN playercontrolled; + INT8 blocktype; +} TETRIS_BLOCK; + +typedef struct +{ + int x; + int y; +} TETRIS_BLOCK_PLAYER; + +#define TETRIS_ORIENTATIONS 4 + +typedef struct coordpair +{ + int x; + int y; + + coordpair( int a, int b ) : x( a ), y( b ) {} + coordpair( ){} +} coordpair; + +typedef struct TETRIS_BLOCK_ORIENTATION +{ + coordpair cords[TETRIS_ORIENTATIONS]; + + TETRIS_BLOCK_ORIENTATION( coordpair a, coordpair b, coordpair c, coordpair d ) + { + cords[0] = a; + cords[1] = b; + cords[2] = c; + cords[3] = d; + } + + TETRIS_BLOCK_ORIENTATION( ){} +} TETRIS_BLOCK_ORIENTATION; + +TETRIS_BLOCK_ORIENTATION gTetrisOrientation[TETRISBLOCKTYPE_MAX][TETRIS_ORIENTATIONS] = +{ + // TETRISBLOCKTYPE_NONE + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + + // TETRISBLOCKTYPE_L + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ), coordpair( 1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 1 ), coordpair( -1, 0 ), coordpair( 1, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, -1 ), coordpair( 0, -1 ), coordpair( 0, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 1, 0 ), coordpair( 1, -1 ) ), + + // TETRISBLOCKTYPE_L_INVERTED + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ), coordpair( -1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 1, 0 ), coordpair( -1, 0 ), coordpair( -1, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ), coordpair( 1, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 1, 0 ), coordpair( -1, 0 ), coordpair( 1, 1 ) ), + + // TETRISBLOCKTYPE_T + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 1, 0 ), coordpair( 0, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 1, 0 ), coordpair( 0, 1 ), coordpair( 0, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 1, 0 ), coordpair( 0, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ) ), + + // TETRISBLOCKTYPE_SQUARE + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, -1 ), coordpair( -1, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, -1 ), coordpair( -1, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, -1 ), coordpair( -1, -1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, -1 ), coordpair( -1, -1 ) ), + + // TETRISBLOCKTYPE_LONG + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ), coordpair( 0, 2 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 1, 0 ), coordpair( 2, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( 0, 1 ), coordpair( 0, 2 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 1, 0 ), coordpair( 2, 0 ) ), + + // TETRISBLOCKTYPE_Z + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 1, 0 ), coordpair( 0, 1 ), coordpair( -1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, -1 ), coordpair( -1, 0 ), coordpair( 0, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 1, 0 ), coordpair( 0, 1 ), coordpair( -1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, -1 ), coordpair( -1, 0 ), coordpair( 0, 1 ) ), + + // TETRISBLOCKTYPE_Z_INVERTED + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, 1 ), coordpair( 1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( -1, 0 ), coordpair( -1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( -1, 0 ), coordpair( 0, 1 ), coordpair( 1, 1 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, -1 ), coordpair( -1, 0 ), coordpair( -1, 1 ) ), + + // TETRISBLOCKTYPE_CONFLICT + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), + TETRIS_BLOCK_ORIENTATION( coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ), coordpair( 0, 0 ) ), +}; + +// the dimensions of the playing field +#define TETRIS_FIELD_ROWS 18 +#define TETRIS_FIELD_COLS 10 + +TETRIS_BLOCK gTetrisBlock[TETRIS_FIELD_ROWS][TETRIS_FIELD_COLS]; + +// rememeber the tiles the player controls (easier than to always look for them) +TETRIS_BLOCK_PLAYER gTetrisBlockPlayer[4]; + +BOOLEAN gTetrisplayercontrolledtile = FALSE; +int gTetrisTimeSinceTileSpawned = 0; +int gTetrisplayertileOrientation = 0; +int gTetrisNextTile = TETRISBLOCKTYPE_NONE; +int gTetrisScore = 0; +int gTetrisLinesDone = 0; +int gTetrisMenuSelection = 0; +int gTetrisMenuScreen = 0; +int gTetrisInitialLevel = 0; +int gTetrisHandicap = 0; +BOOLEAN gTetrisRenewBackground = TRUE; + +// for each level of handicap, we add 2 partially filled lines +#define TETRIS_MAX_HANDICAP 5 + +void MiniGame_Init_Tetris() +{ + for ( int i = 0; i < TETRIS_FIELD_ROWS; ++i ) + { + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + gTetrisBlock[i][j].resting = TRUE; + gTetrisBlock[i][j].playercontrolled = FALSE; + gTetrisBlock[i][j].blocktype = TETRISBLOCKTYPE_NONE; + } + } + + for ( int i = 0; i < 4; ++i ) + { + gTetrisBlockPlayer[i].x = 0; + gTetrisBlockPlayer[i].y = 0; + } + + gTetrisplayercontrolledtile = FALSE; + gTetrisTimeSinceTileSpawned = 0; + gTetrisplayertileOrientation = 0; + gTetrisNextTile = TETRISBLOCKTYPE_NONE; + gTetrisScore = 0; + gTetrisLinesDone = 0; + + gTetrisMenuSelection = 0; + gTetrisMenuScreen = 0; + gTetrisRenewBackground = TRUE; + + // don't reset, so we don't have to set it again every time we start a game + //gTetrisInitialLevel = 0; + //gTetrisHandicap = 0; +} + +void AddScore_Tetris( int aPoints ) +{ + // bonus points: + // - per level (either initial or lines completed / 10) 15% + // per handicap 10% + FLOAT bonusperc = 1.0f + (FLOAT)((15 * (gTetrisInitialLevel + gTetrisLinesDone / 10) + gTetrisHandicap * 10) / 100.0f); + + gTetrisScore += aPoints * bonusperc; +} + +void DisplayPNGImage( SGPRect aDstRect, std::string& arStrImage ) +{ + VSURFACE_DESC vs_desc = {}; + HVSURFACE hVSurface; + UINT32 uiLoadScreen; + + vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE | VSURFACE_CREATE_FROMPNG_FALLBACK; + + arStrImage.copy( vs_desc.ImageFile, sizeof(vs_desc.ImageFile) - 1 ); + + if ( FileExists( vs_desc.ImageFile ) && AddVideoSurface( &vs_desc, &uiLoadScreen ) ) + { + //Blit the background image + GetVideoSurface( &hVSurface, uiLoadScreen ); + + // Stretch the background image + SGPRect SrcRect; + SrcRect.iLeft = 0; + SrcRect.iTop = 0; + SrcRect.iRight = hVSurface->usWidth; + SrcRect.iBottom = hVSurface->usHeight; + + BltStretchVideoSurface( FRAME_BUFFER, uiLoadScreen, 0, 0, 0, &SrcRect, &aDstRect ); + + DeleteVideoSurfaceFromIndex( uiLoadScreen ); + } + else + { + ColorFillVideoSurfaceArea( FRAME_BUFFER, aDstRect.iLeft, aDstRect.iTop, aDstRect.iRight, aDstRect.iBottom, Get16BPPColor( FROMRGB( 55, 55, 55 ) ) ); + } +} + +#define MINIGAME_BG_X_LOW iScreenWidthOffset +#define MINIGAME_BG_X_HIGH (SCREEN_WIDTH - iScreenWidthOffset) +#define MINIGAME_BG_Y_LOW iScreenHeightOffset +#define MINIGAME_BG_Y_HIGH (SCREEN_HEIGHT - iScreenHeightOffset) + +#define TETRIS_BLOCKLENGTH 20 + +// game area +#define MINIGAME_X_LOW (MINIGAME_BG_X_LOW + 100) +#define MINIGAME_X_HIGH (MINIGAME_X_LOW + TETRIS_FIELD_COLS * TETRIS_BLOCKLENGTH) +#define MINIGAME_Y_LOW (MINIGAME_BG_Y_LOW + 100) +#define MINIGAME_Y_HIGH (MINIGAME_Y_LOW + TETRIS_FIELD_ROWS * TETRIS_BLOCKLENGTH) + +// we also need a small 4x4 area to display the next tile +#define TETRIS_PREVIEW_X (MINIGAME_X_HIGH + 50) +#define TETRIS_PREVIEW_Y (MINIGAME_Y_HIGH - 4 * TETRIS_BLOCKLENGTH) + +UINT32 MiniGame_Handle_Tetris() +{ + static UINT32 uiTimeOfLastUpdate = GetJA2Clock( ); + + if ( gMiniGame == TETRIS ) + { + // coordinates for the background rectangle + if ( gTetrisRenewBackground ) + { + SGPRect backgroundrect; + backgroundrect.iLeft = MINIGAME_BG_X_LOW; + backgroundrect.iTop = MINIGAME_BG_Y_LOW; + backgroundrect.iRight = MINIGAME_BG_X_HIGH; + backgroundrect.iBottom = MINIGAME_BG_Y_HIGH; + + // background: display a png picture + std::string strImage = "Interface\\background_tetris_game.png"; + if ( gMiniGameState == MINIGAME_STARTSCREEN ) + strImage = "Interface\\background_tetris_startscreen.png"; + else if ( gMiniGameState == MINIGAME_GAMEOVER ) + strImage = "Interface\\background_tetris_gameover.png"; + + DisplayPNGImage( backgroundrect, strImage ); + + gTetrisRenewBackground = FALSE; + } + + UINT16 menu_x_low = MINIGAME_BG_X_LOW + 250; + UINT16 menu_x_high = MINIGAME_BG_X_HIGH - 250; + UINT16 menu_y_low = MINIGAME_BG_Y_LOW + 200; + UINT16 menu_y_high = MINIGAME_BG_Y_HIGH - 200; + + INT32 fontused = LARGEFONT1; + + SetFontShadow( MILITARY_SHADOW ); + + // we have to keep key presses on a delay, otherwise we move to fast + BOOLEAN keyactivation_up = FALSE; + BOOLEAN keyactivation_down = FALSE; + BOOLEAN keyactivation_left = FALSE; + BOOLEAN keyactivation_right = FALSE; + BOOLEAN keyactivation_enter = FALSE; + BOOLEAN keyactivation_p = FALSE; + + UINT32 TETRIS_MENU_INPUTDELAY = 120; + static int gTetristimesincelastmove = 0; + if ( GetJA2Clock( ) - gTetristimesincelastmove > TETRIS_MENU_INPUTDELAY ) + { + // arrow keys navigate the menu + if ( gfKeyState[UPARROW] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_up = TRUE; + } + + if ( gfKeyState[DNARROW] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_down = TRUE; + } + + if ( gfKeyState[LEFTARROW] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_left = TRUE; + } + + if ( gfKeyState[RIGHTARROW] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_right = TRUE; + } + + if ( gfKeyState[ENTER] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_enter = TRUE; + } + + // 'p' key is 80 + if ( gfKeyState[80] ) + { + gTetristimesincelastmove = GetJA2Clock( ); + + keyactivation_p = TRUE; + } + } + + InvalidateScreen( ); + + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); + + if ( keyactivation_p && gMiniGameState == MINIGAME_GAME ) + { + gMiniGameState = MINIGAME_PAUSE; + gTetrisMenuScreen = 3; + gTetrisMenuSelection = 0; + } + + if ( gMiniGameState == MINIGAME_STARTSCREEN ) + { + // menu background + ColorFillVideoSurfaceArea( FRAME_BUFFER, menu_x_low, menu_y_low, menu_x_high, menu_y_high, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + // display our score + UINT16 sX = menu_x_low + 10; + UINT16 sY = menu_y_low + 10; + UINT16 width = 0; + + CHAR16 sText[800]; + swprintf( sText, L"" ); + + // different options are here, the one currently selected is coloured differently + if ( gTetrisMenuScreen == 0 ) + { + int menuentry = 0; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> New Game" : L" New Game" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Options" : L" Options" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Quit" : L" Quit" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + // arrow keys navigate the menu + if ( keyactivation_up ) + { + gTetrisMenuSelection = max( 0, gTetrisMenuSelection - 1 ); + } + else if ( keyactivation_down ) + { + gTetrisMenuSelection = min( menuentry - 1, gTetrisMenuSelection + 1 ); + } + + // ENTER selects menu entry + if ( keyactivation_enter ) + { + if ( gTetrisMenuSelection == 0 ) + { + gMiniGameState = MINIGAME_GAME; + + gTetrisRenewBackground = TRUE; + } + else if ( gTetrisMenuSelection == 1 ) + { + gTetrisMenuScreen = 1; + + gTetrisRenewBackground = TRUE; + } + else if ( gTetrisMenuSelection == 2 ) + { + return MiniGameExit( ); + } + } + } + else if ( gTetrisMenuScreen == 1 ) + { + // menu background + ColorFillVideoSurfaceArea( FRAME_BUFFER, menu_x_low, menu_y_low, menu_x_high + 100, menu_y_high, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + int menuentry = 0; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Starting Level: %d" : L" Starting Level: %d", gTetrisInitialLevel ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Handicap: %d" : L" Handicap: %d", gTetrisHandicap ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Apply" : L" Apply" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_WHITE, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + // arrow keys navigate the menu + if ( keyactivation_up ) + { + gTetrisMenuSelection = max( 0, gTetrisMenuSelection - 1 ); + } + else if ( keyactivation_down ) + { + gTetrisMenuSelection = min( menuentry - 1, gTetrisMenuSelection + 1 ); + } + // arrow keys alter settings + else if ( keyactivation_left ) + { + if ( gTetrisMenuSelection == 0 ) + { + gTetrisInitialLevel = max( 0, gTetrisInitialLevel - 1 ); + } + else if ( gTetrisMenuSelection == 1 ) + { + gTetrisHandicap = max( 0, gTetrisHandicap - 1 ); + } + } + else if ( keyactivation_right ) + { + if ( gTetrisMenuSelection == 0 ) + { + gTetrisInitialLevel = min( 20, gTetrisInitialLevel + 1 ); + } + else if ( gTetrisMenuSelection == 1 ) + { + gTetrisHandicap = min( TETRIS_MAX_HANDICAP, gTetrisHandicap + 1 ); + } + } + + // ENTER selects menu entry + if ( keyactivation_enter ) + { + if ( gTetrisMenuSelection == 2 ) + { + gTetrisMenuScreen = 0; + gTetrisMenuSelection = 1; + + gTetrisRenewBackground = TRUE; + } + } + } + } + else if ( gMiniGameState == MINIGAME_GAME ) + { + UINT32 TETRIS_TICK_FREQUENCY = max( 150, 800 - (gTetrisInitialLevel + gTetrisLinesDone / 10) * 35 ); + + BOOLEAN fDoLineUpdate = FALSE; + + if ( GetJA2Clock( ) - uiTimeOfLastUpdate > TETRIS_TICK_FREQUENCY ) + { + uiTimeOfLastUpdate = GetJA2Clock( ); + fDoLineUpdate = TRUE; + } + + // on start of the game, if we have a handicap, place handicap tiles + if ( !gTetrisTimeSinceTileSpawned && gTetrisHandicap ) + { + for ( int i = max(0, TETRIS_FIELD_ROWS - 2 * gTetrisHandicap); i < TETRIS_FIELD_ROWS; ++i ) + { + // add several lone blocks per line + int tilestoadd = min( 2 + Random( 4 ), TETRIS_FIELD_COLS - 1); + + while ( tilestoadd ) + { + int j = Random( TETRIS_FIELD_COLS ); + + if ( gTetrisBlock[i][j].blocktype == TETRISBLOCKTYPE_NONE ) + { + gTetrisBlock[i][j].resting = TRUE; + gTetrisBlock[i][j].playercontrolled = FALSE; + gTetrisBlock[i][j].blocktype = 1 + Random( TETRISBLOCKTYPE_Z_INVERTED ); + + --tilestoadd; + } + } + } + + gTetrisTimeSinceTileSpawned = 1; + } + + // coloured block that we can move + int block_x_delta = 0; + int block_y_delta = 0; + + BOOLEAN turnmove = FALSE; + + // we check keypresses to decide whether the player wants to move a piece + // however, after doing a move, wait for a 'cooldown' - we don't want to move to fast + if ( !fDoLineUpdate ) + { + if ( keyactivation_left ) + block_x_delta += -1; + + if ( keyactivation_right ) + block_x_delta += 1; + + if ( keyactivation_up ) + turnmove = TRUE; + + if ( keyactivation_down ) + block_y_delta += 1; + } + + // only continue if there is something to do + if ( fDoLineUpdate || block_x_delta || block_y_delta || turnmove ) + { + // display our score + UINT16 sX = TETRIS_PREVIEW_X + 10; + UINT16 sY = MINIGAME_Y_LOW + 10; + + // score background + ColorFillVideoSurfaceArea( FRAME_BUFFER, TETRIS_PREVIEW_X, MINIGAME_Y_LOW, TETRIS_PREVIEW_X + 130, MINIGAME_Y_LOW + 80, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + UINT16 width = 0; + + CHAR16 sText[800]; + swprintf( sText, L"" ); + + swprintf( sText, L"Score: %d", gTetrisScore ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_WHITE, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + swprintf( sText, L"Lines: %d", gTetrisLinesDone ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_WHITE, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + swprintf( sText, L"Level: %d", gTetrisInitialLevel + gTetrisLinesDone / 10 ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_WHITE, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + swprintf( sText, L"Handicap: %d", gTetrisHandicap ); + width = min( SCREEN_WIDTH - 2 * sX, StringPixLength( sText, fontused ) ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_WHITE, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + if ( turnmove ) + { + int anchor_x = gTetrisBlockPlayer[0].x; + int anchor_y = gTetrisBlockPlayer[0].y; + + INT8 playerblocktype = gTetrisBlock[anchor_y][anchor_x].blocktype; + + // check whether new orientation can be applied + BOOLEAN turnpossible = FALSE; + + int turntestcnt = 0; + + while ( !turnpossible && turntestcnt < 3) + { + ++turntestcnt; + + turnpossible = TRUE; + + ++gTetrisplayertileOrientation; + if ( gTetrisplayertileOrientation >= TETRIS_ORIENTATIONS ) + gTetrisplayertileOrientation = 0; + + TETRIS_BLOCK_ORIENTATION orientation = gTetrisOrientation[playerblocktype][gTetrisplayertileOrientation]; + + for ( int k = 0; k < 4; ++k ) + { + int new_x = anchor_x + orientation.cords[k].x; + int new_y = anchor_y + orientation.cords[k].y; + + if ( new_x < 0 || + new_x >= TETRIS_FIELD_COLS || + new_y < 0 || + new_y >= TETRIS_FIELD_ROWS || + (gTetrisBlock[new_y][new_x].blocktype != TETRISBLOCKTYPE_NONE && !gTetrisBlock[new_y][new_x].playercontrolled) + ) + { + turnpossible = FALSE; + } + } + + // if turn is possible, well, move the tile + if ( turnpossible ) + { + for ( int k = 0; k < 4; ++k ) + { + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].resting = TRUE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].playercontrolled = FALSE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype = TETRISBLOCKTYPE_NONE; + } + + for ( int k = 0; k < 4; ++k ) + { + gTetrisBlockPlayer[k].x = anchor_x + orientation.cords[k].x; + gTetrisBlockPlayer[k].y = anchor_y + orientation.cords[k].y; + + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].resting = FALSE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].playercontrolled = TRUE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype = playerblocktype; + } + + PlayJA2Sample( COMPUTER_SWITCH1_OUT, RATE_11025, 15, 1, MIDDLEPAN ); + } + } + } + + if ( fDoLineUpdate || block_x_delta || block_y_delta ) + { + BOOLEAN playercontrollost = FALSE; + + if ( fDoLineUpdate ) + { + block_y_delta += 1; + } + + if ( gTetrisplayercontrolledtile && (block_x_delta || block_y_delta) ) + { + // move the player-controlled blocks + INT8 playerblocktype = TETRISBLOCKTYPE_NONE; + + for ( int k = 0; k < 4; ++k ) + { + int x = gTetrisBlockPlayer[k].x; + int y = gTetrisBlockPlayer[k].y; + + playerblocktype = gTetrisBlock[y][x].blocktype; + + // check whether move is possible + if ( block_x_delta && + (x + block_x_delta < 0 || + x + block_x_delta >= TETRIS_FIELD_COLS || + (gTetrisBlock[y][x + block_x_delta].blocktype != TETRISBLOCKTYPE_NONE && !gTetrisBlock[y][x + block_x_delta].playercontrolled)) + ) + { + block_x_delta = 0; + } + + if ( block_y_delta && + (y + block_y_delta < 0 || + y + block_y_delta >= TETRIS_FIELD_ROWS || + (gTetrisBlock[y + block_y_delta][x].blocktype != TETRISBLOCKTYPE_NONE && !gTetrisBlock[y + block_y_delta][x].playercontrolled)) + ) + { + block_y_delta = 0; + } + + gTetrisBlock[y][x].resting = TRUE; + gTetrisBlock[y][x].playercontrolled = FALSE; + gTetrisBlock[y][x].blocktype = TETRISBLOCKTYPE_NONE; + } + + for ( int k = 0; k < 4; ++k ) + { + gTetrisBlockPlayer[k].x += block_x_delta; + gTetrisBlockPlayer[k].y += block_y_delta; + } + + // set the new ones + for ( int k = 0; k < 4; ++k ) + { + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].resting = FALSE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].playercontrolled = TRUE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype = playerblocktype; + } + + if ( fDoLineUpdate && !block_y_delta ) + { + playercontrollost = TRUE; + + // give points to the player, depending on how fast the block was placed + + // level of highest placed tile + int highestlevel = TETRIS_FIELD_ROWS; + for ( int i = 0; i < TETRIS_FIELD_ROWS; ++i ) + { + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( gTetrisBlock[i][j].blocktype != TETRISBLOCKTYPE_NONE ) + { + highestlevel = i; + + break; + } + } + + if ( highestlevel < TETRIS_FIELD_ROWS ) + break; + } + + // time the tile would have taken if it dropped on its own, assuming it would land on the highest tile + // tile spawned a bit lower, take that into account + int maxdroptime = TETRIS_TICK_FREQUENCY * ((highestlevel - 4)); + + if ( maxdroptime > 0 ) + { + int timetaken = GetJA2Clock( ) - gTetrisTimeSinceTileSpawned; + + int speedbonuspoints = 10 * max( 0, (maxdroptime - timetaken) ) / maxdroptime; + + AddScore_Tetris( speedbonuspoints ); + } + } + } + + if ( fDoLineUpdate ) + { + for ( int i = TETRIS_FIELD_ROWS - 1; i >= 0; --i ) + { + BOOLEAN lowerline = TRUE; + + // first, check whether we can lower the line in the first place + BOOLEAN emptyline = TRUE; + + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( i == TETRIS_FIELD_ROWS - 1 ) + { + lowerline = FALSE; + break; + } + else if ( gTetrisBlock[i][j].resting ) + { + lowerline = FALSE; + break; + } + else if ( !gTetrisBlock[i][j].playercontrolled && gTetrisBlock[i + 1][j].blocktype != TETRISBLOCKTYPE_NONE ) + { + lowerline = FALSE; + break; + } + + if ( gTetrisBlock[i][j].blocktype != TETRISBLOCKTYPE_NONE ) + { + emptyline = FALSE; + } + } + + // don't bother with empty lines + if ( emptyline ) + lowerline = FALSE; + + if ( lowerline ) + { + // there is space below us - move down + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( !gTetrisBlock[i][j].playercontrolled ) + { + gTetrisBlock[i + 1][j].resting = gTetrisBlock[i][j].resting; + gTetrisBlock[i + 1][j].playercontrolled = gTetrisBlock[i][j].playercontrolled; + gTetrisBlock[i + 1][j].blocktype = gTetrisBlock[i][j].blocktype; + + gTetrisBlock[i][j].resting = TRUE; + gTetrisBlock[i][j].playercontrolled = FALSE; + gTetrisBlock[i][j].blocktype = TETRISBLOCKTYPE_NONE; + } + } + } + else + { + // otherwise stop moving + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( !gTetrisBlock[i][j].playercontrolled ) + { + gTetrisBlock[i][j].resting = TRUE; + } + } + } + } + } + + // if the player-controlled tile has been put down, + // - release player control for all player-controlled blocks if one loses controls + // - erase completed lines + // - award points + BOOLEAN erasecompleteline = FALSE; + if ( playercontrollost ) + { + for ( int i = 0; i < 4; ++i ) + { + gTetrisBlock[gTetrisBlockPlayer[i].y][gTetrisBlockPlayer[i].x].playercontrolled = FALSE; + gTetrisBlock[gTetrisBlockPlayer[i].y][gTetrisBlockPlayer[i].x].resting = TRUE; + + gTetrisBlockPlayer[i].x = 0; + gTetrisBlockPlayer[i].y = 0; + } + + gTetrisplayercontrolledtile = FALSE; + + PlayJA2Sample( COMPUTER_BEEP2_IN, RATE_11025, 15, 1, MIDDLEPAN ); + + // + int linesdone = 0; + for ( int i = TETRIS_FIELD_ROWS - 1; i >= 0; --i ) + { + BOOLEAN eraseline = TRUE; + + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( gTetrisBlock[i][j].blocktype == TETRISBLOCKTYPE_NONE ) + { + eraseline = FALSE; + } + + // if a line has been erased below, we will fall down... + if ( erasecompleteline ) + { + gTetrisBlock[i][j].resting = FALSE; + } + } + + if ( eraseline ) + { + erasecompleteline = TRUE; + + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + gTetrisBlock[i][j].resting = TRUE; + gTetrisBlock[i][j].playercontrolled = FALSE; + gTetrisBlock[i][j].blocktype = TETRISBLOCKTYPE_NONE; + } + + ++linesdone; + } + } + + if ( linesdone ) + { + switch ( linesdone ) + { + case 1: AddScore_Tetris( 40 ); break; + case 2: AddScore_Tetris( 100 ); break; + case 3: AddScore_Tetris( 300 ); break; + case 4: + AddScore_Tetris( 1200 ); + + if ( gusSelectedSoldier != NOBODY ) + { + // Set to current + SOLDIERTYPE* pSoldier = NULL; + GetSoldier( &pSoldier, gusSelectedSoldier ); + + if ( pSoldier ) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); + } + } + break; + } + + gTetrisLinesDone += linesdone; + } + } + + // if the plyer doesn't currently control a tile, add next one + if ( !gTetrisplayercontrolledtile ) + { + // check whether there are still tiles dropping... if not, add new tile + BOOLEAN stilldropping = FALSE; + for ( int i = TETRIS_FIELD_ROWS - 1; i >= 0; --i ) + { + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( !gTetrisBlock[i][j].resting ) + { + stilldropping = TRUE; + break; + } + } + } + + if ( !stilldropping ) + { + // add new playercontrolled piece + // check if entry space is free + BOOLEAN spaceisfree = TRUE; + + if ( gTetrisNextTile == TETRISBLOCKTYPE_NONE ) + gTetrisNextTile = 1 + Random( TETRISBLOCKTYPE_Z_INVERTED ); + + int playerblocktype = gTetrisNextTile; + + gTetrisNextTile = 1 + Random( TETRISBLOCKTYPE_Z_INVERTED ); + + gTetrisplayertileOrientation = 0; + + TETRIS_BLOCK_ORIENTATION orientation = gTetrisOrientation[playerblocktype][gTetrisplayertileOrientation]; + + int anchor_x = 4; + int anchor_y = 1; + + for ( int k = 0; k < 4; ++k ) + { + gTetrisBlockPlayer[k].x = anchor_x + orientation.cords[k].x; + gTetrisBlockPlayer[k].y = anchor_y + orientation.cords[k].y; + + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].resting = FALSE; + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].playercontrolled = TRUE; + + if ( gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype != TETRISBLOCKTYPE_NONE ) + { + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype = TETRISBLOCKTYPE_CONFLICT; + spaceisfree = FALSE; + } + else + { + gTetrisBlock[gTetrisBlockPlayer[k].y][gTetrisBlockPlayer[k].x].blocktype = playerblocktype; + } + } + + gTetrisplayercontrolledtile = TRUE; + gTetrisTimeSinceTileSpawned = GetJA2Clock(); + + if ( !spaceisfree ) + { + gMiniGameState = MINIGAME_GAMEOVER; + gTetrisMenuScreen = 2; + gTetrisMenuSelection = 0; + + // game over, man, game over! + if ( gusSelectedSoldier != NOBODY ) + { + // Set to current + SOLDIERTYPE* pSoldier = NULL; + GetSoldier( &pSoldier, gusSelectedSoldier ); + + if ( pSoldier ) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + } + } + } + } + } + } + + // draw stuff + { + UINT16 col_red = Get16BPPColor( FROMRGB( 255, 0, 0 ) ); + UINT16 col_green = Get16BPPColor( FROMRGB( 0, 255, 0 ) ); + UINT16 col_blue = Get16BPPColor( FROMRGB( 0, 0, 255 ) ); + UINT16 col_yellow = Get16BPPColor( FROMRGB( 255, 255, 0 ) ); + UINT16 col_violet = Get16BPPColor( FROMRGB( 127, 0, 127 ) ); + UINT16 col_cyan = Get16BPPColor( FROMRGB( 0, 127, 127 ) ); + UINT16 col_orange = Get16BPPColor( FROMRGB( 255, 127, 0 ) ); + UINT16 col_pink = Get16BPPColor( FROMRGB( 255, 0, 255 ) ); + UINT16 col_grey = Get16BPPColor( FROMRGB( 55, 55, 55 ) ); + + // draw blocks + { + // background + ColorFillVideoSurfaceArea( FRAME_BUFFER, MINIGAME_X_LOW, MINIGAME_Y_LOW, MINIGAME_X_HIGH, MINIGAME_Y_HIGH, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + for ( int i = 0; i < TETRIS_FIELD_ROWS; ++i ) + { + for ( int j = 0; j < TETRIS_FIELD_COLS; ++j ) + { + if ( gTetrisBlock[i][j].blocktype != TETRISBLOCKTYPE_NONE ) + { + UINT16 x = MINIGAME_X_LOW + j * TETRIS_BLOCKLENGTH; + UINT16 y = MINIGAME_Y_LOW + i * TETRIS_BLOCKLENGTH; + + UINT16 colour1 = 0; + UINT16 colour2 = col_grey; + + switch ( gTetrisBlock[i][j].blocktype ) + { + case TETRISBLOCKTYPE_L: colour1 = col_red; break; + case TETRISBLOCKTYPE_L_INVERTED: colour1 = col_green; break; + case TETRISBLOCKTYPE_T: colour1 = col_blue; break; + case TETRISBLOCKTYPE_SQUARE: colour1 = col_yellow; break; + case TETRISBLOCKTYPE_LONG: colour1 = col_violet; break; + case TETRISBLOCKTYPE_Z: colour1 = col_cyan; break; + case TETRISBLOCKTYPE_Z_INVERTED: colour1 = col_orange; break; + case TETRISBLOCKTYPE_CONFLICT: colour1 = col_pink; break; + case TETRISBLOCKTYPE_NONE: + default: + colour1 = Get16BPPColor( FROMRGB( 0, 0, 0 ) ); + colour2 = colour1; + break; + } + + ColorFillVideoSurfaceArea( FRAME_BUFFER, x, y, x + TETRIS_BLOCKLENGTH, y + TETRIS_BLOCKLENGTH, colour2 ); + ColorFillVideoSurfaceArea( FRAME_BUFFER, x + 1, y + 1, x + TETRIS_BLOCKLENGTH - 1, y + TETRIS_BLOCKLENGTH - 1, colour1 ); + } + } + } + } + + // draw preview area + { + // we also need a small 4x4 area to display the next tile + ColorFillVideoSurfaceArea( FRAME_BUFFER, TETRIS_PREVIEW_X, TETRIS_PREVIEW_Y, TETRIS_PREVIEW_X + 4 * TETRIS_BLOCKLENGTH, MINIGAME_Y_HIGH, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + int preview_anchor_x = 2; + int preview_anchor_y = 1; + + TETRIS_BLOCK_ORIENTATION previeworientation = gTetrisOrientation[gTetrisNextTile][0]; + + UINT16 colour1 = 0; + UINT16 colour2 = col_grey; + + switch ( gTetrisNextTile ) + { + case TETRISBLOCKTYPE_L: colour1 = col_red; break; + case TETRISBLOCKTYPE_L_INVERTED: colour1 = col_green; break; + case TETRISBLOCKTYPE_T: colour1 = col_blue; break; + case TETRISBLOCKTYPE_SQUARE: colour1 = col_yellow; break; + case TETRISBLOCKTYPE_LONG: colour1 = col_violet; break; + case TETRISBLOCKTYPE_Z: colour1 = col_cyan; break; + case TETRISBLOCKTYPE_Z_INVERTED: colour1 = col_orange; break; + case TETRISBLOCKTYPE_CONFLICT: colour1 = col_pink; break; + case TETRISBLOCKTYPE_NONE: + default: + colour1 = Get16BPPColor( FROMRGB( 0, 0, 0 ) ); + colour2 = colour1; + break; + } + + for ( int k = 0; k < 4; ++k ) + { + UINT16 x = TETRIS_PREVIEW_X + (preview_anchor_x + previeworientation.cords[k].x) * TETRIS_BLOCKLENGTH; + UINT16 y = TETRIS_PREVIEW_Y + (preview_anchor_y + previeworientation.cords[k].y) * TETRIS_BLOCKLENGTH; + + ColorFillVideoSurfaceArea( FRAME_BUFFER, x, y, x + TETRIS_BLOCKLENGTH, y + TETRIS_BLOCKLENGTH, colour2 ); + ColorFillVideoSurfaceArea( FRAME_BUFFER, x + 1, y + 1, x + TETRIS_BLOCKLENGTH - 1, y + TETRIS_BLOCKLENGTH - 1, colour1 ); + } + } + } + } + } + else if ( gMiniGameState == MINIGAME_GAMEOVER ) + { + ColorFillVideoSurfaceArea( FRAME_BUFFER, menu_x_low, menu_y_low, menu_x_high, menu_y_high, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + // display our score + UINT16 sX = menu_x_low + 10; + UINT16 sY = menu_y_low + 10; + UINT16 width = 0; + + CHAR16 sText[800]; + swprintf( sText, L"" ); + + swprintf( sText, L"GAME OVER" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_RED, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + if ( gTetrisMenuScreen == 2 ) + { + int menuentry = 0; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Main Menu" : L" Main Menu" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_RED, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Quit" : L" Quit" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_RED, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + // arrow keys navigate the menu + if ( keyactivation_up ) + { + gTetrisMenuSelection = max( 0, gTetrisMenuSelection - 1 ); + } + else if ( keyactivation_down ) + { + gTetrisMenuSelection = min( menuentry - 1, gTetrisMenuSelection + 1 ); + } + + // ENTER selects menu entry + if ( keyactivation_enter ) + { + if ( gTetrisMenuSelection == 0 ) + { + MiniGame_Init_Tetris(); + + gMiniGameState = MINIGAME_STARTSCREEN; + gTetrisRenewBackground = TRUE; + } + else if ( gTetrisMenuSelection == 1 ) + { + return MiniGameExit( ); + } + } + } + } + else if ( gMiniGameState == MINIGAME_PAUSE ) + { + ColorFillVideoSurfaceArea( FRAME_BUFFER, menu_x_low, menu_y_low, menu_x_high, menu_y_high - 20, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + + // display our score + UINT16 sX = menu_x_low + 10; + UINT16 sY = menu_y_low + 10; + UINT16 width = 0; + + CHAR16 sText[800]; + swprintf( sText, L"" ); + + swprintf( sText, L"Game paused" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, FONT_RED, sText, FONT_MCOLOR_BLACK, FALSE, 0 ); + + if ( gTetrisMenuScreen == 3 ) + { + int menuentry = 0; + + swprintf( sText, (gTetrisMenuSelection == menuentry) ? L"-> Continue" : L" Continue" ); + width = StringPixLength( sText, fontused ); + sY += DisplayWrappedString( sX, sY, width, 2, fontused, (gTetrisMenuSelection == menuentry) ? FONT_BLACK : FONT_RED, + sText, (gTetrisMenuSelection == menuentry) ? FONT_MCOLOR_WHITE : FONT_MCOLOR_BLACK, FALSE, 0 ); + ++menuentry; + + if ( keyactivation_enter ) + { + gMiniGameState = MINIGAME_GAME; + + gTetrisRenewBackground = TRUE; + } + } + } + } + + return MINIGAME_SCREEN; +} + +////////////////////////////////////////////// TETRIS ////////////////////////////////////////////// diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index e9c5ccae..f2dd1d6f 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -4031,6 +4031,9 @@ INT16 GetAPsForInteractiveAction( SOLDIERTYPE *pSoldier, UINT8 usActionType ) case INTERACTIVE_STRUCTURE_SODAMACHINE: sAPCost += APBPConstants[AP_SODAMACHINE]; break; + case INTERACTIVE_STRUCTURE_MINIGAME: + sAPCost += APBPConstants[AP_READFILE]; + break; default: break; diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index c9ab8258..354ea439 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -19135,6 +19135,16 @@ UINT16 SOLDIERTYPE::GetInteractiveActionSkill( INT32 sGridNo, UINT8 usLevel, UIN } break; + case INTERACTIVE_STRUCTURE_MINIGAME: + { + if ( this->ubProfile == ROBOT || IsVehicle( this ) ) + return 0; + + // we are pros at playing games + return 100; + } + break; + default: break; } diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index f37e1dbb..ed2e538d 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -530,6 +530,10 @@ RelativePath=".\Militia Control.h" > + + @@ -884,6 +888,10 @@ RelativePath=".\Militia Control.cpp" > + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index 77290a64..4cdf15e0 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -534,6 +534,10 @@ RelativePath="Militia Control.h" > + + @@ -886,6 +890,10 @@ RelativePath="Militia Control.cpp" > + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index 675b153e..7c477e8a 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -71,7 +71,8 @@ - + + @@ -159,7 +160,8 @@ - + + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index 7b9420ed..8f3a055c 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -144,7 +144,10 @@ Header Files - + + Header Files + + Header Files @@ -404,7 +407,10 @@ Source Files - + + Source Files + + Source Files diff --git a/Tactical/Tactical_VS2013.vcxproj b/Tactical/Tactical_VS2013.vcxproj index 27a71c4e..6cf94a47 100644 --- a/Tactical/Tactical_VS2013.vcxproj +++ b/Tactical/Tactical_VS2013.vcxproj @@ -71,6 +71,7 @@ + @@ -160,6 +161,7 @@ + diff --git a/Tactical/Tactical_VS2013.vcxproj.filters b/Tactical/Tactical_VS2013.vcxproj.filters index 55b87bd2..7a3ff08a 100644 --- a/Tactical/Tactical_VS2013.vcxproj.filters +++ b/Tactical/Tactical_VS2013.vcxproj.filters @@ -276,6 +276,9 @@ Header Files + + Header Files + @@ -704,5 +707,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 87e52e45..24aea239 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -2294,6 +2294,8 @@ UINT8 HandleHackCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFla return skill ? WATERTAP_GREY_UICURSOR : WATERTAP_RED_UICURSOR; else if ( possibleaction == INTERACTIVE_STRUCTURE_SODAMACHINE ) return skill ? SODAMACHINE_GREY_UICURSOR : SODAMACHINE_RED_UICURSOR; + else if ( possibleaction == INTERACTIVE_STRUCTURE_MINIGAME ) + return skill ? MINIGAME_GREY_UICURSOR : MINIGAME_RED_UICURSOR; return NO_UICURSOR; } diff --git a/Utils/Cursors.cpp b/Utils/Cursors.cpp index ed64c5ee..d4285a50 100644 --- a/Utils/Cursors.cpp +++ b/Utils/Cursors.cpp @@ -140,6 +140,9 @@ CursorFileData CursorFileDatabase[] = {"CURSORS\\sodamachine.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: soda machine {"CURSORS\\sodamachine_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + {"CURSORS\\minigame.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, // Flugente: minigames + {"CURSORS\\minigame_r.sti" , FALSE, 0, ANIMATED_CURSOR, 3, NULL}, + { "CURSORS\\can_01.sti" , FALSE, 0, 0, 0, NULL }, { "CURSORS\\can_02.sti" , FALSE, 0, 0, 0, NULL }, { "CURSORS\\cur_tagr_ncth.sti" , FALSE, 0, ANIMATED_CURSOR, 7, NULL }, @@ -1290,7 +1293,7 @@ CursorData CursorDatabase[] = 0, 0, 0, 0, 0, 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, - // Flugente: soad machine + // Flugente: soda machine {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, C_SODAMACHINE, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, 0, 0, 0, 0, 0, @@ -1304,6 +1307,21 @@ CursorData CursorDatabase[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + // Flugente: minigames + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_MINIGAME, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, + + {C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, + C_MINIGAME_RED, 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 2, CENTER_CURSOR, CENTER_CURSOR, 0, 0, 0, 0}, { C_TRINGS, 6, 0, HIDE_SUBCURSOR, HIDE_SUBCURSOR, C_FUEL , 0, 0, CENTER_SUBCURSOR, CENTER_SUBCURSOR, diff --git a/Utils/Cursors.h b/Utils/Cursors.h index 0d3fbf1d..5cad24fc 100644 --- a/Utils/Cursors.h +++ b/Utils/Cursors.h @@ -174,6 +174,9 @@ typedef enum CURSOR_SODAMACHINE, CURSOR_SODAMACHINE_RED, + CURSOR_MINIGAME, + CURSOR_MINIGAME_RED, + CURSOR_FUEL, CURSOR_FUEL_RED, @@ -261,6 +264,8 @@ typedef enum C_WATERTAP_RED, C_SODAMACHINE, C_SODAMACHINE_RED, + C_MINIGAME, + C_MINIGAME_RED, C_FUEL, C_FUEL_RED, C_ACTIONMODERED_NCTH, diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 609c1b71..0c001525 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -11184,6 +11184,7 @@ STR16 szInteractiveActionText[] = L"%s 没有足够的钱。那真让人难为情",//L"%s doesn't have enough money. That's just embarassing.", L"%s 从水龙头喝水",//L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; // WANNE: Some Chinese specific strings that needs to be in unicode! diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 3161dc73..a6828367 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -11202,6 +11202,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //DUTCH diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 4b6287f9..737fa09e 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -11185,6 +11185,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", }; #endif //ENGLISH diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 888fcff9..204dac28 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -11184,6 +11184,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //FRENCH diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 44f595cd..179d8292 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -10986,8 +10986,8 @@ STR16 szWeatherTypeText[] = // TODO.Translate STR16 szSnakeText[] = { - L"%s evaded a snake attack!", - L"%s was attacked by a snake!", + L"%s weicht Schlangenangriff aus!", + L"%s wurde von Schlange angegriffen!", }; STR16 szSMilitiaResourceText[] = @@ -11014,6 +11014,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //GERMAN diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 53a88d24..ef9c1c7c 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -11193,6 +11193,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //ITALIAN diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index fe5f5266..34130bc0 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -11206,6 +11206,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //POLISH diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 35010ac2..c292dde6 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -11185,6 +11185,7 @@ STR16 szInteractiveActionText[] = L"%s doesn't have enough money. That's just embarassing.", L"%s drank from water tap", + L"This machine doesn't seem to be working.", // TODO.Translate }; #endif //RUSSIAN diff --git a/jascreens.h b/jascreens.h index 8d5dc579..c1733ee8 100644 --- a/jascreens.h +++ b/jascreens.h @@ -144,6 +144,11 @@ extern UINT32 MPConnectScreenInit( void ); extern UINT32 MPConnectScreenHandle( void ); extern UINT32 MPConnectScreenShutdown( void ); +extern UINT32 MiniGameScreenInit( void ); +extern UINT32 MiniGameScreenHandle( void ); +extern UINT32 MiniGameScreenShutdown( void ); + + // External functions void DisplayFrameRate( ); diff --git a/screenids.h b/screenids.h index 357fe53d..35dfa95c 100644 --- a/screenids.h +++ b/screenids.h @@ -33,6 +33,7 @@ typedef enum ScreenTypes MP_SCORE_SCREEN, // OJW - 20081222 MP_CHAT_SCREEN, // OJW - 20090315 MP_CONNECT_SCREEN, //OJW - 20090422 + MINIGAME_SCREEN, // Flugente #ifdef JA2BETAVERSION AIVIEWER_SCREEN,