From 8fa1c2a4e61fe027cdea39adf672cda02e6054a7 Mon Sep 17 00:00:00 2001 From: Wanne Date: Thu, 19 Mar 2009 15:31:55 +0000 Subject: [PATCH] Merged Multiplayer UI patch from Zathras: New Features - Added hits, misses, accuracy to scoreboard - Added in-game chat with history - Added more options from the ini to the host screen, Use NIV and Enable civillians bugfixes - Clients connecting at the same time controlling the wrong client - Team Deathmatch working again - Refreshing the player list after a player changes team / edge - AI is always on for Co-op now - There is now always a scoreboard in Co-op even when you lose. - scores on the Co-op scoreboard have been fixed for all deaths including bleeding - Start Game button now only appears for server - Fixed cleaning up game resources on disconnection - Disabled the 1,2,3,4 keys for connecting / disconnecting - Fixed victory conditions for all game modes - Fixed players names getting copied into TeamTurnString each game resulting in multiple names - Fixed Assertion bug caused by the game sometimes calling SetCurrentWorldSector more than once before placement of mercs - Fixed a bug that was possible when merging items such as M14 and EBR stock on mapscreen. - Fixed bug with game starting while a player was in chat, closes chat window when game is starting - Fixed bug with game starting while a player was in the options screen, if the player leaves the mapscreen while ready, they are set to unready - Team and Spawn direction popups changed to use buttons to open/close them - Disabled players joining after the laptop has been unlocked, as they would be out of state with any hires git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2628 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameInitOptionsScreen.cpp | 2 +- GameSettings.cpp | 1 + GameVersion.cpp | 4 +- JA2.vcproj | 24 + Laptop/laptop.cpp | 5 + MPChatScreen.cpp | 1569 ++++++++++++++++++++ MPChatScreen.h | 27 + MPHostScreen.cpp | 1507 +++++++++++++++++++ MPHostScreen.h | 12 + MPJoinScreen.cpp | 742 +++++++++ MPJoinScreen.h | 12 + MPScoreScreen.cpp | 642 ++++++++ MPScoreScreen.h | 12 + MainMenuScreen.cpp | 4 +- MessageBoxScreen.cpp | 86 +- MessageBoxScreen.h | 4 + Multiplayer/client.cpp | 1210 ++++++++++++--- Multiplayer/connect.h | 53 + Multiplayer/fresh_header.h | 2 + Multiplayer/network.h | 31 + Multiplayer/server.cpp | 458 ++++-- Options Screen.cpp | 1 - Options Screen.h | 2 + SCREENS.cpp | 5 +- Standard Gaming Platform/Button System.cpp | 37 + Standard Gaming Platform/Button System.h | 3 + Strategic/Map Screen Interface Bottom.cpp | 31 +- Strategic/Map Screen Interface Bottom.h | 2 + Strategic/mapscreen.cpp | 955 +++++++++++- Strategic/mapscreen.h | 1 + Tactical/Overhead.cpp | 52 +- Tactical/Soldier Ani.cpp | 7 + Tactical/TeamTurns.cpp | 3 +- Tactical/Turn Based Input.cpp | 9 +- Utils/Debug Control.cpp | 10 + Utils/Debug Control.h | 1 + Utils/Text.h | 99 ++ Utils/Timer Control.h | 1 + Utils/Utilities.cpp | 1 + Utils/_ChineseText.cpp | 126 ++ Utils/_DutchText.cpp | 126 ++ Utils/_EnglishText.cpp | 125 ++ Utils/_FrenchText.cpp | 126 ++ Utils/_GermanText.cpp | 126 ++ Utils/_ItalianText.cpp | 126 ++ Utils/_PolishText.cpp | 126 ++ Utils/_RussianText.cpp | 126 ++ Utils/_TaiwaneseText.cpp | 126 ++ Utils/message.h | 9 + gameloop.cpp | 15 +- gamescreen.cpp | 2 +- ja2_2005Express.vcproj | 36 +- ja2_VS2008.vcproj | 32 + jascreens.h | 18 + screenids.h | 4 + 55 files changed, 8514 insertions(+), 362 deletions(-) create mode 100644 MPChatScreen.cpp create mode 100644 MPChatScreen.h create mode 100644 MPHostScreen.cpp create mode 100644 MPHostScreen.h create mode 100644 MPJoinScreen.cpp create mode 100644 MPJoinScreen.h create mode 100644 MPScoreScreen.cpp create mode 100644 MPScoreScreen.h diff --git a/GameInitOptionsScreen.cpp b/GameInitOptionsScreen.cpp index 7227d0b7..2ffe2d53 100644 --- a/GameInitOptionsScreen.cpp +++ b/GameInitOptionsScreen.cpp @@ -933,7 +933,7 @@ void BtnDifficultyTogglesCallback( GUI_BUTTON *btn, INT32 reason ) BOOLEAN fAnyChecked=FALSE; //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) diff --git a/GameSettings.cpp b/GameSettings.cpp index 4148cc1a..b6b86d87 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -987,6 +987,7 @@ void LoadGameAPBPConstants() void FreeGameExternalOptions() { + if (gGameExternalOptions.iaIMPSlots != NULL) // OJW - 20081129 - Fix memory leak when calling LoadGameExternalOptions twice MemFree( gGameExternalOptions.iaIMPSlots); } diff --git a/GameVersion.cpp b/GameVersion.cpp index 7212031c..9690bf1f 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -28,11 +28,11 @@ CHAR16 zVersionLabel[256] = { L"Beta v. 0.98" }; #else //RELEASE BUILD VERSION - CHAR16 zVersionLabel[256] = { L"Release v1.13.2620" }; + CHAR16 zVersionLabel[256] = { L"Release v1.13.2628" }; #endif -CHAR8 czVersionNumber[16] = { "Build 09.03.12" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 09.03.19" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; diff --git a/JA2.vcproj b/JA2.vcproj index 1163385d..ef60cbc2 100644 --- a/JA2.vcproj +++ b/JA2.vcproj @@ -1864,6 +1864,18 @@ BrowseInformation="1"/> + + + + + + + + + + + + + + + + diff --git a/Laptop/laptop.cpp b/Laptop/laptop.cpp index 41d37792..e460ff3a 100644 --- a/Laptop/laptop.cpp +++ b/Laptop/laptop.cpp @@ -1025,6 +1025,11 @@ void ExitLaptop() return; } + if (gfEnterLapTop) + { + // we have already exited the laptop, its not currently initialised + return; + } if ( DidGameJustStart() ) { SetMusicMode( MUSIC_LAPTOP ); diff --git a/MPChatScreen.cpp b/MPChatScreen.cpp new file mode 100644 index 00000000..520d733d --- /dev/null +++ b/MPChatScreen.cpp @@ -0,0 +1,1569 @@ +#ifdef PRECOMPILEDHEADERS + #include "JA2 All.h" +#else + #include "sgp.h" + #include "screenids.h" + #include "Timer Control.h" + #include "sys globals.h" + #include "fade screen.h" + #include "sysutil.h" + #include "vobject_blitters.h" + #include "MercTextBox.h" + #include "wcheck.h" + #include "cursors.h" + #include "font control.h" + #include "Game Clock.h" + #include "Map Screen Interface.h" + #include "renderworld.h" + #include "gameloop.h" + #include "english.h" + #include "GameSettings.h" + #include "Interface Control.h" + #include "cursor control.h" + #include "laptop.h" + #include "text.h" + #include "Text Input.h" + #include "overhead map.h" + #include "MPChatScreen.h" + #include "WordWrap.h" + #include "Render Dirty.h" +#include "message.h" +#include "utilities.h" +#include "connect.h" +#endif + +#define CHATBOX_WIDTH 310 // 350 is the max size, the PrepareMercPopupBox will add the X_MARGIN to both sides +#define CHATBOX_Y_MARGIN_NOLOG 25 +#define CHATBOX_Y_MARGIN_LOG 80 +#define CHATBOX_Y_MARGIN_BOTTOM 80 +#define CHATBOX_X_MARGIN 30 // pad box width 20 either side of text pixel length, but i use half of this value for control margins + +#define CHATBOX_LOG_WIDTH 300 +#define CHATBOX_LOG_HEIGHT 80 +#define CHATBOX_LOG_TXTBORDER 4 // offset till text renderable area on all sides + +#define CHATBOX_SCROLL_WIDTH 17 +#define CHATBOX_SCROLL_HEIGHT 80 +#define CHATBOX_SCROLL_GAPX 5 + +#define CHATBOX_BUTTON_WIDTH 61 +#define CHATBOX_BUTTON_HEIGHT 20 +#define CHATBOX_BUTTON_X_SEP 15 + +#define CHATBOX_SMALL_BUTTON_WIDTH 31 +#define CHATBOX_SMALL_BUTTON_X_SEP 8 + +#define CHATBOX_TOGGLE_WIDTH 120 +#define CHATBOX_TOGGLE_HEIGHT 12 + +#define CHATBOX_Y_GAP 10 +#define CHATBOX_SLIDER_GAP 5 + +#define CHATBOX_INPUT_HEIGHT 20 + +#define CHATBOX_FONT_COLOR 73 +#define CHATBOX_FONT_TITLE FONT14ARIAL +#define CHATBOX_FONT_TOGGLE FONT10ARIAL + +// old mouse x and y positions +extern SGPPoint pOldMousePosition; +SGPRect ChatBoxRestrictedCursorRegion; + +// if the cursor was locked to a region +extern BOOLEAN fCursorLockedToArea; +BOOLEAN gfInChatBox = FALSE; + +//extern BOOLEAN fMapExitDueToMessageBox; +extern BOOLEAN fInMapMode; +extern BOOLEAN gfOverheadMapDirty; + +//OJW - 20090208 +CHAR16 gszChatBoxInputString[255]; +BOOLEAN gbChatSendToAll = true; + +void OKChatBoxCallback(GUI_BUTTON *btn, INT32 reason ); +void CancelChatBoxCallback(GUI_BUTTON *btn, INT32 reason ); +void ChatBoxClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); +UINT32 ExitChatBox( INT8 ubExitCode ); +UINT16 GetChatBoxButtonWidth( INT32 iButtonImage ); + +extern SGPRect gOldCursorLimitRectangle; + + +MESSAGE_BOX_STRUCT gChatBox; +BOOLEAN gfNewChatBox = FALSE; +extern BOOLEAN gfStartedFromGameScreen; +extern BOOLEAN gfStartedFromMapScreen; +BOOLEAN fRestoreBackgroundForChatBox = FALSE; +extern BOOLEAN gfDontOverRideSaveBuffer; //this variable can be unset if ur in a non gamescreen and DONT want the msg box to use the save buffer + + +extern void HandleTacticalUILoseCursorFromOtherScreen( ); +extern STR16 pUpdatePanelButtons[]; + + +#define NUM_CHAT_TOGGLES 2 +INT32 guiChatToggles[ NUM_CHAT_TOGGLES ]; +void BtnChatTogglesCallback(GUI_BUTTON *btn,INT32 reason); +void RestoreChatToggleBackGrounds(); + +bool gIncludeChatLog = false; +SGPRect gChatTextBoxRegion; + +// OPTIONAL CHAT MESSAGE LOG SETUP +SGPRect gChatMessageLogRegion; + +UINT32 guiCHATLOGIMG; // Images for chat message log + +// button enums +enum{ + CHAT_SCROLL_MESSAGE_UP =0, + CHAT_SCROLL_MESSAGE_DOWN, +}; + +UINT32 guiChatSliderBar; + +UINT16 CHATLOG_SCROLL_AREA_START_Y; //(SCREEN_HEIGHT - 90) //390 +UINT16 CHATLOG_SCROLL_AREA_END_Y; //(SCREEN_HEIGHT - 32) //448 +UINT16 CHATLOG_SCROLL_AREA_HEIGHT; //( CHATLOG_SCROLL_AREA_END_Y - CHATLOG_SCROLL_AREA_START_Y + 1 ) + +// CHRISL: Use these if we want scroll bar based on left edge of screen +UINT16 CHATLOG_SCROLL_AREA_START_X; //330 +UINT16 CHATLOG_SCROLL_AREA_END_X; //344 +UINT16 CHATLOG_SCROLL_AREA_WIDTH; //( CHATLOG_SCROLL_AREA_END_X - CHATLOG_SCROLL_AREA_START_X + 1 ) + +#define CHATLOG_BTN_SCROLL_TIME 100 + +#define CHAT_SLIDER_HEIGHT 11 +#define CHAT_SLIDER_WIDTH 11 + +#define MAX_CHATLOG_MESSAGES 8 + +UINT16 CHAT_SLIDER_BAR_RANGE; + +// buttons +UINT32 guiChatLogScrollButtons[ 2 ]; + +// buttons images +UINT32 guiChatLogScrollButtonsImage[ 2 ]; + +// mouse regions +MOUSE_REGION gChatLogScrollBarRegion; + +void LoadChatLogSliderBar( void ); +void DeleteChatLogSliderBar( void ); +void DisplayChatLogScrollBarSlider( ); +void CreateChatLogMessageScrollBarRegion( void ); +void DeleteChatLogMessageScrollRegion( void ); + +void ChatScreenMsgScrollDown( UINT8 ubLinesDown ); +void ChatScreenMsgScrollUp( UINT8 ubLinesUp ); +void ChangeCurrentChatScreenMessageIndex( UINT8 ubNewMessageIndex ); +void MoveToEndOfChatScreenMessageList( void ); + +void BtnMessageDownChatLogCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMessageUpChatLogCallback( GUI_BUTTON *btn,INT32 reason ); +void ChatScreenMessageScrollBarCallBack(MOUSE_REGION * pRegion, INT32 iReason ); +void EnableDisableChatLogScrollButtonsAndRegions( void ); + +// the local logical message index +UINT8 gubFirstChatLogMessageIndex = 0; + +// Chat Log Messages List +UINT8 gubStartOfChatLogMessageList = 0; // Front of the Message Queue +UINT8 gubEndOfChatLogMessageList = 0; // End of the Message Queue +UINT8 gubCurrentChatLogMessageString = 0; // // index of the current string we are looking at +static ScrollStringStPtr gChatLogMessageList[ 256 ]; // The message Queue + +void InitChatMessageList( void ); +void FreeChatMessageList( void ); +void DisplayStringsInChatLogMessageList( void ); +void AddStringToChatLogMessageList( STR16 pString, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority ); +UINT8 GetRangeOfChatLogMessages( void ); + +void ClearWrappedStringsCHAT( WRAPPED_STRING *pStringWrapperHead ); + +#define CHAT_LINE_WIDTH 292 +#define CHAT_MESSAGE_FONT TINYFONT1 + + + + +INT32 DoChatBox( bool bIncludeChatLog, const STR16 zString, UINT32 uiExitScreen, MSGBOX_CALLBACK ReturnCallback, SGPRect *pCenteringRect ) +{ + VSURFACE_DESC vs_desc; + UINT16 usTextBoxWidth; + UINT16 usTextBoxHeight; + UINT16 usYMargin; + SGPRect aRect; + UINT32 uiDestPitchBYTES, uiSrcPitchBYTES; + UINT8 *pDestBuf, *pSrcBuf; + INT16 sButtonX, sButtonY, sBlankSpace; + UINT8 ubMercBoxBackground = BASIC_MERC_POPUP_BACKGROUND, ubMercBoxBorder = BASIC_MERC_POPUP_BORDER; + UINT8 ubFontColor, ubFontShadowColor; + UINT16 usCursor; + INT32 iId = -1; + + // clear the ouput string + memset(gszChatBoxInputString,0,sizeof(CHAR16)*255); + + gIncludeChatLog = bIncludeChatLog; + + GetMousePos( &pOldMousePosition ); + + if (bIncludeChatLog) + usYMargin = CHATBOX_Y_MARGIN_LOG; + else + usYMargin = CHATBOX_Y_MARGIN_NOLOG; + + //this variable can be unset if ur in a non gamescreen and DONT want the msg box to use the save buffer + gfDontOverRideSaveBuffer = TRUE; + + SetCurrentCursorFromDatabase( CURSOR_NORMAL ); + + if( gChatBox.BackRegion.uiFlags & MSYS_REGION_EXISTS ) + { + return( 0 ); + } + + // set style + ubMercBoxBackground = DIALOG_MERC_POPUP_BACKGROUND; + ubMercBoxBorder = DIALOG_MERC_POPUP_BORDER; + + // Add button images + gChatBox.iButtonImages = LoadButtonImage( "INTERFACE\\popupbuttons.sti", -1,0,-1,1,-1 ); + ubFontColor = CHATBOX_FONT_COLOR; + ubFontShadowColor = DEFAULT_SHADOW; + usCursor = CURSOR_NORMAL; + + + + + // Use default! + aRect.iTop = 0; + aRect.iLeft = 0; + aRect.iBottom = SCREEN_HEIGHT; + aRect.iRight = SCREEN_WIDTH; + + // Set some values! + //gChatBox.usFlags = usFlags; + gChatBox.uiExitScreen = uiExitScreen; + gChatBox.ExitCallback = ReturnCallback; + gChatBox.fRenderBox = TRUE; + gChatBox.bHandled = 0; + + // Init message box + if (bIncludeChatLog) + // we need a string just long enough to give 1 line, but max length of the box, we render the chatlog over this string so well never see it. DONT DELETE ANY SPACES + gChatBox.iBoxId = PrepareMercPopupBox( iId, ubMercBoxBackground, ubMercBoxBorder, L"A string that will be hidden, ", CHATBOX_WIDTH, CHATBOX_X_MARGIN, usYMargin, CHATBOX_Y_MARGIN_BOTTOM, &usTextBoxWidth, &usTextBoxHeight ); + else + gChatBox.iBoxId = PrepareMercPopupBox( iId, ubMercBoxBackground, ubMercBoxBorder, zString, CHATBOX_WIDTH, CHATBOX_X_MARGIN, usYMargin, CHATBOX_Y_MARGIN_BOTTOM, &usTextBoxWidth, &usTextBoxHeight ); + + if( gChatBox.iBoxId == -1 ) + { + #ifdef JA2BETAVERSION + AssertMsg( 0, "Failed in DoMessageBox(). Probable reason is because the string was too large to fit in max message box size." ); + #endif + return 0; + } + + // Save height,width + gChatBox.usWidth = usTextBoxWidth; + gChatBox.usHeight = usTextBoxHeight; + + // Determine position ( centered in rect ) + gChatBox.sX = (INT16)( ( ( ( aRect.iRight - aRect.iLeft ) - usTextBoxWidth ) / 2 ) + aRect.iLeft ); + gChatBox.sY = (INT16)( ( ( ( aRect.iBottom - aRect.iTop ) - usTextBoxHeight ) / 2 ) + aRect.iTop ); + + if ( guiCurrentScreen == GAME_SCREEN ) + { + gfStartedFromGameScreen = TRUE; + } + + if ( (fInMapMode == TRUE ) ) + { +// fMapExitDueToMessageBox = TRUE; + gfStartedFromMapScreen = TRUE; + fMapPanelDirty = TRUE; + } + + + // Set pending screen + SetPendingNewScreen( MP_CHAT_SCREEN); + + // Init save buffer + vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE; + vs_desc.usWidth = usTextBoxWidth; + vs_desc.usHeight = usTextBoxHeight; + vs_desc.ubBitDepth = 16; + + if( AddVideoSurface( &vs_desc, &gChatBox.uiSaveBuffer) == FALSE ) + { + return( - 1 ); + } + + //Save what we have under here... + pDestBuf = LockVideoSurface( gChatBox.uiSaveBuffer, &uiDestPitchBYTES); + pSrcBuf = LockVideoSurface( FRAME_BUFFER, &uiSrcPitchBYTES); + + Blt16BPPTo16BPP((UINT16 *)pDestBuf, uiDestPitchBYTES, + (UINT16 *)pSrcBuf, uiSrcPitchBYTES, + 0 , 0, + gChatBox.sX , gChatBox.sY, + usTextBoxWidth, usTextBoxHeight ); + + UnLockVideoSurface( gChatBox.uiSaveBuffer ); + UnLockVideoSurface( FRAME_BUFFER ); + + // Create top-level mouse region + MSYS_DefineRegion( &(gChatBox.BackRegion), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST, + usCursor, MSYS_NO_CALLBACK, ChatBoxClickCallback ); + + // Add region + MSYS_AddRegion(&(gChatBox.BackRegion) ); + + // findout if cursor locked, if so, store old params and store, restore when done + if( IsCursorRestricted() ) + { + fCursorLockedToArea = TRUE; + GetRestrictedClipCursor( &ChatBoxRestrictedCursorRegion ); + FreeMouseCursor( ); + } + + // vars for positioning controls on the chatbox + int usPosX = 0; + int usPosY = gChatBox.sY + GetFontHeight(CHATBOX_FONT_TITLE) + CHATBOX_Y_GAP + 5; + + if (bIncludeChatLog) + { + // CREATE BUTTONS AND IMAGES FOR CHATLOG + + VOBJECT_DESC VObjectDesc; + // will create buttons for interface bottom + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP( "INTERFACE\\mpchatbox.sti", VObjectDesc.ImageFile ); + if( !AddVideoObject( &VObjectDesc, &guiCHATLOGIMG ) ) + Assert( false ); + + gChatMessageLogRegion.iTop = usPosY; + gChatMessageLogRegion.iLeft = gChatBox.sX + (CHATBOX_X_MARGIN / 2); + gChatMessageLogRegion.iBottom = usPosY + CHATBOX_LOG_HEIGHT; + gChatMessageLogRegion.iRight = gChatMessageLogRegion.iLeft + CHATBOX_LOG_WIDTH; + + // SETUP SCROLLING AREA BOUNDS + CHATLOG_SCROLL_AREA_START_Y = gChatMessageLogRegion.iTop+20; + CHATLOG_SCROLL_AREA_END_Y = gChatMessageLogRegion.iBottom-20; + CHATLOG_SCROLL_AREA_HEIGHT = ( CHATLOG_SCROLL_AREA_END_Y - CHATLOG_SCROLL_AREA_START_Y + 1 ); + + CHATLOG_SCROLL_AREA_START_X = gChatMessageLogRegion.iRight + CHATBOX_SLIDER_GAP + 1; + CHATLOG_SCROLL_AREA_END_X = gChatMessageLogRegion.iRight + CHATBOX_SLIDER_GAP + 1 + CHAT_SLIDER_WIDTH; + CHATLOG_SCROLL_AREA_WIDTH = ( CHATLOG_SCROLL_AREA_END_X - CHATLOG_SCROLL_AREA_START_X + 1 ); + + CHAT_SLIDER_BAR_RANGE = ( CHATLOG_SCROLL_AREA_HEIGHT - CHAT_SLIDER_HEIGHT ); + + LoadChatLogSliderBar(); + + // Load Scroll button images + guiChatLogScrollButtonsImage[ CHAT_SCROLL_MESSAGE_UP ]= LoadButtonImage( "INTERFACE\\map_screen_bottom_arrows.sti" ,11,4,-1,6,-1 ); + + guiChatLogScrollButtonsImage[ CHAT_SCROLL_MESSAGE_DOWN ]= LoadButtonImage( "INTERFACE\\map_screen_bottom_arrows.sti" ,12,5,-1,7,-1 ); + + // Create buttons + guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_UP ] = QuickCreateButton( guiChatLogScrollButtonsImage[ CHAT_SCROLL_MESSAGE_UP ], gChatMessageLogRegion.iRight + CHATBOX_SLIDER_GAP + 2 , gChatMessageLogRegion.iTop + 1 , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + (GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageUpChatLogCallback); + guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_DOWN ] = QuickCreateButton( guiChatLogScrollButtonsImage[ CHAT_SCROLL_MESSAGE_DOWN ], gChatMessageLogRegion.iRight + CHATBOX_SLIDER_GAP + 2, gChatMessageLogRegion.iBottom - 16, + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + (GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageDownChatLogCallback); + + + + usPosY = gChatBox.sY + CHATBOX_Y_MARGIN_LOG + (CHATBOX_Y_GAP * 2) + GetFontHeight(FONT12ARIAL) + 5; + // END CREATE CHATLOG + } + else + usPosY = gChatBox.sY + CHATBOX_Y_MARGIN_NOLOG + (CHATBOX_Y_GAP * 2) + GetFontHeight(FONT12ARIAL); + + // get the middle of the box + UINT16 middleBox = ( usTextBoxWidth / 2 ); + + // CREATE SEND TO ALLIES / ALL TOGGLES + // send to all + int toggleWidth = 32 + StringPixLength( gzMPChatToggleText[ 0 ], CHATBOX_FONT_TOGGLE ); + usPosX = gChatBox.sX + ((middleBox - toggleWidth)/2); + + guiChatToggles[ 0 ] = CreateCheckBoxButton( usPosX, usPosY, + "INTERFACE\\OptionsCheckBoxes_12x12.sti", MSYS_PRIORITY_HIGHEST, + BtnChatTogglesCallback ); + MSYS_SetBtnUserData( guiChatToggles[ 0 ], 0, 0 ); + + // send to allies + toggleWidth = 32 + StringPixLength( gzMPChatToggleText[ 1 ], CHATBOX_FONT_TOGGLE ); + usPosX = gChatBox.sX + middleBox + ((middleBox - toggleWidth)/2); + + + guiChatToggles[ 1 ] = CreateCheckBoxButton( usPosX, usPosY, + "INTERFACE\\OptionsCheckBoxes_12x12.sti", MSYS_PRIORITY_HIGHEST, + BtnChatTogglesCallback ); + MSYS_SetBtnUserData( guiChatToggles[ 1 ], 0, 1 ); + + usPosY += CHATBOX_TOGGLE_HEIGHT + CHATBOX_Y_GAP; + + // SET DEFAULT FLAGGED + + if (gbChatSendToAll) + ButtonList[ guiChatToggles[ 0 ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiChatToggles[ 1 ] ]->uiFlags |= BUTTON_CLICKED_ON; + + // END CREATE TOGGLES + + // CREATE TEXT INPUT BOX + InitTextInputMode(); // API call to initialise text input mode for this screen + // does not mean we are inputting text right away + + // Player Name field + SetTextInputCursor( CUROSR_IBEAM_WHITE ); + SetTextInputFont( (UINT16) FONT12ARIALFIXEDWIDTH ); //FONT12ARIAL //FONT12ARIALFIXEDWIDTH + Set16BPPTextFieldColor( Get16BPPColor(FROMRGB( 0, 0, 0) ) ); + SetBevelColors( Get16BPPColor(FROMRGB(136, 138, 135)), Get16BPPColor(FROMRGB(24, 61, 81)) ); + SetTextInputRegularColors( FONT_WHITE, 2 ); + SetTextInputHilitedColors( 2, FONT_WHITE, FONT_WHITE ); + SetCursorColor( Get16BPPColor(FROMRGB(255, 255, 255) ) ); + + usPosX = gChatBox.sX + (CHATBOX_X_MARGIN / 2); + //Add Player Name textbox + AddTextInputField( usPosX , + usPosY , + usTextBoxWidth - CHATBOX_X_MARGIN, + 20, + MSYS_PRIORITY_HIGH+2, + gszChatBoxInputString, + 255, + INPUTTYPE_ASCII );//23 + + gChatTextBoxRegion.iTop = usPosY; + gChatTextBoxRegion.iLeft = usPosX; + gChatTextBoxRegion.iBottom = usPosY+20; + gChatTextBoxRegion.iRight = usPosX+usTextBoxWidth - CHATBOX_X_MARGIN; + + // exit text input mode in this screen and clean up text boxes + SetActiveField( 0 ); + + usPosY += CHATBOX_INPUT_HEIGHT + CHATBOX_Y_GAP; + // END CREATE TEXT INPUT BOX + + // CREATE OK AND CANCEL BUTTONS + + // get the button width + UINT16 btnWidth = GetChatBoxButtonWidth( gChatBox.iButtonImages ); + + // Create OK Button + sButtonX = middleBox + ((middleBox - btnWidth)/2); + sButtonY = usTextBoxHeight - CHATBOX_BUTTON_HEIGHT - 10; + + gChatBox.uiOKButton = CreateIconAndTextButton( gChatBox.iButtonImages, pMessageStrings[ MSG_OK ], FONT12ARIAL, + CHATBOX_FONT_COLOR, ubFontShadowColor, + CHATBOX_FONT_COLOR, ubFontShadowColor, + TEXT_CJUSTIFIED, + (INT16)(gChatBox.sX + sButtonX ), (INT16)(gChatBox.sY + sButtonY ), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)OKChatBoxCallback ); + SetButtonCursor(gChatBox.uiOKButton, usCursor); + ForceButtonUnDirty( gChatBox.uiOKButton ); + + // move the mouse over the ok button + if( gGameSettings.fOptions[ TOPTION_DONT_MOVE_MOUSE ] == FALSE ) + { + SimulateMouseMovement( ( gChatBox.sX + sButtonX + 27 ), ( gChatBox.sY + sButtonY + 10) ); + } + + // Create Cancel Button + sButtonX = ((middleBox - btnWidth)/2); + sButtonY = usTextBoxHeight - CHATBOX_BUTTON_HEIGHT - 10; + + gChatBox.uiNOButton = CreateIconAndTextButton( gChatBox.iButtonImages, pMessageStrings[ MSG_CANCEL ], FONT12ARIAL, + CHATBOX_FONT_COLOR, ubFontShadowColor, + CHATBOX_FONT_COLOR, ubFontShadowColor, + TEXT_CJUSTIFIED, + (INT16)(gChatBox.sX + sButtonX ), (INT16)(gChatBox.sY + sButtonY ), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)CancelChatBoxCallback ); + SetButtonCursor(gChatBox.uiNOButton, usCursor); + ForceButtonUnDirty( gChatBox.uiNOButton ); + + // END CREATE BUTTONS + +#if 0 + gChatBox.fWasPaused = GamePaused(); + if (!gChatBox.fWasPaused) + { + InterruptTime(); + PauseGame(); + LockPauseState( 1 ); + // Pause timers as well.... + PauseTime( TRUE ); + } +#endif + + // Save mouse restriction region... + GetRestrictedClipCursor( &gOldCursorLimitRectangle ); + FreeMouseCursor( ); + + gfNewChatBox = TRUE; + + gfInChatBox = TRUE; + + return( iId ); +} + + +UINT32 ExitChatBox( INT8 ubExitCode ) +{ + UINT32 uiDestPitchBYTES, uiSrcPitchBYTES; + UINT8 *pDestBuf, *pSrcBuf; + SGPPoint pPosition; + + // Delete popup! + RemoveMercPopupBoxFromIndex( gChatBox.iBoxId ); + gChatBox.iBoxId = -1; + + + // OJW - 20090208 - Add text input box type + // exit text input mode in this screen and clean up text boxes + KillAllTextInputModes(); + + RemoveButton( gChatBox.uiOKButton ); + RemoveButton( gChatBox.uiNOButton ); + + // Delete button images + UnloadButtonImage( gChatBox.iButtonImages ); + + //Remove the toggle buttons + for(int cnt=0; cnt ChatBoxRestrictedCursorRegion.iRight ) || ( pPosition.iX > ChatBoxRestrictedCursorRegion.iLeft ) && ( pPosition.iY < ChatBoxRestrictedCursorRegion.iTop ) && ( pPosition.iY > ChatBoxRestrictedCursorRegion.iBottom ) ) + { + SimulateMouseMovement( pOldMousePosition.iX , pOldMousePosition.iY ); + } + + fCursorLockedToArea = FALSE; + RestrictMouseCursor( &ChatBoxRestrictedCursorRegion ); + } + + // Remove region + MSYS_RemoveRegion(&(gChatBox.BackRegion) ); + + // Remove save buffer! + DeleteVideoSurfaceFromIndex( gChatBox.uiSaveBuffer ); + + + switch( gChatBox.uiExitScreen ) + { + case GAME_SCREEN: + + if ( InOverheadMap( ) ) + { + gfOverheadMapDirty = TRUE; + } + else + { + SetRenderFlags( RENDER_FLAG_FULL ); + } + break; + case MAP_SCREEN: + fMapPanelDirty = TRUE; + break; + } + + if ( gfFadeInitialized ) + { + SetPendingNewScreen(FADE_SCREEN); + return( FADE_SCREEN ); + } + + return( gChatBox.uiExitScreen ); +} + +UINT32 MPChatScreenInit( ) +{ + InitChatMessageList(); + return( TRUE ); +} + + +UINT32 MPChatScreenHandle( ) +{ + InputAtom InputEvent; + + if ( gfNewChatBox ) + { + // If in game screen.... + if ( ( gfStartedFromGameScreen )||( gfStartedFromMapScreen ) ) + { + //UINT32 uiDestPitchBYTES, uiSrcPitchBYTES; + //UINT8 *pDestBuf, *pSrcBuf; + + if( gfStartedFromGameScreen ) + { + HandleTacticalUILoseCursorFromOtherScreen( ); + } + else + { + HandleMAPUILoseCursorFromOtherScreen( ); + } + + gfStartedFromGameScreen = FALSE; + gfStartedFromMapScreen = FALSE; + + } + + gfNewChatBox = FALSE; + + return( MP_CHAT_SCREEN ); + } + + + + UnmarkButtonsDirty( ); + + // Render the box! + if ( gChatBox.fRenderBox ) + { + + // Render the Background ( this includes the text string) + RenderMercPopUpBoxFromIndex( gChatBox.iBoxId, gChatBox.sX, gChatBox.sY, FRAME_BUFFER ); + + + UINT16 usWidth = StringPixLength( gzMPChatboxText[0], CHATBOX_FONT_TITLE ); + int usPosY = 0; + int usPosX = 0; + + usPosY = gChatBox.sY + 10; + usPosX = gChatBox.sX + ((gChatBox.usWidth - usWidth) / 2); + + DrawTextToScreen( gzMPChatboxText[0], usPosX, usPosY, usWidth, CHATBOX_FONT_TITLE, CHATBOX_FONT_COLOR, DEFAULT_SHADOW, FALSE, CENTER_JUSTIFIED | TEXT_SHADOWED ); + + // Render the toggle button strings + + + for(UINT8 cnt=0; cntXLoc + 12 + 10; + usPosY = btn->YLoc; + usWidth = StringPixLength( gzMPChatToggleText[ cnt ], CHATBOX_FONT_TOGGLE ); + + DrawTextToScreen( gzMPChatToggleText[ cnt ], usPosX, usPosY, usWidth, CHATBOX_FONT_TOGGLE, CHATBOX_FONT_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + } + + if (gIncludeChatLog) + { + // draw chatbox + HVOBJECT hHandle; + // get and blt panel + GetVideoObject(&hHandle, guiCHATLOGIMG ); + BltVideoObject( FRAME_BUFFER , hHandle, 0, gChatMessageLogRegion.iLeft, gChatMessageLogRegion.iTop, VO_BLT_SRCTRANSPARENCY,NULL ); + BltVideoObject( FRAME_BUFFER , hHandle, 1, gChatMessageLogRegion.iRight+CHATBOX_SLIDER_GAP, gChatMessageLogRegion.iTop, VO_BLT_SRCTRANSPARENCY,NULL ); + // draw slider + DisplayChatLogScrollBarSlider( ); + // draw chat log text + DisplayStringsInChatLogMessageList(); + } + } + + MarkButtonsDirty(); + + EnableDisableChatLogScrollButtonsAndRegions(); + + // Render buttons + RenderButtons( ); + + // render text boxes + //SaveFontSettings(); + SetFontDestBuffer( FRAME_BUFFER, gChatTextBoxRegion.iLeft , gChatTextBoxRegion.iTop , gChatTextBoxRegion.iRight , gChatTextBoxRegion.iBottom, FALSE ); + RenderAllTextFields(); // textbox system call + SetFontDestBuffer( FRAME_BUFFER, 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , FALSE ); + //RestoreFontSettings(); + + + EndFrameBufferRender( ); + + // carter, need key shortcuts for clearing up message boxes + // Check for esc + while (DequeueEvent(&InputEvent) == TRUE) + { + if( !HandleTextInput( &InputEvent ) && InputEvent.usEvent == KEY_DOWN ) + { + if( ( InputEvent.usParam == ESC ) || ( InputEvent.usParam == 'n') ) + { + // Exit messagebox + gChatBox.bHandled = MSG_BOX_RETURN_NO; + memset(gszChatBoxInputString,0,sizeof(CHAR16)*255); + } + + if( InputEvent.usParam == ENTER ) + { + // retrieve the string from the text box + Get16BitStringFromField( 0, gszChatBoxInputString ); // these indexes are based on the order created + // Exit messagebox + gChatBox.bHandled = MSG_BOX_RETURN_OK; + } + + + } + } + + if ( gChatBox.bHandled ) + { + SetRenderFlags( RENDER_FLAG_FULL ); + return( ExitChatBox( gChatBox.bHandled ) ); + } + + return( MP_CHAT_SCREEN ); +} + +UINT32 MPChatScreenShutdown( ) +{ + FreeChatMessageList(); + return( FALSE ); +} + +UINT16 GetChatBoxButtonWidth( INT32 iButtonImage ) +{ + return( GetWidthOfButtonPic( (UINT16)iButtonImage, ButtonPictures[iButtonImage].OnNormal ) ); +} + +void CancelChatBoxCallback(GUI_BUTTON *btn, INT32 reason ) +{ + static BOOLEAN fLButtonDown = FALSE; + + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + fLButtonDown = TRUE; + } + else if( ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) && fLButtonDown ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + // OK, exit + gChatBox.bHandled = MSG_BOX_RETURN_NO; + // clear the ouput string + memset(gszChatBoxInputString,0,sizeof(CHAR16)*255); + } + else if ( reason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + fLButtonDown = FALSE; + } +} + +void OKChatBoxCallback(GUI_BUTTON *btn, INT32 reason ) +{ + static BOOLEAN fLButtonDown = FALSE; + + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + fLButtonDown = TRUE; + } + else if( ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) && fLButtonDown ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + // OK, exit + gChatBox.bHandled = MSG_BOX_RETURN_OK; + // retrieve the string from the text box + Get16BitStringFromField( 0, gszChatBoxInputString ); // these indexes are based on the order created + } + else if ( reason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + fLButtonDown = FALSE; + } + +} + +void BtnChatTogglesCallback( GUI_BUTTON *btn, INT32 reason ) +{ + UINT8 ubButton = (UINT8)MSYS_GetBtnUserData( btn, 0 ); + + if (ubButton == 1 && PLAYER_BSIDE != 1) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + // disable all buttons in grp + UINT8 cnt; + for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; + } + + // reselect the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + + gbChatSendToAll = ubButton == 0; // 0 is send to all + } + else + { + // check if any other buttons are checked + UINT8 cnt; + BOOLEAN fAnyChecked=FALSE; + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + fAnyChecked = TRUE; + } + } + + //if none are checked, re check this one + if( !fAnyChecked ) + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } + +} + +void RestoreChatToggleBackGrounds() +{ + UINT8 cnt; + + //Redraw toggle buttons + for( cnt=0; cntArea.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void ChatBoxClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) +{ + +} + +// SCROLLING FOR CHAT LOG + +void BtnMessageDownChatLogCallback( GUI_BUTTON *btn,INT32 reason ) +{ + static INT32 iLastRepeatScrollTime = 0; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + btn->uiFlags|=(BUTTON_CLICKED_ON); + + iLastRepeatScrollTime = 0; + } + else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + // down a line + ChatScreenMsgScrollDown( 1 ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if( GetJA2Clock() - iLastRepeatScrollTime >= CHATLOG_BTN_SCROLL_TIME ) + { + // down a line + ChatScreenMsgScrollDown( 1 ); + + iLastRepeatScrollTime = GetJA2Clock( ); + } + } + else if( reason & MSYS_CALLBACK_REASON_RBUTTON_DWN ) + { + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + btn->uiFlags|=(BUTTON_CLICKED_ON); + + iLastRepeatScrollTime = 0; + } + else if(reason & MSYS_CALLBACK_REASON_RBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + // down a page + ChatScreenMsgScrollDown( MAX_CHATLOG_MESSAGES ); + } + } + else if( reason & MSYS_CALLBACK_REASON_RBUTTON_REPEAT ) + { + if( GetJA2Clock() - iLastRepeatScrollTime >= CHATLOG_BTN_SCROLL_TIME ) + { + // down a page + ChatScreenMsgScrollDown( MAX_CHATLOG_MESSAGES ); + + iLastRepeatScrollTime = GetJA2Clock( ); + } + } +} + + +void BtnMessageUpChatLogCallback( GUI_BUTTON *btn,INT32 reason ) +{ + static INT32 iLastRepeatScrollTime = 0; + + + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + // redraw region + if( btn->Area.uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + iLastRepeatScrollTime = 0; + } + + else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + // up a line + ChatScreenMsgScrollUp( 1 ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if( GetJA2Clock() - iLastRepeatScrollTime >= CHATLOG_BTN_SCROLL_TIME ) + { + // up a line + ChatScreenMsgScrollUp( 1 ); + + iLastRepeatScrollTime = GetJA2Clock( ); + } + } + else if( reason & MSYS_CALLBACK_REASON_RBUTTON_DWN ) + { + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + btn->uiFlags|=(BUTTON_CLICKED_ON); + + iLastRepeatScrollTime = 0; + } + else if(reason & MSYS_CALLBACK_REASON_RBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + + // redraw region + if( btn->uiFlags & MSYS_HAS_BACKRECT ) + { + gChatBox.fRenderBox = TRUE; + } + + // up a page + ChatScreenMsgScrollUp( MAX_CHATLOG_MESSAGES ); + } + } + else if( reason & MSYS_CALLBACK_REASON_RBUTTON_REPEAT ) + { + if( GetJA2Clock() - iLastRepeatScrollTime >= CHATLOG_BTN_SCROLL_TIME ) + { + // up a page + ChatScreenMsgScrollUp( MAX_CHATLOG_MESSAGES ); + + iLastRepeatScrollTime = GetJA2Clock( ); + } + } +} + +void EnableDisableChatLogScrollButtonsAndRegions( void ) +{ + UINT8 ubNumMessages; + + ubNumMessages = GetRangeOfChatLogMessages(); + + // if no scrolling required, or already showing the topmost message + if( ( ubNumMessages <= MAX_CHATLOG_MESSAGES ) || ( gubFirstChatLogMessageIndex == 0 ) ) + { + DisableButton( guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_UP ] ); + ButtonList[ guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_UP ] ]->uiFlags &= ~( BUTTON_CLICKED_ON ); + } + else + { + EnableButton( guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_UP ] ); + } + + // if no scrolling required, or already showing the last message + if( ( ubNumMessages <= MAX_CHATLOG_MESSAGES ) || + ( ( gubFirstChatLogMessageIndex + MAX_CHATLOG_MESSAGES ) >= ubNumMessages ) ) + { + DisableButton( guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_DOWN ] ); + ButtonList[ guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_DOWN ] ]->uiFlags &= ~( BUTTON_CLICKED_ON ); + } + else + { + EnableButton( guiChatLogScrollButtons[ CHAT_SCROLL_MESSAGE_DOWN ] ); + } + + if( ubNumMessages <= MAX_CHATLOG_MESSAGES ) + { + MSYS_DisableRegion( &gChatLogScrollBarRegion ); + } + else + { + MSYS_EnableRegion( &gChatLogScrollBarRegion ); + } + + if (PLAYER_BSIDE==1) + { + // Only enable Allies toggle for team deathmatch + EnableButton( guiChatToggles[1] ); + } + else + { + gbChatSendToAll = true; + DisableButton( guiChatToggles[1] ); + } +} + +void ChatScreenMsgScrollDown( UINT8 ubLinesDown ) +{ + UINT8 ubNumMessages; + + ubNumMessages = GetRangeOfChatLogMessages(); + + // check if we can go that far, only go as far as we can + if ( ( gubFirstChatLogMessageIndex + MAX_CHATLOG_MESSAGES + ubLinesDown ) > ubNumMessages ) + { + ubLinesDown = ubNumMessages - gubFirstChatLogMessageIndex - min( ubNumMessages, MAX_CHATLOG_MESSAGES ); + } + + if ( ubLinesDown > 0 ) + { + ChangeCurrentChatScreenMessageIndex( ( UINT8 ) ( gubFirstChatLogMessageIndex + ubLinesDown ) ); + } +} + + +void ChatScreenMsgScrollUp( UINT8 ubLinesUp ) +{ + UINT8 ubNumMessages; + + ubNumMessages = GetRangeOfChatLogMessages(); + + // check if we can go that far, only go as far as we can + if ( gubFirstChatLogMessageIndex < ubLinesUp ) + { + ubLinesUp = gubFirstChatLogMessageIndex; + } + + if ( ubLinesUp > 0 ) + { + ChangeCurrentChatScreenMessageIndex( ( UINT8 ) ( gubFirstChatLogMessageIndex - ubLinesUp ) ); + } +} + +void MoveToEndOfChatScreenMessageList( void ) +{ + UINT8 ubDesiredMessageIndex; + UINT8 ubNumMessages; + + ubNumMessages = GetRangeOfChatLogMessages(); + + ubDesiredMessageIndex = ubNumMessages - min( ubNumMessages, MAX_CHATLOG_MESSAGES ); + ChangeCurrentChatScreenMessageIndex( ubDesiredMessageIndex ); +} + + + +void ChangeCurrentChatScreenMessageIndex( UINT8 ubNewMessageIndex ) +{ + Assert( ubNewMessageIndex + MAX_CHATLOG_MESSAGES <= max( MAX_CHATLOG_MESSAGES, GetRangeOfChatLogMessages() ) ); + + gubFirstChatLogMessageIndex = ubNewMessageIndex; + gubCurrentChatLogMessageString = ( gubStartOfChatLogMessageList + gubFirstChatLogMessageIndex ) % 256; + + // set fact we just went to a new message +// gfNewScrollMessage = TRUE; + + // refresh screen + gChatBox.fRenderBox = TRUE; +} + +void LoadChatLogSliderBar( void ) +{ + // this function will load the message slider bar + VOBJECT_DESC VObjectDesc; + + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP( "INTERFACE\\map_screen_bottom_arrows.sti", VObjectDesc.ImageFile ); + if( !AddVideoObject( &VObjectDesc, &guiChatSliderBar ) ) + Assert(false); + CreateChatLogMessageScrollBarRegion(); +} + +void DeleteChatLogSliderBar( void ) +{ + // this function will delete message slider bar + DeleteVideoObjectFromIndex( guiChatSliderBar ); + + DeleteChatLogMessageScrollRegion(); +} + + +void CreateChatLogMessageScrollBarRegion( void ) +{ + MSYS_DefineRegion( &gChatLogScrollBarRegion, CHATLOG_SCROLL_AREA_START_X, CHATLOG_SCROLL_AREA_START_Y, + CHATLOG_SCROLL_AREA_END_X, CHATLOG_SCROLL_AREA_END_Y, + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ChatScreenMessageScrollBarCallBack ); +} + + +void DeleteChatLogMessageScrollRegion( void ) +{ + MSYS_RemoveRegion( &gChatLogScrollBarRegion ); +} + + + +void ChatScreenMessageScrollBarCallBack( MOUSE_REGION *pRegion, INT32 iReason ) +{ + POINT MousePos; + UINT8 ubMouseYOffset; + UINT8 ubDesiredSliderOffset; + UINT8 ubDesiredMessageIndex; + UINT8 ubNumMessages; + + + if (iReason & MSYS_CALLBACK_REASON_INIT) + { + return; + } + + + if ( iReason & ( MSYS_CALLBACK_REASON_LBUTTON_DWN | MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) ) + { + // how many messages are there? + ubNumMessages = GetRangeOfChatLogMessages(); + + // region is supposed to be disabled if there aren't enough messages to scroll. Formulas assume this + if ( ubNumMessages > MAX_CHATLOG_MESSAGES ) + { + // where is the mouse? + GetCursorPos( &MousePos ); + ScreenToClient(ghWindow, &MousePos); // In window coords! + + ubMouseYOffset = (UINT8) MousePos.y - CHATLOG_SCROLL_AREA_START_Y; + + // if clicking in the top 5 pixels of the slider bar + if ( ubMouseYOffset < ( CHAT_SLIDER_HEIGHT / 2 ) ) + { + // scroll all the way to the top + ubDesiredMessageIndex = 0; + } + // if clicking in the bottom 6 pixels of the slider bar + else if ( ubMouseYOffset >= ( CHATLOG_SCROLL_AREA_HEIGHT - ( CHAT_SLIDER_HEIGHT / 2 ) ) ) + { + // scroll all the way to the bottom + ubDesiredMessageIndex = ubNumMessages - MAX_CHATLOG_MESSAGES; + } + else + { + // somewhere in between + ubDesiredSliderOffset = ubMouseYOffset - ( CHAT_SLIDER_HEIGHT / 2 ); + + Assert( ubDesiredSliderOffset <= CHAT_SLIDER_BAR_RANGE ); + + // calculate what the index should be to place the slider at this offset (round fractions of .5+ up) + ubDesiredMessageIndex = ( ( ubDesiredSliderOffset * ( ubNumMessages - MAX_CHATLOG_MESSAGES ) ) + ( CHAT_SLIDER_BAR_RANGE / 2 ) ) / CHAT_SLIDER_BAR_RANGE; + } + + // if it's a change + if ( ubDesiredMessageIndex != gubFirstChatLogMessageIndex ) + { + ChangeCurrentChatScreenMessageIndex( ubDesiredMessageIndex ); + } + } + } +} + + +void DisplayChatLogScrollBarSlider( ) +{ + // will display the scroll bar icon + UINT8 ubNumMessages; + UINT8 ubSliderOffset; + HVOBJECT hHandle; + + + ubNumMessages = GetRangeOfChatLogMessages(); + + // only show the slider if there are more messages than will fit on screen + if ( ubNumMessages > MAX_CHATLOG_MESSAGES ) + { + // calculate where slider should be positioned + ubSliderOffset = ( CHAT_SLIDER_BAR_RANGE * gubFirstChatLogMessageIndex ) / ( ubNumMessages - MAX_CHATLOG_MESSAGES ); + + GetVideoObject( &hHandle, guiChatSliderBar ); + BltVideoObject( FRAME_BUFFER, hHandle, 8, CHATLOG_SCROLL_AREA_START_X + 2, CHATLOG_SCROLL_AREA_START_Y + ubSliderOffset, VO_BLT_SRCTRANSPARENCY, NULL ); + } +} + +// END MESSAGE SCROLLING + +// CHAT MESSAGE ADDING AND PRINTING FUNCTIONS + +void ChatLogMessage( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ... ) +{ + // this function sets up the string into several single line structures + + //ScrollStringStPtr pStringSt; + UINT32 uiFont = CHAT_MESSAGE_FONT; + //STR16pString; + va_list argptr; + CHAR16 DestString[512]; + WRAPPED_STRING *pStringWrapper=NULL; + WRAPPED_STRING *pStringWrapperHead=NULL; + BOOLEAN fNewString = FALSE; + UINT16 usLineWidthIfWordIsWiderThenWidth; + + + /*pStringSt=pStringS; + while(GetNextString(pStringSt)) + pStringSt=GetNextString(pStringSt);*/ + + va_start(argptr, pStringA); // Set up variable argument pointer + vswprintf(DestString, pStringA, argptr); // process gprintf string (get output str) + va_end(argptr); + + // send message to tactical screen and map screen + ScreenMsg( usColor, ubPriority, DestString ); + + pStringWrapperHead=LineWrap(uiFont, CHAT_LINE_WIDTH, &usLineWidthIfWordIsWiderThenWidth, DestString); + pStringWrapper=pStringWrapperHead; + if(!pStringWrapper) + return; + + fNewString = TRUE; + + while(pStringWrapper->pNextWrappedString!=NULL) + { + AddStringToChatLogMessageList(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority ); + fNewString = FALSE; + + pStringWrapper=pStringWrapper->pNextWrappedString; + } + + AddStringToChatLogMessageList(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority ); + + + // clear up list of wrapped strings + ClearWrappedStringsCHAT( pStringWrapperHead ); + + // play new message beep + //PlayNewMessageSound( ); + + MoveToEndOfChatScreenMessageList( ); + + //LeaveMutex(SCROLL_MESSAGE_MUTEX, __LINE__, __FILE__); +} + + + +// add string to the chat log message list +void AddStringToChatLogMessageList( STR16 pString, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority ) +{ + ScrollStringStPtr pStringSt = NULL; + + + pStringSt = (ScrollStringStPtr) MemAlloc(sizeof(ScrollStringSt)); + + SetString(pStringSt, pString); + SetStringColor(pStringSt, usColor); + pStringSt->uiFont = uiFont; + pStringSt->fBeginningOfNewString = fStartOfNewString; + pStringSt->uiFlags = ubPriority; + pStringSt->iVideoOverlay = -1; + + // next/previous are not used, it's strictly a wraparound queue + SetStringNext(pStringSt, NULL); + SetStringPrev(pStringSt, NULL); + + + // Figure out which queue slot index we're going to use to store this + // If queue isn't full, this is easy, if is is full, we'll re-use the oldest slot + // Must always keep the wraparound in mind, although this is easy enough with a static, fixed-size queue. + + + // always store the new message at the END index + + // check if slot is being used, if so, clear it up + if( gChatLogMessageList[ gubEndOfChatLogMessageList ] != NULL ) + { + MemFree( gChatLogMessageList[ gubEndOfChatLogMessageList ]->pString16 ); + MemFree( gChatLogMessageList[ gubEndOfChatLogMessageList ] ); + } + + // store the new message there + gChatLogMessageList[ gubEndOfChatLogMessageList ] = pStringSt; + + // increment the end + gubEndOfChatLogMessageList = ( gubEndOfChatLogMessageList + 1 ) % 256; + + // if queue is full, end will now match the start + if ( gubEndOfChatLogMessageList == gubStartOfChatLogMessageList ) + { + // if that's so, increment the start + gubStartOfChatLogMessageList = ( gubStartOfChatLogMessageList + 1 ) % 256; + } +} + + +void DisplayStringsInChatLogMessageList( void ) +{ + UINT8 ubCurrentStringIndex; + UINT8 ubLinesPrinted; + INT16 sX, sY; + UINT16 usSpacing; + + // Limit drawing to chat log region only, dont want any overdraw + sX = gChatMessageLogRegion.iLeft + 4; + SetFontDestBuffer( FRAME_BUFFER, sX , gChatMessageLogRegion.iTop + 4, gChatMessageLogRegion.iRight - 4, gChatMessageLogRegion.iBottom - 4, FALSE ); + + SetFont( CHAT_MESSAGE_FONT ); // no longer supports variable fonts + SetFontBackground( FONT_BLACK ); + SetFontShadow( DEFAULT_SHADOW ); + + ubCurrentStringIndex = gubCurrentChatLogMessageString; + + sY = gChatMessageLogRegion.iTop + 4; + + usSpacing = GetFontHeight( CHAT_MESSAGE_FONT ); + + for ( ubLinesPrinted = 0; ubLinesPrinted < MAX_CHATLOG_MESSAGES; ubLinesPrinted++ ) + { + // reached the end of the list? + if ( ubCurrentStringIndex == gubEndOfChatLogMessageList ) + { + break; + } + + // nothing stored there? + if ( gChatLogMessageList[ ubCurrentStringIndex ] == NULL ) + { + break; + } + + // set font color + SetFontForeground( ( UINT8 )( gChatLogMessageList[ ubCurrentStringIndex ]->usColor ) ); + + // print this line + mprintf_coded( sX, sY, gChatLogMessageList[ ubCurrentStringIndex ]->pString16 ); + + sY = sY + usSpacing; + + // next message index to print (may wrap around) + ubCurrentStringIndex = ( ubCurrentStringIndex + 1 ) % 256; + } + + // reset region to whole screen + SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE ); +} + +void InitChatMessageList( void ) +{ + INT32 iCounter = 0; + + for( iCounter = 0; iCounter < 256; iCounter++ ) + { + gChatLogMessageList[ iCounter ] = NULL; + } + + gubEndOfChatLogMessageList = 0; + gubStartOfChatLogMessageList = 0; + gubCurrentChatLogMessageString = 0; + + return; +} + + +void FreeChatMessageList( void ) +{ + INT32 iCounter = 0; + + for( iCounter = 0; iCounter < 256; iCounter++ ) + { + // check if next unit is empty, if not...clear it up + if( gChatLogMessageList[ iCounter ] != NULL ) + { + MemFree( gChatLogMessageList[ iCounter ]->pString16 ); + MemFree( gChatLogMessageList[ iCounter ] ); + } + } + + InitChatMessageList( ); + + return; +} + +UINT8 GetRangeOfChatLogMessages( void ) +{ + UINT8 ubRange = 0; + + // NOTE: End is non-inclusive, so start/end 0/0 means no messages, 0/1 means 1 message, etc. + if( gubStartOfChatLogMessageList <= gubEndOfChatLogMessageList ) + { + ubRange = gubEndOfChatLogMessageList - gubStartOfChatLogMessageList; + } + else + { + // this should always be 255 now, since this only happens when queue fills up, and we never remove any messages + ubRange = ( gubEndOfChatLogMessageList + 256 ) - gubStartOfChatLogMessageList; + } + + return ( ubRange ); +} + +// helper function to clear a list of wrapped strings +// This same function exists in message.cpp +// copied here because i didnt want to include wordwrap.h in message.h +void ClearWrappedStringsCHAT( WRAPPED_STRING *pStringWrapperHead ) +{ + WRAPPED_STRING *pNode = pStringWrapperHead; + WRAPPED_STRING *pDeleteNode = NULL; + // clear out a link list of wrapped string structures + + // error check, is there a node to delete? + if( pNode == NULL ) + { + // leave, + return; + } + + do + { + + // set delete node as current node + pDeleteNode = pNode; + + // set current node as next node + pNode = pNode->pNextWrappedString; + + //delete the string + MemFree( pDeleteNode->sString ); + pDeleteNode->sString = NULL; + + // clear out delete node + MemFree( pDeleteNode ); + pDeleteNode = NULL; + + } while( pNode ); + + +// MemFree( pNode ); + + pStringWrapperHead = NULL; + +} \ No newline at end of file diff --git a/MPChatScreen.h b/MPChatScreen.h new file mode 100644 index 00000000..6fee1aee --- /dev/null +++ b/MPChatScreen.h @@ -0,0 +1,27 @@ +#ifndef _MP_CHAT_SCREEN_H_ +#define _MP_CHAT_SCREEN_H_ + +#include "MessageBoxScreen.h" + +UINT32 MPChatScreenInit( void ); +UINT32 MPChatScreenHandle( void ); +UINT32 MPChatScreenShutdown( void ); + +extern CHAR16 gszChatBoxInputString[255]; +extern BOOLEAN gbChatSendToAll; +extern MESSAGE_BOX_STRUCT gChatBox; +extern BOOLEAN gfInChatBox; + +//////////////////////////////// +// ubStyle: Determines the look of graphics including buttons +// zString: 16-bit string +// uiExitScreen The screen to exit to +// ubFlags Some flags for button style +// ReturnCallback Callback for return. Can be NULL. Returns any above return value +// pCenteringRect Rect to send if MSG_BOX_FLAG_USE_CENTERING_RECT set. Can be NULL +//////////////////////////////// + +INT32 DoChatBox( bool bIncludeChatLog, const STR16 zString, UINT32 uiExitScreen, MSGBOX_CALLBACK ReturnCallback, SGPRect *pCenteringRect ); +void ChatLogMessage( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ...); + +#endif \ No newline at end of file diff --git a/MPHostScreen.cpp b/MPHostScreen.cpp new file mode 100644 index 00000000..1f1a51be --- /dev/null +++ b/MPHostScreen.cpp @@ -0,0 +1,1507 @@ +#ifdef PRECOMPILEDHEADERS + #include "JA2 All.h" + #include "Intro.h" +#else + #include "Types.h" + #include "MPHostScreen.h" + #include "GameSettings.h" + #include "Utilities.h" + #include "wCheck.h" + #include "Font Control.h" + #include "WordWrap.h" + #include "Render Dirty.h" + #include "Input.h" + #include "Options Screen.h" + #include "English.h" + #include "Sysutil.h" + #include "Fade Screen.h" + #include "Cursor Control.h" + #include "Music Control.h" + #include "cursors.h" + #include "Intro.h" + #include "Text.h" + #include "Text Input.h" + #include "_Ja25EnglishText.h" + #include "Soldier Profile.h" +#endif + +#include "gameloop.h" +#include "connect.h" +#include "network.h" // for client name +#include "saveloadscreen.h" + + +//////////////////////////////////////////// +// +// Global Defines +// +/////////////////////////////////////////// + +#define MPH_TITLE_FONT FONT14ARIAL//FONT16ARIAL +#define MPH_TITLE_COLOR FONT_MCOLOR_WHITE + +#define MPH_LABEL_TEXT_FONT FONT12ARIAL//FONT16ARIAL +#define MPH_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE +#define MPH_TOGGLE_TEXT_FONT FONT12ARIAL//FONT16ARIAL +#define MPH_TOGGLE_TEXT_COLOR FONT_MCOLOR_WHITE + +//buttons +#define MPH_BTN_START_X iScreenWidthOffset + 320 + 143 +#define MPH_BTN_START_Y iScreenHeightOffset + 435 +#define MPH_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) + +//textboxes +#define MPH_TXT_SVRNAME_X iScreenWidthOffset + 100 +#define MPH_TXT_SVRNAME_Y iScreenHeightOffset + 167 +#define MPH_TXT_SVRNAME_WIDTH 120 +#define MPH_TXT_SVRNAME_HEIGHT 17 +#define MPH_TXT_MAXPLAYERS_X iScreenWidthOffset + 100 +#define MPH_TXT_MAXPLAYERS_Y MPH_TXT_SVRNAME_Y + MPH_TXT_SVRNAME_HEIGHT + 13 +#define MPH_TXT_MAXPLAYERS_WIDTH 40 +#define MPH_TXT_MAXPLAYERS_HEIGHT 17 +#define MPH_TXT_SQUAD_X iScreenWidthOffset + 100 +#define MPH_TXT_SQUAD_Y MPH_TXT_MAXPLAYERS_Y + MPH_TXT_MAXPLAYERS_HEIGHT + 13 +#define MPH_TXT_SQUAD_WIDTH 40 +#define MPH_TXT_SQUAD_HEIGHT 17 +#define MPH_TXT_TIME_X iScreenWidthOffset + 100 +#define MPH_TXT_TIME_Y MPH_TXT_SQUAD_Y + MPH_TXT_SQUAD_HEIGHT + 13 +#define MPH_TXT_TIME_WIDTH 60 +#define MPH_TXT_TIME_HEIGHT 17 +#define MPH_TXT_CASH_X iScreenWidthOffset + 100 +#define MPH_TXT_CASH_Y MPH_TXT_TIME_Y + MPH_TXT_TIME_HEIGHT + 13 +#define MPH_TXT_CASH_WIDTH 60 +#define MPH_TXT_CASH_HEIGHT 17 +#define MPH_TXT_DMG_X iScreenWidthOffset + 100 +#define MPH_TXT_DMG_Y MPH_TXT_CASH_Y + MPH_TXT_CASH_HEIGHT + 13 +#define MPH_TXT_DMG_WIDTH 60 +#define MPH_TXT_DMG_HEIGHT 17 +#define MPH_TXT_TIMER_X iScreenWidthOffset + 100 +#define MPH_TXT_TIMER_Y MPH_TXT_DMG_Y + MPH_TXT_DMG_HEIGHT + 13 +#define MPH_TXT_TIMER_WIDTH 60 +#define MPH_TXT_TIMER_HEIGHT 17 + + + +//main title +#define MPH_MAIN_TITLE_X 0 +#define MPH_MAIN_TITLE_Y iScreenHeightOffset + 10 +#define MPH_MAIN_TITLE_WIDTH SCREEN_WIDTH + +//labels +#define MPH_LABEL_SVRNAME_X MPH_TXT_SVRNAME_X - 80 +#define MPH_LABEL_SVRNAME_Y MPH_TXT_SVRNAME_Y + 3 +#define MPH_LABEL_SVRNAME_WIDTH 80 +#define MPH_LABEL_SVRNAME_HEIGHT 17 +#define MPH_LABEL_MAXPLAYERS_X MPH_TXT_MAXPLAYERS_X - 80 +#define MPH_LABEL_MAXPLAYERS_Y MPH_TXT_MAXPLAYERS_Y + 3 +#define MPH_LABEL_MAXPLAYERS_WIDTH 80 +#define MPH_LABEL_MAXPLAYERS_HEIGHT 17 +#define MPH_LABEL_SQUAD_X MPH_TXT_SQUAD_X - 80 +#define MPH_LABEL_SQUAD_Y MPH_TXT_SQUAD_Y + 3 +#define MPH_LABEL_SQUAD_WIDTH 80 +#define MPH_LABEL_SQUAD_HEIGHT 17 +#define MPH_LABEL_TIME_X MPH_TXT_TIME_X - 80 +#define MPH_LABEL_TIME_Y MPH_TXT_TIME_Y + 3 +#define MPH_LABEL_TIME_WIDTH 80 +#define MPH_LABEL_TIME_HEIGHT 17 +#define MPH_LABEL_CASH_X MPH_TXT_CASH_X - 80 +#define MPH_LABEL_CASH_Y MPH_TXT_CASH_Y + 3 +#define MPH_LABEL_CASH_WIDTH 80 +#define MPH_LABEL_CASH_HEIGHT 17 +#define MPH_LABEL_DMG_X MPH_TXT_DMG_X - 80 +#define MPH_LABEL_DMG_Y MPH_TXT_DMG_Y + 3 +#define MPH_LABEL_DMG_WIDTH 80 +#define MPH_LABEL_DMG_HEIGHT 17 +#define MPH_LABEL_TIMER_X MPH_TXT_TIMER_X - 80 +#define MPH_LABEL_TIMER_Y MPH_TXT_TIMER_Y + 3 +#define MPH_LABEL_TIMER_WIDTH 80 +#define MPH_LABEL_TIMER_HEIGHT 17 + +//radio box locations +#define MPH_GAP_BN_SETTINGS 35 +#define MPH_OFFSET_TO_TEXT 30 +#define MPH_OFFSET_TO_TOGGLE_BOX 170 +#define MPH_OFFSET_TO_TOGGLE_BOX_Y 9 + +#define MPH_DIF_SETTINGS_X iScreenWidthOffset + 320 +#define MPH_DIF_SETTINGS_Y iScreenHeightOffset + 75 +#define MPH_DIF_SETTINGS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT + +#define MPH_GAMETYPE_SETTINGS_X iScreenWidthOffset + 20 +#define MPH_GAMETYPE_SETTINGS_Y iScreenHeightOffset + 75 +#define MPH_GAMETYPE_SETTINGS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT + +#define MPH_RNDMERC_X MPH_DIF_SETTINGS_X +#define MPH_RNDMERC_Y MPH_TXT_MAXPLAYERS_Y//iScreenHeightOffset+214 +#define MPH_RNDMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_SAMEMERC_X MPH_DIF_SETTINGS_X +#define MPH_SAMEMERC_Y MPH_RNDMERC_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_SAMEMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_REPORTMERC_X MPH_DIF_SETTINGS_X +#define MPH_REPORTMERC_Y MPH_SAMEMERC_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_REPORTMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_BOBBYRAY_X MPH_DIF_SETTINGS_X +#define MPH_BOBBYRAY_Y MPH_REPORTMERC_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_BOBBYRAY_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_RNDSPAWN_X MPH_DIF_SETTINGS_X +#define MPH_RNDSPAWN_Y MPH_BOBBYRAY_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_RNDSPAWN_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_CIVS_X MPH_DIF_SETTINGS_X +#define MPH_CIVS_Y MPH_RNDSPAWN_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_CIVS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +#define MPH_USENIV_X MPH_DIF_SETTINGS_X +#define MPH_USENIV_Y MPH_CIVS_Y + MPH_GAP_BN_SETTINGS - 5 +#define MPH_USENIV_WIDTH MPH_OFFSET_TO_TOGGLE_BOX + +//Difficulty settings +enum +{ + MPH_DIFF_EASY, + MPH_DIFF_MED, + MPH_DIFF_HARD, + MPH_DIFF_INSANE, + NUM_DIFF_SETTINGS, +}; + + + +//////////////////////////////////////////// +// +// Global Variables +// +/////////////////////////////////////////// + +BOOLEAN gfMPHScreenEntry = TRUE; +BOOLEAN gfMPHScreenExit = FALSE; +BOOLEAN gfReRenderMPHScreen=TRUE; +BOOLEAN gfMPHButtonsAllocated = FALSE; + +//enum for different states of screen +enum +{ + MPH_NOTHING, + MPH_CANCEL, + MPH_START +}; + +UINT8 gubMPHScreenHandler=MPH_NOTHING; // State changer for HandleMPHScreen() + +UINT32 gubMPHExitScreen = MP_HOST_SCREEN; // The screen that is in control next iteration of the game_loop + +UINT32 guiMPHMainBackGroundImage; + +// Wide-char strings that will hold the variables until they are transferred to the CHAR ascii fields +CHAR16 gzServerNameField[ 30 ] = {0} ; +CHAR16 gzMaxPlayersField[ 2 ] = {0} ; +CHAR16 gzSquadSizeField[ 2 ] = {0} ; +CHAR16 gzTimeOfDayField[ 5 ] = {0}; +CHAR16 gzStartingBalanceField[ 10 ] = {0}; +INT16 giMPHTimeHours = 0; +INT16 giMPHTimeMins = 0; +CHAR16 gzDmgMultiplierField[ 5 ] = {0}; +CHAR16 gzTimerField[ 5 ] = {0}; + +UINT8 guiMPHGameType = MP_TYPE_DEATHMATCH; // default value + +INT32 giMPHMessageBox = -1; // message box handle + +INT giMPHRandomMercs = 0; +INT giMPHSameMercs = 0; +INT giMPHReportMercs = 0; +INT giMPHBobbyRays = 0; +INT giMPHRandomSpawn = 0; +INT giMPHEnableCivilians = 0; +INT giMPHUseNIV = 0; + + +//////////////////////////////////////////// +// +// Screen Controls +// +/////////////////////////////////////////// + +// Start Button +void BtnMPHStartCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPHStartButton; +INT32 giMPHStartBtnImage; + +// Cancel Button +void BtnMPHCancelCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPHCancelButton; +INT32 giMPHCancelBtnImage; + +//checkbox to toggle the Diff level +UINT32 guiMPHDifficultySettingsToggles[ NUM_DIFF_SETTINGS ]; +void BtnMPHDifficultyTogglesCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox to toggle Game Type +UINT32 guiMPHGameTypeToggles[ NUM_MP_GAMETYPE ]; +void BtnMPHGameTypeTogglesCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for merc options +UINT32 guiMPHRandomMercsToggle; +void BtnMPHRandomMercCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for same merc +UINT32 guiMPHSameMercToggle; +void BtnMPHSameMercCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for report purchase +UINT32 guiMPHReportMercToggle; +void BtnMPHReportMercCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for bobby rays +UINT32 guiMPHBobbyRayToggle; +void BtnMPHBobbyRayCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for random spawn pos +UINT32 guiMPHRandomSpawnToggle; +void BtnMPHRandomSpawnCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for enable civilians in CO-OP +UINT32 guiMPHCivsToggle; +void BtnMPHCivsCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox for use NIV +UINT32 guiMPHUseNIVToggle; +void BtnMPHUseNIVCallback(GUI_BUTTON *btn,INT32 reason); + + +//////////////////////////////////////////// +// +// Local Function Prototypes +// +/////////////////////////////////////////// + +extern void ClearMainMenu(); + +BOOLEAN EnterMPHScreen(); +BOOLEAN ExitMPHScreen(); +void HandleMPHScreen(); +BOOLEAN RenderMPHScreen(); +void GetMPHScreenUserInput(); +void RestoreMPHButtonBackGrounds(); +bool ValidateMPSettings(); +void SaveMPSettings(); +UINT8 GetMPHCurrentDifficultyButtonSetting(); +UINT8 GetMPHGameTypeButtonSetting(); +BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); +void DoneFadeOutForExitMPHScreen( void ); +void DoneFadeInForExitMPHScreen( void ); + +//////////////////////////////////////////// +// +// Functions +// +/////////////////////////////////////////// + +void SaveMPSettings() +{ + Get16BitStringFromField( 0, gzServerNameField ); // these indexes are based on the order created + Get16BitStringFromField( 1, gzMaxPlayersField ); + Get16BitStringFromField( 2, gzSquadSizeField ); + + // save settings to JA2_mp.ini + WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_NAME", gzServerNameField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"MAX_CLIENTS", gzMaxPlayersField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"MAX_MERCS", gzSquadSizeField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"STARTING_BALANCE", gzStartingBalanceField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"DAMAGE_MULTIPLIER", gzDmgMultiplierField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"TIMED_TURN_SECS_PER_TICK", gzTimerField, L"..\\Ja2_mp.ini" ); + + + guiMPHGameType = GetMPHGameTypeButtonSetting(); + CHAR16 tmpGTStr[2]; + _itow(guiMPHGameType,tmpGTStr,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"GAME_MODE", tmpGTStr, L"..\\Ja2_mp.ini" ); + + CHAR16 tmpTimeStr[6]; + swprintf(tmpTimeStr,L"%i.%i",giMPHTimeHours,giMPHTimeMins); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"TIME", tmpTimeStr, L"..\\Ja2_mp.ini" ); + + CHAR16 tmpVal[2]; + + giMPHRandomMercs = ( ButtonList[ guiMPHRandomMercsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHRandomMercs,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_MERCS", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHSameMercs = ( ButtonList[ guiMPHSameMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHSameMercs,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"SAME_MERC", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHBobbyRays = ( ButtonList[ guiMPHBobbyRayToggle ]->uiFlags & BUTTON_CLICKED_ON ? 0 : 1 ); // This setting is reversed + _itow(giMPHBobbyRays,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHReportMercs = ( ButtonList[ guiMPHReportMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHReportMercs,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"REPORT_NAME", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHRandomSpawn = ( ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHRandomSpawn,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_EDGES", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHEnableCivilians = ( ButtonList[ guiMPHCivsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHEnableCivilians,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"CIV_ENABLED", tmpVal, L"..\\Ja2_mp.ini" ); + + giMPHUseNIV = ( ButtonList[ guiMPHUseNIVToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); + _itow(giMPHUseNIV,tmpVal,10); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", tmpVal, L"..\\Ja2_mp.ini" ); + + + + + /*if ( ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags & BUTTON_CLICKED_ON ) + WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_EDGES", L"1", L"..\\Ja2_mp.ini" ); + else + WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_EDGES", L"0", L"..\\Ja2_mp.ini" );*/ + + // save game difficulty setting + gGameOptions.ubDifficultyLevel = GetMPHCurrentDifficultyButtonSetting(); +} + +bool ValidateMPSettings() +{ + // Check a Server name is entered + Get16BitStringFromField( 0, gzServerNameField ); // these indexes are based on the order created + if (wcscmp(gzServerNameField,L"")<=0) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_SERVERNAME_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + // Verify the Max Players + Get16BitStringFromField( 1, gzMaxPlayersField ); + UINT8 numPlayers = _wtoi(gzMaxPlayersField); + if (numPlayers < 2 || numPlayers > 4) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_MAXPLAYERS_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + // Verify the Squad Size + Get16BitStringFromField( 2, gzSquadSizeField ); + UINT8 squadSize = _wtoi(gzSquadSizeField); + if (squadSize < 1 || squadSize > 6) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_SQUADSIZE_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + // verify the Time of Day + Get16BitStringFromField( 3, gzTimeOfDayField ); + wchar_t* tok; + bool bTimeOK = true; + int hours = 0; + int mins = 0; + + // strtok is destructive, make a copy to work on + CHAR16 tmpTODStr[5]; + memcpy(tmpTODStr,gzTimeOfDayField,sizeof(CHAR16)*5); + + tok = wcstok(tmpTODStr,L":"); + if (tok != NULL) + { + hours = _wtoi(tok); + // check for invalid conversion, ie alpha chars + // wtoi returns 0 if it cant convert, but we need this value + // therefore if tok <> 0 then it was a bad convert. + if (hours == 0 && wcscmp(tok,L"0") != 0) + { + // force error + bTimeOK = false; + } + + tok = wcstok(NULL,L"."); + if (tok != NULL) + { + mins = _wtoi(tok); + if (mins == 0 && wcscmp(tok,L"0") != 0) + { + // force error + bTimeOK = false; + } + + // fix for single digits + if (wcslen(tok) == 1) + mins = mins * 10; + } + else + { + bTimeOK = false; + } + } + else + { + bTimeOK = false; + } + + + if (bTimeOK) + { + giMPHTimeHours = hours; + float ratio = (float)mins / 60.0f; + giMPHTimeMins = (INT16)(ratio * 100); + + } + else + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_TIME_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + + // verify the Starting Balance + Get16BitStringFromField( 4, gzStartingBalanceField ); + UINT32 sBalance = _wtoi(gzStartingBalanceField); + if (sBalance < 1) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_CASH_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + Get16BitStringFromField( 5, gzDmgMultiplierField ); + double fDmg = _wtof(gzDmgMultiplierField); + if (fDmg <= 0.0f || fDmg >= 5.0f) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_DMG_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + Get16BitStringFromField( 6, gzTimerField ); + UINT32 iTimer = _wtoi(gzTimerField); + if (iTimer < 1 || iTimer > 200) + { + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_TIMER_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + return true; +} + +UINT32 MPHostScreenInit( void ) +{ + // read settings from JA2_mp.ini + GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_NAME", L"Mr Server", gzServerNameField, 30, L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"MAX_CLIENTS", L"", gzMaxPlayersField, 2, L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"MAX_MERCS", L"", gzSquadSizeField, 2 , L"..\\Ja2_mp.ini" ); + guiMPHGameType = GetPrivateProfileIntW( L"Ja2_mp Settings",L"GAME_MODE", MP_TYPE_DEATHMATCH, L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"STARTING_BALANCE", L"9:30", gzStartingBalanceField, 10 , L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"DAMAGE_MULTIPLIER", L"0.7", gzDmgMultiplierField, 5 , L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"TIMED_TURN_SECS_PER_TICK", L"100", gzTimerField, 5 , L"..\\Ja2_mp.ini" ); + + giMPHRandomMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"RANDOM_MERCS", 0, L"..\\Ja2_mp.ini" ); + giMPHSameMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"SAME_MERC", 0, L"..\\Ja2_mp.ini" ); + giMPHReportMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"REPORT_NAME", 0, L"..\\Ja2_mp.ini" ); + giMPHBobbyRays = GetPrivateProfileIntW( L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", 0, L"..\\Ja2_mp.ini" ); + giMPHRandomSpawn = GetPrivateProfileIntW( L"Ja2_mp Settings",L"RANDOM_EDGES", 0, L"..\\Ja2_mp.ini" ); + giMPHEnableCivilians = GetPrivateProfileIntW( L"Ja2_mp Settings",L"CIV_ENABLED", 0, L"..\\Ja2_mp.ini" ); + giMPHUseNIV = GetPrivateProfileIntW( L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", 0, L"..\\Ja2_mp.ini" ); + + + // read in time + CHAR16 szTime[5]; + GetPrivateProfileStringW( L"Ja2_mp Settings",L"TIME", L"13.50", szTime, 5 , L"..\\Ja2_mp.ini" ); + + wchar_t* tok; + bool bTimeOK = true; + int hours = 0; + int mins = 0; + + tok = wcstok(szTime,L"."); + + if (tok != NULL) + { + hours = _wtoi(tok); + // check for invalid conversion, ie alpha chars + // wtoi returns 0 if it cant convert, but we need this value + // therefore if tok <> 0 then it was a bad convert. + if (hours == 0 && wcscmp(tok,L"0") != 0) + { + // force error + bTimeOK = false; + } + + tok = wcstok(NULL,L"."); + if (tok != NULL) + { + mins = _wtoi(tok); + if (mins == 0 && wcscmp(tok,L"0") != 0) + { + // force error + bTimeOK = false; + } + + // fix for single digits + if (wcslen(tok) == 1) + mins = mins * 10; + } + else + { + bTimeOK = false; + } + } + else + { + bTimeOK = false; + } + + + + if (bTimeOK) + { + giMPHTimeHours = hours; + float ratio = (float)mins / 100.0f; + giMPHTimeMins = (INT16)(ratio * 60); + swprintf(gzTimeOfDayField,L"%i:%i",giMPHTimeHours,giMPHTimeMins); + } + + return( 1 ); +} + + +UINT32 MPHostScreenHandle( void ) +{ + StartFrameBufferRender(); + + if( gfMPHScreenEntry ) + { +// PauseGame(); + + EnterMPHScreen(); + gfMPHScreenEntry = FALSE; + gfMPHScreenExit = FALSE; + InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + } + + GetMPHScreenUserInput(); + + + HandleMPHScreen(); + + // render buttons marked dirty + MarkButtonsDirty( ); + RenderButtons( ); + + // render text boxes + RenderAllTextFields(); // textbox system call + + // render help +// RenderFastHelp( ); +// RenderButtonsFastHelp( ); + + + ExecuteBaseDirtyRectQueue(); + EndFrameBufferRender(); + + // handle fades in and out + if ( HandleFadeOutCallback( ) ) + { + ClearMainMenu(); + return( gubMPHExitScreen ); + } + + if ( HandleBeginFadeOut( gubMPHExitScreen ) ) + { + return( gubMPHExitScreen ); + } + + if ( HandleFadeInCallback( ) ) + { + // Re-render the scene! + RenderMPHScreen(); + } + + if ( HandleBeginFadeIn( gubMPHExitScreen ) ) + { + + } + + if( gfMPHScreenExit ) // we are exiting this screen + { + ExitMPHScreen(); // perform destruction + } + + return( gubMPHExitScreen ); +} // end MPHoinScreenHandle() + + +UINT32 MPHostScreenShutdown( void ) +{ + return( 1 ); +} + +BOOLEAN EnterMPHScreen() +{ + VOBJECT_DESC VObjectDesc; + UINT16 cnt; + UINT16 usPosY; + + if( gfMPHButtonsAllocated ) + return( TRUE ); + + SetCurrentCursorFromDatabase( CURSOR_NORMAL ); + + // load the Main trade screen backgroiund image + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_800x600.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_1024x768.sti", VObjectDesc.ImageFile); + } + + CHECKF(AddVideoObject(&VObjectDesc, &guiMPHMainBackGroundImage )); + + //Join button + giMPHStartBtnImage = LoadButtonImage("INTERFACE\\PreferencesButtons.sti", -1,0,-1,2,-1 ); + guiMPHStartButton = CreateIconAndTextButton( giMPHStartBtnImage, gzMPHScreenText[MPH_START_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPH_BTN_START_X, MPH_BTN_START_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHStartCallback); + + SpecifyButtonSoundScheme( guiMPHStartButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyDisabledButtonStyle( guiMPHStartButton, DISABLED_STYLE_NONE ); + + //Cancel button + giMPHCancelBtnImage = UseLoadedButtonImage( giMPHStartBtnImage, -1,1,-1,3,-1 ); + guiMPHCancelButton = CreateIconAndTextButton( giMPHCancelBtnImage, gzMPHScreenText[MPH_CANCEL_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPH_CANCEL_X, MPH_BTN_START_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHCancelCallback ); + SpecifyButtonSoundScheme( guiMPHCancelButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + + // Initialise Text Boxes + InitTextInputMode(); // API call to initialise text input mode for this screen + // does not mean we are inputting text right away + + // Player Name field + SetTextInputCursor( CUROSR_IBEAM_WHITE ); + SetTextInputFont( (UINT16) FONT12ARIALFIXEDWIDTH ); //FONT12ARIAL //FONT12ARIALFIXEDWIDTH + Set16BPPTextFieldColor( Get16BPPColor(FROMRGB( 0, 0, 0) ) ); + SetBevelColors( Get16BPPColor(FROMRGB(136, 138, 135)), Get16BPPColor(FROMRGB(24, 61, 81)) ); + SetTextInputRegularColors( FONT_WHITE, 2 ); + SetTextInputHilitedColors( 2, FONT_WHITE, FONT_WHITE ); + SetCursorColor( Get16BPPColor(FROMRGB(255, 255, 255) ) ); + + //AddUserInputField( NULL ); // API Call that sets a special input-handling routine and method for the TAB key + + //Add Player Name textbox + AddTextInputField( MPH_TXT_SVRNAME_X, + MPH_TXT_SVRNAME_Y, + MPH_TXT_SVRNAME_WIDTH, + MPH_TXT_SVRNAME_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzServerNameField, + 30, + INPUTTYPE_ASCII );//23 + + //Add Num Players textbox + AddTextInputField( MPH_TXT_MAXPLAYERS_X, + MPH_TXT_MAXPLAYERS_Y, + MPH_TXT_MAXPLAYERS_WIDTH, + MPH_TXT_MAXPLAYERS_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzMaxPlayersField, + 2, + INPUTTYPE_ASCII );//23 + + //Add Squad Size textbox + AddTextInputField( MPH_TXT_SQUAD_X, + MPH_TXT_SQUAD_Y, + MPH_TXT_SQUAD_WIDTH, + MPH_TXT_SQUAD_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzSquadSizeField, + 2, + INPUTTYPE_ASCII );//23 + + //Add Time of day textbox + AddTextInputField( MPH_TXT_TIME_X, + MPH_TXT_TIME_Y, + MPH_TXT_TIME_WIDTH, + MPH_TXT_TIME_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzTimeOfDayField, + 5, + INPUTTYPE_ASCII );//23 + + //Add Starting Cash textbox + AddTextInputField( MPH_TXT_CASH_X, + MPH_TXT_CASH_Y, + MPH_TXT_CASH_WIDTH, + MPH_TXT_CASH_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzStartingBalanceField, + 10, + INPUTTYPE_ASCII );//23 + + //Add Damage Multiplyer textbox + AddTextInputField( MPH_TXT_DMG_X, + MPH_TXT_DMG_Y, + MPH_TXT_DMG_WIDTH, + MPH_TXT_DMG_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzDmgMultiplierField, + 5, + INPUTTYPE_ASCII );//23 + + //Add Turn Timer textbox + AddTextInputField( MPH_TXT_TIMER_X, + MPH_TXT_TIMER_Y, + MPH_TXT_TIMER_WIDTH, + MPH_TXT_TIMER_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzTimerField, + 5, + INPUTTYPE_ASCII );//23 + + + SetActiveField( 0 ); // Playername textbox has focus + + + // + //Check box to toggle Difficulty settings + // + usPosY = MPH_DIF_SETTINGS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y; + + for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM ) + ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_MED ] ]->uiFlags |= BUTTON_CLICKED_ON; + + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD ) + ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_HARD ] ]->uiFlags |= BUTTON_CLICKED_ON; + + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) + ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_INSANE ] ]->uiFlags |= BUTTON_CLICKED_ON; + + else + ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_MED ] ]->uiFlags |= BUTTON_CLICKED_ON; + + + + + // + //Check box to toggle GameType settings + // + usPosY = MPH_GAMETYPE_SETTINGS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y; + + for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + + + // Random Mercs + guiMPHRandomMercsToggle = CreateCheckBoxButton( MPH_RNDMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_RNDMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHRandomMercCallback ); + if ( giMPHRandomMercs ) + ButtonList[ guiMPHRandomMercsToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + //checkbox for same merc + guiMPHSameMercToggle = CreateCheckBoxButton( MPH_SAMEMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_SAMEMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHSameMercCallback ); + if ( giMPHSameMercs ) + ButtonList[ guiMPHSameMercToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + //checkbox for report purchase + guiMPHReportMercToggle = CreateCheckBoxButton( MPH_REPORTMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_REPORTMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHReportMercCallback ); + if (giMPHReportMercs) + ButtonList[ guiMPHReportMercToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + //checkbox for bobby rays + guiMPHBobbyRayToggle = CreateCheckBoxButton( MPH_BOBBYRAY_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_BOBBYRAY_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHBobbyRayCallback ); + + if (!giMPHBobbyRays) + ButtonList[ guiMPHBobbyRayToggle ]->uiFlags |= BUTTON_CLICKED_ON; // the setting is actually DISABLE / NEGATIVE + + //checkbox for random spawn pos + guiMPHRandomSpawnToggle = CreateCheckBoxButton( MPH_RNDSPAWN_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_RNDSPAWN_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHRandomSpawnCallback ); + + if (giMPHRandomSpawn) + ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + // checkbox for civillians + guiMPHCivsToggle = CreateCheckBoxButton( MPH_CIVS_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_CIVS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHCivsCallback ); + if (giMPHEnableCivilians) + ButtonList[ guiMPHCivsToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + // checkbox for use NIV + guiMPHUseNIVToggle = CreateCheckBoxButton( MPH_USENIV_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_USENIV_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, + "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, + BtnMPHUseNIVCallback ); + if (giMPHUseNIV) + ButtonList[ guiMPHUseNIVToggle ]->uiFlags |= BUTTON_CLICKED_ON; + + + + + //Reset the exit screen - screen the main game loop will call next iteration + gubMPHExitScreen = MP_HOST_SCREEN; + + //REnder the screen once so we can blt ot to ths save buffer + RenderMPHScreen(); + + BlitBufferToBuffer(guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + + gfMPHButtonsAllocated = TRUE; + + return( TRUE ); + +} // End of EnterMPHScreen() + + +BOOLEAN ExitMPHScreen() +{ + UINT16 cnt; + + if( !gfMPHButtonsAllocated ) + return( TRUE ); + + //Delete the main options screen background + DeleteVideoObjectFromIndex( guiMPHMainBackGroundImage ); + + RemoveButton( guiMPHStartButton ); + RemoveButton( guiMPHCancelButton ); + + + UnloadButtonImage( giMPHCancelBtnImage ); + UnloadButtonImage( giMPHStartBtnImage ); + + //Check box to toggle Difficulty settings + for( cnt=0; cnt review this, i think MPH_EXIT is the proceed mode... + //if( gubMPHScreenHandler == MPH_EXIT ) + // SetMusicMode( MUSIC_NONE ); + + gfMPHScreenExit = FALSE; + gfMPHScreenEntry = TRUE; + + return( TRUE ); + +} // End of ExitMPHScreen() + + +void HandleMPHScreen() +{ + if( gubMPHScreenHandler != MPH_NOTHING ) + { + switch( gubMPHScreenHandler ) + { + case MPH_CANCEL: + gubMPHExitScreen = MAINMENU_SCREEN; + gfMPHScreenExit = TRUE; + break; + + + case MPH_START: + { + //if we are already fading out, get out of here + if( gFadeOutDoneCallback != DoneFadeOutForExitMPHScreen ) + { + //Disable the ok button + DisableButton( guiMPHStartButton ); + + gFadeOutDoneCallback = DoneFadeOutForExitMPHScreen; + + FadeOutNextFrame( ); + } + break; + } + + } + + gubMPHScreenHandler = MPH_NOTHING; + } + + + if( gfReRenderMPHScreen ) + { + RenderMPHScreen(); + gfReRenderMPHScreen = FALSE; + } + + RestoreMPHButtonBackGrounds(); +} // end of HandleMPHScreen + + +BOOLEAN RenderMPHScreen() +{ + HVOBJECT hPixHandle; + UINT16 usPosY; + + //Get the main background screen graphic and blt it + GetVideoObject(&hPixHandle, guiMPHMainBackGroundImage ); + BltVideoObject(FRAME_BUFFER, hPixHandle, 0,0,0, VO_BLT_SRCTRANSPARENCY,NULL); + + //Shade the background + ShadowVideoSurfaceRect( FRAME_BUFFER, iScreenWidthOffset, iScreenHeightOffset, iScreenWidthOffset + 640, iScreenHeightOffset + 480 ); + + //Display the title + DrawTextToScreen( gzMPHScreenText[ MPH_TITLE_TEXT ], MPH_MAIN_TITLE_X, MPH_MAIN_TITLE_Y, MPH_MAIN_TITLE_WIDTH, MPH_TITLE_FONT, MPH_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + // Server name text label + DisplayWrappedString( MPH_LABEL_SVRNAME_X, MPH_LABEL_SVRNAME_Y, MPH_LABEL_SVRNAME_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_SERVERNAME_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Num Players text label + DisplayWrappedString( MPH_LABEL_MAXPLAYERS_X, MPH_LABEL_MAXPLAYERS_Y, MPH_LABEL_MAXPLAYERS_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_NUMPLAYERS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Squad Size text label + DisplayWrappedString( MPH_LABEL_SQUAD_X, MPH_LABEL_SQUAD_Y, MPH_LABEL_SQUAD_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_SQUADSIZE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Time Of day text label + DisplayWrappedString( MPH_LABEL_TIME_X, MPH_LABEL_TIME_Y, MPH_LABEL_TIME_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_TIME_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Starting Cash text label + DisplayWrappedString( MPH_LABEL_CASH_X, MPH_LABEL_CASH_Y, MPH_LABEL_CASH_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_BALANCE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Starting Cash text label + DisplayWrappedString( MPH_LABEL_DMG_X, MPH_LABEL_DMG_Y, MPH_LABEL_DMG_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_DMG_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Starting Cash text label + DisplayWrappedString( MPH_LABEL_TIMER_X, MPH_LABEL_TIMER_Y, MPH_LABEL_TIMER_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_TIMER_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + //Display the Dif Settings Title Text + DisplayWrappedString( MPH_DIF_SETTINGS_X, (UINT16)(MPH_DIF_SETTINGS_Y-MPH_GAP_BN_SETTINGS), MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_DIF_LEVEL_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Novice + usPosY = MPH_DIF_SETTINGS_Y+2; + DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_EASY_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Intermediate + usPosY += MPH_GAP_BN_SETTINGS-5; + DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_MEDIUM_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Hard + usPosY += MPH_GAP_BN_SETTINGS-5; + DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_HARD_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Insane + usPosY += MPH_GAP_BN_SETTINGS-5; + //DrawTextToScreen( gzMPHScreenText[ MPH_HARD_TEXT ], (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_MAIN_TITLE_WIDTH, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_INSANE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + //Display the Game Type title + DisplayWrappedString( MPH_GAMETYPE_SETTINGS_X, (UINT16)(MPH_GAMETYPE_SETTINGS_Y-MPH_GAP_BN_SETTINGS), MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_GAMETYPE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Deathmatch + usPosY = MPH_GAMETYPE_SETTINGS_Y+2; + DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_DEATHMATCH_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Team Deathmatch + usPosY += MPH_GAP_BN_SETTINGS-5; + DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_TEAMDM_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Co-operative + usPosY += MPH_GAP_BN_SETTINGS-5; + DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_COOP_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Random Mercs + DisplayWrappedString( (UINT16)MPH_RNDMERC_X, MPH_RNDMERC_Y, MPH_RNDMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RANDOMMERCS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Same Mercs + DisplayWrappedString( (UINT16)MPH_SAMEMERC_X, MPH_SAMEMERC_Y, MPH_SAMEMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SAMEMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Report Mercs + DisplayWrappedString( (UINT16)MPH_REPORTMERC_X, MPH_REPORTMERC_Y, MPH_REPORTMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RPTMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Allow Bobby-Rays + DisplayWrappedString( (UINT16)MPH_BOBBYRAY_X, MPH_BOBBYRAY_Y, MPH_BOBBYRAY_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_BOBBYRAY_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Random Spawn + DisplayWrappedString( (UINT16)MPH_RNDSPAWN_X, MPH_RNDSPAWN_Y, MPH_RNDSPAWN_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RNDMSTART_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Civs + DisplayWrappedString( (UINT16)MPH_CIVS_X, MPH_CIVS_Y, MPH_CIVS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_ENABLECIV_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Use NIV + DisplayWrappedString( (UINT16)MPH_USENIV_X, MPH_USENIV_Y, MPH_CIVS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_USENIV_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + + return( TRUE ); +} // end of RenderMPHScreen() + + + +void GetMPHScreenUserInput() +{ + InputAtom Event; +// POINT MousePos; + +// GetCursorPos(&MousePos); + + while( DequeueEvent( &Event ) ) + { + // check if this event is swallowed by text input, otherwise process key + if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN ) + { + switch( Event.usParam ) + { + + case ESC: + //Exit out of the screen + gubMPHScreenHandler = MPH_CANCEL; + break; + + case ENTER: + if (ValidateMPSettings()) + { + SaveMPSettings(); + gubMPHScreenHandler = MPH_START; + } + break; + } + } + } +} // end of GetMPHScreenUserInput() + + +// CALLBACKS + +void BtnMPHStartCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + if (ValidateMPSettings()) + { + SaveMPSettings(); + gubMPHScreenHandler = MPH_START; + } + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void BtnMPHCancelCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + gubMPHScreenHandler = MPH_CANCEL; + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void BtnMPHDifficultyTogglesCallback( GUI_BUTTON *btn, INT32 reason ) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + UINT8 cnt; + + for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; + } + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + else + { + UINT8 cnt; + BOOLEAN fAnyChecked=FALSE; + + //if none of the other boxes are checked, do not uncheck this box + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + fAnyChecked = TRUE; + } + } + //if none are checked, re check this one + if( !fAnyChecked ) + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHGameTypeTogglesCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + UINT8 cnt; + + for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; + } + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + else + { + UINT8 cnt; + BOOLEAN fAnyChecked=FALSE; + + //if none of the other boxes are checked, do not uncheck this box + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + fAnyChecked = TRUE; + } + } + //if none are checked, re check this one + if( !fAnyChecked ) + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void RestoreMPHButtonBackGrounds() +{ + UINT8 cnt; + UINT16 usPosY; + + + usPosY = MPH_DIF_SETTINGS_Y-MPH_OFFSET_TO_TOGGLE_BOX_Y; + //Check box to toggle Difficulty settings + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + + return( 0 ); +} + +UINT8 GetMPHGameTypeButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + + return( 0 ); +} + +BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ) +{ + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + + // reset exit mode +// gfExitGioDueToMessageBox = TRUE; + + // do message box and return + giMPHMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT16 ) ( usFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &CenteringRect ); + + // send back return state + return( ( giMPHMessageBox != -1 ) ); +} + +void DoneFadeOutForExitMPHScreen( void ) +{ + // As we bypassed the GIO screen, set up some game options for multiplayer here + // most things i have left as thier defaults here for testing. + is_networked = true; + is_host = true; // we want to be the host, not we ARE the host yet (is_server) + auto_retry = true; + giNumTries = 5; + + // loop through and get the status of all the buttons + // Madd + /*gGameOptions.fGunNut = GetCurrentGunButtonSetting(); + gGameOptions.ubGameStyle = GetCurrentGameStyleButtonSetting(); + gGameOptions.ubDifficultyLevel = GetCurrentDifficultyButtonSetting() + 1;*/ + // JA2Gold: no more timed turns setting + //gGameOptions.fTurnTimeLimit = GetCurrentTimedTurnsButtonSetting();//hayden : re-enabled + + if (is_networked) + gGameOptions.fTurnTimeLimit = TRUE; + else + gGameOptions.fTurnTimeLimit = FALSE; + + // JA2Gold: iron man + //gGameOptions.fIronManMode = GetCurrentGameSaveButtonSetting(); + + // Bobby Rays - why would we want anything less than the best + gGameOptions.ubBobbyRay = BR_AWESOME; + + + // CHRISL: + /*if(IsNIVModeValid() == TRUE){ + switch ( GetCurrentINVOptionButtonSetting() ) + { + case GIO_INV_OLD: + gGameOptions.ubInventorySystem = INVENTORY_OLD; + break; + case GIO_INV_NEW: + gGameOptions.ubInventorySystem = INVENTORY_NEW; + break; + } + }*/ + + // gubGIOExitScreen = INIT_SCREEN; + gubMPHExitScreen = INTRO_SCREEN; + + //set the fact that we should do the intro videos +// gbIntroScreenMode = INTRO_BEGINING; +#ifdef JA2TESTVERSION + if( gfKeyState[ ALT ] ) + { + if( gfKeyState[ CTRL ] ) + { + gMercProfiles[ MIGUEL ].bMercStatus = MERC_IS_DEAD; + gMercProfiles[ SKYRIDER ].bMercStatus = MERC_IS_DEAD; + } + + SetIntroType( INTRO_ENDING ); + } + else +#endif + SetIntroType( INTRO_BEGINING ); + + ExitMPHScreen(); // cleanup please, if we called a fadeout then we didnt do it above + + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} + +void DoneFadeInForExitMPHScreen( void ) +{ + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} + + +void BtnMPHRandomMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHRandomMercsToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHSameMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHSameMercToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHReportMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHReportMercToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHBobbyRayCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHBobbyRayToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHRandomSpawnCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHUseNIVCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHUseNIVToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} + +void BtnMPHCivsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + MSYS_GetBtnUserData( btn, 0 ); + + if( btn->uiFlags & BUTTON_CLICKED_ON ) + { + ButtonList[ guiMPHCivsToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + + //enable the current button + btn->uiFlags |= BUTTON_CLICKED_ON; + } + } +} \ No newline at end of file diff --git a/MPHostScreen.h b/MPHostScreen.h new file mode 100644 index 00000000..051947ff --- /dev/null +++ b/MPHostScreen.h @@ -0,0 +1,12 @@ +#ifndef _MP_HOST_SCREEN_H_ +#define _MP_HOST_SCREEN_H_ + + +UINT32 MPHostScreenInit( void ); +UINT32 MPHostScreenHandle( void ); +UINT32 MPHostScreenShutdown( void ); + + + + +#endif \ No newline at end of file diff --git a/MPJoinScreen.cpp b/MPJoinScreen.cpp new file mode 100644 index 00000000..88fdb9bb --- /dev/null +++ b/MPJoinScreen.cpp @@ -0,0 +1,742 @@ +#ifdef PRECOMPILEDHEADERS + #include "JA2 All.h" + #include "Intro.h" +#else + #include "Types.h" + #include "MPJoinScreen.h" + #include "GameSettings.h" + #include "Utilities.h" + #include "wCheck.h" + #include "Font Control.h" + #include "WordWrap.h" + #include "Render Dirty.h" + #include "Input.h" + #include "Options Screen.h" + #include "English.h" + #include "Sysutil.h" + #include "Fade Screen.h" + #include "Cursor Control.h" + #include "Music Control.h" + #include "cursors.h" + #include "Intro.h" + #include "Text.h" + #include "Text Input.h" + #include "_Ja25EnglishText.h" + #include "Soldier Profile.h" +#endif + +#include "gameloop.h" +#include "connect.h" +#include "network.h" // for client name +#include "saveloadscreen.h" + + +//////////////////////////////////////////// +// +// Global Defines +// +/////////////////////////////////////////// + +#define MPJ_TITLE_FONT FONT14ARIAL//FONT16ARIAL +#define MPJ_TITLE_COLOR FONT_MCOLOR_WHITE + +#define MPJ_LABEL_TEXT_FONT FONT12ARIAL//FONT16ARIAL +#define MPJ_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE + +//buttons +#define MPJ_BTN_JOIN_X iScreenWidthOffset + 320 + 143 +#define MPJ_BTN_JOIN_Y iScreenHeightOffset + 435 +#define MPJ_BTN_HOST_X MPJ_BTN_JOIN_X-180 +#define MPJ_BTN_HOST_Y iScreenHeightOffset + 435 +#define MPJ_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) + +//textboxes +#define MPJ_TXT_HANDLE_X iScreenWidthOffset + 100 +#define MPJ_TXT_HANDLE_Y iScreenHeightOffset + 60 +#define MPJ_TXT_HANDLE_WIDTH 120 +#define MPJ_TXT_HANDLE_HEIGHT 17 +#define MPJ_TXT_IP_X iScreenWidthOffset + 100 +#define MPJ_TXT_IP_Y iScreenHeightOffset + 400 +#define MPJ_TXT_IP_WIDTH 100 +#define MPJ_TXT_IP_HEIGHT 17 +#define MPJ_TXT_PORT_X MPJ_TXT_IP_X + MPJ_TXT_IP_WIDTH + 40 +#define MPJ_TXT_PORT_Y iScreenHeightOffset + 400 +#define MPJ_TXT_PORT_WIDTH 40 +#define MPJ_TXT_PORT_HEIGHT 17 + + +//main title +#define MPJ_MAIN_TITLE_X 0 +#define MPJ_MAIN_TITLE_Y iScreenHeightOffset + 10 +#define MPJ_MAIN_TITLE_WIDTH SCREEN_WIDTH + +//labels +#define MPJ_LABEL_HANDLE_X MPJ_TXT_HANDLE_X - 80 +#define MPJ_LABEL_HANDLE_Y MPJ_TXT_HANDLE_Y + 3 +#define MPJ_LABEL_HANDLE_WIDTH 80 +#define MPJ_LABEL_HANDLE_HEIGHT 17 +#define MPJ_LABEL_IP_X MPJ_TXT_IP_X - 80 +#define MPJ_LABEL_IP_Y MPJ_TXT_IP_Y + 3 +#define MPJ_LABEL_IP_WIDTH 80 +#define MPJ_LABEL_IP_HEIGHT 17 +#define MPJ_LABEL_PORT_X MPJ_TXT_PORT_X - 30 +#define MPJ_LABEL_PORT_Y MPJ_TXT_PORT_Y + 3 +#define MPJ_LABEL_PORT_WIDTH 80 +#define MPJ_LABEL_PORT_HEIGHT 17 + + +//////////////////////////////////////////// +// +// Global Variables +// +/////////////////////////////////////////// + +BOOLEAN gfMPJScreenEntry = TRUE; +BOOLEAN gfMPJScreenExit = FALSE; +BOOLEAN gfReRenderMPJScreen=TRUE; +BOOLEAN gfMPJButtonsAllocated = FALSE; + +//enum for different states of screen +enum +{ + MPJ_NOTHING, + MPJ_CANCEL, + MPJ_EXIT, + MPJ_HOST, + MPJ_JOIN +}; + +UINT8 gubMPJScreenHandler=MPJ_NOTHING; // State changer for HandleMPJScreen() + +UINT32 gubMPJExitScreen = MP_JOIN_SCREEN; // The screen that is in control next iteration of the game_loop + +UINT32 guiMPJMainBackGroundImage; + +// Wide-char strings that will hold the variables until they are transferred to the CHAR ascii fields +CHAR16 gzPlayerHandleField[ 30 ] = {0} ; +CHAR16 gzServerIPField[ 15 ] = {0} ; +CHAR16 gzServerPortField[ 5 ] = {0} ; + +//////////////////////////////////////////// +// +// Screen Controls +// +/////////////////////////////////////////// + +// Join Button +void BtnMPJoinCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPJoinButton; +INT32 giMPJoinBtnImage; + +// Host Button +void BtnMPJHostCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPJHostButton; +INT32 giMPJHostBtnImage; + +// Cancel Button +void BtnMPJCancelCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPJCancelButton; +INT32 giMPJCancelBtnImage; + +// Message Box handle +INT8 giMPJMessageBox = -1; + + +//////////////////////////////////////////// +// +// Local Function Prototypes +// +/////////////////////////////////////////// + +extern void ClearMainMenu(); + +BOOLEAN EnterMPJScreen(); +BOOLEAN ExitMPJScreen(); +void HandleMPJScreen(); +BOOLEAN RenderMPJScreen(); +void GetMPJScreenUserInput(); +void SaveJoinSettings(); +bool ValidateJoinSettings(bool bSkipServerAddress); +BOOLEAN DoMPJMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); +void DoneFadeOutForExitMPJScreen( void ); +void DoneFadeInForExitMPJScreen( void ); + + +UINT32 MPJoinScreenInit( void ) +{ + // read settings from JA2 ini + GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_IP", L"", gzServerIPField, 15, L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_PORT", L"", gzServerPortField, 5, L"..\\Ja2_mp.ini" ); + GetPrivateProfileStringW( L"Ja2_mp Settings",L"CLIENT_NAME", L"Fresh Meat", gzPlayerHandleField, 30 , L"..\\Ja2_mp.ini" ); + return( 1 ); +} + +void SaveJoinSettings() +{ + Get16BitStringFromField( 0, gzPlayerHandleField ); // these indexes are based on the order created + Get16BitStringFromField( 1, gzServerIPField ); + Get16BitStringFromField( 2, gzServerPortField ); + + // save settings to JA2_mp.ini + WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_IP", gzServerIPField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_PORT", gzServerPortField, L"..\\Ja2_mp.ini" ); + WritePrivateProfileStringW( L"Ja2_mp Settings",L"CLIENT_NAME", gzPlayerHandleField , L"..\\Ja2_mp.ini" ); +} + +bool ValidateJoinSettings(bool bSkipServerAddress) +{ + // Check a Server name is entered + Get16BitStringFromField( 0, gzPlayerHandleField ); // these indexes are based on the order created + if (wcscmp(gzPlayerHandleField,L"")<=0) + { + DoMPJMessageBox( MSG_BOX_BASIC_STYLE, gzMPJScreenText[MPJ_HANDLE_INVALID], MP_JOIN_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + // dont check server address if we are going to HOST + if (bSkipServerAddress) + return true; + + // Verify the IP Address + Get16BitStringFromField( 1, gzServerIPField ); + + // loop through octets and check + int numOctets = 0; + wchar_t* tok; + tok = wcstok(gzServerIPField,L"."); + while (tok != NULL) + { + numOctets++; + INT32 oct = _wtoi(tok); + // check for invalid conversion, ie alpha chars + // wtoi returns 0 if it cant convert, but we need this value + // therefore if tok <> 0 then it was a bad convert. + if (oct == 0 && wcscmp(tok,L"0") != 0) + { + // force error + numOctets=0; + break; + } + + if (oct < 0 || oct > 254) // dont allow broadcast nums + { + // bad octet, error + numOctets=0; + break; + } + + // get next octet + tok = wcstok(NULL,L"."); + } + + if (numOctets != 4) + { + // not a valid ip address + DoMPJMessageBox( MSG_BOX_BASIC_STYLE, gzMPJScreenText[MPJ_SERVERIP_INVALID], MP_JOIN_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + // Verify the Server Port + Get16BitStringFromField( 2, gzServerPortField ); + INT32 svrPort = _wtoi(gzServerPortField); + if (svrPort < 1 || svrPort > 65535) + { + DoMPJMessageBox( MSG_BOX_BASIC_STYLE, gzMPJScreenText[MPJ_SERVERPORT_INVALID], MP_JOIN_SCREEN, MSG_BOX_FLAG_OK, NULL ); + return false; + } + + return true; +} + +UINT32 MPJoinScreenHandle( void ) +{ + StartFrameBufferRender(); + + if( gfMPJScreenEntry ) + { +// PauseGame(); + + EnterMPJScreen(); + gfMPJScreenEntry = FALSE; + gfMPJScreenExit = FALSE; + InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + } + + GetMPJScreenUserInput(); + + + HandleMPJScreen(); + + // render buttons marked dirty + MarkButtonsDirty( ); + RenderButtons( ); + + // render text boxes + RenderAllTextFields(); // textbox system call + + // render help +// RenderFastHelp( ); +// RenderButtonsFastHelp( ); + + + ExecuteBaseDirtyRectQueue(); + EndFrameBufferRender(); + + // handle fades in and out + if ( HandleFadeOutCallback( ) ) + { + ClearMainMenu(); + return( gubMPJExitScreen ); + } + + if ( HandleBeginFadeOut( gubMPJExitScreen ) ) + { + return( gubMPJExitScreen ); + } + + if ( HandleFadeInCallback( ) ) + { + // Re-render the scene! + RenderMPJScreen(); + } + + if ( HandleBeginFadeIn( gubMPJExitScreen ) ) + { + + } + + if( gfMPJScreenExit ) // we are exiting this screen + { + ExitMPJScreen(); // perform destruction + } + + return( gubMPJExitScreen ); +} // end MPJoinScreenHandle() + + +UINT32 MPJoinScreenShutdown( void ) +{ + return( 1 ); +} + +BOOLEAN EnterMPJScreen() +{ + VOBJECT_DESC VObjectDesc; + UINT16 cnt; + UINT16 usPosY; + + if( gfMPJButtonsAllocated ) + return( TRUE ); + + SetCurrentCursorFromDatabase( CURSOR_NORMAL ); + + // load the Main trade screen backgroiund image + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_800x600.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_1024x768.sti", VObjectDesc.ImageFile); + } + + CHECKF(AddVideoObject(&VObjectDesc, &guiMPJMainBackGroundImage )); + + //Join button + giMPJoinBtnImage = LoadButtonImage("INTERFACE\\PreferencesButtons.sti", -1,0,-1,2,-1 ); + guiMPJoinButton = CreateIconAndTextButton( giMPJoinBtnImage, gzMPJScreenText[MPJ_JOIN_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPJ_BTN_JOIN_X, MPJ_BTN_JOIN_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPJoinCallback); + + SpecifyButtonSoundScheme( guiMPJoinButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyDisabledButtonStyle( guiMPJoinButton, DISABLED_STYLE_NONE ); + + //Host button + giMPJHostBtnImage = UseLoadedButtonImage( giMPJoinBtnImage, -1,1,-1,3,-1 ); + guiMPJHostButton = CreateIconAndTextButton( giMPJHostBtnImage, gzMPJScreenText[MPJ_HOST_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPJ_BTN_HOST_X, MPJ_BTN_HOST_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPJHostCallback); + + SpecifyButtonSoundScheme( guiMPJHostButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyDisabledButtonStyle( guiMPJHostButton, DISABLED_STYLE_NONE ); + + //Cancel button + giMPJCancelBtnImage = UseLoadedButtonImage( giMPJoinBtnImage, -1,1,-1,3,-1 ); + guiMPJCancelButton = CreateIconAndTextButton( giMPJCancelBtnImage, gzMPJScreenText[MPJ_CANCEL_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPJ_CANCEL_X, MPJ_BTN_JOIN_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPJCancelCallback ); + SpecifyButtonSoundScheme( guiMPJCancelButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + + // Initialise Text Boxes + InitTextInputMode(); // API call to initialise text input mode for this screen + // does not mean we are inputting text right away + + // Player Name field + SetTextInputCursor( CUROSR_IBEAM_WHITE ); + SetTextInputFont( (UINT16) FONT12ARIALFIXEDWIDTH ); //FONT12ARIAL //FONT12ARIALFIXEDWIDTH + Set16BPPTextFieldColor( Get16BPPColor(FROMRGB( 0, 0, 0) ) ); + SetBevelColors( Get16BPPColor(FROMRGB(136, 138, 135)), Get16BPPColor(FROMRGB(24, 61, 81)) ); + SetTextInputRegularColors( FONT_WHITE, 2 ); + SetTextInputHilitedColors( 2, FONT_WHITE, FONT_WHITE ); + SetCursorColor( Get16BPPColor(FROMRGB(255, 255, 255) ) ); + + //AddUserInputField( NULL ); // API Call that sets a special input-handling routine and method for the TAB key + + //Add Player Name textbox + AddTextInputField( MPJ_TXT_HANDLE_X, + MPJ_TXT_HANDLE_Y, + MPJ_TXT_HANDLE_WIDTH, + MPJ_TXT_HANDLE_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzPlayerHandleField, + 30, + INPUTTYPE_ASCII );//23 + + //Add Server IP textbox + AddTextInputField( MPJ_TXT_IP_X, + MPJ_TXT_IP_Y, + MPJ_TXT_IP_WIDTH, + MPJ_TXT_IP_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzServerIPField, + 15, + INPUTTYPE_ASCII );//23 + + //Add Server Port textbox + AddTextInputField( MPJ_TXT_PORT_X, + MPJ_TXT_PORT_Y, + MPJ_TXT_PORT_WIDTH, + MPJ_TXT_PORT_HEIGHT, + MSYS_PRIORITY_HIGH+2, + gzServerPortField, + 5, + INPUTTYPE_ASCII );//23 + + SetActiveField( 0 ); // Playername textbox has focus + + //Reset the exit screen - screen the main game loop will call next iteration + gubMPJExitScreen = MP_JOIN_SCREEN; + + //REnder the screen once so we can blt ot to ths save buffer + RenderMPJScreen(); + + BlitBufferToBuffer(guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + + gfMPJButtonsAllocated = TRUE; + + return( TRUE ); + +} // End of EnterMPJScreen() + + +BOOLEAN ExitMPJScreen() +{ + UINT16 cnt; + + if( !gfMPJButtonsAllocated ) + return( TRUE ); + + //Delete the main options screen background + DeleteVideoObjectFromIndex( guiMPJMainBackGroundImage ); + + RemoveButton( guiMPJoinButton ); + RemoveButton( guiMPJHostButton ); + RemoveButton( guiMPJCancelButton ); + + + UnloadButtonImage( giMPJCancelBtnImage ); + UnloadButtonImage( giMPJHostBtnImage ); + UnloadButtonImage( giMPJoinBtnImage ); + + // exit text input mode in this screen and clean up text boxes + KillAllTextInputModes(); + SetTextInputCursor( CURSOR_IBEAM ); + + gfMPJButtonsAllocated = FALSE; + + //If we are starting the game stop playing the music + // review this, i think MPJ_EXIT is the proceed mode... + //if( gubMPJScreenHandler == MPJ_EXIT ) + // SetMusicMode( MUSIC_NONE ); + + gfMPJScreenExit = FALSE; + gfMPJScreenEntry = TRUE; + + return( TRUE ); + +} // End of ExitMPJScreen() + + +void HandleMPJScreen() +{ + if( gubMPJScreenHandler != MPJ_NOTHING ) + { + switch( gubMPJScreenHandler ) + { + case MPJ_CANCEL: + gubMPJExitScreen = MAINMENU_SCREEN; + gfMPJScreenExit = TRUE; + break; + + case MPJ_HOST: + gubMPJExitScreen = MP_HOST_SCREEN; + gfMPJScreenExit = TRUE; + break; + + + case MPJ_JOIN: + { + //if we are already fading out, get out of here + if( gFadeOutDoneCallback != DoneFadeOutForExitMPJScreen ) + { + //Disable the ok button + DisableButton( guiMPJoinButton ); + DisableButton( guiMPJHostButton ); + + gFadeOutDoneCallback = DoneFadeOutForExitMPJScreen; + + FadeOutNextFrame( ); + } + break; + } + + } + + gubMPJScreenHandler = MPJ_NOTHING; + } + + + if( gfReRenderMPJScreen ) + { + RenderMPJScreen(); + gfReRenderMPJScreen = FALSE; + } + + // add restore backgrounds in... + //RestoreGIOButtonBackGrounds(); +} // end of HandleMPJScreen + + +BOOLEAN RenderMPJScreen() +{ + HVOBJECT hPixHandle; + UINT16 usPosY; + + //Get the main background screen graphic and blt it + GetVideoObject(&hPixHandle, guiMPJMainBackGroundImage ); + BltVideoObject(FRAME_BUFFER, hPixHandle, 0,0,0, VO_BLT_SRCTRANSPARENCY,NULL); + + //Shade the background + ShadowVideoSurfaceRect( FRAME_BUFFER, iScreenWidthOffset, iScreenHeightOffset, iScreenWidthOffset + 640, iScreenHeightOffset + 480 ); + + //Display the title + DrawTextToScreen( gzMPJScreenText[ MPJ_TITLE_TEXT ], MPJ_MAIN_TITLE_X, MPJ_MAIN_TITLE_Y, MPJ_MAIN_TITLE_WIDTH, MPJ_TITLE_FONT, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + // Player name text label + DisplayWrappedString( MPJ_LABEL_HANDLE_X, MPJ_LABEL_HANDLE_Y, MPJ_LABEL_HANDLE_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_HANDLE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Server IP text label + DisplayWrappedString( MPJ_LABEL_IP_X, MPJ_LABEL_IP_Y, MPJ_LABEL_IP_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERIP_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Server Port text label + DisplayWrappedString( MPJ_LABEL_PORT_X, MPJ_LABEL_PORT_Y, MPJ_LABEL_PORT_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERPORT_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + return( TRUE ); +} // end of RenderMPJScreen() + + + +void GetMPJScreenUserInput() +{ + InputAtom Event; +// POINT MousePos; + +// GetCursorPos(&MousePos); + + while( DequeueEvent( &Event ) ) + { + // check if this event is swallowed by text input, otherwise process key + if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN ) + { + switch( Event.usParam ) + { + + case ESC: + //Exit out of the screen + gubMPJScreenHandler = MPJ_CANCEL; + break; + + case ENTER: + if (ValidateJoinSettings(false)) + { + SaveJoinSettings(); + gubMPJScreenHandler = MPJ_JOIN; + } + break; + } + } + } +} // end of GetMPJScreenUserInput() + + +// CALLBACKS + +void BtnMPJoinCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + if (ValidateJoinSettings(false)) + { + SaveJoinSettings(); + gubMPJScreenHandler = MPJ_JOIN; + //gubMPJScreenHandler = MPJ_JOIN; + } + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void BtnMPJHostCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + if (ValidateJoinSettings(true)) + { + SaveJoinSettings(); + gubMPJScreenHandler = MPJ_HOST; + } + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void BtnMPJCancelCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + gubMPJScreenHandler = MPJ_CANCEL; + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +BOOLEAN DoMPJMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ) +{ + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + + // reset exit mode +// gfExitGioDueToMessageBox = TRUE; + + // do message box and return + giMPJMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT16 ) ( usFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &CenteringRect ); + + // send back return state + return( ( giMPJMessageBox != -1 ) ); +} + +void DoneFadeOutForExitMPJScreen( void ) +{ + // As we bypassed the GIO screen, set up some game options for multiplayer here + // most things i have left as thier defaults here for testing. + is_networked = true; + is_host = false; // we want to be a client, not we ARE a client yet (is_client) + auto_retry = true; + giNumTries = 5; + + // loop through and get the status of all the buttons + // Madd + /*gGameOptions.fGunNut = GetCurrentGunButtonSetting(); + gGameOptions.ubGameStyle = GetCurrentGameStyleButtonSetting(); + gGameOptions.ubDifficultyLevel = GetCurrentDifficultyButtonSetting() + 1;*/ + // JA2Gold: no more timed turns setting + //gGameOptions.fTurnTimeLimit = GetCurrentTimedTurnsButtonSetting();//hayden : re-enabled + + if (is_networked) + gGameOptions.fTurnTimeLimit = TRUE; + else + gGameOptions.fTurnTimeLimit = FALSE; + + // JA2Gold: iron man + //gGameOptions.fIronManMode = GetCurrentGameSaveButtonSetting(); + + // Bobby Rays - why would we want anything less than the best + gGameOptions.ubBobbyRay = BR_AWESOME; + + + // CHRISL: + /*if(IsNIVModeValid() == TRUE){ + switch ( GetCurrentINVOptionButtonSetting() ) + { + case GIO_INV_OLD: + gGameOptions.ubInventorySystem = INVENTORY_OLD; + break; + case GIO_INV_NEW: + gGameOptions.ubInventorySystem = INVENTORY_NEW; + break; + } + }*/ + + // gubGIOExitScreen = INIT_SCREEN; + gubMPJExitScreen = INTRO_SCREEN; + + //set the fact that we should do the intro videos +// gbIntroScreenMode = INTRO_BEGINING; +#ifdef JA2TESTVERSION + if( gfKeyState[ ALT ] ) + { + if( gfKeyState[ CTRL ] ) + { + gMercProfiles[ MIGUEL ].bMercStatus = MERC_IS_DEAD; + gMercProfiles[ SKYRIDER ].bMercStatus = MERC_IS_DEAD; + } + + SetIntroType( INTRO_ENDING ); + } + else +#endif + SetIntroType( INTRO_BEGINING ); + + ExitMPJScreen(); // cleanup please, if we called a fadeout then we didnt do it above + + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} + +void DoneFadeInForExitMPJScreen( void ) +{ + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} \ No newline at end of file diff --git a/MPJoinScreen.h b/MPJoinScreen.h new file mode 100644 index 00000000..b03b6c61 --- /dev/null +++ b/MPJoinScreen.h @@ -0,0 +1,12 @@ +#ifndef _MP_JOIN_SCREEN_H_ +#define _MP_JOIN_SCREEN_H_ + + +UINT32 MPJoinScreenInit( void ); +UINT32 MPJoinScreenHandle( void ); +UINT32 MPJoinScreenShutdown( void ); + + + + +#endif \ No newline at end of file diff --git a/MPScoreScreen.cpp b/MPScoreScreen.cpp new file mode 100644 index 00000000..77000922 --- /dev/null +++ b/MPScoreScreen.cpp @@ -0,0 +1,642 @@ +#ifdef PRECOMPILEDHEADERS + #include "JA2 All.h" + #include "Intro.h" +#else + #include "Types.h" + #include "MPScoreScreen.h" + #include "GameSettings.h" + #include "Utilities.h" + #include "wCheck.h" + #include "Font Control.h" + #include "WordWrap.h" + #include "Render Dirty.h" + #include "Input.h" + #include "Options Screen.h" + #include "English.h" + #include "Sysutil.h" + #include "Fade Screen.h" + #include "Cursor Control.h" + #include "Music Control.h" + #include "cursors.h" + #include "Intro.h" + #include "Text.h" + #include "Text Input.h" + #include "_Ja25EnglishText.h" + #include "Soldier Profile.h" +#endif + +#include "gameloop.h" +#include "Game Init.h" +#include "connect.h" +#include "network.h" // for client name +#include "saveloadscreen.h" + + +//////////////////////////////////////////// +// +// Global Defines +// +/////////////////////////////////////////// + +#define MPS_TITLE_FONT FONT14ARIAL//FONT16ARIAL +#define MPS_TITLE_COLOR FONT_MCOLOR_WHITE + +#define MPS_LABEL_TEXT_FONT FONT12ARIAL//FONT16ARIAL +#define MPS_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE + +//buttons +#define MPS_BTN_CONTINUE_X iScreenWidthOffset + 320 + 143 +#define MPS_BTN_CONTINUE_Y iScreenHeightOffset + 435 +//#define MPJ_BTN_HOST_X MPJ_BTN_JOIN_X-180 +//#define MPJ_BTN_HOST_Y iScreenHeightOffset + 435 +#define MPS_BTN_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) +#define MPS_BTN_CANCEL_Y MPS_BTN_CONTINUE_Y + +//main title +#define MPS_MAIN_TITLE_X 0 +#define MPS_MAIN_TITLE_Y iScreenHeightOffset + 10 +#define MPS_MAIN_TITLE_WIDTH SCREEN_WIDTH + +//labels +#define MPS_LABEL_PLAYER_X iScreenWidthOffset + 80 +#define MPS_LABEL_PLAYER_Y iScreenHeightOffset + 80 +#define MPS_LABEL_PLAYER_WIDTH 80 +#define MPS_LABEL_KILLS_X MPS_LABEL_PLAYER_X + MPS_LABEL_PLAYER_WIDTH + 20 +#define MPS_LABEL_KILLS_Y MPS_LABEL_PLAYER_Y +#define MPS_LABEL_KILLS_WIDTH 50 +#define MPS_LABEL_DEATHS_X MPS_LABEL_KILLS_X + MPS_LABEL_KILLS_WIDTH + 20 +#define MPS_LABEL_DEATHS_Y MPS_LABEL_PLAYER_Y +#define MPS_LABEL_DEATHS_WIDTH 50 +#define MPS_LABEL_HITS_X MPS_LABEL_DEATHS_X + MPS_LABEL_DEATHS_WIDTH + 20 +#define MPS_LABEL_HITS_Y MPS_LABEL_PLAYER_Y +#define MPS_LABEL_HITS_WIDTH 50 +#define MPS_LABEL_MISSES_X MPS_LABEL_HITS_X + MPS_LABEL_HITS_WIDTH + 20 +#define MPS_LABEL_MISSES_Y MPS_LABEL_PLAYER_Y +#define MPS_LABEL_MISSES_WIDTH 50 +#define MPS_LABEL_ACCURACY_X MPS_LABEL_MISSES_X + MPS_LABEL_MISSES_WIDTH + 20 +#define MPS_LABEL_ACCURACY_Y MPS_LABEL_PLAYER_Y +#define MPS_LABEL_ACCURACY_WIDTH 70 + + +#define MPS_PLAYERLIST_Y MPS_LABEL_PLAYER_Y + 30 +#define MPS_PLAYER_GAP 17 + + + +//////////////////////////////////////////// +// +// Global Variables +// +/////////////////////////////////////////// + +BOOLEAN gfMPSScreenEntry = TRUE; +BOOLEAN gfMPSScreenExit = FALSE; +BOOLEAN gfReRenderMPSScreen=TRUE; +BOOLEAN gfMPSButtonsAllocated = FALSE; + +//enum for different states of screen +enum +{ + MPS_NOTHING, + MPS_CANCEL, + MPS_CONTINUE, +}; + +UINT8 gubMPSScreenHandler=MPS_NOTHING; // State changer for HandleMPJScreen() + +UINT32 gubMPSExitScreen = MP_SCORE_SCREEN; // The screen that is in control next iteration of the game_loop + +UINT32 guiMPSMainBackGroundImage; + +//////////////////////////////////////////// +// +// Screen Controls +// +/////////////////////////////////////////// + +// Cancel Button +void BtnMPSCancelCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPSCancelButton; +INT32 giMPSCancelBtnImage; + +// Continue Button +void BtnMPSContinueCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiMPSContinueButton; +INT32 giMPSContinueBtnImage; + +// Message Box handle +INT8 giMPSMessageBox = -1; + + +//////////////////////////////////////////// +// +// Local Function Prototypes +// +/////////////////////////////////////////// + +extern void ClearMainMenu(); + +BOOLEAN EnterMPSScreen(); +BOOLEAN ExitMPSScreen(); +void HandleMPSScreen(); +BOOLEAN RenderMPSScreen(); + +void GetMPSScreenUserInput(); +void DoneFadeOutForExitMPSScreen( void ); +void DoneFadeInForExitMPSScreen( void ); + +UINT32 MPScoreScreenInit( void ) +{ + return (1); +} + +UINT32 MPScoreScreenHandle( void ) +{ + StartFrameBufferRender(); + + if( gfMPSScreenEntry ) + { +// PauseGame(); + + EnterMPSScreen(); + gfMPSScreenEntry = FALSE; + gfMPSScreenExit = FALSE; + InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + } + + GetMPSScreenUserInput(); + + + HandleMPSScreen(); + + // render buttons marked dirty + MarkButtonsDirty( ); + RenderButtons( ); + + // render text boxes + RenderAllTextFields(); // textbox system call + + // render help +// RenderFastHelp( ); +// RenderButtonsFastHelp( ); + + + ExecuteBaseDirtyRectQueue(); + EndFrameBufferRender(); + + // handle fades in and out + if ( HandleFadeOutCallback( ) ) + { + ClearMainMenu(); + return( gubMPSExitScreen ); + } + + if ( HandleBeginFadeOut( gubMPSExitScreen ) ) + { + return( gubMPSExitScreen ); + } + + if ( HandleFadeInCallback( ) ) + { + // Re-render the scene! + RenderMPSScreen(); + } + + if ( HandleBeginFadeIn( gubMPSExitScreen ) ) + { + + } + + if( gfMPSScreenExit ) // we are exiting this screen + { + ExitMPSScreen(); // perform destruction + } + + return( gubMPSExitScreen ); +} // end MPScoreScreenHandle() + +UINT32 MPScoreScreenShutdown( void ) +{ + return( 1 ); +} + +BOOLEAN EnterMPSScreen() +{ + VOBJECT_DESC VObjectDesc; + UINT16 cnt; + UINT16 usPosY; + + if( gfMPSButtonsAllocated ) + return( TRUE ); + + SetCurrentCursorFromDatabase( CURSOR_NORMAL ); + + // load the Main trade screen backgroiund image + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_800x600.sti", VObjectDesc.ImageFile); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\OptionsScreenBackGround_1024x768.sti", VObjectDesc.ImageFile); + } + + CHECKF(AddVideoObject(&VObjectDesc, &guiMPSMainBackGroundImage )); + + //Cancel button + giMPSCancelBtnImage = LoadButtonImage("INTERFACE\\PreferencesButtons.sti", -1,0,-1,2,-1 ); + guiMPSCancelButton = CreateIconAndTextButton( giMPSCancelBtnImage, gzMPSScreenText[MPS_CANCEL_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPS_BTN_CANCEL_X, MPS_BTN_CANCEL_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPSCancelCallback); + + SpecifyButtonSoundScheme( guiMPSCancelButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyDisabledButtonStyle( guiMPSCancelButton, DISABLED_STYLE_NONE ); + + //Continue button + giMPSContinueBtnImage = UseLoadedButtonImage( giMPSCancelBtnImage, -1,1,-1,3,-1 ); + guiMPSContinueButton = CreateIconAndTextButton( giMPSContinueBtnImage, gzMPSScreenText[MPS_CONTINUE_TEXT], OPT_BUTTON_FONT, + OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, + OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + MPS_BTN_CONTINUE_X, MPS_BTN_CONTINUE_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPSContinueCallback); + + SpecifyButtonSoundScheme( guiMPSContinueButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyDisabledButtonStyle( guiMPSContinueButton, DISABLED_STYLE_NONE ); + + //Reset the exit screen - screen the main game loop will call next iteration + gubMPSExitScreen = MP_SCORE_SCREEN; + + //REnder the screen once so we can blt ot to ths save buffer + RenderMPSScreen(); + + BlitBufferToBuffer(guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + + gfMPSButtonsAllocated = TRUE; + + return( TRUE ); + +} // End of EnterMPSScreen() + + +BOOLEAN ExitMPSScreen() +{ + UINT16 cnt; + + if( !gfMPSButtonsAllocated ) + return( TRUE ); + + //Delete the main options screen background + DeleteVideoObjectFromIndex( guiMPSMainBackGroundImage ); + + RemoveButton( guiMPSContinueButton ); + RemoveButton( guiMPSCancelButton ); + + + UnloadButtonImage( giMPSCancelBtnImage ); + UnloadButtonImage( giMPSContinueBtnImage ); + + // exit text input mode in this screen and clean up text boxes + //KillAllTextInputModes(); + SetTextInputCursor( CURSOR_IBEAM ); + + gfMPSButtonsAllocated = FALSE; + + //If we are starting the game stop playing the music + if( gubMPSScreenHandler == MPS_CONTINUE ) + SetMusicMode( MUSIC_NONE ); + + gfMPSScreenExit = FALSE; + gfMPSScreenEntry = TRUE; + + return( TRUE ); + +} // End of ExitMPJScreen() + + +void HandleMPSScreen() +{ + if( gubMPSScreenHandler != MPS_NOTHING ) + { + switch( gubMPSScreenHandler ) + { + case MPS_CANCEL: + gubMPSExitScreen = MAINMENU_SCREEN; + gfMPSScreenExit = TRUE; + break; + + /*case MPJ_HOST: + gubMPJExitScreen = MP_HOST_SCREEN; + gfMPJScreenExit = TRUE; + break;*/ + + + case MPS_CONTINUE: + { + //if we are already fading out, get out of here + if( gFadeOutDoneCallback != DoneFadeOutForExitMPSScreen ) + { + //Disable the ok button + DisableButton( guiMPSCancelButton ); + DisableButton( guiMPSContinueButton ); + + gFadeOutDoneCallback = DoneFadeOutForExitMPSScreen; + + FadeOutNextFrame( ); + } + break; + } + + } + + gubMPSScreenHandler = MPS_NOTHING; + } + + + if( gfReRenderMPSScreen ) + { + RenderMPSScreen(); + gfReRenderMPSScreen = FALSE; + } + + // add restore backgrounds in... + //RestoreGIOButtonBackGrounds(); +} // end of HandleMPJScreen + + +BOOLEAN RenderMPSScreen() +{ + HVOBJECT hPixHandle; + UINT16 usPosY; + + //Get the main background screen graphic and blt it + GetVideoObject(&hPixHandle, guiMPSMainBackGroundImage ); + BltVideoObject(FRAME_BUFFER, hPixHandle, 0,0,0, VO_BLT_SRCTRANSPARENCY,NULL); + + //Shade the background + ShadowVideoSurfaceRect( FRAME_BUFFER, iScreenWidthOffset, iScreenHeightOffset, iScreenWidthOffset + 640, iScreenHeightOffset + 480 ); + + //Display the title + DrawTextToScreen( gzMPSScreenText[ MPS_TITLE_TEXT ], MPS_MAIN_TITLE_X, MPS_MAIN_TITLE_Y, MPS_MAIN_TITLE_WIDTH, MPS_TITLE_FONT, MPS_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + // Player Column + DisplayWrappedString( MPS_LABEL_PLAYER_X, MPS_LABEL_PLAYER_Y, MPS_LABEL_PLAYER_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_PLAYER_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // Kills Column + DisplayWrappedString( MPS_LABEL_KILLS_X, MPS_LABEL_KILLS_Y, MPS_LABEL_KILLS_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_KILLS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // Deaths Column + DisplayWrappedString( MPS_LABEL_DEATHS_X, MPS_LABEL_DEATHS_Y, MPS_LABEL_DEATHS_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_DEATHS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // Hits Column + DisplayWrappedString( MPS_LABEL_HITS_X, MPS_LABEL_HITS_Y, MPS_LABEL_HITS_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_HITS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // Misses Column + DisplayWrappedString( MPS_LABEL_MISSES_X, MPS_LABEL_MISSES_Y, MPS_LABEL_MISSES_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_MISSES_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // Accuracy Column + DisplayWrappedString( MPS_LABEL_ACCURACY_X, MPS_LABEL_ACCURACY_Y, MPS_LABEL_ACCURACY_WIDTH, 2, MPS_TITLE_FONT, MPS_TITLE_COLOR, gzMPSScreenText[ MPS_ACCURACY_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw players + wchar_t szPlayerName[30]; + wchar_t szPlayerKills[3]; + wchar_t szPlayerDeaths[3]; + wchar_t szPlayerHits[3]; + wchar_t szPlayerMisses[3]; + wchar_t szPlayerAccuracy[8]; + float flAccuracy = 0; + for(int i=0; i < 4; i++) + { + if (client_names[i] != NULL) + { + if (strcmp(client_names[i],"")!=0) + { + // valid player + usPosY = MPS_PLAYERLIST_Y + (i * MPS_PLAYER_GAP); + + // Draw Player Name Column + memset(szPlayerName,0,30*sizeof(wchar_t)); + mbstowcs( szPlayerName,client_names[i],30); + + DisplayWrappedString( MPS_LABEL_PLAYER_X, usPosY, MPS_LABEL_PLAYER_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerName, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Kills Column + memset(szPlayerKills,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[i].kills,szPlayerKills,10); + DisplayWrappedString( MPS_LABEL_KILLS_X, usPosY, MPS_LABEL_KILLS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerKills, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Deaths Column + memset(szPlayerDeaths,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[i].deaths,szPlayerDeaths,10); + DisplayWrappedString( MPS_LABEL_DEATHS_X, usPosY, MPS_LABEL_DEATHS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerDeaths, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Hits Column + memset(szPlayerHits,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[i].hits,szPlayerHits,10); + DisplayWrappedString( MPS_LABEL_HITS_X, usPosY, MPS_LABEL_HITS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerHits, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Misses Column + memset(szPlayerMisses,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[i].misses,szPlayerMisses,10); + DisplayWrappedString( MPS_LABEL_MISSES_X, usPosY, MPS_LABEL_MISSES_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerMisses, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Accuracy Column + if ( gMPPlayerStats[i].misses + gMPPlayerStats[i].hits > 0 ) + flAccuracy = ((float)gMPPlayerStats[i].hits / (float)(gMPPlayerStats[i].misses + gMPPlayerStats[i].hits)) * 100.0f; + else + flAccuracy = 0; + memset(szPlayerAccuracy,0,8*sizeof(wchar_t)); + swprintf(szPlayerAccuracy,L"%i%%%%%%%%",(int)flAccuracy); // this thing goes through like three printfs before being rendered.... + DisplayWrappedString( MPS_LABEL_ACCURACY_X, usPosY, MPS_LABEL_ACCURACY_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerAccuracy, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + } + + } + } + + if (PLAYER_BSIDE==MP_TYPE_COOP) + { + // CO-OP Mode, show stats for queens army + usPosY = MPS_PLAYERLIST_Y + (5 * MPS_PLAYER_GAP); // leave a space between players and AI + + // Draw AI Team Name + DisplayWrappedString( MPS_LABEL_PLAYER_X, usPosY, MPS_LABEL_PLAYER_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, gzMPSScreenText[MPS_AITEAM_TEXT], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Kills Column + memset(szPlayerKills,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[4].kills,szPlayerKills,10); + DisplayWrappedString( MPS_LABEL_KILLS_X, usPosY, MPS_LABEL_KILLS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerKills, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Deaths Column + memset(szPlayerDeaths,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[4].deaths,szPlayerDeaths,10); + DisplayWrappedString( MPS_LABEL_DEATHS_X, usPosY, MPS_LABEL_DEATHS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerDeaths, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Hits Column + memset(szPlayerHits,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[4].hits,szPlayerHits,10); + DisplayWrappedString( MPS_LABEL_HITS_X, usPosY, MPS_LABEL_HITS_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerHits, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Misses Column + memset(szPlayerMisses,0,3*sizeof(wchar_t)); + _itow(gMPPlayerStats[4].misses,szPlayerMisses,10); + DisplayWrappedString( MPS_LABEL_MISSES_X, usPosY, MPS_LABEL_MISSES_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerMisses, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Draw Accuracy Column + if ( gMPPlayerStats[4].misses + gMPPlayerStats[4].hits > 0 ) + flAccuracy = ((float)gMPPlayerStats[4].hits / (float)(gMPPlayerStats[4].misses + gMPPlayerStats[4].hits)) * 100.0f; + else + flAccuracy = 0; + memset(szPlayerAccuracy,0,8*sizeof(wchar_t)); + swprintf(szPlayerAccuracy,L"%i%%%%%%%%",(int)flAccuracy); + DisplayWrappedString( MPS_LABEL_ACCURACY_X, usPosY, MPS_LABEL_ACCURACY_WIDTH, 2, MPS_LABEL_TEXT_FONT, MPS_LABEL_TEXT_COLOR, szPlayerAccuracy, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + } + +/* + // Player name text label + DisplayWrappedString( MPJ_LABEL_HANDLE_X, MPJ_LABEL_HANDLE_Y, MPJ_LABEL_HANDLE_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_HANDLE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Server IP text label + DisplayWrappedString( MPJ_LABEL_IP_X, MPJ_LABEL_IP_Y, MPJ_LABEL_IP_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERIP_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Server Port text label + DisplayWrappedString( MPJ_LABEL_PORT_X, MPJ_LABEL_PORT_Y, MPJ_LABEL_PORT_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERPORT_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); +*/ + return( TRUE ); +} // end of RenderMPSScreen() + + + +void GetMPSScreenUserInput() +{ + InputAtom Event; +// POINT MousePos; + +// GetCursorPos(&MousePos); + + while( DequeueEvent( &Event ) ) + { + // check if this event is swallowed by text input, otherwise process key + if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN ) + { + switch( Event.usParam ) + { + + case ESC: + //Exit out of the screen + gubMPSScreenHandler = MPS_CANCEL; + break; + + case ENTER: + /*if (ValidateJoinSettings(false)) + { + SaveJoinSettings(); + gubMPSScreenHandler = MPS_JOIN; + }*/ + gubMPSScreenHandler = MPS_CONTINUE; + break; + } + } + } +} // end of GetMPSScreenUserInput() + +void DoneFadeOutForExitMPSScreen( void ) +{ + // As we bypassed the GIO screen, set up some game options for multiplayer here + // most things i have left as thier defaults here for testing. + is_networked = true; + + ReStartingGame(); + + if (is_client) + { + client_disconnect(); + } + + if(is_server) + { + server_disconnect(); + } + + //NetworkAutoStart will handle reconnection in Map Screen + // reset client auto_retry for NetworkAutoStart called in MapScreenHandle + auto_retry = true; + giNumTries = 5; + + if (is_networked) + gGameOptions.fTurnTimeLimit = TRUE; + else + gGameOptions.fTurnTimeLimit = FALSE; + + // Bobby Rays - why would we want anything less than the best + gGameOptions.ubBobbyRay = BR_AWESOME; + + + gubMPSExitScreen = INTRO_SCREEN; + + //set the fact that we should do the intro videos +// gbIntroScreenMode = INTRO_BEGINING; +#ifdef JA2TESTVERSION + if( gfKeyState[ ALT ] ) + { + if( gfKeyState[ CTRL ] ) + { + gMercProfiles[ MIGUEL ].bMercStatus = MERC_IS_DEAD; + gMercProfiles[ SKYRIDER ].bMercStatus = MERC_IS_DEAD; + } + + SetIntroType( INTRO_ENDING ); + } + else +#endif + SetIntroType( INTRO_BEGINING ); + + ExitMPSScreen(); // cleanup please, if we called a fadeout then we didnt do it above + + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} + +void DoneFadeInForExitMPSScreen( void ) +{ + SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); +} + +void BtnMPSCancelCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + gubMPSScreenHandler = MPS_CANCEL; + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + +} + +void BtnMPSContinueCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + gubMPSScreenHandler = MPS_CONTINUE; + + + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} \ No newline at end of file diff --git a/MPScoreScreen.h b/MPScoreScreen.h new file mode 100644 index 00000000..70043248 --- /dev/null +++ b/MPScoreScreen.h @@ -0,0 +1,12 @@ +#ifndef _MP_SCORE_SCREEN_H_ +#define _MP_SCORE_SCREEN_H_ + + +UINT32 MPScoreScreenInit( void ); +UINT32 MPScoreScreenHandle( void ); +UINT32 MPScoreScreenShutdown( void ); + + + + +#endif \ No newline at end of file diff --git a/MainMenuScreen.cpp b/MainMenuScreen.cpp index 32cc0686..391475c5 100644 --- a/MainMenuScreen.cpp +++ b/MainMenuScreen.cpp @@ -388,6 +388,7 @@ void ExitMainMenu( ) void InitDependingGameStyleOptions(BOOLEAN isNetworked) { // Load the ja2_options.ini + FreeGameExternalOptions(); LoadGameExternalOptions(); ReStartingGame(); @@ -449,7 +450,8 @@ void MenuButtonCallback(GUI_BUTTON *btn,INT32 reason) //if something didnt work, dont even know how to make error code...//hayden } - SetMainMenuExitScreen( GAME_INIT_OPTIONS_SCREEN ); + SetMainMenuExitScreen( MP_JOIN_SCREEN ); // OJW - 20081129 + //SetMainMenuExitScreen( GAME_INIT_OPTIONS_SCREEN ); } else if( gbHandledMainMenu == LOAD_GAME ) { diff --git a/MessageBoxScreen.cpp b/MessageBoxScreen.cpp index c60a3c26..93c84ff7 100644 --- a/MessageBoxScreen.cpp +++ b/MessageBoxScreen.cpp @@ -23,6 +23,7 @@ #include "cursor control.h" #include "laptop.h" #include "text.h" + #include "Text Input.h" #include "overhead map.h" #endif @@ -49,6 +50,8 @@ BOOLEAN gfInMsgBox = FALSE; extern BOOLEAN fInMapMode; extern BOOLEAN gfOverheadMapDirty; +//OJW - 20090208 +CHAR16 gszMsgBoxInputString[255]; void OKMsgBoxCallback(GUI_BUTTON *btn, INT32 reason ); void YESMsgBoxCallback(GUI_BUTTON *btn, INT32 reason ); @@ -350,6 +353,51 @@ INT32 DoMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UIN ForceButtonUnDirty( gMsgBox.uiButton[1] ); ForceButtonUnDirty( gMsgBox.uiButton[0] ); + } + else if (usFlags & MSG_BOX_FLAG_INPUTBOX) + { + // Initialise Text Boxes + InitTextInputMode(); // API call to initialise text input mode for this screen + // does not mean we are inputting text right away + + // Player Name field + SetTextInputCursor( CUROSR_IBEAM_WHITE ); + SetTextInputFont( (UINT16) FONT12ARIALFIXEDWIDTH ); //FONT12ARIAL //FONT12ARIALFIXEDWIDTH + Set16BPPTextFieldColor( Get16BPPColor(FROMRGB( 0, 0, 0) ) ); + SetBevelColors( Get16BPPColor(FROMRGB(136, 138, 135)), Get16BPPColor(FROMRGB(24, 61, 81)) ); + SetTextInputRegularColors( FONT_WHITE, 2 ); + SetTextInputHilitedColors( 2, FONT_WHITE, FONT_WHITE ); + SetCursorColor( Get16BPPColor(FROMRGB(255, 255, 255) ) ); + + int ibx = gMsgBox.sX + 10; + int iby = gMsgBox.sY +(usTextBoxHeight - 20 - 10); + //Add Player Name textbox + AddTextInputField( ibx, + iby, + usTextBoxWidth - 20, + 20, + MSYS_PRIORITY_HIGH+2, + gszMsgBoxInputString, + 255, + INPUTTYPE_ASCII );//23 + + // exit text input mode in this screen and clean up text boxes + SetActiveField( 0 ); + + // initialise the chat toggle boxes + /*int usPosY = gMsgBox.sY + (usTextBoxHeight - 45); + int usPosX = gMsgBox.sX + (usTextBoxWidth / 3); + + guiChatToggles[ 0 ] = CreateCheckBoxButton( usPosX, usPosY, + "INTERFACE\\OptionsCheckBoxes_12x12.sti", MSYS_PRIORITY_HIGH+10, + BtnChatTogglesCallback ); + MSYS_SetBtnUserData( guiOptionsToggles[ 0 ], 0, 0 ); + + guiChatToggles[ 1 ] = CreateCheckBoxButton( usPosX, usPosY, + "INTERFACE\\OptionsCheckBoxes_12x12.sti", MSYS_PRIORITY_HIGH+10, + BtnChatTogglesCallback ); + MSYS_SetBtnUserData( guiOptionsToggles[ 1 ], 0, 1 );*/ + } else { @@ -810,6 +858,12 @@ UINT32 ExitMsgBox( INT8 ubExitCode ) RemoveButton( gMsgBox.uiButton[2] ); RemoveButton( gMsgBox.uiButton[3] ); } + // OJW - 20090208 - Add text input box type + else if (gMsgBox.usFlags & MSG_BOX_FLAG_INPUTBOX) + { + // exit text input mode in this screen and clean up text boxes + KillAllTextInputModes(); + } else { if ( gMsgBox.usFlags & MSG_BOX_FLAG_OK ) @@ -1102,21 +1156,33 @@ UINT32 MessageBoxScreenHandle( ) // Render buttons RenderButtons( ); + if (gMsgBox.usFlags & MSG_BOX_FLAG_INPUTBOX) + { + // render text boxes + RenderAllTextFields(); // textbox system call + } EndFrameBufferRender( ); // carter, need key shortcuts for clearing up message boxes // Check for esc while (DequeueEvent(&InputEvent) == TRUE) { - if( InputEvent.usEvent == KEY_UP ) + if( !HandleTextInput( &InputEvent ) && InputEvent.usEvent == KEY_DOWN ) { if( ( InputEvent.usParam == ESC ) || ( InputEvent.usParam == 'n') ) { - if ( gMsgBox.usFlags & MSG_BOX_FLAG_YESNO ) - { - // Exit messagebox - gMsgBox.bHandled = MSG_BOX_RETURN_NO; - } + if ( gMsgBox.usFlags & MSG_BOX_FLAG_YESNO ) + { + // Exit messagebox + gMsgBox.bHandled = MSG_BOX_RETURN_NO; + } + //OJW - 20090208 - Input Box + else if( gMsgBox.usFlags & MSG_BOX_FLAG_INPUTBOX ) + { + // Exit messagebox + gMsgBox.bHandled = MSG_BOX_RETURN_NO; + memset(gszMsgBoxInputString,0,sizeof(CHAR16)*255); + } } if( InputEvent.usParam == ENTER ) @@ -1136,6 +1202,14 @@ UINT32 MessageBoxScreenHandle( ) // Exit messagebox gMsgBox.bHandled = MSG_BOX_RETURN_OK; } + //OJW - 20090208 - Input Box + else if( gMsgBox.usFlags & MSG_BOX_FLAG_INPUTBOX ) + { + // retrieve the string from the text box + Get16BitStringFromField( 0, gszMsgBoxInputString ); // these indexes are based on the order created + // Exit messagebox + gMsgBox.bHandled = MSG_BOX_RETURN_OK; + } } if( InputEvent.usParam == 'o' ) { diff --git a/MessageBoxScreen.h b/MessageBoxScreen.h index 66730059..cb7109af 100644 --- a/MessageBoxScreen.h +++ b/MessageBoxScreen.h @@ -16,6 +16,8 @@ #define MSG_BOX_FLAG_OKSKIP 0x0200 // Displays ok or skip (meanwhile) buttons #define MSG_BOX_FLAG_GENERICCONTRACT 0x0400 // displays contract buttoin + 2 user-defined text buttons #define MSG_BOX_FLAG_GENERIC 0x0800 // 2 user-defined text buttons +// OJW - Adding text chatbox +#define MSG_BOX_FLAG_INPUTBOX 0x1000 // has a text input field // message box return codes #define MSG_BOX_RETURN_OK 1 // ENTER or on OK button @@ -83,6 +85,8 @@ extern BOOLEAN fRestoreBackgroundForMessageBox; //this variable can be unset if ur in a non gamescreen and DONT want the msg box to use the save buffer extern BOOLEAN gfDontOverRideSaveBuffer; +//OJW - 20090208 +extern CHAR16 gszMsgBoxInputString[255]; //////////////////////////////// // ubStyle: Determines the look of graphics including buttons // zString: 16-bit string diff --git a/Multiplayer/client.cpp b/Multiplayer/client.cpp index dd4e0ac7..28ecf3e2 100644 --- a/Multiplayer/client.cpp +++ b/Multiplayer/client.cpp @@ -66,6 +66,9 @@ #include "BobbyRMailOrder.h" #include "Finances.h" #include "TeamTurns.h" + #include "gameloop.h" + #include "Options Screen.h" +#include "MPChatScreen.h" #endif #include "MessageIdentifiers.h" @@ -92,7 +95,7 @@ unsigned char GetPacketIdentifier(Packet *p); unsigned char packetIdentifier; -#include "messagebox.h" +#include "MessageBoxScreen.h" #pragma pack(1) @@ -116,6 +119,7 @@ unsigned char packetIdentifier; #include "interface panels.h" #include "game init.h" +#include "Debug Control.h" extern INT8 SquadMovementGroups[ ]; RakPeerInterface *client; @@ -182,7 +186,6 @@ typedef struct UINT8 client_num; bool status; UINT8 ready_stage; - } ready_struct; typedef struct @@ -197,9 +200,24 @@ typedef struct UINT8 ubResult; }kickR; +typedef struct +{ + UINT8 client_num; + BOOLEAN bToAll; + CHAR16 msg[300]; +} chat_msg; + bullets_table bTable[11][50]; char client_names[4][30]; +// OJW - 20081204 +int client_ready[4]; +int client_edges[4]; +int client_teams[4]; +int random_mercs[7]; + +// OJW - 20081222 +player_stats gMPPlayerStats[5]; INT32 MAX_MERCS; @@ -219,6 +237,11 @@ UINT8 ubID_prefix; bool is_server=false; bool is_networked=false; + bool is_host=false; // OJW - added 20081130 - new flag to signal our intention to host, coming in from the HOST screen + bool auto_retry=true; + int giNumTries = 5; // default is 5 retries + UINT32 giNextRetryTime = 0; + bool requested=false; int tcount; @@ -236,6 +259,10 @@ bool DISABLE_MORALE; char SECT_EDGE[30]; char ckbag[100]; char CLIENT_NAME[30]; + // OJW - 20081204 + char SERVER_NAME[30]; + int RANDOM_SPAWN; + int RANDOM_MERCS; char SERVER_IP[30] ; char SERVER_PORT[30]; @@ -279,6 +306,95 @@ INT16 crate_sGridX, crate_sGridY; void overide_callback( UINT8 ubResult ); void kick_callback( UINT8 ubResult ); void turn_callback (UINT8 ubResult); +void ChatCallback (UINT8 ubResult); + +// OJW - 20081222 +void send_gameover( void ); +void StartScoreScreen(); // this screen will send us to the multiplayer score screen +bool is_game_over = false; +UINT32 iScoreScreenTime = 0; +int iTeamsWiped = 0; // counts how many teams have wiped + +//OJW - 20090210 +int iDisconnectedScreen = 0; + +//OJW - 20090302 +int bClosingChatBoxToStartGame = false; +UINT32 iCCStartGameTime = 0; + +// OJW - 20090317 +bool is_game_started = false; + + +// OJW - added 20081130 +// - add retry timer and notification +void NetworkAutoStart() +{ + if (!is_networked) + return; // not networked, bad call + + if (!is_host || is_server) + { + // is pure client or the server has been started + // so do client connection checking...though probably not needed for the server client. cant hurt. + + // user JOIN'd game + if (is_client && is_connected) + { + return; // should be set up and running + } + else if (is_connecting) + { + return; // we're waiting on a connection , do nothing + } + else + { + if (giNumTries <= 0 || !auto_retry) + return; // dont auto-retry + + if (guiBaseJA2NoPauseClock < giNextRetryTime) + return; // we are waiting for a retry timer + + // try and connect + giNumTries--; + connect_client(); + + // next rety time is set in client_packet() + } + } + else + { + // is host and server isnt started so start it + start_server(); + } +} + +void HireRandomMercs() +{ + MERC_HIRE_STRUCT HireMercStruct; + for (int i=0; i < MAX_MERCS; i++) + { + memset(&HireMercStruct, 0, sizeof(MERC_HIRE_STRUCT)); + + HireMercStruct.ubProfileID = random_mercs[i];// use the merc list recieved from the server + + //DEF: temp + HireMercStruct.sSectorX = gsMercArriveSectorX; + HireMercStruct.sSectorY = gsMercArriveSectorY; + HireMercStruct.fUseLandingZoneForArrival = TRUE; + HireMercStruct.ubInsertionCode = INSERTION_CODE_ARRIVING_GAME; + HireMercStruct.iTotalContractLength = 1; + HireMercStruct.fCopyProfileItemsOver = true; + + gMercProfiles[ HireMercStruct.ubProfileID ].ubMiscFlags |= PROFILE_MISC_FLAG_ALREADY_USED_ITEMS; + + HireMerc(&HireMercStruct); + } + + fDrawCharacterList = true; + fTeamPanelDirty = true; + ReBuildCharactersList(); +} //***************** @@ -781,10 +897,11 @@ void send_EndTurn( UINT8 ubNextTeam ) { //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"sendEndTurn" ); - if(ubNextTeam==0) - { - ubNextTeam=netbTeam; - } + if(ubNextTeam==0) + { + // translate next team id for clients + ubNextTeam=netbTeam; + } turn_struct tStruct; @@ -802,22 +919,23 @@ void send_EndTurn( UINT8 ubNextTeam ) void recieveEndTurn(RPCParameters *rpcParameters) { - turn_struct* tStruct = (turn_struct*)rpcParameters->input; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveEndTurn" ); - UINT8 sender_bTeam; - UINT8 ubTeam; - sender_bTeam=tStruct->tsnetbTeam; - ubTeam=tStruct->tsubNextTeam; - if(is_server)Sawarded=false; + turn_struct* tStruct = (turn_struct*)rpcParameters->input; + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveEndTurn" ); + UINT8 sender_bTeam; + UINT8 ubTeam; + sender_bTeam=tStruct->tsnetbTeam; + ubTeam=tStruct->tsubNextTeam; + if(is_server)Sawarded=false; + // if the message was recieved from the server.. if(is_server || sender_bTeam==6) { + // if not the server and we're not in combat... if (!is_server && !(gTacticalStatus.uiFlags & INCOMBAT)) { EnterCombatMode(0); } - if(ubTeam==netbTeam)ubTeam=0; { if(!is_server && is_client) @@ -988,6 +1106,9 @@ void send_ready ( void ) status=1; numready = numready+1; ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[7],numready,MAX_CLIENTS ); + // OJW - 20081204 + client_ready[info.client_num-1]=1; + fDrawCharacterList = true; // set the character list to be redrawn } else { @@ -995,6 +1116,9 @@ void send_ready ( void ) status=0; numready = numready-1; ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[8],numready,MAX_CLIENTS ); + // OJW - 20081204 + client_ready[info.client_num-1]=0; + fDrawCharacterList = true; // set the character list to be redrawn } } @@ -1044,13 +1168,17 @@ void recieveREADY (RPCParameters *rpcParameters) { numready = numready+1; ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[10], info->client_num,client_names[info->client_num-1],numready,MAX_CLIENTS ); - + // OJW - 20081204 + client_ready[info->client_num-1]=1; + fDrawCharacterList = true; // set the character list to be redrawn } else { numready = numready-1; ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[11], info->client_num,client_names[info->client_num-1],numready,MAX_CLIENTS ); - + // OJW - 20081204 + client_ready[info->client_num-1]=0; + fDrawCharacterList = true; // set the character list to be redrawn } if(is_server && numready == MAX_CLIENTS) //all ready. and server tells all to load...and loads himself @@ -1066,6 +1194,18 @@ void recieveREADY (RPCParameters *rpcParameters) { ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[36] ); allowlaptop=1; + if (RANDOM_MERCS) + HireRandomMercs(); + + // server is starting the game, adjust the games max players + // this will allow the game to be started, rather than saying 2/4 players are connected + // where there are only two players connected + int iPlayersConnected = 0; + for (int i=0; i< 4; i++) + if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) + iPlayersConnected++; + + MAX_CLIENTS = iPlayersConnected; } } @@ -1217,78 +1357,131 @@ void allowlaptop_callback ( UINT8 ubResult ) info.ready_stage=36; info.status=1; + if (RANDOM_MERCS) + HireRandomMercs(); + + // server client is starting the game, adjust the games max players + // this will allow the game to be started, rather than saying 2/4 players are connected + // where there are only two players connected + int iPlayersConnected = 0; + for (int i=0; i< 4; i++) + if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) + iPlayersConnected++; + + MAX_CLIENTS = iPlayersConnected; + client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } } +void StartBattleChatBoxClosedCallback(void) +{ + // The chat box has been closed, now we can start + SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); + is_game_started = true; +} + + void start_battle ( void ) { -if(!is_client) -{ -ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[14] ); -} -else if(!allowlaptop && is_server) -{ - SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; - DoMessageBox( MSG_BOX_BASIC_STYLE, MPClientMessage[35], guiCurrentScreen, MSG_BOX_FLAG_YESNO | MSG_BOX_FLAG_USE_CENTERING_RECT, allowlaptop_callback, &CenterRect ); - -} -else if(allowlaptop) -{ - - if ( NumberOfMercsOnPlayerTeam() ==0) + if(!is_client) { - ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[15] ); + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[14] ); } - else if(goahead==1) - { - goahead=0; - status=0;//reset - numready=0; - SOLDIERTYPE *pSoldier = MercPtrs[ 0 ]; - UINT8 ubGroupID = pSoldier->ubGroupID; + else if(!allowlaptop && is_server) + { + // check that another player is actually connected + int iPlayersConnected = 0; + for (int i=0; i< 4; i++) + if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) + iPlayersConnected++; - GROUP *pGroup; - pGroup = GetGroup( ubGroupID ); - gpBattleGroup = pGroup; - gubPBSectorX = gpBattleGroup->ubSectorX; - gubPBSectorY = gpBattleGroup->ubSectorY; - gubPBSectorZ = gpBattleGroup->ubSectorZ; - - gfEnterTacticalPlacementGUI = 1; - - UINT32 i; - for(i=0; i<4;i++) - { - CHAR16 name[255]; - int nm = mbstowcs( name, client_names[i], sizeof (char)*30 ); - //copy in client specified name for the player turn bar :) - if(nm) + if (iPlayersConnected > 1) { - CHAR16 string[255]; - memcpy(string,TeamTurnString[ (i+6) ], sizeof( CHAR16) * 255 ); + SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; + DoMessageBox( MSG_BOX_BASIC_STYLE, MPClientMessage[35], guiCurrentScreen, MSG_BOX_FLAG_YESNO | MSG_BOX_FLAG_USE_CENTERING_RECT, allowlaptop_callback, &CenterRect ); + } + else + { + // notify the server that at least one other player must be connected + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[51] ); + } + + } + else if(allowlaptop) + { + if ( NumberOfMercsOnPlayerTeam() ==0) + { + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[15] ); + } + else if(goahead==1) + { + goahead=0; // this ensures that we dont reload the sector again the next time this function is called - CHAR16 full[255]; - swprintf(full, L"%s - '%s'",string,name); + if (is_game_started) + return; // 20090317 - OJW - there is a bug or out of sync condition that rarely somestimes causes a client to reach here + // twice, and reload the sector, which causes an assertion failure on line 1782 of strategicmap.cpp in SetCurrentWorldSector() + // therefore i'm adding this to make sure if they client loaded the map once, it wont do it again + + status=0;//reset + numready=0; + SOLDIERTYPE *pSoldier = MercPtrs[ 0 ]; + UINT8 ubGroupID = pSoldier->ubGroupID; - memcpy( TeamTurnString[ (i+6) ] , full, sizeof( CHAR16) * 255 ); + GROUP *pGroup; + pGroup = GetGroup( ubGroupID ); + gpBattleGroup = pGroup; + gubPBSectorX = gpBattleGroup->ubSectorX; + gubPBSectorY = gpBattleGroup->ubSectorY; + gubPBSectorZ = gpBattleGroup->ubSectorZ; + + gfEnterTacticalPlacementGUI = 1; + // OJW - 20090205 + iTeamsWiped = 0; // reset the number of wiped teams to Zero + + UINT32 i; + for(i=0; i<4;i++) + { + CHAR16 name[255]; + int nm = mbstowcs( name, client_names[i], sizeof (char)*30 ); + //copy in client specified name for the player turn bar :) + if(nm) + { + // OJW - 20090318 - fixed name copying bug with multiple games + CHAR16 full[255]; + swprintf(full, MPClientMessage[57],i+1,name); + + memcpy( TeamTurnString[ (i+6) ] , full, sizeof( CHAR16) * 255 ); + } + } + + // this closes the chat window if its open and the game is starting + // if this is open then the client will crash when the screen returns + if (guiCurrentScreen == MP_CHAT_SCREEN) + { + gChatBox.bHandled = MSG_BOX_RETURN_NO; + bClosingChatBoxToStartGame = true; + iCCStartGameTime = guiBaseJA2NoPauseClock+1000; + } + else + { + SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); + is_game_started = true; + } + + } + else + { + send_ready(); } } - - SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); - } - else + else if(!allowlaptop && is_client && !is_server) { - send_ready(); + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[16] ); } -} -else if(!allowlaptop && is_client && !is_server) -{ - ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[16] ); -} } @@ -1797,15 +1990,22 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve settings_struct* cl_lan = (settings_struct*)rpcParameters->input; - char szDefault[30]; - sprintf(szDefault, "%s",cl_lan->client_name); + char szDefault[30]; + sprintf(szDefault, "%s",cl_lan->client_name); - if(!recieved_settings) + // OJW - 20081204 + // get complete client data from the server + memcpy( client_edges, cl_lan->client_edges , sizeof(int) * 4); + memcpy( client_teams, cl_lan->client_teams , sizeof(int) * 4); + + if(!recieved_settings && strcmp(cl_lan->client_name, CLIENT_NAME)==0) { + // This settings packet contains information and settings specifically for us recieved_settings=1; CLIENT_NUM=cl_lan->client_num;//assign client number from server + netbTeam = (CLIENT_NUM)+5; ubID_prefix = gTacticalStatus.Team[ netbTeam ].bFirstID;//over here now @@ -1813,7 +2013,23 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve strcpy(client_names[cl_lan->client_num-1],szDefault); - + // OJW - 20081204 + strcpy(SERVER_NAME,cl_lan->server_name); + RANDOM_MERCS = cl_lan->RANDOM_MERCS; + RANDOM_SPAWN = cl_lan->RANDOM_SPAWN; + + if (RANDOM_SPAWN) + { + // store sector edge + _itoa(cl_lan->cl_edge,SECT_EDGE,10); + } + + if(RANDOM_MERCS) + { + // copy the random merc list locally + memcpy(random_mercs,cl_lan->random_mercs,sizeof(int) * 7); + } + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[2] ); @@ -1957,8 +2173,14 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve // WANNE - MP: We also have to reinitialize the merc profiles because // they depend on the inventory! LoadMercProfiles(); - - ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,cl_lan->cl_edge,cl_lan->team ); + + if (!RANDOM_SPAWN) + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,cl_lan->cl_edge,cl_lan->team ); + else + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,L"?",cl_lan->team ); + + fDrawCharacterList = true; // set the character list to be redrawn + // if(PLAYER_BSIDE==0)ScreenMsg(FONT_LTGREEN,MSG_CHAT,MPClientMessage[27],cl_lan->cl_ops[0],cl_lan->cl_ops[1],cl_lan->cl_ops[2],cl_lan->cl_ops[3]); //ScreenMsg(FONT_LTGREEN,MSG_CHAT,MPClientMessage[27],cl_lan->team); @@ -1967,9 +2189,13 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve } else { + fDrawCharacterList = true; // set the character list to be redrawn - - ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,cl_lan->cl_edge,cl_lan->team ); + if (!RANDOM_SPAWN) + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,cl_lan->cl_edge,cl_lan->team ); + else + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[26],cl_lan->client_num,szDefault,L"?",cl_lan->team ); + // ScreenMsg(FONT_LTGREEN,MSG_CHAT,MPClientMessage[27],cl_lan->team); strcpy(client_names[cl_lan->client_num-1],szDefault); @@ -1977,6 +2203,80 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve } +void recieveTEAMCHANGE( RPCParameters *rpcParameters ) +{ + teamchange_struct* cl_lan = (teamchange_struct*)rpcParameters->input; + + if (!can_teamchange()) + { + // error + ScreenMsg( FONT_YELLOW, MSG_CHAT, L"An error occured in recieveTEAMCHANGE that should not occur"); + } + else + { + // redraw the character list on the map screen + fTeamPanelDirty = true; + fDrawCharacterList = true; + client_teams[cl_lan->client_num-1] = cl_lan->newteam; + if (cl_lan->client_num == CLIENT_NUM) + { + TEAM = cl_lan->newteam; + } + } +} + +void recieveEDGECHANGE( RPCParameters *rpcParameters ) +{ + edgechange_struct* cl_lan = (edgechange_struct*)rpcParameters->input; + + if (!can_edgechange()) + { + // error + ScreenMsg( FONT_YELLOW, MSG_CHAT, L"An error occured in recieveEDGECHANGE that should not occur"); + } + else + { + // redraw the character list on the map screen + fTeamPanelDirty = true; + fDrawCharacterList = true; + client_edges[cl_lan->client_num-1] = cl_lan->newedge; + if (cl_lan->client_num == CLIENT_NUM) + { + // store the setting locally + _itoa(cl_lan->newedge,SECT_EDGE,10); + } + } +} + + +void recieveMAPCHANGE( RPCParameters *rpcParameters ) +{ + mapchange_struct* cl_lan = (mapchange_struct*)rpcParameters->input; + + if (!is_client || allowlaptop) + { + // error + ScreenMsg( FONT_YELLOW, MSG_CHAT, L"An error occured in recieveMAPCHANGE that should not occur"); + } + else + { + // copy new map settings locally + gsMercArriveSectorX=cl_lan->gsMercArriveSectorX; + gsMercArriveSectorY=cl_lan->gsMercArriveSectorY; + + + ChangeSelectedMapSector( gsMercArriveSectorX, gsMercArriveSectorY, 0 ); + + gGameExternalOptions.iGameStartingTime= NUM_SEC_IN_DAY + int(cl_lan->TIME*3600); + + CHAR16 str[128]; + GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, str, TRUE ); + + // notify clients of map change in console + ScreenMsg( FONT_YELLOW, MSG_CHAT, MPClientMessage[46],str); + } +} + void send_bullet( BULLET * pBullet,UINT16 usHandItem ) { @@ -2095,34 +2395,101 @@ void send_death( SOLDIERTYPE *pSoldier ) death_struct nDeath; nDeath.soldier_id=pSoldier->ubID; nDeath.attacker_id=pSoldier->ubAttackerID; - if(pSoldier->ubAttackerID==NULL)nDeath.attacker_id=pSoldier->ubPreviousAttackerID; - if(pSoldier->ubID<20)nDeath.soldier_id=nDeath.soldier_id+ubID_prefix; - - client->RPC("sendDEATH",(const char*)&nDeath, (int)sizeof(death_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - + + // Translate soldier id for other clients if the soldier was one of ours + if(pSoldier->ubID<20)nDeath.soldier_id=nDeath.soldier_id+ubID_prefix; + + + // if soldier died from bleeding + if(pSoldier->ubAttackerID==NULL || pSoldier->ubAttackerID == NOBODY) + { + if (pSoldier->ubPreviousAttackerID != NOBODY && pSoldier->ubPreviousAttackerID != NULL) + nDeath.attacker_id = pSoldier->ubPreviousAttackerID; + else if (pSoldier->ubNextToPreviousAttackerID != NOBODY && pSoldier->ubNextToPreviousAttackerID != NULL) + nDeath.attacker_id = pSoldier->ubNextToPreviousAttackerID; + } + SOLDIERTYPE * pAttacker=MercPtrs[ nDeath.attacker_id ]; INT8 pA_bTeam; CHAR16 pA_name[ 10 ]; INT8 pS_bTeam; CHAR16 pS_name[ 10 ]; + + // OJW - 20081222 + // save stats if(pAttacker) { - pA_bTeam=pAttacker->bTeam; - memcpy(pA_name,pAttacker->name,sizeof(CHAR16)*10); - if(pA_bTeam>5)pA_bTeam=pA_bTeam-5; - if(pA_bTeam==0)pA_bTeam=CLIENT_NUM; + // if attacker was one of our own mercs, use the last hostile attacker as the killer if there is one + if (pAttacker->bTeam == pSoldier->bTeam && pSoldier->ubPreviousAttackerID != NULL && pSoldier->ubPreviousAttackerID != NOBODY) + { + pAttacker=MercPtrs[ pSoldier->ubPreviousAttackerID ]; + // check if the new attacker was also a friendly... + if (pAttacker->bTeam == pSoldier->bTeam && pSoldier->ubNextToPreviousAttackerID != NULL && pSoldier->ubNextToPreviousAttackerID != NOBODY) + pAttacker=MercPtrs[ pSoldier->ubNextToPreviousAttackerID ]; + // if its still a friendly, use the original attacker id...for posterity + // guy must snore too loudly if all his mates wanna kill him :) + if (pAttacker->bTeam == pSoldier->bTeam && pSoldier->ubAttackerID != NULL && pSoldier->ubAttackerID != NOBODY) + pAttacker = MercPtrs[ pSoldier->ubAttackerID ]; + + nDeath.attacker_id = pAttacker->ubID; + } + + + + // Translate attacker id for other clients if attacker was one of ours + if(pAttacker->ubID<20)nDeath.attacker_id=pAttacker->ubID+ubID_prefix; + + pA_bTeam=pAttacker->bTeam; + memcpy(pA_name,pAttacker->name,sizeof(CHAR16)*10); + if (pA_bTeam==1 && PLAYER_BSIDE==MP_TYPE_COOP) + { + // CO-OP Kill by an enemy ai + pA_bTeam = 5; // the server subtracts 1 from these numbers to score in scoreboard, AI is index 4 + } + else + { + // Any mode, kill by a players merc + if(pA_bTeam>5)pA_bTeam=pA_bTeam-5; + if(pA_bTeam==0)pA_bTeam= CLIENT_NUM; + } } if(pSoldier) { - pS_bTeam=pSoldier->bTeam; - memcpy(pS_name,pSoldier->name,sizeof(CHAR16)*10); - if(pS_bTeam>5)pS_bTeam=pS_bTeam-5; - if(pS_bTeam==0)pS_bTeam=CLIENT_NUM; + pS_bTeam=pSoldier->bTeam; + memcpy(pS_name,pSoldier->name,sizeof(CHAR16)*10); + if(pS_bTeam==1 && PLAYER_BSIDE==MP_TYPE_COOP) + { + // CO-OP Death of an enemy ai + pS_bTeam = 5; // the server subtracts 1 from these numbers to score in scoreboard, AI is index 4 + } + else + { + // Any mode death of a players merc + if(pS_bTeam>5)pS_bTeam=pS_bTeam-5; + if(pS_bTeam==0)pS_bTeam=CLIENT_NUM; + } } + + nDeath.attacker_team = pA_bTeam; + nDeath.soldier_team = pS_bTeam; + + // notify other clients of death + client->RPC("sendDEATH",(const char*)&nDeath, (int)sizeof(death_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + + // print kill notice to screen if (pSoldier->bTeam==1) ScreenMsg( FONT_YELLOW, MSG_CHAT, L"You Killed An Enemy AI"); else ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[28],pS_name,(pS_bTeam),client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); - //ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[28],(pS_bTeam), pS_name,client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); +#if _DEBUG + char s_name[10]; + char a_name[10]; + WideCharToMultiByte(CP_UTF8,0,pS_name,-1, s_name,10,NULL,NULL); + WideCharToMultiByte(CP_UTF8,0,pA_name,-1, a_name,10,NULL,NULL); + if (pSoldier->bTeam==1) MPDebugMsg( String ( "MPDEBUG SEND - Enemy AI #%d was killed by ('%s' - %d) (client %d - '%s')\n",nDeath.soldier_id,a_name,nDeath.attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); + else if (pAttacker->bTeam==1) MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); + else MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); +#endif + //ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[28],(pS_bTeam), pS_name,client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); } void recieveDEATH (RPCParameters *rpcParameters) @@ -2183,6 +2550,16 @@ void recieveDEATH (RPCParameters *rpcParameters) CheckForEndOfBattle( FALSE ); } +#if _DEBUG + char s_name[10]; + char a_name[10]; + WideCharToMultiByte(CP_UTF8,0,pS_name,-1, s_name,10,NULL,NULL); + WideCharToMultiByte(CP_UTF8,0,pA_name,-1, a_name,10,NULL,NULL); + if (pSoldier->bTeam==1) MPDebugMsg( String ( "MPDEBUG RECV - Enemy AI #%d was killed by ('%s' - #%d) (client %d - '%s')\n",nDeath->soldier_id,a_name,nDeath->attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); + else if (pAttacker->bTeam==1) MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); + else MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); +#endif + } void send_hitstruct(EV_S_STRUCTUREHIT * SStructureHit) @@ -2269,53 +2646,89 @@ BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? SOLDIERTYPE *pSoldier; int cnt; int soldiers= 0 ; + int numActiveSides = 0; + int dm_teams[4] = {0 , 0 , 0 , 0}; + for(int x=0;x < MAXTEAMS; x++) + { + soldiers=0; - for(int x=0;x < MAXTEAMS; x++) - { + for(cnt = gTacticalStatus.Team[ x ].bFirstID;cnt <= gTacticalStatus.Team[ x ].bLastID; cnt++) + { + pSoldier = MercPtrs[ cnt ]; + if(pSoldier->stats.bLife >= OKLIFE && pSoldier->bActive && pSoldier->bInSector) + { + soldiers++; + } + } + if(soldiers>0) + { + gTacticalStatus.Team[ x ].bTeamActive=1; + gTacticalStatus.Team[ x ].bMenInSector=soldiers; - for(cnt = gTacticalStatus.Team[ x ].bFirstID;cnt <= gTacticalStatus.Team[ x ].bLastID; cnt++) - { - pSoldier = MercPtrs[ cnt ]; - if(pSoldier->stats.bLife!=0 && pSoldier->bActive && pSoldier->bInSector) - { - soldiers++; - } - } - if(soldiers>0) - { - gTacticalStatus.Team[ x ].bTeamActive=1; - gTacticalStatus.Team[x].bMenInSector=soldiers; - - soldiers=0 ; - } - else - { - - gTacticalStatus.Team[ x ].bTeamActive=0; - gTacticalStatus.Team[x].bMenInSector=0; - } - } - if( (gTacticalStatus.Team[ 0 ].bTeamActive == 0) && wiped==0)//server's team has been knocked out - { - wiped=1; - ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[40] ); + if (PLAYER_BSIDE==1 && (x==0 || x>5)) + { + // store the number of active DM teams, and number of players per team still alive + int cl_num = CLIENT_NUM; // 1 based + if (x>5) cl_num = x - 5; + dm_teams[ client_teams[ cl_num - 1 ] ]++; + } + else if (PLAYER_BSIDE != 1) + { + // count number of active teams + numActiveSides++; + } + } + else + { + gTacticalStatus.Team[ x ].bTeamActive=0; + gTacticalStatus.Team[x].bMenInSector=0; + } + } + if( (gTacticalStatus.Team[ 0 ].bTeamActive == 0) && wiped==0)//server's team has been knocked out + { + wiped=1; + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[40] ); if(!DISABLE_SPEC_MODE) { - gTacticalStatus.uiFlags |= SHOW_ALL_MERCS;//hayden - ScreenMsg( FONT_YELLOW, MSG_CHAT, MPClientMessage[41] ); + gTacticalStatus.uiFlags |= SHOW_ALL_MERCS;//hayden + ScreenMsg( FONT_YELLOW, MSG_CHAT, MPClientMessage[41] ); } else ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"spectator mode disabled"); - teamwiped(); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[42] ); - } - if((gTacticalStatus.Team[ 0 ].bTeamActive==1 || gTacticalStatus.Team[ 6 ].bTeamActive==1 || gTacticalStatus.Team[ 7 ].bTeamActive==1 || gTacticalStatus.Team[ 0 ].bTeamActive==1 || gTacticalStatus.Team[ 9 ].bTeamActive==1 )&& NumEnemyInSector() > 0)return(TRUE); - else return(FALSE); + teamwiped(); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[42] ); + } - - + if (PLAYER_BSIDE == 0) + { + // check game end for DeathMatch + return (numActiveSides > 1); + } + else if (PLAYER_BSIDE == 1) + { + // check game end for Team Deathmatch + // count how many active deathmatch teams are alive (two players could be alive but might be on the same TEAM) + for (int i=0; i < 4; i++) + { + if (dm_teams[i] > 0) + { + numActiveSides++; + } + } + + return (numActiveSides > 1); + } + else if (PLAYER_BSIDE == 2) + { + // check for game end for CO-OP + // If any player team is alive && the number of enemies > 0 then continue game (true), else quit (false) + return ((gTacticalStatus.Team[ 0 ].bTeamActive==1 || gTacticalStatus.Team[ 6 ].bTeamActive==1 || gTacticalStatus.Team[ 7 ].bTeamActive==1 || gTacticalStatus.Team[ 8 ].bTeamActive==1 || gTacticalStatus.Team[ 9 ].bTeamActive==1 )&& NumEnemyInSector() > 0); + } + + // dont stop the game by default + return true; } void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ) @@ -2554,6 +2967,174 @@ void recieve_door (RPCParameters *rpcParameters) } +void recieveCHATMSG(RPCParameters* rpcParameters) +{ + chat_msg* cmsg = (chat_msg*)rpcParameters->input; + + if (PLAYER_BSIDE==1 && cmsg->bToAll == false) + { + // If Team deathmatch && msg is allies only + if (client_teams[cmsg->client_num-1] == TEAM) + { + // only display on an ally client + ChatLogMessage( FONT_LTGREEN, MSG_CHAT, cmsg->msg); + } + } + else + { + // display to all clients + ChatLogMessage( FONT_LTGREEN, MSG_CHAT, cmsg->msg); + } +} + +/// OJW - 20081223 +// recieveDISCONNECT - Handle disconnection +void recieveDISCONNECT(RPCParameters* rpcParameters) +{ + // for starters - we shouldnt get a message for ourselves :) + int cl_num = (int) *rpcParameters->input; // cl_num starts at 1 + + wchar_t szPlayerName[30]; + memset(szPlayerName,0,30*sizeof(wchar_t)); + mbstowcs( szPlayerName,client_names[cl_num-1],30); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[47], szPlayerName ); + + // clear our records from this client + memset(client_names[cl_num-1],NULL,sizeof(char)*30); + memset(&client_ready[cl_num-1],0,sizeof(int)); + memset(&client_teams[cl_num-1],0,sizeof(int)); + + if (guiCurrentScreen == MAP_SCREEN && !(gTacticalStatus.uiFlags & INCOMBAT)) + { + // in the map screen and not in combat + // refresh player list to remove from the game + fDrawCharacterList = true; // set the character list to be redrawn + fTeamPanelDirty = true; // redraw the background + } + else if (guiCurrentScreen == GAME_SCREEN) // get a more valid check that the game is in progress here + { + // in tactical screen and in combat + // kill the dead clients mercs out of the game + + UINT8 iNetbTeam = (cl_num)+5; + UINT8 iubID_prefix = gTacticalStatus.Team[ iNetbTeam ].bFirstID;//over here now + + // kill any alive soldiers for the disconnected team + SOLDIERTYPE *pTeamSoldier; + INT32 cnt = 0; + + for ( pTeamSoldier = Menptr, cnt = 0; cnt < TOTAL_SOLDIERS; pTeamSoldier++, cnt++ ) + { + if ( pTeamSoldier->bActive && pTeamSoldier->bInSector && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) ) + { + // Checkf for any more bacguys + if ( !pTeamSoldier->aiData.bNeutral && (pTeamSoldier->bTeam == iNetbTeam ) ) + { + // KIll...... + pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE ); + } + } + } + + // if it was that teams turn then end it + if(is_server) + { + if(gTacticalStatus.ubCurrentTeam==iNetbTeam)EndTurn( iNetbTeam+1 ); + } + } + +} + +void disconnected_callback(UINT8 ubResult) +{ + if (iDisconnectedScreen == MAP_SCREEN) + { + // clean up all resources and exit from map to main menu + RequestTriggerExitFromMapscreen(MAP_EXIT_TO_MAINMENU); + // game is restarted in HandleExitsFromMapScreen() + } + else if (iDisconnectedScreen == GAME_SCREEN) + { + // clean up all resources and exit from tactical to main menu + LeaveTacticalScreen(MAINMENU_SCREEN); + } + else if (iDisconnectedScreen == OPTIONS_SCREEN) + { + // Re-initialise the game + ReStartingGame(); + // clean up all resources and exit from options to main menu + SetOptionsExitScreen( MAINMENU_SCREEN ); + } + else if (iDisconnectedScreen == LAPTOP_SCREEN) + { + // Re-initialise the game + ReStartingGame(); + // clean up all resources and exit from laptop to main menu + SetPendingNewScreen(MAINMENU_SCREEN); // Laptop screen is always cleaned up on screen change in gameloop + } + else + { + // Re-initialise the game + ReStartingGame(); + // else dont clean "everything" but still exit to main menu + SetPendingNewScreen(MAINMENU_SCREEN); + } + +} + +// Gracefully handle self-disconnection of the client by Dropout +void HandleClientConnectionLost() +{ + if (guiCurrentScreen != MP_SCORE_SCREEN) + { + // cleanup client + client_disconnect(); + auto_retry = false; + + if (is_server) + server_disconnect(); + + // connection lost, let user know via popup then quit to main menu + iDisconnectedScreen = guiCurrentScreen; + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + + UINT32 giMPHMessageBox = DoMessageBox( MSG_BOX_BASIC_STYLE, (recieved_settings ? MPClientMessage[48] : MPClientMessage[55] ), guiCurrentScreen, ( UINT16 ) ( MSG_BOX_FLAG_OK | MSG_BOX_FLAG_USE_CENTERING_RECT ),disconnected_callback, &CenteringRect ); + + } + + /* + // handle UI + if (guiCurrentScreen == MAP_SCREEN && !(gTacticalStatus.uiFlags & INCOMBAT)) + { + // in the map screen and not in combat + + + // refresh player list to remove from the game + fDrawCharacterList = true; // set the character list to be redrawn + fTeamPanelDirty = true; // redraw the background + // can set connection retries here if desired + + } + else if (guiCurrentScreen == GAME_SCREEN) // get a more valid check that the game is in progress here + { + // connection lost, let user know via popup then quit to main menu + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + UINT32 giMPHMessageBox = DoMessageBox( MSG_BOX_BASIC_STYLE, MPClientMessage[48], MAINMENU_SCREEN, ( UINT16 ) ( MSG_BOX_FLAG_OK | MSG_BOX_FLAG_USE_CENTERING_RECT ), NULL, &CenteringRect ); + + if (is_networked) + { + // haydent + if (is_server) + server_disconnect(); + + client_disconnect(); + + } + + //We want to reinitialize the game + ReStartingGame(); + }*/ +} void sendRT(void) { @@ -2614,6 +3195,16 @@ void teamwiped ( void ) client->RPC("sendWIPE",(const char*)&data, (int)sizeof(sc_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + if (is_server) + { + // end the co-op game if all player teams have wiped + if (PLAYER_BSIDE==MP_TYPE_COOP) + { + iTeamsWiped++; + if (iTeamsWiped >= MAX_CLIENTS) + game_over(); + } + } } void recieve_wipe (RPCParameters *rpcParameters) @@ -2621,10 +3212,18 @@ void recieve_wipe (RPCParameters *rpcParameters) { sc_struct* data = (sc_struct*)rpcParameters->input; ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"Team #%d is wiped out.", data->ubStartingTeam ); -if(is_server) -{ - if(gTacticalStatus.ubCurrentTeam==data->ubStartingTeam)EndTurn( data->ubStartingTeam+1 ); -} + if(is_server) + { + if(gTacticalStatus.ubCurrentTeam==data->ubStartingTeam)EndTurn( data->ubStartingTeam+1 ); + + // end the co-op game if all player teams have wiped + if (PLAYER_BSIDE==MP_TYPE_COOP) + { + iTeamsWiped++; + if (iTeamsWiped >= MAX_CLIENTS) + game_over(); + } + } } void send_heal (SOLDIERTYPE *pSoldier ) @@ -2681,6 +3280,44 @@ void awardINT (RPCParameters *rpcParameters) } +void game_over() +{ + // wait 3 seconds then notify all clients + is_game_over = true; + iScoreScreenTime = guiBaseJA2NoPauseClock + 5000; +} + +// OJW - note: i dont use the internal timer callback for this because +// death notices use it and i want all those to go through normally +// so all clients have time to receive death notice of the last merc +// which creates victory condition + +void send_gameover() +{ + // handle the user calling the wrong function first + if (!is_game_over) + { + game_over(); // start the event + return; + } + + // stop the event from firing again + is_game_over = false; + iScoreScreenTime = 0; + + // notify all the clients that the game is over + client->RPC("sendGAMEOVER",(const char*)&CLIENT_NUM, (int)sizeof(CLIENT_NUM)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); +} + +void recieveGAMEOVER(RPCParameters *rpcParameters) +{ + player_stats* data= (player_stats*)rpcParameters->input; + memcpy(gMPPlayerStats,data,sizeof(player_stats)*5); + + // fire the score screen + StartScoreScreen(); +} + //*************************** //*** client connection***** @@ -2715,6 +3352,9 @@ void connect_client ( void ) REGISTER_STATIC_RPC(client, recieveREADY); REGISTER_STATIC_RPC(client, recieveGUI); REGISTER_STATIC_RPC(client, recieveSETTINGS); + REGISTER_STATIC_RPC(client, recieveTEAMCHANGE); + REGISTER_STATIC_RPC(client, recieveEDGECHANGE); + REGISTER_STATIC_RPC(client, recieveMAPCHANGE); REGISTER_STATIC_RPC(client, recieveBULLET); REGISTER_STATIC_RPC(client, recieveSTATE); REGISTER_STATIC_RPC(client, recieveDEATH); @@ -2730,6 +3370,9 @@ void connect_client ( void ) REGISTER_STATIC_RPC(client, recieve_wipe); REGISTER_STATIC_RPC(client, recieve_heal); REGISTER_STATIC_RPC(client, awardINT); + REGISTER_STATIC_RPC(client, recieveGAMEOVER); + REGISTER_STATIC_RPC(client, recieveDISCONNECT); + REGISTER_STATIC_RPC(client, recieveCHATMSG); //*** if (b) @@ -2763,9 +3406,18 @@ void connect_client ( void ) numready = 0; readystage = 0; status = 0; + is_game_started = false; gTacticalStatus.uiFlags&= (~SHOW_ALL_MERCS ); memset( &readyteamreg , 0 , sizeof (int) * 10); - + //OJW - 20081204 + memset ( &client_names,NULL,sizeof(int)*4); + memset ( &client_ready,0,sizeof(int)*4); + memset ( &client_teams,0,sizeof(int)*4); + if (!RANDOM_SPAWN) + memset ( &client_edges,0,sizeof(int)*4); + if (RANDOM_MERCS) + memset (random_mercs,0,sizeof(int)*7); + memset( gMPPlayerStats,0,sizeof(player_stats)*5); //retrieve settings from Ja2_mp.ini @@ -2880,6 +3532,10 @@ void connect_client ( void ) ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[1],SERVER_IP); client->Connect(SERVER_IP, atoi(SERVER_PORT), 0,0); is_connecting=true; + +#if _DEBUG + MPDebugMsg( String ( "connect_client()\n" ) ); +#endif } @@ -2903,79 +3559,118 @@ void client_packet ( void ) if (is_client) { - p = client->Receive(); + p = client->Receive(); - while(p) - { - //continue; // Didn't get any packets - - // We got a packet, get the identifier with our handy function - packetIdentifier = GetPacketIdentifier(p); - //ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"packet recieved"); - // Check if this is a network message packet - switch (packetIdentifier) + while(p) { - case ID_DISCONNECTION_NOTIFICATION: - // Connection lost normally - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_DISCONNECTION_NOTIFICATION"); - is_connected=false; - break; - case ID_ALREADY_CONNECTED: - // Connection lost normally - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_ALREADY_CONNECTED"); - break; - case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully. You can manually broadcast this in a peer to peer enviroment if you want. - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_DISCONNECTION_NOTIFICATION"); - break; - case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully. You can manually broadcast this in a peer to peer enviroment if you want. - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_CONNECTION_LOST"); - break; - case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting. You can manually broadcast this in a peer to peer enviroment if you want. - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_NEW_INCOMING_CONNECTION"); - break; - case ID_CONNECTION_ATTEMPT_FAILED: - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_ATTEMPT_FAILED"); - is_connected=false; - is_connecting=false; - break; - case ID_NO_FREE_INCOMING_CONNECTIONS: - // Sorry, the server is full. I don't do anything here but - // A real app should tell the user - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_NO_FREE_INCOMING_CONNECTIONS"); - break; - case ID_CONNECTION_LOST: - // Couldn't deliver a reliable packet - i.e. the other system was abnormally - // terminated - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_LOST"); - is_connected=false; - break; - case ID_CONNECTION_REQUEST_ACCEPTED: - // This tells the client they have connected - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_REQUEST_ACCEPTED"); - is_connected=true; - is_connecting=false; - requestSETTINGS(); - //request_settings();//ask server for game settings... - break; - case ID_NEW_INCOMING_CONNECTION: - //tells server client has connected - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_NEW_INCOMING_CONNECTION"); - break; - case ID_MODIFIED_PACKET: - // Cheater! - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_MODIFIED_PACKET"); - break; - default: - - ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"** a packet has been recieved for which i dont know what to do... **"); - break; + //continue; // Didn't get any packets + + // We got a packet, get the identifier with our handy function + packetIdentifier = GetPacketIdentifier(p); + //ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"packet recieved"); + // Check if this is a network message packet + switch (packetIdentifier) + { + case ID_DISCONNECTION_NOTIFICATION: + // Connection lost normally + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_DISCONNECTION_NOTIFICATION"); + is_connected=false; + //OJW - 20081223 + //Gracefully notify and disconnect the client + client->DeallocatePacket(p); // HandleClientConnectionLost shuts down the client + HandleClientConnectionLost(); + //OJW - 2009 + return; + break; + case ID_ALREADY_CONNECTED: + // Connection lost normally + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_ALREADY_CONNECTED"); + break; + case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully. You can manually broadcast this in a peer to peer enviroment if you want. + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_DISCONNECTION_NOTIFICATION"); + break; + case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully. You can manually broadcast this in a peer to peer enviroment if you want. + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_CONNECTION_LOST"); + break; + case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting. You can manually broadcast this in a peer to peer enviroment if you want. + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_REMOTE_NEW_INCOMING_CONNECTION"); + break; + case ID_CONNECTION_ATTEMPT_FAILED: + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_ATTEMPT_FAILED"); + is_connected=false; + is_connecting=false; + + //OJW - 20081224 + // handle auto retry + if (auto_retry && giNumTries > 0) + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[49],giNumTries); // we already tried once, let the user know we are retrying + else + ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[50],giNumTries); // we already tried once, let the user know we are retrying + giNextRetryTime = guiBaseJA2NoPauseClock + 5000; // 5 seconds? + break; + case ID_NO_FREE_INCOMING_CONNECTIONS: + // Sorry, the server is full. I don't do anything here but + // A real app should tell the user + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_NO_FREE_INCOMING_CONNECTIONS"); + break; + case ID_CONNECTION_LOST: + // Couldn't deliver a reliable packet - i.e. the other system was abnormally + // terminated + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_LOST"); + is_connected=false; + //OJW - 20081223 + //Gracefully notify and disconnect the client + client->DeallocatePacket(p); // HandleClientConnectionLost shuts down the client + HandleClientConnectionLost(); + return; + break; + case ID_CONNECTION_REQUEST_ACCEPTED: + // This tells the client they have connected + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_CONNECTION_REQUEST_ACCEPTED"); + is_connected=true; + is_connecting=false; + requestSETTINGS(); + //request_settings();//ask server for game settings... + break; + case ID_NEW_INCOMING_CONNECTION: + //tells server client has connected + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_NEW_INCOMING_CONNECTION"); + break; + case ID_MODIFIED_PACKET: + // Cheater! + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"ID_MODIFIED_PACKET"); + break; + default: + + ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"** a packet has been recieved for which i dont know what to do... **"); + break; + } + + + // We're done with the packet, get more :) + client->DeallocatePacket(p); + p = client->Receive(); } + // OJW - 20081223 + if (is_game_over) + { + if (guiBaseJA2NoPauseClock >= iScoreScreenTime) + { + send_gameover(); + } + } - // We're done with the packet, get more :) - client->DeallocatePacket(p); - p = client->Receive(); - } + // OJW - 20090203 + // Using the built in callback functions didnt work, so doing manually here + if (bClosingChatBoxToStartGame) + { + if (guiBaseJA2NoPauseClock >= iCCStartGameTime) + { + bClosingChatBoxToStartGame = false; + StartBattleChatBoxClosedCallback(); + } + } } } // Copied from Multiplayer.cpp @@ -3007,14 +3702,127 @@ void client_disconnect (void) allowlaptop=false; + // clear local client cache + memset(client_names,0,sizeof(char)*4*30); + memset(client_edges,0,sizeof(int)*4); + memset(client_ready,0,sizeof(int)*4); + memset(client_teams,0,sizeof(int)*4); + memset(gMPPlayerStats,0,sizeof(player_stats)*5); + memset(random_mercs,0,sizeof(int)*7); + + // We're done with the network RakNetworkFactory::DestroyRakPeerInterface(client); ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"client disconnected and shutdown"); + +#if _DEBUG + MPDebugMsg( "client_disconnect()\n" ); +#endif } else { ScreenMsg( FONT_LTGREEN, MSG_CHAT, L"client is not running"); } } + +//OJW - 20081204 - send a starting edge change to all the clients +void send_edgechange(int newedge) +{ + // remove this godawful hack with a proper game status check + if (can_edgechange()) + { + edgechange_struct lan; + + lan.client_num = CLIENT_NUM; + lan.newedge = newedge; + + client->RPC("sendEDGECHANGE",(const char*)&lan, (int)sizeof(edgechange_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + + // redraw the character list on the map screen + fDrawCharacterList = true; + fTeamPanelDirty = true; + client_edges[CLIENT_NUM-1] =newedge; + // store the setting locally + _itoa(newedge,SECT_EDGE,10); + + } + else + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[3]); + } +} + +bool can_edgechange() +{ + return (is_game_started != 1 && client_ready[CLIENT_NUM-1] == 0 && !allowlaptop && !RANDOM_SPAWN); +} + +//OJW - 20081204 - send a starting team change to all the clients +void send_teamchange(int newteam) +{ + // remove this godawful hack with a proper game status check + if (can_teamchange()) + { + teamchange_struct lan; + + lan.client_num = CLIENT_NUM; + lan.newteam = newteam; + + client->RPC("sendTEAMCHANGE",(const char*)&lan, (int)sizeof(teamchange_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + + // redraw the character list on the map screen + fDrawCharacterList = true; + fTeamPanelDirty = true; + client_teams[lan.client_num-1] = lan.newteam; + TEAM = newteam; + + } + else + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[4]); + } +} + +bool can_teamchange() +{ + return (is_game_started != 1 && client_ready[CLIENT_NUM-1] == 0 && !allowlaptop); +} + +// 20081222 - OJW +void StartScoreScreen( void ) +{ + // pause game + + // set main screen as score screen + LeaveTacticalScreen( MP_SCORE_SCREEN ); +} + +void ChatCallback( UINT8 ubResult ) +{ + if (ubResult == MSG_BOX_RETURN_OK && wcscmp(gszChatBoxInputString,L"") > 0) + { + chat_msg cmsg; + wchar_t szPlayerName[30]; + memset(szPlayerName,0,30*sizeof(wchar_t)); + mbstowcs( szPlayerName,CLIENT_NAME,30); + + cmsg.bToAll = gbChatSendToAll; + if (PLAYER_BSIDE==1 && !cmsg.bToAll) + swprintf(cmsg.msg,MPClientMessage[56], szPlayerName, gszChatBoxInputString); + else + swprintf(cmsg.msg,MPClientMessage[52], szPlayerName, gszChatBoxInputString); + cmsg.client_num = CLIENT_NUM; + + // notify all of the chat message + client->RPC("sendCHATMSG",(const char*)&cmsg, (int)sizeof(chat_msg)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + } + + memset(gszMsgBoxInputString,0,sizeof(gszMsgBoxInputString)); +} + +void OpenChatMsgBox( void ) +{ + DoChatBox((guiCurrentScreen == GAME_SCREEN? true : false),gzMPChatboxText[1],guiCurrentScreen,ChatCallback,NULL); +} \ No newline at end of file diff --git a/Multiplayer/connect.h b/Multiplayer/connect.h index f059ac6e..2f1e5a86 100644 --- a/Multiplayer/connect.h +++ b/Multiplayer/connect.h @@ -10,6 +10,7 @@ extern bool is_connecting; extern bool is_client; extern bool is_server; extern bool is_networked; +extern bool is_host; // OJW - added 20081129 extern int PLAYER_TEAM_TIMER_SEC_PER_TICKS; @@ -23,6 +24,7 @@ extern int CIV_ENABLED; extern int MAX_CLIENTS; extern int SAME_MERC; +extern int PLAYER_BSIDE; extern bool allowlaptop; @@ -30,6 +32,13 @@ extern UINT8 netbTeam; extern UINT8 ubID_prefix; extern FLOAT DAMAGE_MULTIPLIER; +//OJW - 20081218 +extern int RANDOM_SPAWN; +extern int RANDOM_MERCS; + +//OJW - 20090317 +extern bool is_game_started; + extern UINT16 crate_usMapPos; //extern int INTERRUPTS; @@ -60,6 +69,8 @@ void start_server (void); void client_packet ( void ); void server_packet ( void ); +void NetworkAutoStart(); // OJW - 20081130 - Automate connection functions + void server_disconnect (void); void client_disconnect (void); @@ -85,11 +96,53 @@ void send_stop (EV_S_STOP_MERC *SStopMerc); void send_interrupt(SOLDIERTYPE *pSoldier); +void OpenChatMsgBox(void); + BOOLEAN CheckConditionsForBattle( GROUP *pGroup ); // this comes from strategic movement.cpp extern char client_names[4][30]; +// OJW - 20081204 +// I need to keep track of all the clients readyness, spawn edge and team +// want to change this all to use client_info, but dont want to make sweeping +// changes to the codebase without talking to the other devs +extern int client_ready[4]; +extern int client_teams[4]; +extern int client_edges[4]; + +extern char SERVER_NAME[30]; + +//OJW - 20081224 +extern bool auto_retry; +extern int giNumTries; void send_settings(); +void send_mapchange(); // added 20081201 by OJW +void send_teamchange( int newteam ); // send team a change +void send_edgechange( int newedge ); // send an edge change +bool can_teamchange(); // UI Checks +bool can_edgechange(); // UI Checks + void StartInterrupt( void ); + +// MP GameTypes +enum +{ + MP_TYPE_DEATHMATCH, + MP_TYPE_TEAMDEATMATCH, + MP_TYPE_COOP, + NUM_MP_GAMETYPE +}; + +typedef struct +{ + int kills; + int deaths; + int hits; + int misses; +} player_stats; + +extern player_stats gMPPlayerStats[5]; + +extern void game_over( void ); diff --git a/Multiplayer/fresh_header.h b/Multiplayer/fresh_header.h index 87df7f1e..ecdbde14 100644 --- a/Multiplayer/fresh_header.h +++ b/Multiplayer/fresh_header.h @@ -10,6 +10,8 @@ typedef struct { UINT16 soldier_id; UINT16 attacker_id; + UINT8 attacker_team; + UINT8 soldier_team; }death_struct; typedef struct diff --git a/Multiplayer/network.h b/Multiplayer/network.h index abc22942..48aa3cb8 100644 --- a/Multiplayer/network.h +++ b/Multiplayer/network.h @@ -3,6 +3,7 @@ //this one just for structs, variables and functions used between the client and server scripts... extern char CLIENT_NAME[30]; +extern char SERVER_NAME[30]; extern bool Sawarded; @@ -41,6 +42,10 @@ typedef struct UINT8 client_num; char client_name[30]; char client_names[4][30]; + // OJW - added 20081204 + int client_edges[4]; + int client_teams[4]; + char server_name[30]; //int cl_ops[4]; int team; int TESTING; @@ -52,8 +57,34 @@ typedef struct int WEAPON_READIED_BONUS; int ALLOW_CUSTOM_NIV; int DISABLE_SPEC_MODE; + // OJW - added 20081220 + int RANDOM_SPAWN; + int RANDOM_MERCS; + int random_mercs[7]; } settings_struct; + + +// added 080101 by OJW +typedef struct +{ + INT16 gsMercArriveSectorX; + INT16 gsMercArriveSectorY; + float TIME; +} mapchange_struct; + +typedef struct +{ + UINT8 client_num; + UINT8 newedge; +} edgechange_struct; + +typedef struct +{ + UINT8 client_num; + UINT8 newteam; +} teamchange_struct; + //typedef struct //{ // int clnum; diff --git a/Multiplayer/server.cpp b/Multiplayer/server.cpp index 9cda3c0d..32bea4d3 100644 --- a/Multiplayer/server.cpp +++ b/Multiplayer/server.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "types.h" #include "gamesettings.h" @@ -26,11 +28,12 @@ int gsREPORT_NAME; #include "game init.h" #include "text.h" +#include "network.h" #include "connect.h" #include "message.h" -#include "network.h" #include "overhead.h" #include "fresh_header.h" +#include "Debug Control.h" UINT16 nc; //number of open connection UINT16 ncr; //number of ready confirmed connections //something keep record of ready connections .. @@ -74,6 +77,68 @@ typedef struct client_data client_d[4]; +// OJW - 20081223 +// Random Merc teams +// First attempt at "balanced" teams +int random_merc_teams[4][7] = +{ + { 16, 10, 19, 25, 4 , 11, 39 } , // Gus , Shadow, Spider , Raven , Vicki , Red , Meltdown + { 29, 36, 28, 2 , 22, 8 , 32 } , // Magic , Scope, Danny , Lynx , Hitman , Steroid , Malice + { 12, 5 , 20, 23, 48, 34, 17 } , // Reaper , Trevor, Cliff , Buzz , Cougar , Nails , Buns + { 31, 7 , 33, 35, 27, 37, 1 } // Scully , Ivan , Dr Q , Thor , Len , Wolf , Blood +}; + +int client_mercteam[4] = { 0 , 1 , 2 , 3 }; // random index of random_merc_teams per player + +bool inline can_joingame(); + +int f_rec_num(int mode, SystemAddress sender)//from client data +{ + int x; + client_data cl_record; + for ( x=0; x<4;x++) + { + cl_record = client_d[x]; + + if(mode==0)//find empty slot for new record + { + if(cl_record.address.binaryAddress==0) + return(x); + } + if(mode==1)//wipe clean all + { + client_d[x].address.binaryAddress=0; + client_d[x].address.port=0; + client_d[x].cl_number=0; + } + if(mode==2)//clear one record + { + if(cl_record.address.binaryAddress==sender.binaryAddress && cl_record.address.port==sender.port) + { + client_d[x].address.port=0; + client_d[x].cl_number=0; + client_d[x].address.binaryAddress=0; + return(254); + } + + } + // OJW - 090212 - look up client number + if (mode == 3) + { + if(cl_record.address.binaryAddress==sender.binaryAddress && cl_record.address.port==sender.port) + { + return (x); + } + } + } + if(mode == 0)//'no free slots' + { + ScreenMsg( FONT_RED, MSG_CHAT, L"Client Record Error, Restart Server, and Report Error." ); + return (255); + } + return(254); +} + // use UNASSIGNED_SYSTEM_ADDRESS instead of rpcParameters->sender to send it back to yourself (the sender) // there is very little in here dependant on the game engine and originally started out as an independant dedicated server .exe, and could if go ther again ... hayden. //********* RPC SECTION ************ @@ -100,6 +165,15 @@ void sendFIRE(RPCParameters *rpcParameters) void sendHIT(RPCParameters *rpcParameters) { + EV_S_WEAPONHIT* hit = (EV_S_WEAPONHIT*)rpcParameters->input; + + int team = MercPtrs[ hit->ubAttackerID ]->bTeam; + if (team == 1) team = 5; + else if (team >= 6) team -= 6; + else if (team == 0) team = CLIENT_NUM-1; // this case should not be possible, including as a precaution + + gMPPlayerStats[team].hits++; + server->RPC("recieveHIT",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); } @@ -157,18 +231,69 @@ void sendSTATE(RPCParameters *rpcParameters) } void sendDEATH(RPCParameters *rpcParameters) { + // the master copy of the scoreboard is kept on the server + death_struct* nDeath = (death_struct*)rpcParameters->input; + + // Save Stats on the server side + gMPPlayerStats[nDeath->soldier_team-1].deaths++; + gMPPlayerStats[nDeath->attacker_team-1].kills++; + + + // get the client number of the client sending the message + int iCLnum = f_rec_num(3,rpcParameters->sender)+1; + server->RPC("recieveDEATH",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); + +#if _DEBUG + wchar_t ateam[5]; + wchar_t steam[5]; + wchar_t clnum[5]; + _itow(nDeath->attacker_team,ateam,10); + _itow(nDeath->soldier_team,steam,10); + _itow(iCLnum,clnum,10); + ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"DEBUG: Soldier Killed : Attacking team %s , Soldier Team %s, Sender %s",ateam,steam,clnum); + char logmsg[100]; + sprintf(logmsg, "MP DEBUG: Soldier Killed #%i : Attacking team %i , Soldier Team %i, Sender %i\n",nDeath->soldier_id,nDeath->attacker_team,nDeath->soldier_team,iCLnum); + MPDebugMsg( logmsg ); +#endif } void sendhitSTRUCT(RPCParameters *rpcParameters) { + EV_S_STRUCTUREHIT* miss = (EV_S_STRUCTUREHIT*)rpcParameters->input; + + int team = MercPtrs[ miss->ubAttackerID ]->bTeam; + if (team == 1) team = 5; + else if (team >= 6) team -= 6; + else if (team == 0) team = CLIENT_NUM-1; // this case should not be possible, including as a precaution + + gMPPlayerStats[team].misses++; + server->RPC("recievehitSTRUCT",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); } void sendhitWINDOW(RPCParameters *rpcParameters) { + EV_S_WINDOWHIT* miss = (EV_S_WINDOWHIT*)rpcParameters->input; + + int team = MercPtrs[ miss->ubAttackerID ]->bTeam; + if (team == 1) team = 5; + else if (team >= 6) team -= 6; + else if (team == 0) team = CLIENT_NUM-1; // this case should not be possible, including as a precaution + + gMPPlayerStats[team].misses++; + server->RPC("recievehitWINDOW",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); } void sendMISS(RPCParameters *rpcParameters) { + EV_S_MISS* miss = (EV_S_MISS*)rpcParameters->input; + + int team = MercPtrs[ miss->ubAttackerID ]->bTeam; + if (team == 1) team = 5; + else if (team >= 6) team -= 6; + else if (team == 0) team = CLIENT_NUM-1; // this case should not be possible, including as a precaution + + gMPPlayerStats[team].misses++; + server->RPC("recieveMISS",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); } void updatenetworksoldier(RPCParameters *rpcParameters) @@ -205,6 +330,18 @@ void sendHEAL(RPCParameters *rpcParameters) { server->RPC("recieve_heal",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); } + +// OJW - edge and team changes +void sendEDGECHANGE(RPCParameters *rpcParameters) +{ + server->RPC("recieveEDGECHANGE",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); +} + +void sendTEAMCHANGE(RPCParameters *rpcParameters) +{ + server->RPC("recieveTEAMCHANGE",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, true, 0, UNASSIGNED_NETWORK_ID,0); +} + // //void rINT(RPCParameters *rpcParameters)//who is first //{ @@ -276,119 +413,218 @@ void sendREAL(RPCParameters *rpcParameters) } } -int f_rec_num(int mode, SystemAddress sender)//from client data + +// 20081222 - OJW +void sendGAMEOVER(RPCParameters *rpcParameters) { + // ignore the RPCParams and send the server side scoreboard + server->RPC("recieveGAMEOVER",(const char*)gMPPlayerStats, sizeof(gMPPlayerStats)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); +} + +void sendCHATMSG(RPCParameters *rpcParameters) +{ + // ignore the RPCParams and send the server side scoreboard + server->RPC("recieveCHATMSG",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); +} + + + + +// OJW - 20081223 +// fix client disconnecting mid game, allowing the game to proceed +void HandleDisconnect(SystemAddress sender) +{ + // find the CLIENT_NUM of the player int x; client_data cl_record; + for ( x=0; x<4;x++) { cl_record = client_d[x]; - - if(mode==0)//find empty slot for new record + if(cl_record.address.binaryAddress==sender.binaryAddress && cl_record.address.port==sender.port) { - if(cl_record.address.binaryAddress==0) - return(x); + // notify all the clients of the disconnect + server->RPC("recieveDISCONNECT",(const char*)&cl_record.cl_number , sizeof(int)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + f_rec_num(2,sender); // remove from server's client list + break; } - if(mode==1)//wipe clean all - { - client_d[x].address.binaryAddress=0; - client_d[x].address.port=0; - client_d[x].cl_number=0; - } - if(mode==2)//clear one record - { - if(cl_record.address.binaryAddress==sender.binaryAddress && cl_record.address.port==sender.port) - { - client_d[x].address.port=0; - client_d[x].cl_number=0; - client_d[x].address.binaryAddress=0; - return(254); - } - - } - - } - if(mode == 0)//'no free slots' - { - ScreenMsg( FONT_RED, MSG_CHAT, L"Client Record Error, Restart Server, and Report Error." ); - return (255); - } - return(254); } +// OJW - 20081218 +// shuffle an integer array +// remove shuffledList and put directly into arr[] +void rSortArray(int* arr, int len) +{ + std::list tmpList; + std::list shuffledList; + std::list::iterator Iter; + int i=0; + + // add all our array items + for(i=0; i0; iRandPos--, Iter++); + //Iter += iRandPos; + shuffledList.push_front(*Iter); + tmpList.erase(Iter); + } + + // add all our elements + for(i=0; iinput; - client_info* clinf = (client_info*)rpcParameters->input; + //server assigned client numbers - hayden. + SystemAddress sender = rpcParameters->sender;//get senders address + int bslot = f_rec_num(0,blank);//get empty record slot + client_d[bslot].address=sender; //record clients address + int new_cl_num = bslot+1;//client number to assign + client_d[bslot].cl_number=new_cl_num; //record clients number - //server assigned client numbers - hayden. - SystemAddress sender = rpcParameters->sender;//get senders address - int bslot = f_rec_num(0,blank);//get empty record slot - client_d[bslot].address=sender; //record clients address - int new_cl_num = bslot+1;//client number to assign - client_d[bslot].cl_number=new_cl_num; //record clients number - - settings_struct lan; + settings_struct lan; - //lan.client_num = clinf->client_num;//old client assigned number - lan.client_num = new_cl_num; //new server assigned number - strcpy(lan.client_name , clinf->client_name); + //lan.client_num = clinf->client_num;//old client assigned number + lan.client_num = new_cl_num; //new server assigned number + strcpy(lan.client_name , clinf->client_name); - lan.max_clients = gsMAX_CLIENTS; - memcpy(lan.kitbag , kbag,sizeof (char)*100); - lan.damage_multiplier = gsDAMAGE_MULTIPLIER; + // OJW - 20081204 + strcpy(lan.server_name , SERVER_NAME); + memcpy(lan.client_edges,client_edges,sizeof(int)*4); + memcpy(lan.client_teams,client_teams,sizeof(int)*4); + + lan.RANDOM_SPAWN = RANDOM_SPAWN; + lan.RANDOM_MERCS = RANDOM_MERCS; + + lan.max_clients = gsMAX_CLIENTS; + memcpy(lan.kitbag , kbag,sizeof (char)*100); + lan.damage_multiplier = gsDAMAGE_MULTIPLIER; + + lan.same_merc = gsSAME_MERC; + lan.gsMercArriveSectorX=gsMercArriveSectorX; + lan.gsMercArriveSectorY=gsMercArriveSectorY; + + lan.ENEMY_ENABLED=ENEMY_ENABLED; + lan.CREATURE_ENABLED=CREATURE_ENABLED; + lan.MILITIA_ENABLED=MILITIA_ENABLED; + lan.CIV_ENABLED=CIV_ENABLED; + + lan.gsPLAYER_BSIDE=gsPLAYER_BSIDE; + + lan.emorale=gsMORALE; + lan.gsREPORT_NAME=gsREPORT_NAME; + //something new + lan.secs_per_tick=gssecs_per_tick; + lan.soubBobbyRay=gGameOptions.ubBobbyRay; + lan.sofGunNut=gGameOptions.fGunNut; + lan.soubGameStyle=gGameOptions.ubGameStyle; + lan.soubDifficultyLevel=gGameOptions.ubDifficultyLevel; + lan.sofTurnTimeLimit=gGameOptions.fTurnTimeLimit; + lan.sofIronManMode=gGameOptions.fIronManMode; + lan.starting_balance=gsstarting_balance; - lan.same_merc = gsSAME_MERC; + // OJW - 20090319 - Changing allow custom NIV to force NIV on all clients + // as with the new join screen setup, no way for the individual client to choose + // whether or not to use NIV. If this is wrong, its easily fixed... + // just change description text for the toggle option on the host screen to + // "Allow custom inventory" and delete this if statement. + if (sALLOW_CUSTOM_NIV==1) + gGameOptions.ubInventorySystem = INVENTORY_NEW; + + lan.sofNewInv=gGameOptions.ubInventorySystem; + + lan.soDis_Bobby=gsDis_Bobby; + lan.soDis_Equip=gsDis_Equip; + + lan.gsMAX_MERCS=gsMAX_MERCS; + + memcpy( lan.client_names , client_names, sizeof( char ) * 4 * 30 ); + lan.team=clinf->team; + + lan.TESTING=gsTESTING; + + // OJW - 20081218 + if (RANDOM_SPAWN) + lan.cl_edge = client_edges[lan.client_num-1]; + else + lan.cl_edge=clinf->cl_edge; + + // OJW - 20081223 + if (RANDOM_MERCS) + { + memcpy(lan.random_mercs, random_merc_teams[client_mercteam[lan.client_num - 1]], sizeof(int) * 7); + } + + lan.TIME=TIME; + lan.WEAPON_READIED_BONUS=sWEAPON_READIED_BONUS; + lan.ALLOW_CUSTOM_NIV=sALLOW_CUSTOM_NIV; + lan.DISABLE_SPEC_MODE=sDISABLE_SPEC_MODE; + + + server->RPC("recieveSETTINGS",(const char*)&lan, (int)sizeof(settings_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + } // end if(can_joingame) +} + +// added 081201 by Owen , allow the server to change the map while its still not in laptop mode +void send_mapchange(void) +{ + if (is_server && !allowlaptop) + { + mapchange_struct lan; + lan.gsMercArriveSectorX=gsMercArriveSectorX; lan.gsMercArriveSectorY=gsMercArriveSectorY; + lan.TIME=TIME; - lan.ENEMY_ENABLED=ENEMY_ENABLED; - lan.CREATURE_ENABLED=CREATURE_ENABLED; - lan.MILITIA_ENABLED=MILITIA_ENABLED; - lan.CIV_ENABLED=CIV_ENABLED; + server->RPC("recieveMAPCHANGE",(const char*)&lan, (int)sizeof(mapchange_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + } + else + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, MPServerMessage[45]); + } +} - lan.gsPLAYER_BSIDE=gsPLAYER_BSIDE; - - lan.emorale=gsMORALE; - lan.gsREPORT_NAME=gsREPORT_NAME; -//something new - lan.secs_per_tick=gssecs_per_tick; - lan.soubBobbyRay=gGameOptions.ubBobbyRay; - lan.sofGunNut=gGameOptions.fGunNut; - lan.soubGameStyle=gGameOptions.ubGameStyle; - lan.soubDifficultyLevel=gGameOptions.ubDifficultyLevel; - lan.sofTurnTimeLimit=gGameOptions.fTurnTimeLimit; - lan.sofIronManMode=gGameOptions.fIronManMode; - lan.starting_balance=gsstarting_balance; - - lan.sofNewInv=gGameOptions.ubInventorySystem; - - lan.soDis_Bobby=gsDis_Bobby; - lan.soDis_Equip=gsDis_Equip; - - lan.gsMAX_MERCS=gsMAX_MERCS; - - memcpy( lan.client_names , client_names, sizeof( char ) * 4 * 30 ); - lan.team=clinf->team; - - - lan.TESTING=gsTESTING; - - lan.cl_edge=clinf->cl_edge; - lan.TIME=TIME; - lan.WEAPON_READIED_BONUS=sWEAPON_READIED_BONUS; - lan.ALLOW_CUSTOM_NIV=sALLOW_CUSTOM_NIV; - lan.DISABLE_SPEC_MODE=sDISABLE_SPEC_MODE; - - - server->RPC("recieveSETTINGS",(const char*)&lan, (int)sizeof(settings_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); +// OJW 090212 +bool inline can_joingame() +{ + return !allowlaptop; +} +// Allow server to disconnect incoming clients after the game has started +void CheckIncomingConnection(Packet* p) +{ + // some clients might reconnect after disconnecting, either after the laptop is unlocked + // or after the game has started + // we dont want to allow this as thier game will be out of state + if (!can_joingame()) + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"CONNECTION REJECTED - GAME HAS STARTED"); + // disconnect this client, no need to notify them as they will know if they disconnected + // before receiving a settings packet that they were not allowed to join + server->CloseConnection(p->systemAddress, true); + } } @@ -428,10 +664,18 @@ void start_server (void) char time_div[30]; char mor[30]; + char sRandomMercs[30]; + char sRandomEdges[30]; + + // OJW - 20081204 + GetPrivateProfileString( "Ja2_mp Settings","SERVER_NAME", "", SERVER_NAME, MAX_PATH, "..\\Ja2_mp.ini" ); + GetPrivateProfileString( "Ja2_mp Settings","SAME_MERC", "", hire_same_merc, MAX_PATH, "..\\Ja2_mp.ini" ); GetPrivateProfileString( "Ja2_mp Settings","DISABLE_MORALE", "", mor, MAX_PATH, "..\\Ja2_mp.ini" ); GetPrivateProfileString( "Ja2_mp Settings","MAX_CLIENTS", "", maxclients, MAX_PATH, "..\\Ja2_mp.ini" ); GetPrivateProfileString( "Ja2_mp Settings","DAMAGE_MULTIPLIER", "", net_div, MAX_PATH, "..\\Ja2_mp.ini" ); + GetPrivateProfileString( "Ja2_mp Settings","RANDOM_MERCS", "", sRandomMercs, MAX_PATH, "..\\Ja2_mp.ini" ); + GetPrivateProfileString( "Ja2_mp Settings","RANDOM_EDGES", "", sRandomEdges, MAX_PATH, "..\\Ja2_mp.ini" ); GetPrivateProfileString( "Ja2_mp Settings","ENEMY_ENABLED", "", bteam1_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); //GetPrivateProfileString( "Ja2_mp Settings","CREATURE_ENABLED", "", bteam2_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); @@ -479,14 +723,30 @@ void start_server (void) MILITIA_ENABLED=0; CIV_ENABLED=0; -if(gsPLAYER_BSIDE==2)//only enable ai during coop -{ - ENEMY_ENABLED =atoi(bteam1_enabled); - //CREATURE_ENABLED =atoi(bteam2_enabled); - MILITIA_ENABLED =atoi(bteam3_enabled); - CIV_ENABLED =atoi(bteam4_enabled); + RANDOM_MERCS = atoi(sRandomMercs); + RANDOM_SPAWN = atoi(sRandomEdges); -} + if (RANDOM_SPAWN) + { + // create random starting edges + int spawns[4] = { 0 , 1 , 2 , 3 }; + rSortArray(spawns,4); + memcpy(client_edges,spawns,sizeof(int)*4); + } + + if (RANDOM_MERCS) + { + // randomly sort team indexes to give client + // one of four random merc teams + rSortArray(client_mercteam,4); + } + + if(gsPLAYER_BSIDE==2)//only enable ai during coop + { + ENEMY_ENABLED = 1; // always enable enemies in co-op + MILITIA_ENABLED = atoi(bteam3_enabled); + CIV_ENABLED = atoi(bteam4_enabled); + } gsSAME_MERC = atoi(hire_same_merc); gsDAMAGE_MULTIPLIER =(FLOAT)atof(net_div); @@ -560,6 +820,10 @@ if(gsPLAYER_BSIDE==2)//only enable ai during coop REGISTER_STATIC_RPC(server, startCOMBAT); REGISTER_STATIC_RPC(server, sendWIPE); REGISTER_STATIC_RPC(server, sendHEAL); + REGISTER_STATIC_RPC(server, sendEDGECHANGE); + REGISTER_STATIC_RPC(server, sendTEAMCHANGE); + REGISTER_STATIC_RPC(server, sendGAMEOVER); + REGISTER_STATIC_RPC(server, sendCHATMSG); //REGISTER_STATIC_RPC(server, rINT); // @@ -614,7 +878,7 @@ void server_packet ( void ) case ID_DISCONNECTION_NOTIFICATION://client disconnected purposefullly // Connection lost normally ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"ID_DISCONNECTION_NOTIFICATION"); - f_rec_num(2, p->systemAddress);//clear record + HandleDisconnect(p->systemAddress);//clear record break; case ID_ALREADY_CONNECTED: // Connection lost normally @@ -641,7 +905,7 @@ void server_packet ( void ) // Couldn't deliver a reliable packet - i.e. the other system was abnormally // terminated ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"ID_CONNECTION_LOST");//client dropped - f_rec_num(2, p->systemAddress);//clear record + HandleDisconnect(p->systemAddress);//clear record break; case ID_CONNECTION_REQUEST_ACCEPTED: // This tells the client they have connected @@ -650,6 +914,8 @@ void server_packet ( void ) case ID_NEW_INCOMING_CONNECTION: //tells server client has connected ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"ID_NEW_INCOMING_CONNECTION"); + // make sure they can connect + CheckIncomingConnection(p); //send_settings();//send off server set settings break; case ID_MODIFIED_PACKET: @@ -700,4 +966,4 @@ void server_disconnect (void) { ScreenMsg( FONT_LTBLUE, MSG_CHAT, MPServerMessage[7]); } -} +} \ No newline at end of file diff --git a/Options Screen.cpp b/Options Screen.cpp index 172a7e5b..af84da1f 100644 --- a/Options Screen.cpp +++ b/Options Screen.cpp @@ -253,7 +253,6 @@ void RenderOptionsScreen(); void ExitOptionsScreen(); void HandleOptionsScreen(); void GetOptionsScreenUserInput(); -void SetOptionsExitScreen( UINT32 uiExitScreen ); void SoundFXSliderChangeCallBack( INT32 iNewValue ); diff --git a/Options Screen.h b/Options Screen.h index 46872b8e..e4f3194a 100644 --- a/Options Screen.h +++ b/Options Screen.h @@ -23,6 +23,8 @@ UINT32 OptionsScreenInit( void ); void SetOptionsScreenToggleBoxes(); void GetOptionsScreenToggleBoxes(); +// OJW - moved this here so can exit options screen on client disconnect +void SetOptionsExitScreen( UINT32 uiExitScreen ); BOOLEAN DoOptionsMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); diff --git a/SCREENS.cpp b/SCREENS.cpp index 7387c435..46b2745e 100644 --- a/SCREENS.cpp +++ b/SCREENS.cpp @@ -55,7 +55,10 @@ Screens GameScreens[MAX_SCREENS] = { DemoExitScreenInit, DemoExitScreenHandle, DemoExitScreenShutdown }, { IntroScreenInit, IntroScreenHandle, IntroScreenShutdown }, { CreditScreenInit, CreditScreenHandle, CreditScreenShutdown }, - + { MPJoinScreenInit, MPJoinScreenHandle, MPJoinScreenShutdown }, // OJW - 20081129 + { MPHostScreenInit, MPHostScreenHandle, MPHostScreenShutdown }, + { MPScoreScreenInit, MPScoreScreenHandle, MPScoreScreenShutdown }, // OJW - 20081222 + { MPChatScreenInit, MPChatScreenHandle, MPChatScreenShutdown }, // OJW - 20090314 #ifdef JA2BETAVERSION { AIViewerScreenInit, AIViewerScreenHandle, AIViewerScreenShutdown }, diff --git a/Standard Gaming Platform/Button System.cpp b/Standard Gaming Platform/Button System.cpp index f1adb7a7..aad234aa 100644 --- a/Standard Gaming Platform/Button System.cpp +++ b/Standard Gaming Platform/Button System.cpp @@ -2467,6 +2467,43 @@ BOOLEAN SpecifyButtonIcon( INT32 iButtonID, INT32 iVideoObjectID, UINT16 usVideo return TRUE; } +//OJW - 20081224 +BOOLEAN SpecifyButtonImage( INT32 iButtonID, UINT32 iButtonImageID) +{ + GUI_BUTTON *b; + + Assert( iButtonID >= 0 ); + Assert( iButtonID < MAX_BUTTONS ); + b = ButtonList[ iButtonID ]; + Assert( b ); + + // Is there a QuickButton image in the given image slot? + if(ButtonPictures[iButtonImageID].vobj == NULL) + { + DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number"); + return false; + } + + b->ImageNum = iButtonImageID; + + return TRUE; +} + +BOOLEAN SpecifyButtonImage( GUI_BUTTON *b, UINT32 iButtonImageID) +{ + Assert( b ); + + // Is there a QuickButton image in the given image slot? + if(ButtonPictures[iButtonImageID].vobj == NULL) + { + DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number"); + return false; + } + + b->ImageNum = iButtonImageID; + + return TRUE; +} void RemoveTextFromButton( INT32 iButtonID ) { GUI_BUTTON *b; diff --git a/Standard Gaming Platform/Button System.h b/Standard Gaming Platform/Button System.h index fd00a0d8..1970b131 100644 --- a/Standard Gaming Platform/Button System.h +++ b/Standard Gaming Platform/Button System.h @@ -287,6 +287,9 @@ void SpecifyButtonTextSubOffsets( INT32 iButtonID, INT8 bTextXOffset, INT8 bText void SpecifyButtonTextWrappedWidth(INT32 iButtonID, INT16 sWrappedWidth); void SpecifyButtonSoundScheme( INT32 iButtonID, INT8 bSoundScheme ); +//OJW - 20081224 +BOOLEAN SpecifyButtonImage( INT32 iButtonID, UINT32 iButtonImageID); +BOOLEAN SpecifyButtonImage( GUI_BUTTON *b, UINT32 iButtonImageID); void PlayButtonSound( INT32 iButtonID, INT32 iSoundType ); void AllowDisabledButtonFastHelp( INT32 iButtonID, BOOLEAN fAllow ); diff --git a/Strategic/Map Screen Interface Bottom.cpp b/Strategic/Map Screen Interface Bottom.cpp index f322f90d..410b5b65 100644 --- a/Strategic/Map Screen Interface Bottom.cpp +++ b/Strategic/Map Screen Interface Bottom.cpp @@ -49,6 +49,7 @@ #include "GameSettings.h" #include "_Ja25EnglishText.h" #include "SaveLoadScreen.h" +#include "game init.h" #endif #include "connect.h" @@ -1649,7 +1650,7 @@ BOOLEAN AnyUsableRealMercenariesOnTeam( void ) void RequestTriggerExitFromMapscreen( INT8 bExitToWhere ) { - Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_SAVE ) ); + Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_MAINMENU ) ); // if allowed to do so if ( AllowedToExitFromMapscreenTo( bExitToWhere ) ) @@ -1665,6 +1666,18 @@ void RequestTriggerExitFromMapscreen( INT8 bExitToWhere ) return; } } + else if (!(bExitToWhere == MAP_EXIT_TO_TACTICAL || bExitToWhere == MAP_EXIT_TO_MAINMENU)) + { + // OJW - 20090301 + if (is_networked && is_client) + { + if (client_ready[CLIENT_NUM-1]==1 && is_game_started == false) + { + // un-ready if we are not on map screen + start_battle(); + } + } + } // permit it, and get the ball rolling gbExitingMapScreenToWhere = bExitToWhere; @@ -1680,7 +1693,7 @@ void RequestTriggerExitFromMapscreen( INT8 bExitToWhere ) BOOLEAN AllowedToExitFromMapscreenTo( INT8 bExitToWhere ) { - Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_SAVE ) ); + Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_MAINMENU ) ); // if already leaving, disallow any other attempts to exit if ( fLeavingMapScreen ) @@ -1688,6 +1701,13 @@ BOOLEAN AllowedToExitFromMapscreenTo( INT8 bExitToWhere ) return( FALSE ); } + // OJW - 20090210 - clean resources on disconnect + if (bExitToWhere == MAP_EXIT_TO_MAINMENU) + { + // always allow this + return( TRUE ); + } + // WANNE: At least one merc must be hired so we can go to tactical. // This was an exploit. If you go to tactical in Omerta and have not hired any merc // then go back to laptop and hire a merc. After the merc arrives the heli landing was not @@ -1839,7 +1859,12 @@ void HandleExitsFromMapScreen( void ) guiPreviousOptionScreen = guiCurrentScreen; SetPendingNewScreen( SAVE_LOAD_SCREEN ); break; - + // OJW - 20090210 - clean resources on disconnect + case MAP_EXIT_TO_MAINMENU: + // Re-initialise the game + ReStartingGame(); + SetPendingNewScreen( MAINMENU_SCREEN ); + break; default: // invalid exit type Assert( FALSE ); diff --git a/Strategic/Map Screen Interface Bottom.h b/Strategic/Map Screen Interface Bottom.h index 25bb2820..54950ea6 100644 --- a/Strategic/Map Screen Interface Bottom.h +++ b/Strategic/Map Screen Interface Bottom.h @@ -15,6 +15,8 @@ enum{ MAP_EXIT_TO_OPTIONS, MAP_EXIT_TO_LOAD, MAP_EXIT_TO_SAVE, + // OJW - 20090210 - clean resources on disconnect + MAP_EXIT_TO_MAINMENU }; // there's no button for entering SAVE/LOAD screen directly... diff --git a/Strategic/mapscreen.cpp b/Strategic/mapscreen.cpp index dad46dff..a619022f 100644 --- a/Strategic/mapscreen.cpp +++ b/Strategic/mapscreen.cpp @@ -341,6 +341,37 @@ int SOLDIER_HAND_Y; //int CLOCK_X; //int CLOCK_Y; +// OJW: MP POSITIONS +int MP_BTN_Y; +int MP_ROWSTART_Y; +int MP_PLAYER_X; +int MP_PLAYER_W; +int MP_TEAM_X; +int MP_TEAM_W; +int MP_COMPASS_X; +int MP_COMPASS_W; +int MP_GAMEINFO_X; +int MP_GAMEINFO_W; + +#define MAX_MP_BUTTONS 4 + +INT gMapMPButtonsX[ MAX_MP_BUTTONS ] = {5 , 84 , 130 , 154 }; + +#define MP_BTN_STARTGAME 4 +#define MP_BTN_READY 3 + + +INT32 giMapMPButtonImage[ MAX_MP_BUTTONS+1 ] = { -1, -1, -1, -1 ,-1}; +INT32 giMapMPButton[ MAX_MP_BUTTONS ] = { -1, -1, -1, -1}; + +// Compass Drowndown +INT32 ghMPCompassBox; +INT32 ghMPTeamBox; +MOUSE_REGION gMPReadyButtonRegion; +MOUSE_REGION gCompassMenuRegion[MAX_EDGES]; +MOUSE_REGION gTeamMenuRegion[MAX_MP_TEAMS]; +bool is_compass_box_open = false; +bool is_team_box_open = false; #define RGB_WHITE ( FROMRGB( 255, 255, 255 ) ) #define RGB_YELLOW ( FROMRGB( 255, 255, 0 ) ) @@ -825,6 +856,23 @@ void AddTeamPanelSortButtonsForMapScreen( void ); void RemoveTeamPanelSortButtonsForMapScreen( void ); void SortListOfMercsInTeamPanel( BOOLEAN fRetainSelectedMercs, BOOLEAN fReverse = FALSE ); +// OJW - buttons and boxes for MP interface +void AddMPButtonsForMapScreen( void ); +void RemoveMPButtonsForMapScreen( void ); +void InitializeMPCoordinates( void ); +void CreateMPCompassBox( void ); +void DestroyMPCompassBox( void ); +void CreateMPTeamBox( void ); +void DestroyMPTeamBox( void ); +void MPReadyButtonCallback( GUI_BUTTON *btn, INT32 reason ); +void MPCompassChangeCallback( MOUSE_REGION * pReason, INT32 iReason); +void CreateDestroyMouseRegionsForCompassBox(); +void CompassBoxMvtCallback ( MOUSE_REGION* pRegion, INT32 iReason); +void CompassBoxBtnCallback ( MOUSE_REGION* pRegion, INT32 iReason); +void MPTeamChangeCallback( MOUSE_REGION * pReason, INT32 iReason); +void CreateDestroyMouseRegionsForTeamBox(); +void TeamBoxMvtCallback ( MOUSE_REGION* pRegion, INT32 iReason); +void TeamBoxBtnCallback ( MOUSE_REGION* pRegion, INT32 iReason); // Rendering void RenderCharacterInfoBackground( void ); @@ -977,6 +1025,7 @@ void BltCharInvPanel(); void DrawCharacterInfo(INT16 sCharNumber); void DisplayCharacterInfo( void ); void UpDateStatusOfContractBox( void ); +void DrawMPPlayerList (); // OJW - 20081201 // get which index in the mapscreen character list is this guy INT32 GetIndexForthis( SOLDIERTYPE *pSoldier ); @@ -1347,6 +1396,8 @@ BOOLEAN InitializeInvPanelCoordsOld() //CLOCK_X = (SCREEN_WIDTH - 86); //CLOCK_Y = (SCREEN_HEIGHT - 21); + //OJW - MP interface changes + InitializeMPCoordinates(); gSCamoXY.sX = INV_BODY_X; gSCamoXY.sY = INV_BODY_Y; // X, Y Location of Map screen's Camouflage region return ( TRUE ); @@ -1667,8 +1718,40 @@ BOOLEAN InitializeInvPanelCoordsNew() gSCamoXY.sX = INV_BODY_X; gSCamoXY.sY = INV_BODY_Y; // X, Y Location of Map screen's Camouflage region + //OJW - MP interface changes + InitializeMPCoordinates(); + + return ( TRUE ); } +void InitializeMPCoordinates() +{ + //OJW - MP interface changes + if (iResolution == 0) + { + MP_BTN_Y = 268; + } + else if (iResolution == 1) + { + MP_BTN_Y = 386; + } + else if (iResolution == 2) + { + MP_BTN_Y = 554; + } + + MP_ROWSTART_Y = MP_BTN_Y + 21; + MP_PLAYER_X = 5; + MP_PLAYER_W = 75; + MP_TEAM_X = 84; + MP_TEAM_W = 40; + MP_COMPASS_X = 130; + MP_COMPASS_W = 19; + MP_GAMEINFO_X = 154; + MP_GAMEINFO_W = 81; + + // End of MP interface changes +} BOOLEAN InitializeInvPanelCoordsVehicle( ) { InitializeInvPanelCoordsNew(); @@ -3666,6 +3749,9 @@ void DisplayCharacterList() } } + // draw multiplayer player list + if (is_networked && is_client) + DrawMPPlayerList(); HandleDisplayOfSelectedMercArrows( ); SetFontDestBuffer(FRAME_BUFFER ,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,FALSE); @@ -3677,6 +3763,487 @@ void DisplayCharacterList() return; } +// OJW - Added 081201 +// Draw Lan clients in the vehicle slots +// change the graphics, add more relevant info... +// this is just a temp test +void DrawMPPlayerList () +{ + INT16 usX=0; + INT16 usY=0; + + if (is_networked && is_client && is_connected) + { + wchar_t szPlayerName[30]; + wchar_t szTeam[20]; + wchar_t szCompass[2]; + int row=0; + for(int i=0; i < 4; i++) + { + //if (i != CLIENT_NUM) + //{ + if (client_names[i] != NULL) + { + if (client_ready[i]==1) + { + SetFontForeground( FONT_GREEN ); + } + else + { + SetFontForeground( FONT_WHITE ); + } + + if (strcmp(client_names[i],"")!=0) + { + // valid player + memset(szPlayerName,0,30*sizeof(wchar_t)); + mbstowcs( szPlayerName,client_names[i],30); + FindFontCenterCoordinates((short)MP_PLAYER_X + 1, (short)(MP_ROWSTART_Y+(row*Y_SIZE)), (short)MP_PLAYER_W, (short)Y_SIZE, szPlayerName, (long)MAP_SCREEN_FONT, &usX, &usY); + DrawString( (STR16)szPlayerName , usX,usY, MAP_SCREEN_FONT); + + // check for gametype here + //wcscpy(szTeam,L"N/A"); + if (PLAYER_BSIDE==MP_TYPE_DEATHMATCH) + wcscpy(szTeam,L"N/A"); + else + wcscpy(szTeam,gszMPTeamNames[client_teams[i]]); + FindFontCenterCoordinates((short)MP_TEAM_X + 1, (short)(MP_ROWSTART_Y+(row*Y_SIZE)), (short)MP_TEAM_W, (short)Y_SIZE, szTeam, (long)MAP_SCREEN_FONT, &usX, &usY); + DrawString( szTeam,usX,(short)usY, MAP_SCREEN_FONT); + + wcscpy(szCompass,(RANDOM_SPAWN==1 ? L"?" : gszMPEdgesText[client_edges[i]])); + FindFontCenterCoordinates((short)MP_COMPASS_X + 1, (short)(MP_ROWSTART_Y+(row*Y_SIZE)), (short)MP_COMPASS_W, (short)Y_SIZE, szCompass, (long)MAP_SCREEN_FONT, &usX, &usY); + DrawString(szCompass , usX,(short)usY, MAP_SCREEN_FONT); + + row++; + } + + } + + //} + } + + // Draw the Server Info + + // Server name + // change this text to wrap + /*wchar_t szServerName[30]; + memset(szServerName,0,30*sizeof(wchar_t)); + mbstowcs( szServerName,SERVER_NAME,30); + + SetFontForeground( FONT_YELLOW ); + DrawString( L"Server Name:" , MP_GAMEINFO_X ,MP_ROWSTART_Y, MAP_SCREEN_FONT); + SetFontForeground( FONT_WHITE ); + DrawString( (STR16)szServerName , MP_GAMEINFO_X ,MP_ROWSTART_Y+(1*Y_SIZE), MAP_SCREEN_FONT);*/ + + // Game Type + SetFontForeground( FONT_YELLOW ); + DrawString( gszMPMapscreenText[0] , MP_GAMEINFO_X ,MP_ROWSTART_Y, MAP_SCREEN_FONT); + SetFontForeground( FONT_WHITE ); + + switch(PLAYER_BSIDE) + { + case MP_TYPE_DEATHMATCH: + DrawString( gzMPHScreenText[MPH_DEATHMATCH_TEXT] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(1*Y_SIZE), MAP_SCREEN_FONT); + break; + case MP_TYPE_TEAMDEATMATCH: + DrawString( gzMPHScreenText[MPH_TEAMDM_TEXT] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(1*Y_SIZE), MAP_SCREEN_FONT); + break; + case MP_TYPE_COOP: + DrawString( gzMPHScreenText[MPH_COOP_TEXT] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(1*Y_SIZE), MAP_SCREEN_FONT); + break; + } + + // Max Players + SetFontForeground( FONT_YELLOW ); + DrawString( gszMPMapscreenText[1] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(2*Y_SIZE), MAP_SCREEN_FONT); + SetFontForeground( FONT_WHITE ); + + wchar_t szMaxPlayers[10]; + swprintf(szMaxPlayers,L"%i",MAX_CLIENTS); + DrawString( szMaxPlayers , MP_GAMEINFO_X + StringPixLength(gszMPMapscreenText[1],MAP_SCREEN_FONT),MP_ROWSTART_Y+(2*Y_SIZE), MAP_SCREEN_FONT); + + // Number of Mercs + SetFontForeground( FONT_YELLOW ); + DrawString( gszMPMapscreenText[2] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(3*Y_SIZE), MAP_SCREEN_FONT); + SetFontForeground( FONT_WHITE ); + + wchar_t szSquadSize[10]; + swprintf(szSquadSize,L"%i",MAX_MERCS); + DrawString( szSquadSize , MP_GAMEINFO_X + StringPixLength(gszMPMapscreenText[2],MAP_SCREEN_FONT),MP_ROWSTART_Y+(3*Y_SIZE), MAP_SCREEN_FONT); + + if (RANDOM_MERCS) + { + // Random Mercs + SetFontForeground( FONT_YELLOW ); + DrawString( gszMPMapscreenText[5] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(4*Y_SIZE), MAP_SCREEN_FONT); + SetFontForeground( FONT_WHITE ); + DrawString( gszMPMapscreenText[6] , MP_GAMEINFO_X + StringPixLength(gszMPMapscreenText[5],MAP_SCREEN_FONT),MP_ROWSTART_Y+(4*Y_SIZE), MAP_SCREEN_FONT); + } + + } +} +void DestroyMPCompassBox( void ) +{ + RemoveBox(ghMPCompassBox); + ghMPCompassBox = -1; +} +void CreateMPCompassBox( void ) +{ + UINT32 hStringHandle; + UINT32 uiCounter; + + + // will create attribute pop up menu for mapscreen assignments + SGPPoint CompassPosition = { MP_COMPASS_X, MP_ROWSTART_Y }; + SGPRect CompassDimensions = { 0,0, 100, 95}; + + + // create basic box + CreatePopUpBox(&ghMPCompassBox, CompassDimensions, CompassPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE )); + + // which buffer will box render to + SetBoxBuffer(ghMPCompassBox, FRAME_BUFFER); + + // border type? + SetBorderType(ghMPCompassBox,guiPOPUPBORDERS); + + // background texture + SetBackGroundSurface(ghMPCompassBox, guiPOPUPTEX); + + // margin sizes + SetMargins(ghMPCompassBox, 6, 6, 4, 4 ); + + // space between lines + SetLineSpace(ghMPCompassBox, 2); + + // set current box to this one + SetCurrentBox( ghMPCompassBox ); + + // add strings for box + for(uiCounter=0; uiCounter < MAX_EDGES; uiCounter++) + { + + AddMonoString(&hStringHandle, gszMPEdgesText[uiCounter] ); + + // make sure it is unhighlighted + UnHighLightLine(hStringHandle); + } + + // set font type + SetBoxFont(ghMPCompassBox, MAP_SCREEN_FONT); + + // set highlight color + SetBoxHighLight(ghMPCompassBox, FONT_WHITE); + + // unhighlighted color + SetBoxForeground(ghMPCompassBox, FONT_LTGREEN); + + // background color + SetBoxBackground(ghMPCompassBox, FONT_BLACK); + + // shaded color..for darkened text + SetBoxShade( ghMPCompassBox, FONT_GRAY7 ); + SetBoxSecondaryShade( ghMPCompassBox, FONT_YELLOW ); + + // resize box to text + ResizeBoxToText( ghMPCompassBox ); + + //DetermineBoxPositions( ); +} +void CreateDestroyMouseRegionsForCompassBox() +{ + INT32 iFontHeight = 0; + INT32 iBoxXPosition = 0; + INT32 iBoxYPosition = 0; + INT32 iCounter = 0; + SGPPoint pPosition; + INT32 iBoxWidth = 0; + SGPRect pDimensions; + + if (!is_compass_box_open) + { + + // grab height of font + iFontHeight = GetLineSpace( ghMPCompassBox ) + GetFontHeight( GetBoxFont( ghMPCompassBox ) ); + + // get x.y position of box + GetBoxPosition( ghMPCompassBox, &pPosition); + + // grab box x and y position + iBoxXPosition = pPosition.iX; + iBoxYPosition = pPosition.iY; + + // get dimensions..mostly for width + GetBoxSize( ghMPCompassBox, &pDimensions ); + + // get width + iBoxWidth = pDimensions.iRight; + + SetCurrentBox( ghMPCompassBox ); + + // define regions + for( iCounter = 0; iCounter < MAX_EDGES; iCounter++ ) + { + // add mouse region for each line of text..and set user data + MSYS_DefineRegion( &gCompassMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghMPCompassBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghMPCompassBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 , + MSYS_NO_CURSOR, CompassBoxMvtCallback, CompassBoxBtnCallback ); + + MSYS_SetRegionUserData( &gCompassMenuRegion[ iCounter ], 0, iCounter ); + } + } + else + { + // destroy regions + for( iCounter = 0; iCounter < MAX_EDGES; iCounter++ ) + { + // add mouse region for each line of text..and set user data + MSYS_RemoveRegion( &gCompassMenuRegion[ iCounter ] ); + } + } +} +void CompassBoxMvtCallback ( MOUSE_REGION* pRegion, INT32 iReason) +{ + // mvt callback handler for assignment region + INT32 iValue = -1; + + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + + if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE ) + { + if( GetBoxShadeFlag( ghMPCompassBox, iValue ) == FALSE ) + { + HighLightBoxLine( ghMPCompassBox, iValue ); + } + } + else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + // unhighlight all strings in box + UnHighLightBox( ghMPCompassBox ); + } +} +void CompassBoxBtnCallback ( MOUSE_REGION* pRegion, INT32 iReason) +{ + INT32 iValue = -1; + + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + + + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + UnHighLightBox( ghMPCompassBox ); + + /*switch( iValue ) + { + case MP_EDGE_NORTH: + break; + case MP_EDGE_SOUTH: + break; + case MP_EDGE_EAST: + break; + case MP_EDGE_WEST: + break; + }*/ + + // send edge change to all clients, if allowed :) + send_edgechange(iValue); + + + // close the box + CreateDestroyMouseRegionsForCompassBox(); + HideBox(ghMPCompassBox); + is_compass_box_open = false; + fTeamPanelDirty = true; + } + else if( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) + { + // close the box + CreateDestroyMouseRegionsForCompassBox(); + HideBox(ghMPCompassBox); + is_compass_box_open = false; + fTeamPanelDirty = true; + } +} +void DestroyMPTeamBox( void ) +{ + RemoveBox(ghMPTeamBox); + ghMPTeamBox = -1; +} +void CreateMPTeamBox( void ) +{ + UINT32 hStringHandle; + UINT32 uiCounter; + + + // will create attribute pop up menu for mapscreen assignments + SGPPoint TeamPosition = { MP_TEAM_X, MP_ROWSTART_Y }; + SGPRect TeamDimensions = { 0,0, 100, 95}; + + + // create basic box + CreatePopUpBox(&ghMPTeamBox, TeamDimensions, TeamPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE )); + + // which buffer will box render to + SetBoxBuffer(ghMPTeamBox, FRAME_BUFFER); + + // border type? + SetBorderType(ghMPTeamBox,guiPOPUPBORDERS); + + // background texture + SetBackGroundSurface(ghMPTeamBox, guiPOPUPTEX); + + // margin sizes + SetMargins(ghMPTeamBox, 6, 6, 4, 4 ); + + // space between lines + SetLineSpace(ghMPTeamBox, 2); + + // set current box to this one + SetCurrentBox( ghMPTeamBox ); + + // add strings for box + for(uiCounter=0; uiCounter < MAX_MP_TEAMS; uiCounter++) + { + + AddMonoString(&hStringHandle, gszMPTeamNames[uiCounter] ); + + // make sure it is unhighlighted + UnHighLightLine(hStringHandle); + } + + // set font type + SetBoxFont(ghMPTeamBox, MAP_SCREEN_FONT); + + // set highlight color + SetBoxHighLight(ghMPTeamBox, FONT_WHITE); + + // unhighlighted color + SetBoxForeground(ghMPTeamBox, FONT_LTGREEN); + + // background color + SetBoxBackground(ghMPTeamBox, FONT_BLACK); + + // shaded color..for darkened text + SetBoxShade( ghMPTeamBox, FONT_GRAY7 ); + SetBoxSecondaryShade( ghMPTeamBox, FONT_YELLOW ); + + // resize box to text + ResizeBoxToText( ghMPTeamBox ); + + //DetermineBoxPositions( ); +} +void CreateDestroyMouseRegionsForTeamBox() +{ + INT32 iFontHeight = 0; + INT32 iBoxXPosition = 0; + INT32 iBoxYPosition = 0; + INT32 iCounter = 0; + SGPPoint pPosition; + INT32 iBoxWidth = 0; + SGPRect pDimensions; + + if (!is_team_box_open) + { + + // grab height of font + iFontHeight = GetLineSpace( ghMPTeamBox ) + GetFontHeight( GetBoxFont( ghMPTeamBox ) ); + + // get x.y position of box + GetBoxPosition( ghMPTeamBox, &pPosition); + + // grab box x and y position + iBoxXPosition = pPosition.iX; + iBoxYPosition = pPosition.iY; + + // get dimensions..mostly for width + GetBoxSize( ghMPTeamBox, &pDimensions ); + + // get width + iBoxWidth = pDimensions.iRight; + + SetCurrentBox( ghMPTeamBox ); + + // define regions + for( iCounter = 0; iCounter < MAX_EDGES; iCounter++ ) + { + // add mouse region for each line of text..and set user data + MSYS_DefineRegion( &gTeamMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghMPTeamBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghMPTeamBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 , + MSYS_NO_CURSOR, TeamBoxMvtCallback, TeamBoxBtnCallback ); + + MSYS_SetRegionUserData( &gTeamMenuRegion[ iCounter ], 0, iCounter ); + } + } + else + { + // destroy regions + for( iCounter = 0; iCounter < MAX_MP_TEAMS; iCounter++ ) + { + // add mouse region for each line of text..and set user data + MSYS_RemoveRegion( &gTeamMenuRegion[ iCounter ] ); + } + } +} +void TeamBoxMvtCallback ( MOUSE_REGION* pRegion, INT32 iReason) +{ + // mvt callback handler for assignment region + INT32 iValue = -1; + + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + + if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE ) + { + if( GetBoxShadeFlag( ghMPTeamBox, iValue ) == FALSE ) + { + HighLightBoxLine( ghMPTeamBox, iValue ); + } + } + else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + // unhighlight all strings in box + UnHighLightBox( ghMPTeamBox ); + } +} +void TeamBoxBtnCallback ( MOUSE_REGION* pRegion, INT32 iReason) +{ + INT32 iValue = -1; + + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + + + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + UnHighLightBox( ghMPTeamBox ); + + /*switch( iValue ) + { + case MP_EDGE_NORTH: + break; + case MP_EDGE_SOUTH: + break; + case MP_EDGE_EAST: + break; + case MP_EDGE_WEST: + break; + }*/ + + // send team change to all clients, if allowed :) + send_teamchange(iValue); + + + // close the box + CreateDestroyMouseRegionsForTeamBox(); + HideBox(ghMPTeamBox); + is_team_box_open = false; + fTeamPanelDirty = true; + } + else if( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) + { + // close the box + CreateDestroyMouseRegionsForTeamBox(); + HideBox(ghMPTeamBox); + is_team_box_open = false; + fTeamPanelDirty = true; + } +} // THIS IS STUFF THAT RUNS *ONCE* DURING APPLICATION EXECUTION, AT INITIAL STARTUP @@ -3716,6 +4283,12 @@ UINT32 MapScreenShutdown(void) // destroy some popup boxes fShowAssignmentMenu = FALSE; CreateDestroyAssignmentPopUpBoxes( ); + // OJW + if (is_networked) + { + DestroyMPCompassBox(); + DestroyMPTeamBox(); + } fShowContractMenu = FALSE; DetermineIfContractMenuCanBeShown( ); @@ -3827,6 +4400,9 @@ UINT32 MapScreenHandle(void) // handle the sort buttons AddTeamPanelSortButtonsForMapScreen( ); + // OJW - 20081204 + if (is_networked) + AddMPButtonsForMapScreen(); // load bottom graphics LoadMapScreenInterfaceBottom( ); @@ -3917,17 +4493,36 @@ UINT32 MapScreenHandle(void) CHECKF(AddVideoSurface( &vs_desc, &guiCHARLIST ));*/ VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; - if (iResolution == 0) + if (!is_networked) { - FilenameForBPP("INTERFACE\\newgoldpiece3.sti", VObjectDesc.ImageFile ); + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\newgoldpiece3.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\newgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\newgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + } } - else if (iResolution == 1) + else { - FilenameForBPP("INTERFACE\\newgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); - } - else if (iResolution == 2) - { - FilenameForBPP("INTERFACE\\newgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + // OJW - 20081204 - change mapscreen interface for MP games + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + } } CHECKF(AddVideoObject(&VObjectDesc, &guiCHARLIST)); @@ -4200,6 +4795,12 @@ UINT32 MapScreenHandle(void) CreateDestroyAssignmentPopUpBoxes( ); fShowAssignmentMenu = FALSE; + // OJW + if (is_networked) + { + CreateMPCompassBox(); + CreateMPTeamBox(); + } // create merc remove box CreateMercRemoveAssignBox( ); @@ -4305,6 +4906,25 @@ UINT32 MapScreenHandle(void) // don't process any input until we've been through here once if( gfFirstMapscreenFrame == FALSE ) { + // OJW - 20081129 + // Auto-start server or join server + if (is_networked) + { + // this function does nothing if + // already connected + NetworkAutoStart(); + + // handle changing picture on start game button + // for server + if (is_server) + { + if (allowlaptop && ButtonList [ giMapMPButton[3] ]->ImageNum == giMapMPButtonImage [4]) + { + // Change server's button to "ready" + SpecifyButtonImage( giMapMPButton [3] , giMapMPButtonImage [3] ); + } + } + } // Handle Interface uiNewScreen = HandleMapUI( ); if ( uiNewScreen != MAP_SCREEN ) @@ -5499,7 +6119,13 @@ UINT32 HandleMapUI( ) // added by haydent if (is_networked) + { ChangeSelectedMapSector( sMapX, sMapY, ( INT8 )iCurrentMapSectorZ ); + // OJW - 20081201 - change this state away from allowlaptop to its own field + // or something more seperate from that concept + if (is_server && !allowlaptop) + send_mapchange(); + } } else { @@ -6097,53 +6723,55 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) // ROMAN:0 multiplayer: Maybe we need to change the keys, because they are bound to other functions + // OJW - 20090210 - disabling the old method's for starting server and disconnecting + // as they are no longer needed case '1': { - if (is_networked) + /*if (is_networked) { // haydent start_server(); break; - } + }*/ } case '2': { - if (is_networked) + /*if (is_networked) { // haydent connect_client(); break; - } + }*/ } case '3': { - if (is_networked) + /*if (is_networked) { // haydent start_battle(); break; - } + }*/ } case '4': { - if (is_networked) + /*if (is_networked) { // haydent server_disconnect(); client_disconnect(); break; - } + }*/ } case '5': case '6': case '7': // WANNE: Only show the override panel when '7' is pressed - if (is_networked && InputEvent.usParam == '7') + /*if (is_networked && InputEvent.usParam == '7') { // haydent manual_overide(); break; - } + }*/ case '8': case '9': // multi-selects all characters in that squad. SHIFT key and 1-0 for squads 11-20 @@ -6818,6 +7446,15 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) fSAMSitesDisabledFromAttackingPlayer = !fSAMSitesDisabledFromAttackingPlayer; #endif } + // OJW - 20090208 + // Adding ingame chat + else + { + if (is_networked && is_client) + { + OpenChatMsgBox(); + } + } break; case 'z': @@ -6931,6 +7568,9 @@ void EndMapScreen( BOOLEAN fDuringFade ) // remove team panel sort button RemoveTeamPanelSortButtonsForMapScreen( ); + // OJW - 20081204 + if (is_networked) + RemoveMPButtonsForMapScreen( ); // for th merc insurance help text CreateDestroyInsuranceMouseRegionForMercs( FALSE ); @@ -6963,6 +7603,12 @@ void EndMapScreen( BOOLEAN fDuringFade ) // remove contract pop up box (always created upon mapscreen entry) RemoveBox(ghContractBox); ghContractBox = -1; + // OJW + if (is_networked) + { + DestroyMPCompassBox(); + DestroyMPTeamBox(); + } CreateDestroyAssignmentPopUpBoxes( ); CreateDestroyMilitiaControlPopUpBoxes( ); //lal @@ -7949,6 +8595,14 @@ void MAPInvClickCallback( MOUSE_REGION *pRegion, INT32 iReason ) UINT16 usOldItemIndex, usNewItemIndex; static BOOLEAN fRightDown = FALSE; + // OJW - 20090319 - fix merging bug on mapscreen + // If you left click a merge item such as EBR stock, then left click it on the item to merge, such as M-14... + // instead of right clicking (which is the correct action to merge) + // it will open an ItemDescriptionPanel, but then after that call PlaceObject, which performs a swap + // and overwites the gpItemDescObject pointer. Hence when the ItemDescriptionPanel is deleted + // it no longer references the right object, and does not necessarily free up all resources + // creating an error the next time it is called + bool bJustOpenedItemDescPanel = false; if (iReason & MSYS_CALLBACK_REASON_INIT) { @@ -8076,6 +8730,7 @@ void MAPInvClickCallback( MOUSE_REGION *pRegion, INT32 iReason ) // TOO PAINFUL TO DO!! --CC if ( !InItemDescriptionBox( ) ) { + bJustOpenedItemDescPanel = true; // OJW - 20090319 - fix merging on mapscreen - see top of function MAPInternalInitItemDescriptionBox( &(pSoldier->inv[ uiHandPos ]), 0, pSoldier ); } @@ -8110,6 +8765,8 @@ void MAPInvClickCallback( MOUSE_REGION *pRegion, INT32 iReason ) } // Else, try to place here + if ( !bJustOpenedItemDescPanel ) // OJW - 20090319 - fix merging on mapscreen - see top of function + { if ( PlaceObject( pSoldier, (UINT8)uiHandPos, gpItemPointer ) ) { @@ -8153,6 +8810,7 @@ void MAPInvClickCallback( MOUSE_REGION *pRegion, INT32 iReason ) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_ITEM_PASSED_TO_MERC ], ShortItemNames[ usNewItemIndex ], pSoldier->name ); } + } } } } @@ -8656,7 +9314,12 @@ void CreateMouseRegionsForTeamList( void ) // the info region...is the background for the list itself - for( sCounter = 0; sCounter < CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; sCounter++ ) + // OJW - MP + int max_rows = CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; + if (is_networked) + max_rows = 7; // check this value is correct / unhardcode it + + for( sCounter = 0; sCounter < max_rows; sCounter++ ) { if( sCounter >= FIRST_VEHICLE ) { @@ -8758,6 +9421,157 @@ void DestroyMouseRegionsForTeamList( void ) MSYS_RemoveRegion( &gTeamListContractRegion[ sCounter ]); } } +void MPReadyButtonCallback( GUI_BUTTON *btn, INT32 reason ) +{ + int iIndex = MSYS_GetBtnUserData(btn,0); + if (iIndex >= 1 || iIndex <= 4) + { + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + } + else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags &= ~(BUTTON_CLICKED_ON); + + if (iIndex == 3 || iIndex == 4) + { + // ready / start button was clicked + if (is_networked) + { + start_battle(); + } + } + else if (iIndex == 2) + { + // compass button clicked + if (!is_compass_box_open) + { + if (can_edgechange()) + { + // open the box + CreateDestroyMouseRegionsForCompassBox(); + ShowBox(ghMPCompassBox); + is_compass_box_open = true; + } + else if (allowlaptop) + { + // warn the user that cannot change once buying has commenced + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[3]); + } + } + else + { + // close the box + CreateDestroyMouseRegionsForCompassBox(); + HideBox(ghMPCompassBox); + is_compass_box_open = false; + fTeamPanelDirty = true; + } + + } + else if (iIndex == 1) + { + // team button clicked + if (!is_team_box_open) + { + if (can_teamchange()) + { + // open the box + CreateDestroyMouseRegionsForTeamBox(); + ShowBox(ghMPTeamBox); + is_team_box_open = true; + } + else if (allowlaptop) + { + // warn the user that cannot change once buying has commenced + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[4]); + } + else if (RANDOM_SPAWN) + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"Cannot change edge, the game is set to random spawn"); + } + } + else + { + // close the box + CreateDestroyMouseRegionsForTeamBox(); + HideBox(ghMPTeamBox); + is_team_box_open = false; + fTeamPanelDirty = true; + } + } + } + } + } + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); +} +void MPCompassChangeCallback( MOUSE_REGION * pReason, INT32 iReason) +{ + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + if (!is_compass_box_open) + { + if (can_edgechange()) + { + // open the box + CreateDestroyMouseRegionsForCompassBox(); + ShowBox(ghMPCompassBox); + is_compass_box_open = true; + } + else if (allowlaptop) + { + // warn the user that cannot change once buying has commenced + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[3]); + } + } + else + { + // close the box + CreateDestroyMouseRegionsForCompassBox(); + HideBox(ghMPCompassBox); + is_compass_box_open = false; + fTeamPanelDirty = true; + } + } +} +void MPTeamChangeCallback( MOUSE_REGION * pReason, INT32 iReason) +{ + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + if (!is_team_box_open) + { + if (can_teamchange()) + { + // open the box + CreateDestroyMouseRegionsForTeamBox(); + ShowBox(ghMPTeamBox); + is_team_box_open = true; + } + else if (allowlaptop) + { + // warn the user that cannot change once buying has commenced + ScreenMsg( FONT_LTBLUE, MSG_CHAT, gszMPMapscreenText[4]); + } + else if (RANDOM_SPAWN) + { + ScreenMsg( FONT_LTBLUE, MSG_CHAT, L"Cannot change edge, the game is set to random spawn"); + } + } + else + { + // close the box + CreateDestroyMouseRegionsForTeamBox(); + HideBox(ghMPTeamBox); + is_team_box_open = false; + fTeamPanelDirty = true; + } + } +} + +// OJW - End MP Mouse Regions and Callbacks // mask for mapscreen region @@ -10992,6 +11806,14 @@ void UpdateStatusOfMapSortButtons( void ) { HideButton( giMapSortButton[ iCounter ] ); } + // OJW - 20090210 - hide MP buttons here + if (is_networked) + { + for( iCounter = 0; iCounter < MAX_MP_BUTTONS; iCounter++ ) + { + HideButton( giMapMPButton[ iCounter ] ); + } + } if ( gfPreBattleInterfaceActive ) { HideButton( giCharInfoButton[ 0 ] ); @@ -11010,6 +11832,14 @@ void UpdateStatusOfMapSortButtons( void ) ShowButton( giMapSortButton[ iCounter ] ); } + // OJW - 20090210 - show MP buttons here + if (is_networked) + { + for( iCounter = 0; iCounter < MAX_MP_BUTTONS; iCounter++ ) + { + ShowButton( giMapMPButton[ iCounter ] ); + } + } ShowButton( giCharInfoButton[ 0 ] ); ShowButton( giCharInfoButton[ 1 ] ); @@ -11456,17 +12286,36 @@ BOOLEAN HandlePreloadOfMapGraphics( void ) CHECKF(AddVideoSurface( &vs_desc, &guiCHARLIST ));*/ VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; - if (iResolution == 0) + if (!is_networked) { - FilenameForBPP("INTERFACE\\newgoldpiece3.sti", VObjectDesc.ImageFile ); + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\newgoldpiece3.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\newgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\newgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + } } - else if (iResolution == 1) + else { - FilenameForBPP("INTERFACE\\newgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); - } - else if (iResolution == 2) - { - FilenameForBPP("INTERFACE\\newgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + // OJW - 20081204 - change mapscreen interface for MP games + if (iResolution == 0) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 1) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3_800x600.sti", VObjectDesc.ImageFile ); + } + else if (iResolution == 2) + { + FilenameForBPP("INTERFACE\\mpgoldpiece3_1024x768.sti", VObjectDesc.ImageFile ); + } } CHECKF(AddVideoObject(&VObjectDesc, &guiCHARLIST)); @@ -12089,8 +12938,41 @@ void AddTeamPanelSortButtonsForMapScreen( void ) return; } +void AddMPButtonsForMapScreen( void ) +{ + INT32 iCounter = 0; + //SGPFILENAME filename; + INT32 iImageIndex[ MAX_MP_BUTTONS+1 ] = { 0, 1, 3, 5 , 7 }; // sleep image is out or order (last) + INT32 iPressedIndex[ MAX_MP_BUTTONS+1 ] = { 0 , 2 , 4 , 6 , 8 }; + // add start game button and hide it... + for( iCounter = 0; iCounter < MAX_MP_BUTTONS+1; iCounter++ ) + { + giMapMPButtonImage[ iCounter ] = LoadButtonImage( "INTERFACE\\MPGOLDPIECEBUTTONS.STI", -1, iImageIndex[ iCounter ] , -1, iPressedIndex[ iCounter ] , -1 ); + + if (iCounter < MAX_MP_BUTTONS) + { + // buttonmake + giMapMPButton[ iCounter ]= QuickCreateButton( giMapMPButtonImage[ iCounter ], ( INT16 )( gMapMPButtonsX[ iCounter ] ), ( INT16 )( MP_BTN_Y ), + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 5, + (GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)MPReadyButtonCallback ); + + // so we can tell which button was clicked + MSYS_SetBtnUserData(giMapMPButton[ iCounter ], 0, iCounter ); + } + + //SetButtonFastHelpText( giMapSortButton[ iCounter ], wMapScreenSortButtonHelpText[ iCounter ] ); + } + + if ((is_server || is_host) && !allowlaptop) + { + // Server has 'Start game' button showing first if the game hasnt started + SpecifyButtonImage( giMapMPButton [3] , giMapMPButtonImage [4] ); + } + + return; +} void SortListOfMercsInTeamPanel( BOOLEAN fRetainSelectedMercs, BOOLEAN fReverse ) { INT32 iCounter = 0, iCounterA = 0; @@ -12428,6 +13310,22 @@ void RemoveTeamPanelSortButtonsForMapScreen( void ) return; } +void RemoveMPButtonsForMapScreen( void ) +{ + INT32 iCounter = 0; + + for( iCounter = 0; iCounter < MAX_MP_BUTTONS+1; iCounter++ ) + { + UnloadButtonImage( giMapMPButtonImage[ iCounter ] ); + + if(iCounter < MAX_MP_BUTTONS) + RemoveButton( giMapMPButton[ iCounter ] ); + + giMapMPButtonImage[ iCounter ] = -1; + giMapMPButton[ iCounter ] = -1; + } + return; +} void HandleCommonGlowTimer( ) { @@ -13661,7 +14559,8 @@ BOOLEAN CanMoveBullseyeAndClickedOnIt( INT16 sMapX, INT16 sMapY ) if (is_networked) { // haydent - if (!is_server && !is_client) + // OJW 080101 - allow map change before laptop unlock + if ((!is_server && !is_client) || (is_server && !allowlaptop)) { // if he clicked on the bullseye, and we're on the surface level if ( ( sMapX == gsMercArriveSectorX ) && ( sMapY == gsMercArriveSectorY ) && ( iCurrentMapSectorZ == 0 ) ) diff --git a/Strategic/mapscreen.h b/Strategic/mapscreen.h index de248330..e10a43d3 100644 --- a/Strategic/mapscreen.h +++ b/Strategic/mapscreen.h @@ -42,6 +42,7 @@ extern INT8 NUM_TOWNS; extern BOOLEAN fCharacterInfoPanelDirty; extern BOOLEAN fTeamPanelDirty; extern BOOLEAN fMapPanelDirty; +extern BOOLEAN fDrawCharacterList; // OJW - 20081204 extern BOOLEAN fMapInventoryItem; extern BOOLEAN gfInConfirmMapMoveMode; diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index e25a7ae0..34c4c7f0 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -6218,21 +6218,29 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) return( FALSE ); } - // We can only check for end of battle if in combat mode or there are enemies - // present (they might bleed to death or run off the map!) - if ( ! ( gTacticalStatus.uiFlags & INCOMBAT ) ) + // OJW - 090212 - Fix end conditions for multiplayer - TeamDM + if(is_server) { - if ( ! (gTacticalStatus.fEnemyInSector) ) + // check the server's conditions for continueing the game, if the server wants to continue the game it returns true + // hence we return false that the battle has ended. If not, when this function returns below we will force the game to end. + if ( check_status() ) + return(FALSE); + // the block of code below would always cause this function to exit before checking the servers desires + // in cases of team deathmatch where there were no more enemies + } + else + { + // We can only check for end of battle if in combat mode or there are enemies + // present (they might bleed to death or run off the map!) + if ( ! ( gTacticalStatus.uiFlags & INCOMBAT ) ) { - return( FALSE ); + if ( ! (gTacticalStatus.fEnemyInSector) ) + { + return( FALSE ); + } } } - if(is_server && check_status()) - { - return(FALSE); - } - // ATE: If attack busy count.. get out... if ( (gTacticalStatus.ubAttackBusyCount > 0 ) ) { @@ -6329,6 +6337,10 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) //Whenever returning TRUE, make sure you clear gfBlitBattleSectorLocator; LogBattleResults( LOG_DEFEAT ); gfBlitBattleSectorLocator = FALSE; + // If we are the server, we escape this function at the top if we think the game should still be running + // hence if we get here the game is over for all clients and we should report it + if (is_networked && is_server) + game_over(); return( TRUE ); } @@ -6438,11 +6450,15 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) { SetMusicMode( MUSIC_TACTICAL_VICTORY ); - ShouldBeginAutoBandage( ); + // OJW - 20081222 - dont auto-bandage if networked + if (!is_networked) + ShouldBeginAutoBandage( ); } else if ( gfLastMercTalkedAboutKillingID != NOBODY && ( MercPtrs[ gfLastMercTalkedAboutKillingID ]->flags.uiStatusFlags & SOLDIER_MONSTER ) ) { - ShouldBeginAutoBandage( ); + // OJW - 20081222 - dont auto-bandage if networked + if (!is_networked) + ShouldBeginAutoBandage( ); } // Say battle end quote.... @@ -6474,7 +6490,9 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) { // Change to nothing music... SetMusicMode( MUSIC_TACTICAL_NOTHING ); - ShouldBeginAutoBandage(); + // OJW - 20081222 - dont auto bandage if networked + if (!is_networked) + ShouldBeginAutoBandage(); } HandleMilitiaStatusInCurrentMapBeforeLoadingNewMap(); @@ -6550,8 +6568,16 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) if(gGameExternalOptions.gfRevealItems) RevealAllDroppedEnemyItems(); + // If we are the server, we escape this function at the top if we think the game should still be running + // hence if we get here the game is over for all clients and we should report it + if (is_networked && is_server) + game_over(); return( TRUE ); } + // If we are the server, we escape this function at the top if we think the game should still be running + // hence if we get here the game is over for all clients and we should report it + if (is_networked && is_server) + game_over(); return( FALSE ); } diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index 965013e8..cbe7272d 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -3692,6 +3692,13 @@ BOOLEAN CheckForAndHandleSoldierDyingNotFromHit( SOLDIERTYPE *pSoldier ) // Increment being attacked count // pSoldier->bBeingAttackedCount++; + // OJW - Send bleeding death + if (is_networked) + { + if(pSoldier->bTeam==0) send_death(pSoldier); + else if(pSoldier->bTeam <6 && ((gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE) || (gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE)))send_death(pSoldier); + else if (pSoldier->bTeam < 6 && (is_server)) send_death(pSoldier); + } if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] ) { switch( pSoldier->usAnimState ) diff --git a/Tactical/TeamTurns.cpp b/Tactical/TeamTurns.cpp index ae087a0c..d210c80d 100644 --- a/Tactical/TeamTurns.cpp +++ b/Tactical/TeamTurns.cpp @@ -530,8 +530,7 @@ void BeginTeamTurn( UINT8 ubTeam ) } break; } - else - if (ubTeam > 4 || (is_client && !is_server )) //hayden + else if (ubTeam > 4 || (is_client && !is_server )) //hayden { InitEnemyUIBar( 0, 0 ); diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index b7fe2b7f..4fbc2cbc 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -1643,7 +1643,14 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } } } - } + + // OJW - 090209 - ingame chat + if (InputEvent.usEvent == KEY_UP && InputEvent.usParam == 'y') + { + OpenChatMsgBox(); + continue; + } + } // end is_networked // Break of out IN CONV... diff --git a/Utils/Debug Control.cpp b/Utils/Debug Control.cpp index 21a5eac1..2a36a417 100644 --- a/Utils/Debug Control.cpp +++ b/Utils/Debug Control.cpp @@ -67,3 +67,13 @@ void LiveMessage( CHAR8 *strMessage) fclose(OutFile); } } +void MPDebugMsg( CHAR8 *strMessage) +{ + FILE *OutFile; + + if ((OutFile = fopen("MPDebug.txt", "a+t")) != NULL) + { + fprintf(OutFile, "%s\n", strMessage); + fclose(OutFile); + } +} diff --git a/Utils/Debug Control.h b/Utils/Debug Control.h index 257caaa7..8d562fa5 100644 --- a/Utils/Debug Control.h +++ b/Utils/Debug Control.h @@ -14,6 +14,7 @@ void LiveMessage( CHAR8 *strMessage); +void MPDebugMsg( CHAR8 *strMessage); #ifdef _ANIMSUBSYSTEM_DEBUG diff --git a/Utils/Text.h b/Utils/Text.h index 281cec0d..7d78b76b 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -1436,7 +1436,104 @@ enum }; extern STR16 gzGIOScreenText[]; +// OJW - 20081129 +// Multiplayer Join Screen +enum +{ + MPJ_TITLE_TEXT, + MPJ_JOIN_TEXT, + MPJ_HOST_TEXT, + MPJ_CANCEL_TEXT, + MPJ_REFRESH_TEXT, + MPJ_HANDLE_TEXT, + MPJ_SERVERIP_TEXT, + MPJ_SERVERPORT_TEXT, + MPJ_SERVERNAME_TEXT, + MPJ_NUMPLAYERS_TEXT, + MPJ_SERVERVER_TEXT, + MPJ_GAMETYPE_TEXT, + MPJ_PING_TEXT, + MPJ_HANDLE_INVALID, + MPJ_SERVERIP_INVALID, + MPJ_SERVERPORT_INVALID +}; +extern STR16 gzMPJScreenText[]; +//Multiplayer Host Screen +enum +{ + MPH_TITLE_TEXT, + MPH_START_TEXT, + MPH_CANCEL_TEXT, + MPH_SERVERNAME_TEXT, + MPH_GAMETYPE_TEXT, + MPH_DEATHMATCH_TEXT, + MPH_TEAMDM_TEXT, + MPH_COOP_TEXT, + MPH_NUMPLAYERS_TEXT, + MPH_SQUADSIZE_TEXT, + MPH_MERCSELECT_TEXT, + MPH_RANDOMMERCS_TEXT, + MPH_PLAYERMERCS_TEXT, + MPH_BALANCE_TEXT, + MPH_SAMEMERC_TEXT, + MPH_RPTMERC_TEXT, + MPH_BOBBYRAY_TEXT, + MPH_RNDMSTART_TEXT, + MPH_SERVERNAME_INVALID, + MPH_MAXPLAYERS_INVALID, + MPH_SQUADSIZE_INVALID, + MPH_TIME_TEXT, + MPH_TIME_INVALID, + MPH_CASH_INVALID, + MPH_DMG_TEXT, + MPH_DMG_INVALID, + MPH_TIMER_TEXT, + MPH_TIMER_INVALID, + MPH_ENABLECIV_TEXT, + MPH_USENIV_TEXT, +}; +extern STR16 gzMPHScreenText[]; +enum +{ + MPS_TITLE_TEXT, + MPS_CONTINUE_TEXT, + MPS_CANCEL_TEXT, + MPS_PLAYER_TEXT, + MPS_KILLS_TEXT, + MPS_DEATHS_TEXT, + MPS_AITEAM_TEXT, + MPS_HITS_TEXT, + MPS_MISSES_TEXT, + MPS_ACCURACY_TEXT, + MPS_DMGDONE_TEXT, + MPS_DMGTAKEN_TEXT, +}; +extern STR16 gzMPSScreenText[]; +// Multiplayer Starting Edges +enum +{ + MP_EDGE_NORTH, + MP_EDGE_SOUTH, + MP_EDGE_EAST, + MP_EDGE_WEST, + MAX_EDGES, +}; +extern STR16 gszMPEdgesText[]; +// MP TEAM NAMES +enum +{ + MP_TEAM_1, + MP_TEAM_2, + MP_TEAM_3, + MP_TEAM_4, + MAX_MP_TEAMS, +}; +extern STR16 gszMPTeamNames[]; + +extern STR16 gzMPChatToggleText[]; + +extern STR16 gzMPChatboxText[]; enum { @@ -1608,4 +1705,6 @@ enum NIV_NO_CLIMB, }; +// OJW - MP +extern STR16 gszMPMapscreenText[]; #endif diff --git a/Utils/Timer Control.h b/Utils/Timer Control.h index 2e1b29f2..777ed2d0 100644 --- a/Utils/Timer Control.h +++ b/Utils/Timer Control.h @@ -82,6 +82,7 @@ void CheckCustomizableTimer( void ); //Don't modify this value extern UINT32 guiBaseJA2Clock; +extern UINT32 guiBaseJA2NoPauseClock; extern CUSTOMIZABLE_TIMER_CALLBACK gpCustomizableTimerCallback; // MACROS diff --git a/Utils/Utilities.cpp b/Utils/Utilities.cpp index acb3709f..818304aa 100644 --- a/Utils/Utilities.cpp +++ b/Utils/Utilities.cpp @@ -371,6 +371,7 @@ UINT32 gCheckFileMinSizes[] = 187000000, 236000000 }; +#define NOCDCHECK #if defined( JA2TESTVERSION ) || defined( _DEBUG ) #define NOCDCHECK diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 7e596738..1ff659cf 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -4572,6 +4572,60 @@ STR16 gzGIOScreenText[] = L"游戏初始设置(仅在服务器设置时有效)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"奥斯汀", //"Austin", //Austin, Texas, USA @@ -5477,6 +5531,22 @@ STR16 MPClientMessage[] = L"你已被击败!", L"对不起, 在多人游戏中无法攀登。", L"你雇佣了 '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -5504,6 +5574,62 @@ STR16 MPHelp[] = L"'F1' - 显示基本帮助", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + // WANNE: Some Chinese specific strings that needs to be in unicode! STR16 ChineseSpecString1 = L"%%"; //defined in _ChineseText.cpp as this file is already unicode STR16 ChineseSpecString2 = L"*%3d%%%%"; //defined in _ChineseText.cpp as this file is already unicode diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 2b4ad606..b292a98f 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -3797,6 +3797,60 @@ STR16 gzGIOScreenText[] = L"INITIAL GAME SETTINGS (Only the server settings take effect)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4530,6 +4584,22 @@ STR16 MPClientMessage[] = L"You have been defeated!", L"Sorry, climbing is disable in MP", L"You Hired '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4557,4 +4627,60 @@ STR16 MPHelp[] = L"'F1' - Display primary help", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //DUTCH diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 4d7892fc..181d0f22 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -3810,6 +3810,60 @@ STR16 gzGIOScreenText[] = L"INITIAL GAME SETTINGS (Only the server settings take effect)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4543,6 +4597,22 @@ STR16 MPClientMessage[] = L"You have been defeated!", L"Sorry, climbing is disable in MP", L"You Hired '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4570,4 +4640,59 @@ STR16 MPHelp[] = L"'F1' - Display primary help", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; #endif //ENGLISH diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 78388be1..9f33b34a 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -3811,6 +3811,60 @@ STR16 gzGIOScreenText[] = L"CONFIGURATION DU JEU (Les paramtres serveur seulement prennent effet)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4544,6 +4598,22 @@ STR16 MPClientMessage[] = L"You have been defeated!", L"Sorry, climbing is disable in MP", L"You Hired '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4571,4 +4641,60 @@ STR16 MPHelp[] = L"'F1' - Display primary help", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //FRENCH diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index cd22b377..abf6291a 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -3615,6 +3615,60 @@ STR16 gzGIOScreenText[] = L"GRUNDEINSTELLUNGEN (Nur Servereinstellungen werden verwendet)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4343,6 +4397,22 @@ STR16 MPClientMessage[] = L"Sie wurden besiegt!", L"Auf Dcher klettern ist nicht erlaubt in einem Mehrspieler Spiel", L"Sie haben '%s' angeheuert.", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4370,4 +4440,60 @@ STR16 MPHelp[] = L"'F1' - Anzeige der primren Hilfe", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //GERMAN diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 9a211254..333818b9 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -3790,6 +3790,60 @@ STR16 gzGIOScreenText[] = L"INITIAL GAME SETTINGS (Only the server settings take effect)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4528,6 +4582,22 @@ STR16 MPClientMessage[] = L"You have been defeated!", L"Sorry, climbing is disable in MP", L"You Hired '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4555,4 +4625,60 @@ STR16 MPHelp[] = L"'F1' - Display primary help", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //ITALIAN diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index b83fc856..2e348a50 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -3803,6 +3803,60 @@ STR16 gzGIOScreenText[] = L"POCZTKOWE USTAWIENIA GRY (Only the server settings take effect)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4535,6 +4589,22 @@ STR16 MPClientMessage[] = L"Zostae pokonany!", L"Wspinanie wyczone w MP", L"Wynajto '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4562,4 +4632,60 @@ STR16 MPHelp[] = L"'F1' - Wywietl 1. pomoc", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //POLISH diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 4b167316..3b13e8c4 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -3805,6 +3805,60 @@ STR16 gzGIOScreenText[] = L" ( )", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"", //Austin, Texas, USA @@ -4539,6 +4593,22 @@ STR16 MPClientMessage[] = L" !", L", .", L" %s.", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4566,4 +4636,60 @@ STR16 MPHelp[] = L"'F1' - .", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //RUSSIAN diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index 739f3bdd..d2b3221d 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -3810,6 +3810,60 @@ STR16 gzGIOScreenText[] = L"INITIAL GAME SETTINGS (Only the server settings take effect)", }; +STR16 gzMPJScreenText[] = +{ + L"MULTIPLAYER", + L"Join", + L"Host", + L"Cancel", + L"Refresh", + L"Player Name", + L"Server IP", + L"Port", + L"Server Name", + L"# Plrs", + L"Version", + L"Game Type", + L"Ping", + L"You must enter a player name", + L"You must enter a valid server IP address.\n (eg 192.168.0.1)", + L"You must enter a valid Server Port between 1 and 65535" +}; + +STR16 gzMPHScreenText[] = +{ + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team Deathmatch", + L"Co-operative", + L"Max Players", + L"Squad Size", + L"Merc Selection", + L"Random Mercs", + L"Hired by Player", + L"Starting Balance", + L"Can Hire Same Merc", + L"Report Hired Mercs", + L"Allow Bobby Rays", + L"Randomise Starting Edge", + L"You must enter a server name", + L"Max Players must be between 2 and 4", + L"Squad size must be between 1 and 6", + L"Time of Day", + L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", + L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , + L"Damage Multiplier", + L"Damage Multiplier must be a number between 0 and 5", + L"Turn Timer Multiplier", + L"Turn Timer multiplier must be a number between 1 and 200", + L"Enable Civilians in CO-OP", + L"Use New Inventory (NIV)", +}; + STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA @@ -4542,6 +4596,22 @@ STR16 MPClientMessage[] = L"You have been defeated!", L"Sorry, climbing is disable in MP", L"You Hired '%s'", + // 45 + L"You cant change the map once purchasing has commenced", + L"Map changed to '%s'", + L"Client '%s' disconnected, removing from game", + L"You were disconnected from the game, returning to the Main Menu", + L"Connection failed, Retrying in 5 seconds, %i retries left...", + //50 + L"Connection failed, giving up...", + L"You cannot start the game until another player has connected", + L"%s : %s", + L"Send to All", + L"Allies only", + // 55 + L"Cannot join game. This game has already started.", + L"%s (team): %s", + L"Client #%i - '%s'", }; STR16 MPHelp[] = @@ -4569,4 +4639,60 @@ STR16 MPHelp[] = L"'F1' - Display primary help", }; +STR16 gszMPEdgesText[] = +{ + L"N", + L"S", + L"E", + L"W" +}; + +STR16 gszMPTeamNames[] = +{ + L"Foxtrot", + L"Bravo", + L"Delta", + L"Charlie" +}; + +STR16 gszMPMapscreenText[] = +{ + L"Game Type: ", + L"Players: ", + L"Mercs each: ", + L"You cannot change starting edge once Laptop is unlocked", + L"You cannot change teams once the Laptop is unlocked", + L"Random Mercs: ", + L"Y", + L"Difficulty:" +}; + +STR16 gzMPSScreenText[] = +{ + L"Scoreboard", + L"Continue", + L"Cancel", + L"Player", + L"Kills", + L"Deaths", + L"Queen's Army", + L"Hits", + L"Misses", + L"Accuracy", + L"Damage Dealt", + L"Damage Taken" +}; + +STR16 gzMPChatToggleText[] = +{ + L"Send to All", + L"Send to Allies only", +}; + +STR16 gzMPChatboxText[] = +{ + L"Multiplayer Chat", + L"Chat: press ENTER to send of ESC to cancel", +}; + #endif //TAIWANESE diff --git a/Utils/message.h b/Utils/message.h index 85b84594..d8aeedca 100644 --- a/Utils/message.h +++ b/Utils/message.h @@ -69,6 +69,15 @@ UINT8 GetRangeOfMapScreenMessages( void ); void EnableDisableScrollStringVideoOverlay( BOOLEAN fEnable ); +// OJW - 20090315 - Allow access to these functions outside of message +// adding chat log +ScrollStringStPtr GetNextString(ScrollStringStPtr pStringSt); +ScrollStringStPtr GetPrevString(ScrollStringStPtr pStringSt); +void SetStringPosition(ScrollStringStPtr pStringSt, UINT16 x, UINT16 y); +void SetStringColor(ScrollStringStPtr pStringSt, UINT16 color); +ScrollStringStPtr SetStringNext(ScrollStringStPtr pStringSt, ScrollStringStPtr pNext); +ScrollStringStPtr SetStringPrev(ScrollStringStPtr pStringSt, ScrollStringStPtr pPrev); +void SetString(ScrollStringStPtr pStringSt, STR16 String); // will go and clear all displayed strings off the screen void ClearDisplayedListOfTacticalStrings( void ); diff --git a/gameloop.cpp b/gameloop.cpp index cecb9fe1..21599f48 100644 --- a/gameloop.cpp +++ b/gameloop.cpp @@ -56,6 +56,7 @@ extern BOOLEAN gfTacticalPlacementGUIActive; extern BOOLEAN gfTacticalPlacementGUIDirty; extern BOOLEAN gfValidLocationsChanged; extern BOOLEAN gfInMsgBox; +extern BOOLEAN gfInChatBox; // OJW - 20090314 - new chatbox extern void InitSightRange(); //lal @@ -152,7 +153,10 @@ BOOLEAN InitializeGame(void) //InitGameOptions(); // preload mapscreen graphics - HandlePreloadOfMapGraphics( ); + // OJW - Temporarily disabliing this as is_networked is not set up yet + // see if there is a better place we can pre-load the gfx if nessesary + // or perhaps just reload the bits that will change + //HandlePreloadOfMapGraphics( ); guiCurrentScreen = INIT_SCREEN; @@ -300,6 +304,11 @@ void GameLoop(void) guiPendingScreen = MSG_BOX_SCREEN; } + // OJW - 20090314 - new chatbox + if (gfInChatBox) + { + guiPendingScreen = MP_CHAT_SCREEN; + } if ( guiPendingScreen != NO_PENDING_SCREEN ) { // Based on active screen, deinit! @@ -308,7 +317,7 @@ void GameLoop(void) switch( guiCurrentScreen ) { case MAP_SCREEN: - if( guiPendingScreen != MSG_BOX_SCREEN ) + if( guiPendingScreen != MSG_BOX_SCREEN && guiPendingScreen != MP_CHAT_SCREEN ) { EndMapScreen( FALSE ); } @@ -411,7 +420,7 @@ extern UINT32 guiRainLoop; void HandleNewScreenChange( UINT32 uiNewScreen, UINT32 uiOldScreen ) { //if we are not going into the message box screen, and we didnt just come from it - if( ( uiNewScreen != MSG_BOX_SCREEN && uiOldScreen != MSG_BOX_SCREEN ) ) + if( ( uiNewScreen != MSG_BOX_SCREEN && uiOldScreen != MSG_BOX_SCREEN && uiNewScreen != MP_CHAT_SCREEN && uiOldScreen != MP_CHAT_SCREEN ) ) { //reset the help screen NewScreenSoResetHelpScreen( ); diff --git a/gamescreen.cpp b/gamescreen.cpp index 0b329622..e24aba5d 100644 --- a/gamescreen.cpp +++ b/gamescreen.cpp @@ -654,7 +654,7 @@ UINT32 MainGameScreenHandle(void) return( GAME_SCREEN ); } - if ( guiCurrentScreen != MSG_BOX_SCREEN ) + if ( guiCurrentScreen != MSG_BOX_SCREEN && guiCurrentScreen != MP_CHAT_SCREEN ) { if ( HandleBeginFadeOut( GAME_SCREEN ) ) { diff --git a/ja2_2005Express.vcproj b/ja2_2005Express.vcproj index a163fc06..987fbb9c 100644 --- a/ja2_2005Express.vcproj +++ b/ja2_2005Express.vcproj @@ -66,7 +66,7 @@ + + + + + + + + @@ -550,6 +566,22 @@ RelativePath=".\MessageBoxScreen.h" > + + + + + + + + diff --git a/ja2_VS2008.vcproj b/ja2_VS2008.vcproj index ecfea221..0420a83f 100644 --- a/ja2_VS2008.vcproj +++ b/ja2_VS2008.vcproj @@ -435,6 +435,22 @@ RelativePath="MessageBoxScreen.h" > + + + + + + + + @@ -597,6 +613,22 @@ RelativePath="MessageBoxScreen.cpp" > + + + + + + + + diff --git a/jascreens.h b/jascreens.h index 265ed9f7..33ccbab3 100644 --- a/jascreens.h +++ b/jascreens.h @@ -118,6 +118,24 @@ extern UINT32 CreditScreenInit( void ); extern UINT32 CreditScreenHandle( void ); extern UINT32 CreditScreenShutdown( void ); +// OJW - 20081129 +extern UINT32 MPJoinScreenInit( void ); +extern UINT32 MPJoinScreenHandle( void ); +extern UINT32 MPJoinScreenShutdown( void ); + +extern UINT32 MPHostScreenInit( void ); +extern UINT32 MPHostScreenHandle( void ); +extern UINT32 MPHostScreenShutdown( void ); + +// OJW - 20081222 +extern UINT32 MPScoreScreenInit( void ); +extern UINT32 MPScoreScreenHandle( void ); +extern UINT32 MPScoreScreenShutdown( void ); + +// OJW - 20090314 +extern UINT32 MPChatScreenInit( void ); +extern UINT32 MPChatScreenHandle( void ); +extern UINT32 MPChatScreenShutdown( void ); // External functions void DisplayFrameRate( ); diff --git a/screenids.h b/screenids.h index 67168194..7e7f86a1 100644 --- a/screenids.h +++ b/screenids.h @@ -28,6 +28,10 @@ typedef enum ScreenTypes DEMO_EXIT_SCREEN, INTRO_SCREEN, CREDIT_SCREEN, + MP_JOIN_SCREEN, // OJW - 20081129 + MP_HOST_SCREEN, + MP_SCORE_SCREEN, // OJW - 20081222 + MP_CHAT_SCREEN, // OJW - 20090315 #ifdef JA2BETAVERSION AIVIEWER_SCREEN,